frame.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. import sys
  2. import wx
  3. import time
  4. import grass.script as grass
  5. from gui_core.mapdisp import DoubleMapFrame
  6. from core.render import Map
  7. from mapdisp import statusbar as sb
  8. from core.debug import Debug
  9. from mapdisp.statusbar import EVT_AUTO_RENDER
  10. from swipe.toolbars import SwipeMapToolbar, SwipeMainToolbar, SwipeMiscToolbar
  11. from swipe.mapwindow import SwipeBufferedWindow
  12. from swipe.dialogs import SwipeMapDialog
  13. class SwipeMapFrame(DoubleMapFrame):
  14. def __init__(self, parent = None, title = _("Map Swipe"), name = "swipe", **kwargs):
  15. DoubleMapFrame.__init__(self, parent = parent, title = title, name = name,
  16. firstMap = Map(), secondMap = Map(), **kwargs)
  17. Debug.msg (1, "SwipeMapFrame.__init__()")
  18. #
  19. # Add toolbars
  20. #
  21. toolbars = ['swipeMisc', 'swipeMap', 'swipeMain']
  22. if sys.platform == 'win32':
  23. self.AddToolbar(toolbars.pop(1))
  24. toolbars.reverse()
  25. else:
  26. self.AddToolbar(toolbars.pop(0))
  27. for toolb in toolbars:
  28. self.AddToolbar(toolb)
  29. #
  30. # create widgets
  31. #
  32. self.splitter = MapSplitter(parent = self, id = wx.ID_ANY)
  33. self.sliderH = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
  34. self.sliderV = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_VERTICAL)
  35. self.firstMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.firstMap, frame = self)
  36. self.secondMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.secondMap, frame = self)
  37. self.MapWindow = self.firstMapWindow # current by default
  38. self.firstMap.region = self.secondMap.region
  39. self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
  40. self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  41. self._addPanes()
  42. self._bindWindowsActivation()
  43. self._mgr.GetPane('sliderV').Hide()
  44. self._mgr.GetPane('sliderH').Show()
  45. self.slider = self.sliderH
  46. self.InitStatusbar()
  47. self.Bind(wx.EVT_SIZE, self.OnSize)
  48. self.Bind(EVT_AUTO_RENDER, self.OnAutoRenderChanged)
  49. self.Bind(wx.EVT_IDLE, self.OnIdle)
  50. self.SetSize((800, 600))
  51. self._mgr.Update()
  52. self.rasters = {'first': None, 'second': None}
  53. # default action in map toolbar
  54. self.OnPan(event = None)
  55. self.resize = False
  56. wx.CallAfter(self.CallAfterInit)
  57. def CallAfterInit(self):
  58. self.InitSliderBindings()
  59. self.OnSelectRasters(event = None)
  60. def InitStatusbar(self):
  61. """!Init statusbar (default items)."""
  62. # items for choice
  63. self.statusbarItems = [sb.SbCoordinates,
  64. sb.SbRegionExtent,
  65. sb.SbCompRegionExtent,
  66. sb.SbShowRegion,
  67. sb.SbAlignExtent,
  68. sb.SbResolution,
  69. sb.SbDisplayGeometry,
  70. sb.SbMapScale,
  71. sb.SbGoTo,
  72. sb.SbProjection]
  73. # create statusbar and its manager
  74. statusbar = self.CreateStatusBar(number = 4, style = 0)
  75. statusbar.SetStatusWidths([-5, -2, -1, -1])
  76. self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
  77. # fill statusbar manager
  78. self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
  79. self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
  80. self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
  81. self.statusbarManager.Update()
  82. def ResetSlider(self):
  83. if self.splitter.GetSplitMode() == wx.SPLIT_VERTICAL:
  84. size = self.splitter.GetSize()[0]
  85. else:
  86. size = self.splitter.GetSize()[1]
  87. self.slider.SetRange(0, size)
  88. self.slider.SetValue(self.splitter.GetSashPosition())
  89. def InitSliderBindings(self):
  90. self.sliderH.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
  91. self.sliderH.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
  92. self.sliderV.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
  93. self.sliderV.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
  94. self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  95. self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  96. def OnSliderPositionChanging(self, event):
  97. """!Slider changes its position, sash must be moved too."""
  98. Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanging()")
  99. self.GetFirstWindow().movingSash = True
  100. self.GetSecondWindow().movingSash = True
  101. pos = event.GetPosition()
  102. if pos > 0:
  103. self.splitter.SetSashPosition(pos)
  104. self.splitter.OnSashChanging(None)
  105. def OnSliderPositionChanged(self, event):
  106. """!Slider position changed, sash must be moved too."""
  107. Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanged()")
  108. self.splitter.SetSashPosition(event.GetPosition())
  109. self.splitter.OnSashChanged(None)
  110. def OnSashChanging(self, event):
  111. """!Sash position is changing, slider must be moved too."""
  112. Debug.msg (5, "SwipeMapFrame.OnSashChanging()")
  113. self.slider.SetValue(self.splitter.GetSashPosition())
  114. event.Skip()
  115. def OnSashChanged(self, event):
  116. """!Sash position changed, slider must be moved too."""
  117. Debug.msg (5, "SwipeMapFrame.OnSashChanged()")
  118. self.OnSashChanging(event)
  119. event.Skip()
  120. def OnSize(self, event):
  121. Debug.msg (4, "SwipeMapFrame.OnSize()")
  122. self.resize = time.clock()
  123. w1 = self.GetFirstWindow()
  124. w2 = self.GetSecondWindow()
  125. sizeAll = self.splitter.GetSize()
  126. w1.SetClientSize(sizeAll)
  127. w2.SetClientSize(sizeAll)
  128. w1.OnSize(event)
  129. w2.OnSize(event)
  130. def OnIdle(self, event):
  131. if self.resize and time.clock() - self.resize > 0.2:
  132. self.ResetSlider()
  133. self.resize = False
  134. def OnAutoRenderChanged(self, event):
  135. """!Auto rendering state changed."""
  136. style = self.splitter.GetWindowStyle()
  137. style ^= wx.SP_LIVE_UPDATE
  138. self.splitter.SetWindowStyle(style)
  139. def AddToolbar(self, name):
  140. """!Add defined toolbar to the window
  141. Currently known toolbars are:
  142. - 'swipeMap' - basic map toolbar
  143. - 'swipeMain' - swipe functionality
  144. """
  145. if name == "swipeMap":
  146. self.toolbars[name] = SwipeMapToolbar(self)
  147. self._mgr.AddPane(self.toolbars[name],
  148. wx.aui.AuiPaneInfo().
  149. Name(name).Caption(_("Map Toolbar")).
  150. ToolbarPane().Top().
  151. LeftDockable(False).RightDockable(False).
  152. BottomDockable(False).TopDockable(True).
  153. CloseButton(False).Layer(2).Row(1).
  154. BestSize((self.toolbars[name].GetBestSize())))
  155. if name == "swipeMain":
  156. self.toolbars[name] = SwipeMainToolbar(self)
  157. self._mgr.AddPane(self.toolbars[name],
  158. wx.aui.AuiPaneInfo().
  159. Name(name).Caption(_("Main Toolbar")).
  160. ToolbarPane().Top().
  161. LeftDockable(False).RightDockable(False).
  162. BottomDockable(False).TopDockable(True).
  163. CloseButton(False).Layer(2).Row(1).
  164. BestSize((self.toolbars[name].GetBestSize())))
  165. if name == "swipeMisc":
  166. self.toolbars[name] = SwipeMiscToolbar(self)
  167. self._mgr.AddPane(self.toolbars[name],
  168. wx.aui.AuiPaneInfo().
  169. Name(name).Caption(_("Misc Toolbar")).
  170. ToolbarPane().Top().
  171. LeftDockable(False).RightDockable(False).
  172. BottomDockable(False).TopDockable(True).
  173. CloseButton(False).Layer(2).Row(1).
  174. BestSize((self.toolbars[name].GetBestSize())))
  175. def _addPanes(self):
  176. """!Add splitter window and sliders to aui manager"""
  177. # splitter window
  178. self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
  179. Name('splitter').CaptionVisible(False).PaneBorder(True).
  180. Dockable(False).Floatable(False).CloseButton(False).
  181. Center().Layer(1).BestSize((self.splitter.GetBestSize())))
  182. # sliders
  183. self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
  184. Name('sliderH').CaptionVisible(False).PaneBorder(False).
  185. CloseButton(False).Gripper(True).GripperTop(False).
  186. BottomDockable(True).TopDockable(True).
  187. LeftDockable(False).RightDockable(False).
  188. Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))
  189. self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
  190. Name('sliderV').CaptionVisible(False).PaneBorder(False).
  191. CloseButton(False).Gripper(True).GripperTop(True).
  192. BottomDockable(False).TopDockable(False).
  193. LeftDockable(True).RightDockable(True).
  194. Right().Layer(1).BestSize((self.sliderV.GetBestSize())))
  195. def UpdateRegion(self):
  196. """!
  197. Rerender the second window
  198. when the region of the first changed.
  199. """
  200. Debug.msg(3, "SwipeMapFrame.UpdateRegion()")
  201. if self.GetWindow() == self.GetSecondWindow():
  202. self.Render(self.GetFirstWindow())
  203. else:
  204. self.Render(self.GetSecondWindow())
  205. def OnZoomToMap(self, event):
  206. """!
  207. Set display extents to match selected raster (including NULLs)
  208. or vector map.
  209. """
  210. self.GetFirstWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
  211. self.GetSecondWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
  212. # needed again, don't know why
  213. self.firstMap.region = self.secondMap.region
  214. def OnZoomBack(self, event):
  215. self.GetFirstWindow().ZoomBack()
  216. self.secondMap.region = self.firstMap.region
  217. self.Render(self.GetSecondWindow())
  218. def OnSelectRasters(self, event):
  219. """!Choose raster maps and rerender."""
  220. dlg = SwipeMapDialog(self, first = self.rasters['first'], second = self.rasters['second'])
  221. if dlg.ShowModal() == wx.ID_OK:
  222. maps = dlg.GetValues()
  223. self.SetFirstRaster(name = maps[0])
  224. self.SetSecondRaster(name = maps[1])
  225. dlg.Destroy()
  226. self.OnRender(event = None)
  227. def SetFirstRaster(self, name):
  228. """!Set raster map to first Map"""
  229. raster = grass.find_file(name = name, element = 'cell')
  230. if raster['fullname']:
  231. self.rasters['first'] = raster['fullname']
  232. self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
  233. self.OnZoomToMap(event = None)
  234. def SetSecondRaster(self, name):
  235. """!Set raster map to second Map"""
  236. raster = grass.find_file(name = name, element = 'cell')
  237. if raster['fullname']:
  238. self.rasters['second'] = raster['fullname']
  239. self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
  240. self.OnZoomToMap(event = None)
  241. def SetLayer(self, name, mapInstance):
  242. """!Sets layer in Map.
  243. @param name layer (raster) name
  244. """
  245. Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
  246. # this simple application enables to keep only one raster
  247. mapInstance.DeleteAllLayers()
  248. cmdlist = ['d.rast', 'map=%s' % name]
  249. # add layer to Map instance (core.render)
  250. newLayer = mapInstance.AddLayer(type = 'raster', command = cmdlist, l_active = True,
  251. name = name, l_hidden = False, l_opacity = 1.0,
  252. l_render = True)
  253. def OnSwitchWindows(self, event):
  254. """!Switch windows position."""
  255. Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
  256. splitter = self.splitter
  257. w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
  258. splitter.ReplaceWindow(w1, w2)
  259. splitter.ReplaceWindow(w2, w1)
  260. # self.OnSize(None)
  261. splitter.OnSashChanged(None)
  262. def OnSwitchOrientation(self, event):
  263. """!Switch orientation of the sash."""
  264. Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
  265. splitter = self.splitter
  266. splitter.Unsplit()
  267. if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  268. splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  269. self.slider = self.sliderH
  270. self._mgr.GetPane('sliderH').Show()
  271. self._mgr.GetPane('sliderV').Hide()
  272. else:
  273. splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
  274. self.slider = self.sliderV
  275. self._mgr.GetPane('sliderV').Show()
  276. self._mgr.GetPane('sliderH').Hide()
  277. self._mgr.Update()
  278. splitter.OnSashChanged(None)
  279. self.OnSize(None)
  280. def GetMapToolbar(self):
  281. """!Returns toolbar with zooming tools"""
  282. return self.toolbars['swipeMap']
  283. def IsStandalone(self):
  284. if self.parent:
  285. return False
  286. return True
  287. def OnCloseWindow(self, event):
  288. self.Destroy()
  289. class MapSplitter(wx.SplitterWindow):
  290. """!Splitter window for displaying two maps"""
  291. def __init__(self, parent, id):
  292. wx.SplitterWindow.__init__(self, parent = parent, id = id,
  293. style = wx.SP_LIVE_UPDATE
  294. )
  295. Debug.msg(2, "MapSplitter.__init__()")
  296. self.sashWidthMin = 1
  297. self.sashWidthMax = 10
  298. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  299. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  300. wx.CallAfter(self.Init)
  301. def Init(self):
  302. self.OnSashChanged(evt = None)
  303. self.SetMinimumPaneSize(0)
  304. self.SetSashSize(self.sashWidthMin)
  305. # def OnMotion(self, event):
  306. # w = self.GetSashSize()
  307. # w1, w2 = self.GetWindow1(), self.GetWindow2()
  308. # if self.SashHitTest(event.GetX(), event.GetY(), tolerance = 20):
  309. # if w == self.sashWidthMin:
  310. # self.SetSashSize(self.sashWidthMax)
  311. # self.SetNeedUpdating(True)
  312. # w1.movingSash = True
  313. # w2.movingSash = True
  314. # else:
  315. # w1.movingSash = False
  316. # w1.movingSash = False
  317. # else:
  318. # if w == self.sashWidthMax:
  319. # self.SetSashSize(self.sashWidthMin)
  320. # self.SetNeedUpdating(True)
  321. # w1.movingSash = True
  322. # w2.movingSash = True
  323. # else:
  324. # w1.movingSash = False
  325. # w2.movingSash = False
  326. # event.Skip()
  327. def OnSashChanged(self, evt):
  328. Debug.msg(5, "MapSplitter.OnSashChanged()")
  329. w1, w2 = self.GetWindow1(), self.GetWindow2()
  330. w1.movingSash = False
  331. w2.movingSash = False
  332. wx.CallAfter(self.SashChanged)
  333. def SashChanged(self):
  334. Debug.msg(5, "MapSplitter.SashChanged()")
  335. w1, w2 = self.GetWindow1(), self.GetWindow2()
  336. w1.SetImageCoords((0, 0))
  337. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  338. w = w1.GetSize()[0]
  339. w2.SetImageCoords((-w, 0))
  340. else:
  341. h = w1.GetSize()[1]
  342. w2.SetImageCoords((0, -h))
  343. w1.UpdateMap(render = False, renderVector = False)
  344. w2.UpdateMap(render = False, renderVector = False)
  345. pos = self.GetSashPosition()
  346. self.last = pos
  347. def OnSashChanging(self, event):
  348. Debug.msg(5, "MapSplitter.OnSashChanging()")
  349. if not (self.GetWindowStyle() & wx.SP_LIVE_UPDATE):
  350. if event:
  351. event.Skip()
  352. return
  353. pos = self.GetSashPosition()
  354. dpos = pos - self.last
  355. self.last = pos
  356. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  357. dx = -dpos
  358. dy = 0
  359. else:
  360. dx = 0
  361. dy = -dpos
  362. self.GetWindow2().TranslateImage(dx, dy)
  363. self.GetWindow1().movingSash = True
  364. self.GetWindow2().movingSash = True