mapwindow.py 11 KB

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