frame.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. import os
  2. import sys
  3. import wx
  4. import time
  5. if __name__ == "__main__":
  6. sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
  7. import grass.script as grass
  8. from gui_core.mapdisp import DoubleMapFrame
  9. from core.render import Map, MapLayer
  10. from mapdisp import statusbar as sb
  11. from core.debug import Debug
  12. from mapdisp.statusbar import EVT_AUTO_RENDER
  13. from swipe.toolbars import SwipeMapToolbar, SwipeMainToolbar
  14. from swipe.mapwindow import SwipeBufferedWindow, EVT_MOTION
  15. from swipe.dialogs import SwipeMapDialog
  16. class SwipeMapFrame(DoubleMapFrame):
  17. def __init__(self, parent = None, title = _("Map Swipe"), name = "swipe", **kwargs):
  18. DoubleMapFrame.__init__(self, parent = parent, title = title, name = name,
  19. firstMap = Map(), secondMap = Map(), **kwargs)
  20. Debug.msg (1, "SwipeMapFrame.__init__()")
  21. #
  22. # Add toolbars
  23. #
  24. toolbars = ['swipeMap', 'swipeMain']
  25. if sys.platform == 'win32':
  26. self.AddToolbar(toolbars.pop(1))
  27. toolbars.reverse()
  28. else:
  29. self.AddToolbar(toolbars.pop(0))
  30. for toolb in toolbars:
  31. self.AddToolbar(toolb)
  32. #
  33. # create widgets
  34. #
  35. self.splitter = MapSplitter(parent = self, id = wx.ID_ANY)
  36. self.sliderH = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
  37. self.sliderV = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_VERTICAL)
  38. self.firstMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.firstMap, frame = self)
  39. self.secondMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.secondMap, frame = self)
  40. self.MapWindow = self.firstMapWindow # current by default
  41. self.firstMap.region = self.secondMap.region
  42. self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
  43. self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  44. self._addPanes()
  45. self._bindWindowsActivation()
  46. self._mgr.GetPane('sliderV').Hide()
  47. self._mgr.GetPane('sliderH').Show()
  48. self.slider = self.sliderH
  49. self.InitStatusbar()
  50. self.Bind(wx.EVT_SIZE, self.OnSize)
  51. self.Bind(EVT_AUTO_RENDER, self.OnAutoRenderChanged)
  52. self.Bind(wx.EVT_IDLE, self.OnIdle)
  53. self.SetSize((800, 600))
  54. self._mgr.Update()
  55. self.rasters = {'first': None, 'second': None}
  56. # default action in map toolbar
  57. self.OnPan(event = None)
  58. self.resize = False
  59. wx.CallAfter(self.CallAfterInit)
  60. def CallAfterInit(self):
  61. self.InitSliderBindings()
  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. w1 = self.GetFirstWindow()
  127. w2 = self.GetSecondWindow()
  128. sizeAll = self.splitter.GetSize()
  129. w1.SetClientSize(sizeAll)
  130. w2.SetClientSize(sizeAll)
  131. w1.OnSize(event)
  132. w2.OnSize(event)
  133. def OnIdle(self, event):
  134. if self.resize and time.clock() - self.resize > 0.2:
  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. def _addPanes(self):
  169. """!Add splitter window and sliders to aui manager"""
  170. # splitter window
  171. self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
  172. Name('splitter').CaptionVisible(False).PaneBorder(True).
  173. Dockable(False).Floatable(False).CloseButton(False).
  174. Center().Layer(1).BestSize((self.splitter.GetBestSize())))
  175. # sliders
  176. self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
  177. Name('sliderH').CaptionVisible(False).PaneBorder(False).
  178. CloseButton(False).Gripper(True).GripperTop(False).
  179. BottomDockable(True).TopDockable(True).
  180. LeftDockable(False).RightDockable(False).
  181. Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))
  182. self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
  183. Name('sliderV').CaptionVisible(False).PaneBorder(False).
  184. CloseButton(False).Gripper(True).GripperTop(True).
  185. BottomDockable(False).TopDockable(False).
  186. LeftDockable(True).RightDockable(True).
  187. Right().Layer(1).BestSize((self.sliderV.GetBestSize())))
  188. def UpdateRegion(self):
  189. """!
  190. Rerender the second window
  191. when the region of the first changed.
  192. """
  193. Debug.msg(3, "SwipeMapFrame.UpdateRegion()")
  194. if self.GetWindow() == self.GetSecondWindow():
  195. self.Render(self.GetFirstWindow())
  196. else:
  197. self.Render(self.GetSecondWindow())
  198. def OnZoomToMap(self, event):
  199. """!
  200. Set display extents to match selected raster (including NULLs)
  201. or vector map.
  202. """
  203. self.GetFirstWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
  204. self.GetSecondWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
  205. # needed again, don't know why
  206. self.firstMap.region = self.secondMap.region
  207. def OnZoomBack(self, event):
  208. self.GetFirstWindow().ZoomBack()
  209. self.secondMap.region = self.firstMap.region
  210. self.Render(self.GetSecondWindow())
  211. def OnSelectRasters(self, event):
  212. """!Choose raster maps and rerender."""
  213. dlg = SwipeMapDialog(self, first = self.rasters['first'], second = self.rasters['second'])
  214. if dlg.ShowModal() == wx.ID_OK:
  215. maps = dlg.GetValues()
  216. raster1 = grass.find_file(name = maps[0], element = 'cell')
  217. raster2 = grass.find_file(name = maps[1], element = 'cell')
  218. self.SetFirstRaster(name = maps[0])
  219. self.SetSecondRaster(name = maps[1])
  220. dlg.Destroy()
  221. self.OnRender(event = None)
  222. def SetFirstRaster(self, name):
  223. """!Set raster map to first Map"""
  224. raster = grass.find_file(name = name, element = 'cell')
  225. if raster['fullname']:
  226. self.rasters['first'] = raster['fullname']
  227. self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
  228. self.OnZoomToMap(event = None)
  229. def SetSecondRaster(self, name):
  230. """!Set raster map to second Map"""
  231. raster = grass.find_file(name = name, element = 'cell')
  232. if raster['fullname']:
  233. self.rasters['second'] = raster['fullname']
  234. self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
  235. self.OnZoomToMap(event = None)
  236. def SetLayer(self, name, mapInstance):
  237. """!Sets layer in Map.
  238. @param name layer (raster) name
  239. """
  240. Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
  241. # this simple application enables to keep only one raster
  242. mapInstance.DeleteAllLayers()
  243. cmdlist = ['d.rast', 'map=%s' % name]
  244. # add layer to Map instance (core.render)
  245. newLayer = mapInstance.AddLayer(type = 'raster', command = cmdlist, l_active = True,
  246. name = name, l_hidden = False, l_opacity = 1.0,
  247. l_render = True)
  248. def OnSwitchWindows(self, event):
  249. """!Switch windows position."""
  250. Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
  251. splitter = self.splitter
  252. w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
  253. splitter.ReplaceWindow(w1, w2)
  254. splitter.ReplaceWindow(w2, w1)
  255. # self.OnSize(None)
  256. splitter.OnSashChanged(None)
  257. def OnSwitchOrientation(self, event):
  258. """!Switch orientation of the sash."""
  259. Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
  260. splitter = self.splitter
  261. splitter.Unsplit()
  262. if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  263. splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  264. self.slider = self.sliderH
  265. self._mgr.GetPane('sliderH').Show()
  266. self._mgr.GetPane('sliderV').Hide()
  267. else:
  268. splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
  269. self.slider = self.sliderV
  270. self._mgr.GetPane('sliderV').Show()
  271. self._mgr.GetPane('sliderH').Hide()
  272. self._mgr.Update()
  273. splitter.OnSashChanged(None)
  274. self.OnSize(None)
  275. def GetMapToolbar(self):
  276. """!Returns toolbar with zooming tools"""
  277. return self.toolbars['swipeMap']
  278. def IsStandalone(self):
  279. if parent:
  280. return False
  281. return True
  282. class MapSplitter(wx.SplitterWindow):
  283. """!Splitter window for displaying two maps"""
  284. def __init__(self, parent, id):
  285. wx.SplitterWindow.__init__(self, parent = parent, id = id,
  286. style = wx.SP_LIVE_UPDATE
  287. )
  288. Debug.msg(2, "MapSplitter.__init__()")
  289. self.sashWidthMin = 1
  290. self.sashWidthMax = 10
  291. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  292. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  293. wx.CallAfter(self.Init)
  294. def Init(self):
  295. self.OnSashChanged(evt = None)
  296. self.SetMinimumPaneSize(0)
  297. self.SetSashSize(self.sashWidthMin)
  298. # def OnMotion(self, event):
  299. # w = self.GetSashSize()
  300. # w1, w2 = self.GetWindow1(), self.GetWindow2()
  301. # if self.SashHitTest(event.GetX(), event.GetY(), tolerance = 20):
  302. # if w == self.sashWidthMin:
  303. # self.SetSashSize(self.sashWidthMax)
  304. # self.SetNeedUpdating(True)
  305. # w1.movingSash = True
  306. # w2.movingSash = True
  307. # else:
  308. # w1.movingSash = False
  309. # w1.movingSash = False
  310. # else:
  311. # if w == self.sashWidthMax:
  312. # self.SetSashSize(self.sashWidthMin)
  313. # self.SetNeedUpdating(True)
  314. # w1.movingSash = True
  315. # w2.movingSash = True
  316. # else:
  317. # w1.movingSash = False
  318. # w2.movingSash = False
  319. # event.Skip()
  320. def OnSashChanged(self, evt):
  321. Debug.msg(5, "MapSplitter.OnSashChanged()")
  322. w1, w2 = self.GetWindow1(), self.GetWindow2()
  323. w1.movingSash = False
  324. w2.movingSash = False
  325. wx.CallAfter(self.SashChanged)
  326. def SashChanged(self):
  327. Debug.msg(5, "MapSplitter.SashChanged()")
  328. w1, w2 = self.GetWindow1(), self.GetWindow2()
  329. w1.SetImageCoords((0, 0))
  330. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  331. w = w1.GetSize()[0]
  332. w2.SetImageCoords((-w, 0))
  333. else:
  334. h = w1.GetSize()[1]
  335. w2.SetImageCoords((0, -h))
  336. w1.UpdateMap(render = False, renderVector = False)
  337. w2.UpdateMap(render = False, renderVector = False)
  338. pos = self.GetSashPosition()
  339. self.last = pos
  340. def OnSashChanging(self, event):
  341. Debug.msg(5, "MapSplitter.OnSashChanging()")
  342. if not (self.GetWindowStyle() & wx.SP_LIVE_UPDATE):
  343. if event:
  344. event.Skip()
  345. return
  346. pos = self.GetSashPosition()
  347. dpos = pos - self.last
  348. self.last = pos
  349. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  350. dx = -dpos
  351. dy = 0
  352. else:
  353. dx = 0
  354. dy = -dpos
  355. self.GetWindow2().TranslateImage(dx, dy)
  356. self.GetWindow1().movingSash = True
  357. self.GetWindow2().movingSash = True
  358. def main():
  359. import gettext
  360. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
  361. app = wx.PySimpleApp()
  362. wx.InitAllImageHandlers()
  363. frame = SwipeMapFrame()
  364. frame.Show()
  365. app.MainLoop()
  366. if __name__ == '__main__':
  367. main()