frame.py 17 KB

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