frame.py 24 KB

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