mapwindow.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. """
  2. @package swipe.mapwindow
  3. @brief Map Swipe map window.
  4. Class _MouseEvent taken from wxPython FloatCanvas source code (Christopher Barker).
  5. Classes:
  6. - mapwindow::SwipeBufferedWindow
  7. - mapwindow::_MouseEvent
  8. (C) 2012 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. @author Anna Kratochvilova <kratochanna gmail.com>
  12. """
  13. import wx
  14. from core.debug import Debug
  15. from core.utils import _
  16. from core.settings import UserSettings
  17. from mapwin.buffered import BufferedMapWindow
  18. from gui_core.wrap import Rect
  19. EVT_MY_MOUSE_EVENTS = wx.NewEventType()
  20. EVT_MY_MOTION = wx.NewEventType()
  21. EVT_MOUSE_EVENTS = wx.PyEventBinder(EVT_MY_MOUSE_EVENTS)
  22. EVT_MOTION = wx.PyEventBinder(EVT_MY_MOTION)
  23. class SwipeBufferedWindow(BufferedMapWindow):
  24. """A subclass of BufferedWindow class.
  25. Enables to draw the image translated.
  26. Special mouse events with changed coordinates are used.
  27. """
  28. def __init__(self, parent, giface, Map, properties, **kwargs):
  29. BufferedMapWindow.__init__(self, parent=parent, giface=giface, Map=Map,
  30. properties=properties, **kwargs)
  31. Debug.msg(2, "SwipeBufferedWindow.__init__()")
  32. self.specialSize = super(SwipeBufferedWindow, self).GetClientSize()
  33. self.specialCoords = [0, 0]
  34. self.imageId = 99
  35. self.movingSash = False
  36. self._mode = 'swipe'
  37. self.lineid = wx.NewId()
  38. def _bindMouseEvents(self):
  39. """Binds wx mouse events and custom mouse events"""
  40. self.Bind(wx.EVT_MOUSE_EVENTS, self._mouseActions)
  41. self.Bind(wx.EVT_MOTION, self._mouseMotion)
  42. self.Bind(EVT_MOTION, self.OnMotion)
  43. self.Bind(EVT_MOUSE_EVENTS, self.MouseActions)
  44. self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
  45. def _RaiseMouseEvent(self, Event, EventType):
  46. """This is called in various other places to raise a Mouse Event
  47. """
  48. Debug.msg(5, "SwipeBufferedWindow._RaiseMouseEvent()")
  49. # this computes the new coordinates from the mouse coords.
  50. x, y = Event.GetPosition()
  51. pt = x - self.GetImageCoords()[0], y - self.GetImageCoords()[1]
  52. evt = _MouseEvent(EventType, Event, self.GetId(), pt)
  53. self.GetEventHandler().ProcessEvent(evt)
  54. # this skip was not in the original code but is needed here
  55. Event.Skip()
  56. def _mouseActions(self, event):
  57. self._RaiseMouseEvent(event, EVT_MY_MOUSE_EVENTS)
  58. def _mouseMotion(self, event):
  59. self._RaiseMouseEvent(event, EVT_MY_MOTION)
  60. def GetClientSize(self):
  61. """Overriden method which returns simulated window size.
  62. """
  63. if self._mode == 'swipe':
  64. return self.specialSize
  65. else:
  66. return super(SwipeBufferedWindow, self).GetClientSize()
  67. def SetClientSize(self, size):
  68. """Overriden method which sets simulated window size.
  69. """
  70. Debug.msg(3, "SwipeBufferedWindow.SetClientSize(): size = %s" % size)
  71. self.specialSize = size
  72. def SetMode(self, mode):
  73. """Sets mode of the window.
  74. :param mode: mode can be 'swipe' or 'mirror'
  75. """
  76. self._mode = mode
  77. def GetImageCoords(self):
  78. """Returns coordinates of rendered image"""
  79. if self._mode == 'swipe':
  80. return self.specialCoords
  81. else:
  82. return (0, 0)
  83. def SetImageCoords(self, coords):
  84. """Sets coordinates of rendered image"""
  85. Debug.msg(
  86. 3, "SwipeBufferedWindow.SetImageCoords(): coords = %s, %s" %
  87. (coords[0], coords[1]))
  88. self.specialCoords = coords
  89. def OnSize(self, event):
  90. """Calls superclass's OnSize method only when needed"""
  91. Debug.msg(5, "SwipeBufferedWindow.OnSize()")
  92. if not self.movingSash:
  93. super(SwipeBufferedWindow, self).OnSize(event)
  94. def Draw(self, pdc, img=None, drawid=None, pdctype='image',
  95. coords=[0, 0, 0, 0], pen=None, brush=None):
  96. """Draws image (map) with translated coordinates.
  97. """
  98. Debug.msg(2, "SwipeBufferedWindow.Draw()")
  99. if pdctype == 'image':
  100. coords = self.GetImageCoords()
  101. return super(SwipeBufferedWindow, self).Draw(
  102. pdc, img, drawid, pdctype, coords, pen, brush)
  103. def OnLeftDown(self, event):
  104. """Left mouse button pressed.
  105. In case of 'pointer' mode, coordinates must be adjusted.
  106. """
  107. if self.mouse['use'] == 'pointer':
  108. evX, evY = event.GetPositionTuple()[:]
  109. imX, imY = self.GetImageCoords()
  110. self.lastpos = evX + imX, evY + imY
  111. # get decoration or text id
  112. self.dragid = None
  113. idlist = self.pdc.FindObjects(self.lastpos[0], self.lastpos[1],
  114. self.hitradius)
  115. if 99 in idlist:
  116. idlist.remove(99)
  117. if idlist:
  118. self.dragid = idlist[0] # drag whatever is on top
  119. else:
  120. super(SwipeBufferedWindow, self).OnLeftDown(event)
  121. def OnDragging(self, event):
  122. """Mouse dragging - overlay (text) is moving.
  123. Coordinates must be adjusted.
  124. """
  125. if (self.mouse['use'] == 'pointer' and self.dragid is not None):
  126. evX, evY = event.GetPositionTuple()
  127. imX, imY = self.GetImageCoords()
  128. self.DragItem(self.dragid, (evX + imX, evY + imY))
  129. else:
  130. super(SwipeBufferedWindow, self).OnDragging(event)
  131. def TranslateImage(self, dx, dy):
  132. """Translate image and redraw.
  133. """
  134. Debug.msg(
  135. 5, "SwipeBufferedWindow.TranslateImage(): dx = %s, dy = %s" %
  136. (dx, dy))
  137. self.pdc.TranslateId(self.imageId, dx, dy)
  138. self.Refresh()
  139. def SetRasterNameText(self, name, textId):
  140. """Sets text label with map name."""
  141. self.textdict[textId] = {'bbox': Rect(), 'coords': [10, 10],
  142. 'font': self.GetFont(), 'color': wx.BLACK,
  143. 'background': wx.LIGHT_GREY,
  144. 'rotation': 0, 'text': name,
  145. 'active': True}
  146. def MouseDraw(self, pdc=None, begin=None, end=None):
  147. """Overriden method to recompute coordinates back to original values
  148. so that e.g. drawing of zoom box is done properly"""
  149. Debug.msg(5, "SwipeBufferedWindow.MouseDraw()")
  150. offsetX, offsetY = self.GetImageCoords()
  151. begin = (
  152. self.mouse['begin'][0] +
  153. offsetX,
  154. self.mouse['begin'][1] +
  155. offsetY)
  156. end = (self.mouse['end'][0] + offsetX, self.mouse['end'][1] + offsetY)
  157. super(SwipeBufferedWindow, self).MouseDraw(pdc, begin, end)
  158. def DrawMouseCursor(self, coords):
  159. """Draw moving cross."""
  160. self.pdcTmp.ClearId(self.lineid)
  161. color = UserSettings.Get(
  162. group='mapswipe',
  163. key='cursor',
  164. subkey='color')
  165. cursType = UserSettings.Get(
  166. group='mapswipe', key='cursor', subkey=[
  167. 'type', 'selection'])
  168. size = UserSettings.Get(group='mapswipe', key='cursor', subkey='size')
  169. width = UserSettings.Get(
  170. group='mapswipe',
  171. key='cursor',
  172. subkey='width')
  173. if cursType == 0:
  174. self.lineid = self.DrawCross(
  175. pdc=self.pdcTmp,
  176. coords=coords,
  177. size=size,
  178. pen=wx.Pen(
  179. wx.Colour(
  180. *color),
  181. width))
  182. elif cursType == 1:
  183. self.lineid = self.DrawRectangle(
  184. pdc=self.pdcTmp,
  185. point1=(
  186. coords[0] - size / 2,
  187. coords[1] - size / 2),
  188. point2=(
  189. coords[0] + size / 2,
  190. coords[1] + size / 2),
  191. pen=wx.Pen(
  192. wx.Colour(
  193. *color),
  194. width))
  195. elif cursType == 2:
  196. self.lineid = self.DrawCircle(pdc=self.pdcTmp,
  197. coords=coords, radius=size / 2,
  198. pen=wx.Pen(wx.Colour(*color), width))
  199. class _MouseEvent(wx.PyCommandEvent):
  200. """
  201. This event class takes a regular wxWindows mouse event as a parameter,
  202. and wraps it so that there is access to all the original methods. This
  203. is similar to subclassing, but you can't subclass a wxWindows event.
  204. The goal is to be able to it just like a regular mouse event.
  205. Difference is that it is a CommandEvent, which propagates up the
  206. window hierarchy until it is handled.
  207. """
  208. def __init__(self, EventType, NativeEvent, WinID, changed=None):
  209. Debug.msg(5, "_MouseEvent:__init__()")
  210. wx.PyCommandEvent.__init__(self)
  211. self.__dict__['_NativeEvent'] = NativeEvent
  212. self.__dict__['changed'] = changed
  213. self.SetEventType(EventType)
  214. def GetPosition(self):
  215. return wx.Point(*self.changed)
  216. def GetPositionTuple(self):
  217. return self.changed
  218. def GetX(self):
  219. return self.changed[0]
  220. def GetY(self):
  221. return self.changed[1]
  222. # this delegates all other attributes to the native event.
  223. def __getattr__(self, name):
  224. return getattr(self._NativeEvent, name)