mapwindow.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. """!
  2. @package gui_core.mapwindow
  3. @brief Map display canvas - base class for buffered window.
  4. Classes:
  5. - mapwindow::MapWindow
  6. (C) 2006-2012 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Martin Landa <landa.martin gmail.com>
  10. @author Michael Barton
  11. @author Jachym Cepicky
  12. @author Vaclav Petras <wenzeslaus gmail.com> (handlers support)
  13. @author Stepan Turek <stepan.turek seznam.cz> (handlers support)
  14. """
  15. import wx
  16. from core.settings import UserSettings
  17. from core.gcmd import GError
  18. from grass.script import core as grass
  19. class MapWindow(object):
  20. """!Abstract map display window class
  21. Superclass for BufferedWindow class (2D display mode), and GLWindow
  22. (3D display mode).
  23. Subclasses have to define
  24. - _bindMouseEvents method which binds MouseEvent handlers
  25. - Pixel2Cell
  26. - Cell2Pixel (if it is possible)
  27. """
  28. def __init__(self, parent, giface, Map, frame, **kwargs):
  29. self.parent = parent
  30. self.Map = Map
  31. self.frame = frame
  32. self._giface = giface
  33. # mouse attributes -- position on the screen, begin and end of
  34. # dragging, and type of drawing
  35. self.mouse = {
  36. 'begin': [0, 0], # screen coordinates
  37. 'end' : [0, 0],
  38. 'use' : "pointer",
  39. 'box' : "point"
  40. }
  41. # last east, north coordinates, changes on mouse motion
  42. self.lastEN = None
  43. # stores overridden cursor
  44. self._overriddenCursor = None
  45. # dictionary where event types are stored as keys and lists of
  46. # handlers for these types as values
  47. self.handlersContainer = {
  48. wx.EVT_LEFT_DOWN : [],
  49. wx.EVT_LEFT_UP : [],
  50. wx.EVT_LEFT_DCLICK : [],
  51. wx.EVT_MIDDLE_DOWN : [],
  52. wx.EVT_MIDDLE_UP : [],
  53. wx.EVT_MIDDLE_DCLICK : [],
  54. wx.EVT_RIGHT_DOWN : [],
  55. wx.EVT_RIGHT_UP : [],
  56. wx.EVT_RIGHT_DCLICK : [],
  57. wx.EVT_MOTION : [],
  58. wx.EVT_ENTER_WINDOW : [],
  59. wx.EVT_LEAVE_WINDOW : [],
  60. wx.EVT_MOUSEWHEEL : [],
  61. wx.EVT_MOUSE_EVENTS : []
  62. }
  63. wx.CallAfter(self.InitBinding)
  64. def __del__(self):
  65. self.UnregisterAllHandlers()
  66. def InitBinding(self):
  67. """!Binds helper functions, which calls all handlers
  68. registered to events with the events
  69. """
  70. for ev, handlers in self.handlersContainer.iteritems():
  71. self.Bind(ev, self.EventTypeHandler(handlers))
  72. def EventTypeHandler(self, evHandlers):
  73. return lambda event:self.HandlersCaller(event, evHandlers)
  74. def HandlersCaller(self, event, handlers):
  75. """!Hepler function which calls all handlers registered for
  76. event
  77. """
  78. for handler in handlers:
  79. try:
  80. handler(event)
  81. except:
  82. handlers.remove(handler)
  83. GError(parent = self,
  84. message=_("Error occured during calling of handler: %s \n"
  85. "Handler was unregistered.") % handler.__name__)
  86. event.Skip()
  87. def RegisterMouseEventHandler(self, event, handler, cursor = None):
  88. """!Binds event handler
  89. Call event.Skip() in handler to allow default processing in MapWindow.
  90. If any error occures inside of handler, the handler is removed.
  91. Before handler is unregistered it is called with
  92. string value "unregistered" of event parameter.
  93. @code
  94. # your class methods
  95. def OnButton(self, event):
  96. # current map display's map window
  97. # expects LayerManager to be the parent
  98. self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
  99. if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
  100. wx.StockCursor(wx.CURSOR_CROSS)):
  101. self.parent.GetLayerTree().GetMapDisplay().Raise()
  102. else:
  103. # handle that you cannot get coordinates
  104. def OnMouseAction(self, event):
  105. # get real world coordinates of mouse click
  106. coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
  107. self.text.SetLabel('Coor: ' + str(coor))
  108. self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction)
  109. event.Skip()
  110. @endcode
  111. @param event one of mouse events
  112. @param handler function to handle event
  113. @param cursor cursor which temporary overrides current cursor
  114. @return True if successful
  115. @return False if event cannot be bind
  116. """
  117. # inserts handler into list
  118. for containerEv, handlers in self.handlersContainer.iteritems():
  119. if event == containerEv:
  120. handlers.append(handler)
  121. self.mouse['useBeforeGenericEvent'] = self.mouse['use']
  122. self.mouse['use'] = 'genericEvent'
  123. if cursor:
  124. self._overriddenCursor = self.GetCursor()
  125. self.SetCursor(cursor)
  126. return True
  127. def UnregisterAllHandlers(self):
  128. """!Unregisters all registered handlers
  129. Before each handler is unregistered it is called with string
  130. value "unregistered" of event parameter.
  131. """
  132. for containerEv, handlers in self.handlersContainer.iteritems():
  133. for handler in handlers:
  134. try:
  135. handler("unregistered")
  136. handlers.remove(handler)
  137. except:
  138. GError(parent = self,
  139. message = _("Error occured during unregistration of handler: %s \n \
  140. Handler was unregistered.") % handler.__name__)
  141. handlers.remove(handler)
  142. def UnregisterMouseEventHandler(self, event, handler):
  143. """!Unbinds event handler for event
  144. Before handler is unregistered it is called with string value
  145. "unregistered" of event parameter.
  146. @param handler handler to unbind
  147. @param event event from which handler will be unbinded
  148. @return True if successful
  149. @return False if event cannot be unbind
  150. """
  151. # removes handler from list
  152. for containerEv, handlers in self.handlersContainer.iteritems():
  153. if event != containerEv:
  154. continue
  155. try:
  156. handler("unregistered")
  157. if handler in handlers:
  158. handlers.remove(handler)
  159. else:
  160. grass.warning(_("Handler: %s was not registered") \
  161. % handler.__name__)
  162. except:
  163. GError(parent = self,
  164. message = _("Error occured during unregistration of handler: %s \n \
  165. Handler was unregistered") % handler.__name__)
  166. handlers.remove(handler)
  167. # restore mouse use (previous state)
  168. self.mouse['use'] = self.mouse['useBeforeGenericEvent']
  169. # restore overridden cursor
  170. if self._overriddenCursor:
  171. self.SetCursor(self._overriddenCursor)
  172. return True
  173. def Pixel2Cell(self, (x, y)):
  174. raise NotImplementedError()
  175. def Cell2Pixel(self, (east, north)):
  176. raise NotImplementedError()
  177. def OnMotion(self, event):
  178. """!Tracks mouse motion and update statusbar
  179. @see GetLastEN
  180. """
  181. try:
  182. self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
  183. except (ValueError):
  184. self.lastEN = None
  185. # FIXME: special case for vdigit and access to statusbarManager
  186. if self.frame.statusbarManager.GetMode() == 0: # Coordinates
  187. updated = False
  188. if hasattr(self, "digit"):
  189. precision = int(UserSettings.Get(group = 'projection', key = 'format',
  190. subkey = 'precision'))
  191. updated = self._onMotion(self.lastEN, precision)
  192. if not updated:
  193. self.frame.CoordinatesChanged()
  194. event.Skip()
  195. def GetLastEN(self):
  196. """!Returns last coordinates of mouse cursor.
  197. @see OnMotion
  198. """
  199. return self.lastEN