mapwindow.py 9.0 KB

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