mapwindow.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. """!
  2. @package gui_core.mapwindow
  3. @brief Map display canvas - base class for buffered window.
  4. Classes:
  5. - mapwindow::MapWindow
  6. (C) 2006-2011 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. """
  13. import wx
  14. from core.settings import UserSettings
  15. class MapWindow(object):
  16. """!Abstract map display window class
  17. Superclass for BufferedWindow class (2D display mode), and GLWindow
  18. (3D display mode).
  19. Subclasses have to define
  20. - _bindMouseEvents method which binds MouseEvent handlers
  21. - Pixel2Cell
  22. - Cell2Pixel (if it is possible)
  23. """
  24. def __init__(self, parent, id = wx.ID_ANY,
  25. Map = None, tree = None, lmgr = None, **kwargs):
  26. self.parent = parent # MapFrame
  27. self.Map = Map
  28. self.tree = tree
  29. self.lmgr = lmgr
  30. # mouse attributes -- position on the screen, begin and end of
  31. # dragging, and type of drawing
  32. self.mouse = {
  33. 'begin': [0, 0], # screen coordinates
  34. 'end' : [0, 0],
  35. 'use' : "pointer",
  36. 'box' : "point"
  37. }
  38. # last east, north coordinates, changes on mouse motion
  39. self.lastEN = None
  40. # stores overridden cursor
  41. self._overriddenCursor = None
  42. def RegisterMouseEventHandler(self, event, handler, cursor = None):
  43. """!Binds event handler
  44. Call event.Skip() in handler to allow default processing in MapWindow.
  45. @code
  46. # your class methods
  47. def OnButton(self, event):
  48. # current map display's map window
  49. # expects LayerManager to be the parent
  50. self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
  51. if self.mapwin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
  52. wx.StockCursor(wx.CURSOR_CROSS)):
  53. self.parent.GetLayerTree().GetMapDisplay().Raise()
  54. else:
  55. # handle that you cannot get coordinates
  56. def OnMouseAction(self, event):
  57. # get real world coordinates of mouse click
  58. coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
  59. self.text.SetLabel('Coor: ' + str(coor))
  60. self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN)
  61. event.Skip()
  62. @endcode
  63. @param event one of mouse events
  64. @param handler function to handle event
  65. @param cursor cursor which temporary overrides current cursor
  66. @return True if successful
  67. @return False if event cannot be bind
  68. """
  69. # if it is a VDigitWindow it cannot be used
  70. # hasattr is ugly
  71. if hasattr(self, "digit"):
  72. return False
  73. self.Bind(event, handler)
  74. self.mouse['useBeforeGenericEvent'] = self.mouse['use']
  75. self.mouse['use'] = 'genericEvent'
  76. if cursor:
  77. self._overriddenCursor = self.GetCursor()
  78. self.SetCursor(cursor)
  79. return True
  80. def UnregisterMouseEventHandler(self, event):
  81. """!Unbinds event handler a restores previous state
  82. You should unbind to restore normal MapWindow behaviour.
  83. Note that this operation will unbind any other external (non-MapWindow) handlers.
  84. @param event event to unbind
  85. @return True if successful
  86. @return False if event cannot be unbind
  87. """
  88. if hasattr(self, "digit"):
  89. return False
  90. # it is not yet possible in wxPython to unbind exact event
  91. ret = self.Unbind(event)
  92. # restore bind state
  93. self._bindMouseEvents()
  94. # restore mouse use (previous state)
  95. self.mouse['use'] = self.mouse['useBeforeGenericEvent']
  96. # restore overridden cursor
  97. if self._overriddenCursor:
  98. self.SetCursor(self._overriddenCursor)
  99. return ret
  100. def Pixel2Cell(self, (x, y)):
  101. raise NotImplementedError()
  102. def Cell2Pixel(self, (east, north)):
  103. raise NotImplementedError()
  104. def OnMotion(self, event):
  105. """!Tracks mouse motion and update statusbar
  106. @see GetLastEN
  107. """
  108. try:
  109. self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
  110. except (ValueError):
  111. self.lastEN = None
  112. # FIXME: special case for vdigit and access to statusbarManager
  113. if self.parent.statusbarManager.GetMode() == 0: # Coordinates
  114. updated = False
  115. if hasattr(self, "digit"):
  116. precision = int(UserSettings.Get(group = 'projection', key = 'format',
  117. subkey = 'precision'))
  118. updated = self._onMotion(self.lastEN, precision)
  119. if not updated:
  120. self.parent.CoordinatesChanged()
  121. event.Skip()
  122. def GetLastEN(self):
  123. """!Returns last coordinates of mouse cursor.
  124. @see OnMotion
  125. """
  126. return self.lastEN
  127. def GetLayerByName(self, name, mapType, dataType = 'layer'):
  128. """!Get layer from layer tree by nam
  129. @param name layer name
  130. @param type 'item' / 'layer' / 'nviz'
  131. @return layer / map layer properties / nviz properties
  132. @return None
  133. """
  134. if not self.tree:
  135. return None
  136. try:
  137. mapLayer = self.Map.GetListOfLayers(l_type = mapType, l_name = name)[0]
  138. except IndexError:
  139. return None
  140. if dataType == 'layer':
  141. return mapLayer
  142. item = self.tree.FindItemByData('maplayer', mapLayer)
  143. if not item:
  144. return None
  145. if dataType == 'nviz':
  146. return self.tree.GetPyData(item)[0]['nviz']
  147. return item
  148. def GetSelectedLayer(self, type = 'layer', multi = False):
  149. """!Get selected layer from layer tree
  150. @param type 'item' / 'layer' / 'nviz'
  151. @param multi return first selected layer or all
  152. @return layer / map layer properties / nviz properties
  153. @return None / [] on failure
  154. """
  155. ret = []
  156. if not self.tree or \
  157. not self.tree.GetSelection():
  158. if multi:
  159. return []
  160. else:
  161. return None
  162. if multi and \
  163. type == 'item':
  164. return self.tree.GetSelections()
  165. for item in self.tree.GetSelections():
  166. if not item.IsChecked():
  167. if multi:
  168. continue
  169. else:
  170. return None
  171. if type == 'item': # -> multi = False
  172. return item
  173. try:
  174. if type == 'nviz':
  175. layer = self.tree.GetPyData(item)[0]['nviz']
  176. else:
  177. layer = self.tree.GetPyData(item)[0]['maplayer']
  178. except:
  179. layer = None
  180. if multi:
  181. ret.append(layer)
  182. else:
  183. return layer
  184. return ret