123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- """
- @package mapwin.mapwindow
- @brief Map display canvas basic functionality - base class and properties.
- Classes:
- - mapwindow::MapWindowProperties
- - mapwindow::MapWindowBase
- (C) 2006-2012 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Martin Landa <landa.martin gmail.com>
- @author Michael Barton
- @author Jachym Cepicky
- @author Vaclav Petras <wenzeslaus gmail.com> (handlers support)
- @author Stepan Turek <stepan.turek seznam.cz> (handlers support)
- """
- import wx
- from core.settings import UserSettings
- from core.gcmd import GError
- from core.utils import _
- from grass.script import core as grass
- from grass.pydispatch.signal import Signal
- class MapWindowProperties(object):
- def __init__(self):
- self._resolution = None
- self.resolutionChanged = Signal('MapWindowProperties.resolutionChanged')
- self._autoRender = None
- self.autoRenderChanged = Signal('MapWindowProperties.autoRenderChanged')
- self._showRegion = None
- self.showRegionChanged = Signal('MapWindowProperties.showRegionChanged')
- self._alignExtent = None
- self.alignExtentChanged = Signal('MapWindowProperties.alignExtentChanged')
- def setValuesFromUserSettings(self):
- """Convenient function to get values from user settings into this object."""
- self._resolution = UserSettings.Get(group='display',
- key='compResolution',
- subkey='enabled')
- self._autoRender = UserSettings.Get(group='display',
- key='autoRendering',
- subkey='enabled')
- self._showRegion = False # in statusbar.py was not from settings
- self._alignExtent = UserSettings.Get(group='display',
- key='alignExtent',
- subkey='enabled')
- @property
- def resolution(self):
- return self._resolution
- @resolution.setter
- def resolution(self, value):
- if value != self._resolution:
- self._resolution = value
- self.resolutionChanged.emit(value=value)
- @property
- def autoRender(self):
- return self._autoRender
- @autoRender.setter
- def autoRender(self, value):
- if value != self._autoRender:
- self._autoRender = value
- self.autoRenderChanged.emit(value=value)
- @property
- def showRegion(self):
- return self._showRegion
- @showRegion.setter
- def showRegion(self, value):
- if value != self._showRegion:
- self._showRegion = value
- self.showRegionChanged.emit(value=value)
- @property
- def alignExtent(self):
- return self._alignExtent
- @alignExtent.setter
- def alignExtent(self, value):
- if value != self._alignExtent:
- self._alignExtent = value
- self.alignExtentChanged.emit(value=value)
- class MapWindowBase(object):
- """Abstract map display window class
- Superclass for BufferedWindow class (2D display mode), and GLWindow
- (3D display mode).
- Subclasses have to define
- - _bindMouseEvents method which binds MouseEvent handlers
- - Pixel2Cell
- - Cell2Pixel (if it is possible)
- """
- def __init__(self, parent, giface, Map):
- self.parent = parent
- self.Map = Map
- self._giface = giface
- # Emitted when someone registers as mouse event handler
- self.mouseHandlerRegistered = Signal('MapWindow.mouseHandlerRegistered')
- # Emitted when mouse event handler is unregistered
- self.mouseHandlerUnregistered = Signal('MapWindow.mouseHandlerUnregistered')
- # emitted after double click in pointer mode on legend, text, scalebar
- self.overlayActivated = Signal('MapWindow.overlayActivated')
- # emitted when overlay should be hidden
- self.overlayHidden = Signal('MapWindow.overlayHidden')
- # mouse attributes -- position on the screen, begin and end of
- # dragging, and type of drawing
- self.mouse = {
- 'begin': [0, 0], # screen coordinates
- 'end' : [0, 0],
- 'use' : "pointer",
- 'box' : "point"
- }
- # last east, north coordinates, changes on mouse motion
- self.lastEN = None
- # stores overridden cursor
- self._overriddenCursor = None
- # dictionary where event types are stored as keys and lists of
- # handlers for these types as values
- self.handlersContainer = {
- wx.EVT_LEFT_DOWN : [],
- wx.EVT_LEFT_UP : [],
- wx.EVT_LEFT_DCLICK : [],
- wx.EVT_MIDDLE_DOWN : [],
- wx.EVT_MIDDLE_UP : [],
- wx.EVT_MIDDLE_DCLICK : [],
- wx.EVT_RIGHT_DOWN : [],
- wx.EVT_RIGHT_UP : [],
- wx.EVT_RIGHT_DCLICK : [],
- wx.EVT_MOTION : [],
- wx.EVT_ENTER_WINDOW : [],
- wx.EVT_LEAVE_WINDOW : [],
- wx.EVT_MOUSEWHEEL : [],
- wx.EVT_MOUSE_EVENTS : []
- }
- # available cursors
- self._cursors = {
- "default": wx.StockCursor(wx.CURSOR_ARROW),
- "cross": wx.StockCursor(wx.CURSOR_CROSS),
- "hand": wx.StockCursor(wx.CURSOR_HAND),
- "pencil": wx.StockCursor(wx.CURSOR_PENCIL),
- "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
- }
- # default cursor for window is arrow (at least we rely on it here)
- # but we need to define attribute here
- # cannot call SetNamedCursor since it expects the instance
- # to be a wx window, so setting only the attribute
- self._cursor = 'default'
- wx.CallAfter(self.InitBinding)
- def __del__(self):
- self.UnregisterAllHandlers()
- def InitBinding(self):
- """Binds helper functions, which calls all handlers
- registered to events with the events
- """
- for ev, handlers in self.handlersContainer.iteritems():
- self.Bind(ev, self.EventTypeHandler(handlers))
- def EventTypeHandler(self, evHandlers):
- return lambda event : self.HandlersCaller(event, evHandlers)
- def HandlersCaller(self, event, handlers):
- """Hepler function which calls all handlers registered for
- event
- """
- for handler in handlers:
- try:
- handler(event)
- except:
- handlers.remove(handler)
- GError(parent=self,
- message=_("Error occurred during calling of handler: %s \n"
- "Handler was unregistered.") % handler.__name__)
- event.Skip()
- def RegisterMouseEventHandler(self, event, handler, cursor=None):
- """Binds event handler
- @depreciated This method is depreciated. Use Signals or drawing API
- instead. Signals do not cover all events but new Signals can be added
- when needed consider also adding generic signal. However, more
- interesing and useful is higher level API to create objects, graphics etc.
- Call event.Skip() in handler to allow default processing in MapWindow.
- If any error occurs inside of handler, the handler is removed.
- Before handler is unregistered it is called with
- string value "unregistered" of event parameter.
- ::
- # your class methods
- def OnButton(self, event):
- # current map display's map window
- # expects LayerManager to be the parent
- self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
- if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
- 'cross'):
- self.parent.GetLayerTree().GetMapDisplay().Raise()
- else:
- # handle that you cannot get coordinates
- def OnMouseAction(self, event):
- # get real world coordinates of mouse click
- coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
- self.text.SetLabel('Coor: ' + str(coor))
- self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction)
- event.Skip()
- Emits mouseHandlerRegistered signal before handler is registered.
- :param event: one of mouse events
- :param handler: function to handle event
- :param cursor: cursor which temporary overrides current cursor
- :return: True if successful
- :return: False if event cannot be bind
- """
- self.mouseHandlerRegistered.emit()
- # inserts handler into list
- for containerEv, handlers in self.handlersContainer.iteritems():
- if event == containerEv:
- handlers.append(handler)
-
- self.mouse['useBeforeGenericEvent'] = self.mouse['use']
- self.mouse['use'] = 'genericEvent'
-
- if cursor:
- self._overriddenCursor = self.GetNamedCursor()
- self.SetNamedCursor(cursor)
-
- return True
- def UnregisterAllHandlers(self):
- """Unregisters all registered handlers
- @depreciated This method is depreciated. Use Signals or drawing API instead.
- Before each handler is unregistered it is called with string
- value "unregistered" of event parameter.
- """
- for containerEv, handlers in self.handlersContainer.iteritems():
- for handler in handlers:
- try:
- handler("unregistered")
- handlers.remove(handler)
- except:
- GError(parent = self,
- message = _("Error occurred during unregistration of handler: %s \n \
- Handler was unregistered.") % handler.__name__)
- handlers.remove(handler)
-
- def UnregisterMouseEventHandler(self, event, handler):
- """Unbinds event handler for event
- @depreciated This method is depreciated. Use Signals or drawing API instead.
- Before handler is unregistered it is called with string value
- "unregistered" of event parameter.
- Emits mouseHandlerUnregistered signal after handler is unregistered.
- :param handler: handler to unbind
- :param event: event from which handler will be unbinded
-
- :return: True if successful
- :return: False if event cannot be unbind
- """
- # removes handler from list
- for containerEv, handlers in self.handlersContainer.iteritems():
- if event != containerEv:
- continue
- try:
- handler("unregistered")
- if handler in handlers:
- handlers.remove(handler)
- else:
- grass.warning(_("Handler: %s was not registered") \
- % handler.__name__)
- except:
- GError(parent = self,
- message = _("Error occurred during unregistration of handler: %s \n \
- Handler was unregistered") % handler.__name__)
- handlers.remove(handler)
-
- # restore mouse use (previous state)
- self.mouse['use'] = self.mouse['useBeforeGenericEvent']
-
- # restore overridden cursor
- if self._overriddenCursor:
- self.SetNamedCursor(self._overriddenCursor)
- self.mouseHandlerUnregistered.emit()
- return True
-
- def Pixel2Cell(self, xyCoords):
- raise NotImplementedError()
-
- def Cell2Pixel(self, enCoords):
- raise NotImplementedError()
- def OnMotion(self, event):
- """Tracks mouse motion and update statusbar
- .. todo::
- remove this method when lastEN is not used
- :func:`GetLastEN`
- """
- try:
- self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
- except (ValueError):
- self.lastEN = None
- event.Skip()
- def GetLastEN(self):
- """Returns last coordinates of mouse cursor.
- @depreciated This method is depreciated. Use Signal with coordinates as parameters.
- :func:`OnMotion`
- """
- return self.lastEN
- def SetNamedCursor(self, cursorName):
- """Sets cursor defined by name."""
- cursor = self._cursors[cursorName]
- self.SetCursor(cursor)
- self._cursor = cursorName
- def GetNamedCursor(self):
- """Returns current cursor name."""
- return self._cursor
- cursor = property(fget=GetNamedCursor, fset=SetNamedCursor)
- def SetModePointer(self):
- """Sets mouse mode to pointer."""
- self.mouse['use'] = 'pointer'
- self.mouse['box'] = 'point'
- self.SetNamedCursor('default')
- def SetModePan(self):
- """Sets mouse mode to pan."""
- self.mouse['use'] = "pan"
- self.mouse['box'] = "box"
- self.zoomtype = 0
- self.SetNamedCursor('hand')
- def SetModeZoomIn(self):
- self._setModeZoom(zoomType=1)
- def SetModeZoomOut(self):
- self._setModeZoom(zoomType=-1)
- def _setModeZoom(self, zoomType):
- self.zoomtype = zoomType
- self.mouse['use'] = "zoom"
- self.mouse['box'] = "box"
- self.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
- self.SetNamedCursor('cross')
- def SetModeDrawRegion(self):
- self.mouse['use'] = 'drawRegion'
- self.mouse['box'] = "box"
- self.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
- self.SetNamedCursor('cross')
- def SetModeQuery(self):
- """Query mode on"""
- self.mouse['use'] = "query"
- self.mouse['box'] = "point"
- self.zoomtype = 0
- self.SetNamedCursor('cross')
- def DisactivateWin(self):
- """Use when the class instance is hidden in MapFrame."""
- raise NotImplementedError()
- def ActivateWin(self):
- """Used when the class instance is activated in MapFrame."""
- raise NotImplementedError()
|