frame.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. """!
  2. @package mapswipe.frame
  3. @brief Map Swipe Frame
  4. Classes:
  5. - dialogs::SwipeMapDialog
  6. (C) 2012 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Anna Kratochvilova <kratochanna gmail.com>
  10. """
  11. import os
  12. import sys
  13. import wx
  14. import time
  15. import grass.script as grass
  16. from gui_core.mapdisp import DoubleMapFrame
  17. from gui_core.dialogs import GetImageHandlers
  18. from mapwin.base import MapWindowProperties
  19. from core.render import Map
  20. from mapdisp import statusbar as sb
  21. from core.debug import Debug
  22. from core.gcmd import GError, GMessage
  23. from core.utils import _
  24. from core.layerlist import LayerListToRendererConverter
  25. from mapswipe.toolbars import SwipeMapToolbar, SwipeMainToolbar, SwipeMiscToolbar
  26. from mapswipe.mapwindow import SwipeBufferedWindow
  27. from mapswipe.dialogs import SwipeMapDialog, PreferencesDialog
  28. class SwipeMapFrame(DoubleMapFrame):
  29. def __init__(self, parent = None, giface = None,
  30. title = _("GRASS GIS Map Swipe"), name = "swipe", **kwargs):
  31. DoubleMapFrame.__init__(self, parent = parent, title = title, name = name,
  32. firstMap = Map(), secondMap = Map(), **kwargs)
  33. Debug.msg (1, "SwipeMapFrame.__init__()")
  34. #
  35. # Add toolbars
  36. #
  37. toolbars = ['swipeMisc', 'swipeMap', 'swipeMain']
  38. if sys.platform == 'win32':
  39. self.AddToolbar(toolbars.pop(1))
  40. toolbars.reverse()
  41. else:
  42. self.AddToolbar(toolbars.pop(0))
  43. for toolb in toolbars:
  44. self.AddToolbar(toolb)
  45. self._giface = giface
  46. #
  47. # create widgets
  48. #
  49. self.splitter = MapSplitter(parent = self, id = wx.ID_ANY)
  50. self.sliderH = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
  51. self.sliderV = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_VERTICAL)
  52. self.mapWindowProperties = MapWindowProperties()
  53. self.mapWindowProperties.setValuesFromUserSettings()
  54. self.mapWindowProperties.autoRenderChanged.connect(self.OnAutoRenderChanged)
  55. self.firstMapWindow = SwipeBufferedWindow(parent = self.splitter, giface = self._giface,
  56. properties=self.mapWindowProperties,
  57. Map = self.firstMap)
  58. self.secondMapWindow = SwipeBufferedWindow(parent = self.splitter, giface = self._giface,
  59. properties=self.mapWindowProperties,
  60. Map = self.secondMap)
  61. self.MapWindow = self.firstMapWindow # current by default
  62. self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
  63. self.SetBindRegions(True)
  64. self._mode = 'swipe'
  65. self._addPanes()
  66. self._bindWindowsActivation()
  67. self._setUpMapWindow(self.firstMapWindow)
  68. self._setUpMapWindow(self.secondMapWindow)
  69. self._mgr.GetPane('sliderV').Hide()
  70. self._mgr.GetPane('sliderH').Show()
  71. self.slider = self.sliderH
  72. self.InitStatusbar()
  73. self.Bind(wx.EVT_SIZE, self.OnSize)
  74. self.Bind(wx.EVT_IDLE, self.OnIdle)
  75. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  76. self.SetSize((800, 600))
  77. self._mgr.Update()
  78. self.rasters = {'first': None, 'second': None}
  79. self._inputDialog = None
  80. self._preferencesDialog = None
  81. # default action in map toolbar
  82. self.GetMapToolbar().SelectDefault()
  83. self.resize = False
  84. wx.CallAfter(self.CallAfterInit)
  85. def TrackCursor(self, event, showInFirst):
  86. """!Track cursor in one window and show cross in the other.
  87. Only for mirror mode.
  88. """
  89. if self._mode == 'swipe':
  90. event.Skip()
  91. return
  92. coords = event.GetPosition()
  93. if showInFirst:
  94. self.firstMapWindow.DrawMouseCursor(coords=coords)
  95. else:
  96. self.secondMapWindow.DrawMouseCursor(coords=coords)
  97. event.Skip()
  98. def ActivateFirstMap(self, event = None):
  99. """!Switch tracking direction"""
  100. super(SwipeMapFrame, self).ActivateFirstMap(event)
  101. self.firstMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt, showInFirst = False))
  102. self.secondMapWindow.Unbind(wx.EVT_MOTION)
  103. self.firstMapWindow.ClearLines()
  104. self.firstMapWindow.Refresh()
  105. def ActivateSecondMap(self, event = None):
  106. """!Switch tracking direction"""
  107. super(SwipeMapFrame, self).ActivateSecondMap(event)
  108. self.secondMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt, showInFirst = True))
  109. self.firstMapWindow.Unbind(wx.EVT_MOTION)
  110. self.secondMapWindow.ClearLines()
  111. self.secondMapWindow.Refresh()
  112. def CallAfterInit(self):
  113. self.InitSliderBindings()
  114. self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  115. self.splitter.Init()
  116. if not (self.rasters['first'] and self.rasters['second']):
  117. self.OnSelectLayers(event=None)
  118. def InitStatusbar(self):
  119. """!Init statusbar (default items)."""
  120. # items for choice
  121. self.statusbarItems = [sb.SbCoordinates,
  122. sb.SbRegionExtent,
  123. sb.SbCompRegionExtent,
  124. sb.SbShowRegion,
  125. sb.SbAlignExtent,
  126. sb.SbResolution,
  127. sb.SbDisplayGeometry,
  128. sb.SbMapScale,
  129. sb.SbGoTo,
  130. sb.SbProjection]
  131. # create statusbar and its manager
  132. statusbar = self.CreateStatusBar(number = 4, style = 0)
  133. statusbar.SetStatusWidths([-5, -2, -1, -1])
  134. self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
  135. # fill statusbar manager
  136. self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
  137. self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
  138. sbRender = sb.SbRender(self, statusbar = statusbar, position = 3)
  139. self.statusbarManager.AddStatusbarItem(sbRender)
  140. self.statusbarManager.Update()
  141. def ResetSlider(self):
  142. if self.splitter.GetSplitMode() == wx.SPLIT_VERTICAL:
  143. size = self.splitter.GetSize()[0]
  144. else:
  145. size = self.splitter.GetSize()[1]
  146. self.slider.SetRange(0, size)
  147. self.slider.SetValue(self.splitter.GetSashPosition())
  148. def InitSliderBindings(self):
  149. self.sliderH.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
  150. self.sliderH.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
  151. self.sliderV.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
  152. self.sliderV.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
  153. self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  154. self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  155. def OnSliderPositionChanging(self, event):
  156. """!Slider changes its position, sash must be moved too."""
  157. Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanging()")
  158. self.GetFirstWindow().movingSash = True
  159. self.GetSecondWindow().movingSash = True
  160. pos = event.GetPosition()
  161. if pos > 0:
  162. self.splitter.SetSashPosition(pos)
  163. self.splitter.OnSashChanging(None)
  164. def OnSliderPositionChanged(self, event):
  165. """!Slider position changed, sash must be moved too."""
  166. Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanged()")
  167. self.splitter.SetSashPosition(event.GetPosition())
  168. self.splitter.OnSashChanged(None)
  169. def OnSashChanging(self, event):
  170. """!Sash position is changing, slider must be moved too."""
  171. Debug.msg (5, "SwipeMapFrame.OnSashChanging()")
  172. self.slider.SetValue(self.splitter.GetSashPosition())
  173. event.Skip()
  174. def OnSashChanged(self, event):
  175. """!Sash position changed, slider must be moved too."""
  176. Debug.msg (5, "SwipeMapFrame.OnSashChanged()")
  177. self.OnSashChanging(event)
  178. event.Skip()
  179. def OnSize(self, event):
  180. Debug.msg (4, "SwipeMapFrame.OnSize()")
  181. self.resize = time.clock()
  182. super(SwipeMapFrame, self).OnSize(event)
  183. def OnIdle(self, event):
  184. if self.resize and time.clock() - self.resize > 0.2:
  185. w1 = self.GetFirstWindow()
  186. w2 = self.GetSecondWindow()
  187. sizeAll = self.splitter.GetSize()
  188. w1.SetClientSize(sizeAll)
  189. w2.SetClientSize(sizeAll)
  190. w1.OnSize(event)
  191. w2.OnSize(event)
  192. self.ResetSlider()
  193. self.resize = False
  194. def OnAutoRenderChanged(self, value):
  195. """!Auto rendering state changed."""
  196. style = self.splitter.GetWindowStyle()
  197. style ^= wx.SP_LIVE_UPDATE
  198. self.splitter.SetWindowStyle(style)
  199. def AddToolbar(self, name):
  200. """!Add defined toolbar to the window
  201. Currently known toolbars are:
  202. - 'swipeMap' - basic map toolbar
  203. - 'swipeMain' - swipe functionality
  204. """
  205. if name == "swipeMap":
  206. self.toolbars[name] = SwipeMapToolbar(self, self._toolSwitcher)
  207. self._mgr.AddPane(self.toolbars[name],
  208. wx.aui.AuiPaneInfo().
  209. Name(name).Caption(_("Map Toolbar")).
  210. ToolbarPane().Top().
  211. LeftDockable(False).RightDockable(False).
  212. BottomDockable(False).TopDockable(True).
  213. CloseButton(False).Layer(2).Row(1).
  214. BestSize((self.toolbars[name].GetBestSize())))
  215. if name == "swipeMain":
  216. self.toolbars[name] = SwipeMainToolbar(self)
  217. self._mgr.AddPane(self.toolbars[name],
  218. wx.aui.AuiPaneInfo().
  219. Name(name).Caption(_("Main Toolbar")).
  220. ToolbarPane().Top().
  221. LeftDockable(False).RightDockable(False).
  222. BottomDockable(False).TopDockable(True).
  223. CloseButton(False).Layer(2).Row(1).
  224. BestSize((self.toolbars[name].GetBestSize())))
  225. if name == "swipeMisc":
  226. self.toolbars[name] = SwipeMiscToolbar(self)
  227. self._mgr.AddPane(self.toolbars[name],
  228. wx.aui.AuiPaneInfo().
  229. Name(name).Caption(_("Misc Toolbar")).
  230. ToolbarPane().Top().
  231. LeftDockable(False).RightDockable(False).
  232. BottomDockable(False).TopDockable(True).
  233. CloseButton(False).Layer(2).Row(1).
  234. BestSize((self.toolbars[name].GetBestSize())))
  235. def _addPanes(self):
  236. """!Add splitter window and sliders to aui manager"""
  237. # splitter window
  238. self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
  239. Name('splitter').CaptionVisible(False).PaneBorder(True).
  240. Dockable(False).Floatable(False).CloseButton(False).
  241. Center().Layer(1).BestSize((self.splitter.GetBestSize())))
  242. # sliders
  243. self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
  244. Name('sliderH').CaptionVisible(False).PaneBorder(False).
  245. CloseButton(False).Gripper(True).GripperTop(False).
  246. BottomDockable(True).TopDockable(True).
  247. LeftDockable(False).RightDockable(False).
  248. Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))
  249. self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
  250. Name('sliderV').CaptionVisible(False).PaneBorder(False).
  251. CloseButton(False).Gripper(True).GripperTop(True).
  252. BottomDockable(False).TopDockable(False).
  253. LeftDockable(True).RightDockable(True).
  254. Right().Layer(1).BestSize((self.sliderV.GetBestSize())))
  255. def ZoomToMap(self):
  256. """!
  257. Set display extents to match selected raster (including NULLs)
  258. or vector map.
  259. """
  260. layers = []
  261. if self.rasters['first']:
  262. layers += self.firstMap.GetListOfLayers()
  263. if self.rasters['second']:
  264. layers += self.secondMap.GetListOfLayers()
  265. self.GetFirstWindow().ZoomToMap(layers = layers)
  266. self.GetSecondWindow().ZoomToMap(layers = layers)
  267. def OnZoomToMap(self, event):
  268. """!Zoom to map"""
  269. self.ZoomToMap()
  270. def OnZoomBack(self, event):
  271. self.GetFirstWindow().ZoomBack()
  272. self.secondMap.region = self.firstMap.region
  273. self.Render(self.GetSecondWindow())
  274. def OnSelectLayers(self, event):
  275. if self._inputDialog is None:
  276. dlg = SwipeMapDialog(self, first=self.rasters['first'],
  277. second=self.rasters['second'],
  278. firstLayerList=None, secondLayerList=None)
  279. dlg.applyChanges.connect(self.OnApplyInputChanges)
  280. # connect to convertor object to convert to Map
  281. # store reference to convertor is needed otherwise it would be discarded
  282. self._firstConverter = self._connectSimpleLmgr(dlg.GetFirstSimpleLmgr(),
  283. self.GetFirstMap())
  284. self._secondConverter = self._connectSimpleLmgr(dlg.GetSecondSimpleLmgr(),
  285. self.GetSecondMap())
  286. self._inputDialog = dlg
  287. dlg.CentreOnParent()
  288. dlg.Show()
  289. else:
  290. if self._inputDialog.IsShown():
  291. self._inputDialog.Raise()
  292. self._inputDialog.SetFocus()
  293. else:
  294. self._inputDialog.Show()
  295. def _connectSimpleLmgr(self, lmgr, renderer):
  296. converter = LayerListToRendererConverter(renderer)
  297. lmgr.opacityChanged.connect(converter.ChangeLayerOpacity)
  298. lmgr.cmdChanged.connect(converter.ChangeLayerCmd)
  299. lmgr.layerAdded.connect(converter.AddLayer)
  300. lmgr.layerRemoved.connect(converter.RemoveLayer)
  301. lmgr.layerActivated.connect(converter.ChangeLayerActive)
  302. lmgr.layerMovedUp.connect(converter.MoveLayerUp)
  303. lmgr.layerMovedDown.connect(converter.MoveLayerDown)
  304. lmgr.anyChange.connect(self._simpleLmgrChanged)
  305. return converter
  306. def _simpleLmgrChanged(self):
  307. if self.IsAutoRendered():
  308. self.OnRender(event=None)
  309. def OnApplyInputChanges(self):
  310. first, second = self._inputDialog.GetValues()
  311. if self._inputDialog.IsSimpleMode():
  312. self.rasters['first'], self.rasters['second'] = first, second
  313. res1 = self.SetFirstRaster(name=self.rasters['first'])
  314. res2 = self.SetSecondRaster(name=self.rasters['second'])
  315. if not (res1 and res2) and first and second:
  316. message = ''
  317. if not res1:
  318. message += _("Map <%s> not found. ") % self.rasters['first']
  319. if not res2:
  320. message += _("Map <%s> not found.") % self.rasters['second']
  321. GError(parent = self, message = message)
  322. return
  323. self.ZoomToMap()
  324. else:
  325. LayerListToRendererConverter(self.GetFirstMap()).ConvertAll(first)
  326. LayerListToRendererConverter(self.GetSecondMap()).ConvertAll(second)
  327. self.SetRasterNames()
  328. if self.IsAutoRendered():
  329. self.OnRender(event=None)
  330. def SetFirstRaster(self, name):
  331. """!Set raster map to first Map"""
  332. raster = grass.find_file(name = name, element = 'cell')
  333. if raster['fullname']:
  334. self.rasters['first'] = raster['fullname']
  335. self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
  336. return True
  337. return False
  338. def SetSecondRaster(self, name):
  339. """!Set raster map to second Map"""
  340. raster = grass.find_file(name = name, element = 'cell')
  341. if raster['fullname']:
  342. self.rasters['second'] = raster['fullname']
  343. self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
  344. return True
  345. return False
  346. def SetLayer(self, name, mapInstance):
  347. """!Sets layer in Map.
  348. @param name layer (raster) name
  349. """
  350. Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
  351. # this simple application enables to keep only one raster
  352. mapInstance.DeleteAllLayers()
  353. cmdlist = ['d.rast', 'map=%s' % name]
  354. # add layer to Map instance (core.render)
  355. newLayer = mapInstance.AddLayer(ltype = 'raster', command = cmdlist, active = True,
  356. name = name, hidden = False, opacity = 1.0,
  357. render = True)
  358. def OnSwitchWindows(self, event):
  359. """!Switch windows position."""
  360. Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
  361. splitter = self.splitter
  362. w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
  363. splitter.ReplaceWindow(w1, w2)
  364. splitter.ReplaceWindow(w2, w1)
  365. # self.OnSize(None)
  366. splitter.OnSashChanged(None)
  367. def _saveToFile(self, fileName, fileType):
  368. """!Creates composite image by rendering both images and
  369. pasting them into the new one.
  370. @todo specify size of the new image (problem is inaccurate scaling)
  371. @todo make dividing line width and color optional
  372. """
  373. w1 = self.splitter.GetWindow1()
  374. w2 = self.splitter.GetWindow2()
  375. lineWidth = 1
  376. # render to temporary files
  377. filename1 = grass.tempfile(False) + '1'
  378. filename2 = grass.tempfile(False) + '2'
  379. width, height = self.splitter.GetClientSize()
  380. if self._mode == 'swipe':
  381. x, y = w2.GetImageCoords()
  382. w1.SaveToFile(filename1, fileType, width, height)
  383. w2.SaveToFile(filename2, fileType, width, height)
  384. else:
  385. fw, fh = w1.GetClientSize()
  386. w1.SaveToFile(filename1, fileType, fw, fh)
  387. sw, sh = w2.GetClientSize()
  388. w2.SaveToFile(filename2, fileType, sw, sh)
  389. # create empty white image - needed for line
  390. im = wx.EmptyImage(width, height)
  391. im.Replace(0, 0, 0, 255, 255, 255)
  392. # paste images
  393. if self._mode == 'swipe':
  394. if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  395. im1 = wx.Image(filename1).GetSubImage((0, 0, width, -y))
  396. im.Paste(im1, 0, 0)
  397. im.Paste(wx.Image(filename2), -x, -y + lineWidth)
  398. else:
  399. im1 = wx.Image(filename1).GetSubImage((0, 0, -x, height))
  400. im.Paste(im1, 0, 0)
  401. im.Paste(wx.Image(filename2), -x + lineWidth, -y)
  402. else:
  403. if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  404. im1 = wx.Image(filename1)
  405. im.Paste(im1, 0, 0)
  406. im.Paste(wx.Image(filename2), 0, fh + lineWidth)
  407. else:
  408. im1 = wx.Image(filename1)
  409. im.Paste(im1, 0, 0)
  410. im.Paste(wx.Image(filename2), fw + lineWidth, 0)
  411. im.SaveFile(fileName, fileType)
  412. # remove temporary files
  413. grass.try_remove(filename1)
  414. grass.try_remove(filename2)
  415. def SaveToFile(self, event):
  416. """!Save map to image
  417. """
  418. img = self.firstMapWindow.img or self.secondMapWindow.img
  419. if not img:
  420. GMessage(parent = self,
  421. message = _("Nothing to render (empty map). Operation canceled."))
  422. return
  423. filetype, ltype = GetImageHandlers(img)
  424. # get filename
  425. dlg = wx.FileDialog(parent = self,
  426. message = _("Choose a file name to save the image "
  427. "(no need to add extension)"),
  428. wildcard = filetype,
  429. style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
  430. if dlg.ShowModal() == wx.ID_OK:
  431. path = dlg.GetPath()
  432. if not path:
  433. dlg.Destroy()
  434. return
  435. base, ext = os.path.splitext(path)
  436. fileType = ltype[dlg.GetFilterIndex()]['type']
  437. extType = ltype[dlg.GetFilterIndex()]['ext']
  438. if ext != extType:
  439. path = base + '.' + extType
  440. self._saveToFile(path, fileType)
  441. dlg.Destroy()
  442. def OnSwitchOrientation(self, event):
  443. """!Switch orientation of the sash."""
  444. Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
  445. splitter = self.splitter
  446. splitter.Unsplit()
  447. if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  448. splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
  449. self.slider = self.sliderH
  450. if self._mode == 'swipe':
  451. self._mgr.GetPane('sliderH').Show()
  452. self._mgr.GetPane('sliderV').Hide()
  453. else:
  454. splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
  455. self.slider = self.sliderV
  456. if self._mode == 'swipe':
  457. self._mgr.GetPane('sliderV').Show()
  458. self._mgr.GetPane('sliderH').Hide()
  459. self._mgr.Update()
  460. splitter.OnSashChanged(None)
  461. self.OnSize(None)
  462. self.SetRasterNames()
  463. def OnAddText(self, event):
  464. """!Double click on text overlay
  465. So far not implemented.
  466. """
  467. pass
  468. def SetViewMode(self, mode):
  469. """!Sets view mode.
  470. @param mode view mode ('swipe', 'mirror')
  471. """
  472. if self._mode == mode:
  473. return
  474. self._mode = mode
  475. self.toolbars['swipeMain'].SetMode(mode)
  476. # set window mode
  477. self.GetFirstWindow().SetMode(mode)
  478. self.GetSecondWindow().SetMode(mode)
  479. # hide/show slider
  480. if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
  481. self._mgr.GetPane('sliderV').Show(mode == 'swipe')
  482. size = self.splitter.GetSize()[1] / 2
  483. else:
  484. self._mgr.GetPane('sliderH').Show(mode == 'swipe')
  485. size = self.splitter.GetSize()[0] / 2
  486. # set sash in the middle
  487. self.splitter.SetSashPosition(size)
  488. self.slider.SetValue(size)
  489. self._mgr.Update()
  490. # enable / disable sash
  491. self.splitter.EnableSash(mode == 'swipe')
  492. # hack to make it work
  493. self.splitter.OnSashChanged(None)
  494. self.SendSizeEvent()
  495. def SetRasterNames(self):
  496. if not self._inputDialog or self._inputDialog.IsSimpleMode():
  497. if self.rasters['first']:
  498. self.GetFirstWindow().SetRasterNameText(self.rasters['first'], 101)
  499. if self.rasters['second']:
  500. self.GetSecondWindow().SetRasterNameText(self.rasters['second'], 102)
  501. else:
  502. self.GetFirstWindow().SetRasterNameText('', 101)
  503. self.GetSecondWindow().SetRasterNameText('', 102)
  504. def GetMapToolbar(self):
  505. """!Returns toolbar with zooming tools"""
  506. return self.toolbars['swipeMap']
  507. def IsStandalone(self):
  508. """!Since we do not need layer manager, we are standalone"""
  509. return True
  510. def OnHelp(self, event):
  511. self._giface.Help(entry = 'wxGUI.mapswipe')
  512. def OnPreferences(self, event):
  513. if not self._preferencesDialog:
  514. dlg = PreferencesDialog(parent=self, giface=self._giface)
  515. self._preferencesDialog = dlg
  516. self._preferencesDialog.CenterOnParent()
  517. self._preferencesDialog.ShowModal()
  518. def OnCloseWindow(self, event):
  519. self.GetFirstMap().Clean()
  520. self.GetSecondMap().Clean()
  521. self.Destroy()
  522. class MapSplitter(wx.SplitterWindow):
  523. """!Splitter window for displaying two maps"""
  524. def __init__(self, parent, id):
  525. wx.SplitterWindow.__init__(self, parent = parent, id = id,
  526. style = wx.SP_LIVE_UPDATE
  527. )
  528. Debug.msg(2, "MapSplitter.__init__()")
  529. self.sashWidthMin = 1
  530. self.sashWidthMax = 10
  531. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
  532. self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
  533. self._moveSash = True
  534. def EnableSash(self, enable):
  535. self._moveSash = enable
  536. def Init(self):
  537. self.OnSashChanged(evt = None)
  538. self.SetMinimumPaneSize(0)
  539. self.SetSashSize(self.sashWidthMin)
  540. # def OnMotion(self, event):
  541. # w = self.GetSashSize()
  542. # w1, w2 = self.GetWindow1(), self.GetWindow2()
  543. # if self.SashHitTest(event.GetX(), event.GetY(), tolerance = 20):
  544. # if w == self.sashWidthMin:
  545. # self.SetSashSize(self.sashWidthMax)
  546. # self.SetNeedUpdating(True)
  547. # w1.movingSash = True
  548. # w2.movingSash = True
  549. # else:
  550. # w1.movingSash = False
  551. # w1.movingSash = False
  552. # else:
  553. # if w == self.sashWidthMax:
  554. # self.SetSashSize(self.sashWidthMin)
  555. # self.SetNeedUpdating(True)
  556. # w1.movingSash = True
  557. # w2.movingSash = True
  558. # else:
  559. # w1.movingSash = False
  560. # w2.movingSash = False
  561. # event.Skip()
  562. def OnSashChanged(self, evt):
  563. Debug.msg(5, "MapSplitter.OnSashChanged()")
  564. if not self._moveSash:
  565. return
  566. w1, w2 = self.GetWindow1(), self.GetWindow2()
  567. w1.movingSash = False
  568. w2.movingSash = False
  569. wx.CallAfter(self.SashChanged)
  570. def SashChanged(self):
  571. Debug.msg(5, "MapSplitter.SashChanged()")
  572. w1, w2 = self.GetWindow1(), self.GetWindow2()
  573. w1.SetImageCoords((0, 0))
  574. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  575. w = w1.GetSize()[0]
  576. w2.SetImageCoords((-w, 0))
  577. else:
  578. h = w1.GetSize()[1]
  579. w2.SetImageCoords((0, -h))
  580. w1.UpdateMap(render = False, renderVector = False)
  581. w2.UpdateMap(render = False, renderVector = False)
  582. pos = self.GetSashPosition()
  583. self.last = pos
  584. def OnSashChanging(self, event):
  585. Debug.msg(5, "MapSplitter.OnSashChanging()")
  586. if not self._moveSash:
  587. event.SetSashPosition(-1)
  588. return
  589. if not (self.GetWindowStyle() & wx.SP_LIVE_UPDATE):
  590. if event:
  591. event.Skip()
  592. return
  593. pos = self.GetSashPosition()
  594. dpos = pos - self.last
  595. self.last = pos
  596. if self.GetSplitMode() == wx.SPLIT_VERTICAL:
  597. dx = -dpos
  598. dy = 0
  599. else:
  600. dx = 0
  601. dy = -dpos
  602. self.GetWindow2().TranslateImage(dx, dy)
  603. self.GetWindow1().movingSash = True
  604. self.GetWindow2().movingSash = True