mapwindow.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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, Map, frame,
  29. id = wx.ID_ANY, tree = None, lmgr = None, **kwargs):
  30. self.parent = parent # MapFrame
  31. self.Map = Map
  32. self.frame = frame
  33. self.tree = tree
  34. self.lmgr = lmgr
  35. # mouse attributes -- position on the screen, begin and end of
  36. # dragging, and type of drawing
  37. self.mouse = {
  38. 'begin': [0, 0], # screen coordinates
  39. 'end' : [0, 0],
  40. 'use' : "pointer",
  41. 'box' : "point"
  42. }
  43. # last east, north coordinates, changes on mouse motion
  44. self.lastEN = None
  45. # stores overridden cursor
  46. self._overriddenCursor = None
  47. # dictionary where event types are stored as keys and lists of
  48. # handlers for these types as values
  49. self.handlersContainer = {
  50. wx.EVT_LEFT_DOWN : [],
  51. wx.EVT_LEFT_UP : [],
  52. wx.EVT_LEFT_DCLICK : [],
  53. wx.EVT_MIDDLE_DOWN : [],
  54. wx.EVT_MIDDLE_UP : [],
  55. wx.EVT_MIDDLE_DCLICK : [],
  56. wx.EVT_RIGHT_DOWN : [],
  57. wx.EVT_RIGHT_UP : [],
  58. wx.EVT_RIGHT_DCLICK : [],
  59. wx.EVT_MOTION : [],
  60. wx.EVT_ENTER_WINDOW : [],
  61. wx.EVT_LEAVE_WINDOW : [],
  62. wx.EVT_MOUSEWHEEL : [],
  63. wx.EVT_MOUSE_EVENTS : []
  64. }
  65. wx.CallAfter(self.InitBinding)
  66. def __del__(self):
  67. self.UnregisterAllHandlers()
  68. def InitBinding(self):
  69. """!Binds helper functions, which calls all handlers
  70. registered to events with the events
  71. """
  72. for ev, handlers in self.handlersContainer.iteritems():
  73. self.Bind(ev, self.EventTypeHandler(handlers))
  74. def EventTypeHandler(self, evHandlers):
  75. return lambda event:self.HandlersCaller(event, evHandlers)
  76. def HandlersCaller(self, event, handlers):
  77. """!Hepler function which calls all handlers registered for
  78. event
  79. """
  80. for handler in handlers:
  81. try:
  82. handler(event)
  83. except:
  84. handlers.remove(handler)
  85. GError(parent = self,
  86. message=_("Error occured during calling of handler: %s \n"
  87. "Handler was unregistered.") % handler.__name__)
  88. event.Skip()
  89. def RegisterMouseEventHandler(self, event, handler, cursor = None):
  90. """!Binds event handler
  91. Call event.Skip() in handler to allow default processing in MapWindow.
  92. If any error occures inside of handler, the handler is removed.
  93. Before handler is unregistered it is called with
  94. string value "unregistered" of event parameter.
  95. @code
  96. # your class methods
  97. def OnButton(self, event):
  98. # current map display's map window
  99. # expects LayerManager to be the parent
  100. self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
  101. if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
  102. wx.StockCursor(wx.CURSOR_CROSS)):
  103. self.parent.GetLayerTree().GetMapDisplay().Raise()
  104. else:
  105. # handle that you cannot get coordinates
  106. def OnMouseAction(self, event):
  107. # get real world coordinates of mouse click
  108. coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
  109. self.text.SetLabel('Coor: ' + str(coor))
  110. self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction)
  111. event.Skip()
  112. @endcode
  113. @param event one of mouse events
  114. @param handler function to handle event
  115. @param cursor cursor which temporary overrides current cursor
  116. @return True if successful
  117. @return False if event cannot be bind
  118. """
  119. # inserts handler into list
  120. for containerEv, handlers in self.handlersContainer.iteritems():
  121. if event == containerEv:
  122. handlers.append(handler)
  123. self.mouse['useBeforeGenericEvent'] = self.mouse['use']
  124. self.mouse['use'] = 'genericEvent'
  125. if cursor:
  126. self._overriddenCursor = self.GetCursor()
  127. self.SetCursor(cursor)
  128. return True
  129. def UnregisterAllHandlers(self):
  130. """!Unregisters all registered handlers
  131. Before each handler is unregistered it is called with string
  132. value "unregistered" of event parameter.
  133. """
  134. for containerEv, handlers in self.handlersContainer.iteritems():
  135. for handler in handlers:
  136. try:
  137. handler("unregistered")
  138. handlers.remove(handler)
  139. except:
  140. GError(parent = self,
  141. message = _("Error occured during unregistration of handler: %s \n \
  142. Handler was unregistered.") % handler.__name__)
  143. handlers.remove(handler)
  144. def UnregisterMouseEventHandler(self, event, handler):
  145. """!Unbinds event handler for event
  146. Before handler is unregistered it is called with string value
  147. "unregistered" of event parameter.
  148. @param handler handler to unbind
  149. @param event event from which handler will be unbinded
  150. @return True if successful
  151. @return False if event cannot be unbind
  152. """
  153. # removes handler from list
  154. for containerEv, handlers in self.handlersContainer.iteritems():
  155. if event != containerEv:
  156. continue
  157. try:
  158. handler("unregistered")
  159. if handler in handlers:
  160. handlers.remove(handler)
  161. else:
  162. grass.warning(_("Handler: %s was not registered") \
  163. % handler.__name__)
  164. except:
  165. GError(parent = self,
  166. message = _("Error occured during unregistration of handler: %s \n \
  167. Handler was unregistered") % handler.__name__)
  168. handlers.remove(handler)
  169. # restore mouse use (previous state)
  170. self.mouse['use'] = self.mouse['useBeforeGenericEvent']
  171. # restore overridden cursor
  172. if self._overriddenCursor:
  173. self.SetCursor(self._overriddenCursor)
  174. return True
  175. def Pixel2Cell(self, (x, y)):
  176. raise NotImplementedError()
  177. def Cell2Pixel(self, (east, north)):
  178. raise NotImplementedError()
  179. def OnMotion(self, event):
  180. """!Tracks mouse motion and update statusbar
  181. @see GetLastEN
  182. """
  183. try:
  184. self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
  185. except (ValueError):
  186. self.lastEN = None
  187. # FIXME: special case for vdigit and access to statusbarManager
  188. if self.frame.statusbarManager.GetMode() == 0: # Coordinates
  189. updated = False
  190. if hasattr(self, "digit"):
  191. precision = int(UserSettings.Get(group = 'projection', key = 'format',
  192. subkey = 'precision'))
  193. updated = self._onMotion(self.lastEN, precision)
  194. if not updated:
  195. self.frame.CoordinatesChanged()
  196. event.Skip()
  197. def GetLastEN(self):
  198. """!Returns last coordinates of mouse cursor.
  199. @see OnMotion
  200. """
  201. return self.lastEN
  202. def GetLayerByName(self, name, mapType, dataType = 'layer'):
  203. """!Get layer from layer tree by nam
  204. @param name layer name
  205. @param type 'item' / 'layer' / 'nviz'
  206. @return layer / map layer properties / nviz properties
  207. @return None
  208. """
  209. if not self.tree:
  210. return None
  211. try:
  212. mapLayer = self.Map.GetListOfLayers(l_type = mapType, l_name = name)[0]
  213. except IndexError:
  214. return None
  215. if dataType == 'layer':
  216. return mapLayer
  217. item = self.tree.FindItemByData('maplayer', mapLayer)
  218. if not item:
  219. return None
  220. if dataType == 'nviz':
  221. return self.tree.GetPyData(item)[0]['nviz']
  222. return item
  223. def GetSelectedLayer(self, type = 'layer', multi = False):
  224. """!Get selected layer from layer tree
  225. @param type 'item' / 'layer' / 'nviz'
  226. @param multi return first selected layer or all
  227. @return layer / map layer properties / nviz properties
  228. @return None / [] on failure
  229. """
  230. ret = []
  231. if not self.tree or \
  232. not self.tree.GetSelection():
  233. if multi:
  234. return []
  235. else:
  236. return None
  237. if multi and \
  238. type == 'item':
  239. return self.tree.GetSelections()
  240. for item in self.tree.GetSelections():
  241. if not item.IsChecked():
  242. if multi:
  243. continue
  244. else:
  245. return None
  246. if type == 'item': # -> multi = False
  247. return item
  248. try:
  249. if type == 'nviz':
  250. layer = self.tree.GetPyData(item)[0]['nviz']
  251. else:
  252. layer = self.tree.GetPyData(item)[0]['maplayer']
  253. except:
  254. layer = None
  255. if multi:
  256. ret.append(layer)
  257. else:
  258. return layer
  259. return ret