123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- """
- @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
- import six
- from core.settings import UserSettings
- from core.gcmd import GError
- from gui_core.wrap import StockCursor
- 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")
- self._useDefinedProjection = False
- self.useDefinedProjectionChanged = Signal(
- "MapWindowProperties.useDefinedProjectionChanged"
- )
- self._sbItem = None
- self.sbItemChanged = Signal("MapWindowProperties.sbItemChanged")
- 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)
- @property
- def useDefinedProjection(self):
- return self._useDefinedProjection
- @useDefinedProjection.setter
- def useDefinedProjection(self, value):
- if value != self._useDefinedProjection:
- self._useDefinedProjection = value
- self.useDefinedProjectionChanged.emit(value=value)
- @property
- def epsg(self):
- return UserSettings.Get(group="projection", key="statusbar", subkey="epsg")
- @property
- def sbItem(self):
- return self._sbItem
- @sbItem.setter
- def sbItem(self, mode):
- if mode != self._sbItem:
- self._sbItem = mode
- self.sbItemChanged.emit(mode=mode)
- 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.overlayRemoved = Signal("MapWindow.overlayRemoved")
- # 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": StockCursor(cursorId=wx.CURSOR_ARROW),
- "cross": StockCursor(cursorId=wx.CURSOR_CROSS),
- "hand": StockCursor(cursorId=wx.CURSOR_HAND),
- "pencil": StockCursor(cursorId=wx.CURSOR_PENCIL),
- "sizenwse": StockCursor(cursorId=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 six.iteritems(self.handlersContainer):
- 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
- @deprecated This method is deprecated. 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
- interesting 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 six.iteritems(self.handlersContainer):
- 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
- @deprecated This method is deprecated. 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 six.iteritems(self.handlersContainer):
- 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
- @deprecated This method is deprecated. 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 six.iteritems(self.handlersContainer):
- 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.GetPosition())
- except (ValueError):
- self.lastEN = None
- event.Skip()
- def GetLastEN(self):
- """Returns last coordinates of mouse cursor.
- @deprecated This method is deprecated. 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()
|