frame.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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, GError
  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 = _("GRASS GIS 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. res1 = self.SetFirstRaster(name = maps[0])
  227. res2 = self.SetSecondRaster(name = maps[1])
  228. if not (res1 and res2):
  229. message = ''
  230. if not res1:
  231. message += _("Map <%s> not found. ") % maps[0]
  232. if not res2:
  233. message += _("Map <%s> not found.") % maps[1]
  234. GError(parent = self, message = message)
  235. dlg.Destroy()
  236. dlg.Destroy()
  237. self.OnRender(event = None)
  238. def SetFirstRaster(self, name):
  239. """!Set raster map to first Map"""
  240. raster = grass.find_file(name = name, element = 'cell')
  241. if raster['fullname']:
  242. self.rasters['first'] = raster['fullname']
  243. self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
  244. self.OnZoomToMap(event = None)
  245. return True
  246. return False
  247. def SetSecondRaster(self, name):
  248. """!Set raster map to second Map"""
  249. raster = grass.find_file(name = name, element = 'cell')
  250. if raster['fullname']:
  251. self.rasters['second'] = raster['fullname']
  252. self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
  253. self.OnZoomToMap(event = None)
  254. return True
  255. return False
  256. def SetLayer(self, name, mapInstance):
  257. """!Sets layer in Map.
  258. @param name layer (raster) name
  259. """
  260. Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
  261. # this simple application enables to keep only one raster
  262. mapInstance.DeleteAllLayers()
  263. cmdlist = ['d.rast', 'map=%s' % name]
  264. # add layer to Map instance (core.render)
  265. newLayer = mapInstance.AddLayer(type = 'raster', command = cmdlist, l_active = True,
  266. name = name, l_hidden = False, l_opacity = 1.0,
  267. l_render = True)
  268. def OnSwitchWindows(self, event):
  269. """!Switch windows position."""
  270. Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
  271. splitter = self.splitter
  272. w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
  273. splitter.ReplaceWindow(w1, w2)
  274. splitter.ReplaceWindow(w2, w1)
  275. # self.OnSize(None)
  276. splitter.OnSashChanged(None)
  277. def OnSwitchOrientation(self, event):
  278. """!Switch orientation of the sash."""
  279. Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
  280. splitter = self.splitter
  281. splitter.Unsplit()
  282. if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  283. splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  284. self.slider = self.sliderH
  285. self._mgr.GetPane('sliderH').Show()
  286. self._mgr.GetPane('sliderV').Hide()
  287. else:
  288. splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
  289. self.slider = self.sliderV
  290. self._mgr.GetPane('sliderV').Show()
  291. self._mgr.GetPane('sliderH').Hide()
  292. self._mgr.Update()
  293. splitter.OnSashChanged(None)
  294. self.OnSize(None)
  295. def GetMapToolbar(self):
  296. """!Returns toolbar with zooming tools"""
  297. return self.toolbars['swipeMap']
  298. def IsStandalone(self):
  299. if self.parent:
  300. return False
  301. return True
  302. def OnHelp(self, event):
  303. RunCommand('g.manual',
  304. quiet = True,
  305. entry = 'wxGUI.MapSwipe')
  306. def OnCloseWindow(self, event):
  307. self.GetFirstMap().Clean()
  308. self.GetSecondMap().Clean()
  309. self.Destroy()
  310. class MapSplitter(wx.SplitterWindow):
  311. """!Splitter window for displaying two maps"""
  312. def __init__(self, parent, id):
  313. wx.SplitterWindow.__init__(self, parent = parent, id = id,
  314. style = wx.SP_LIVE_UPDATE
  315. )
  316. Debug.msg(2, "MapSplitter.__init__()")
  317. self.sashWidthMin = 1
  318. self.sashWidthMax = 10
  319. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  320. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  321. wx.CallAfter(self.Init)
  322. def Init(self):
  323. self.OnSashChanged(evt = None)
  324. self.SetMinimumPaneSize(0)
  325. self.SetSashSize(self.sashWidthMin)
  326. # def OnMotion(self, event):
  327. # w = self.GetSashSize()
  328. # w1, w2 = self.GetWindow1(), self.GetWindow2()
  329. # if self.SashHitTest(event.GetX(), event.GetY(), tolerance = 20):
  330. # if w == self.sashWidthMin:
  331. # self.SetSashSize(self.sashWidthMax)
  332. # self.SetNeedUpdating(True)
  333. # w1.movingSash = True
  334. # w2.movingSash = True
  335. # else:
  336. # w1.movingSash = False
  337. # w1.movingSash = False
  338. # else:
  339. # if w == self.sashWidthMax:
  340. # self.SetSashSize(self.sashWidthMin)
  341. # self.SetNeedUpdating(True)
  342. # w1.movingSash = True
  343. # w2.movingSash = True
  344. # else:
  345. # w1.movingSash = False
  346. # w2.movingSash = False
  347. # event.Skip()
  348. def OnSashChanged(self, evt):
  349. Debug.msg(5, "MapSplitter.OnSashChanged()")
  350. w1, w2 = self.GetWindow1(), self.GetWindow2()
  351. w1.movingSash = False
  352. w2.movingSash = False
  353. wx.CallAfter(self.SashChanged)
  354. def SashChanged(self):
  355. Debug.msg(5, "MapSplitter.SashChanged()")
  356. w1, w2 = self.GetWindow1(), self.GetWindow2()
  357. w1.SetImageCoords((0, 0))
  358. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  359. w = w1.GetSize()[0]
  360. w2.SetImageCoords((-w, 0))
  361. else:
  362. h = w1.GetSize()[1]
  363. w2.SetImageCoords((0, -h))
  364. w1.UpdateMap(render = False, renderVector = False)
  365. w2.UpdateMap(render = False, renderVector = False)
  366. pos = self.GetSashPosition()
  367. self.last = pos
  368. def OnSashChanging(self, event):
  369. Debug.msg(5, "MapSplitter.OnSashChanging()")
  370. if not (self.GetWindowStyle() & wx.SP_LIVE_UPDATE):
  371. if event:
  372. event.Skip()
  373. return
  374. pos = self.GetSashPosition()
  375. dpos = pos - self.last
  376. self.last = pos
  377. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  378. dx = -dpos
  379. dy = 0
  380. else:
  381. dx = 0
  382. dy = -dpos
  383. self.GetWindow2().TranslateImage(dx, dy)
  384. self.GetWindow1().movingSash = True
  385. self.GetWindow2().movingSash = True