Browse Source

wxGUI: new tool Map Swipe added, a few changes in base gui code needed

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@52602 15284696-431f-4ddb-bdfa-cd5b030d7da7
Anna Petrášová 13 years ago
parent
commit
f678609904

+ 2 - 2
gui/wxpython/Makefile

@@ -11,12 +11,12 @@ ETCDIR = $(ETC)/gui/wxpython
 
 
 SRCFILES := $(wildcard icons/*.* scripts/* xml/*) \
 SRCFILES := $(wildcard icons/*.* scripts/* xml/*) \
 	$(wildcard core/* dbmgr/* gcp/* gmodeler/* gui_core/* iclass/* lmgr/* location_wizard/* \
 	$(wildcard core/* dbmgr/* gcp/* gmodeler/* gui_core/* iclass/* lmgr/* location_wizard/* \
-	mapdisp/* modules/* nviz/* psmap/* vdigit/* wxplot/* ogc_services/* ) \
+	mapdisp/* modules/* nviz/* psmap/* swipe/* vdigit/* wxplot/* ogc_services/*) \
 	gis_set.py gis_set_error.py wxgui.py README
 	gis_set.py gis_set_error.py wxgui.py README
 DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
 DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
 
 
 PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbmgr gcp gmodeler gui_core iclass lmgr location_wizard \
 PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbmgr gcp gmodeler gui_core iclass lmgr location_wizard \
-	mapdisp modules nviz psmap vdigit wxplot ogc_services)
+	mapdisp modules nviz psmap swipe vdigit wxplot ogc_services)
 DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
 DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
 
 
 default: $(DSTFILES) menustrings.py
 default: $(DSTFILES) menustrings.py

+ 2 - 2
gui/wxpython/gcp/mapdisplay.py

@@ -114,11 +114,11 @@ class MapFrame(SingleMapFrame):
         #
         #
         self.grwiz.SwitchEnv('source')
         self.grwiz.SwitchEnv('source')
         self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
         self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
-                                          Map=self.SrcMap, tree=self.tree, lmgr=self._layerManager)
+                                          Map=self.SrcMap, frame = self, tree=self.tree, lmgr=self._layerManager)
 
 
         self.grwiz.SwitchEnv('target')
         self.grwiz.SwitchEnv('target')
         self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
         self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
-                                          Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
+                                          Map=self.TgtMap, frame = self, tree=self.tree, lmgr=self._layerManager)
         self.MapWindow = self.SrcMapWindow
         self.MapWindow = self.SrcMapWindow
         self.Map = self.SrcMap
         self.Map = self.SrcMap
         self.SrcMapWindow.SetCursor(self.cursors["cross"])
         self.SrcMapWindow.SetCursor(self.cursors["cross"])

+ 5 - 4
gui/wxpython/gui_core/mapwindow.py

@@ -36,10 +36,11 @@ class MapWindow(object):
      - Pixel2Cell
      - Pixel2Cell
      - Cell2Pixel (if it is possible)
      - Cell2Pixel (if it is possible)
     """
     """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None, **kwargs):
+    def __init__(self, parent, Map, frame,
+                 id = wx.ID_ANY, tree = None, lmgr = None, **kwargs):
         self.parent = parent # MapFrame
         self.parent = parent # MapFrame
         self.Map    = Map
         self.Map    = Map
+        self.frame = frame
         self.tree   = tree
         self.tree   = tree
         self.lmgr   = lmgr
         self.lmgr   = lmgr
         
         
@@ -228,7 +229,7 @@ class MapWindow(object):
         except (ValueError):
         except (ValueError):
             self.lastEN = None
             self.lastEN = None
         # FIXME: special case for vdigit and access to statusbarManager
         # FIXME: special case for vdigit and access to statusbarManager
-        if self.parent.statusbarManager.GetMode() == 0: # Coordinates            
+        if self.frame.statusbarManager.GetMode() == 0: # Coordinates            
             updated = False
             updated = False
             if hasattr(self, "digit"):
             if hasattr(self, "digit"):
                 precision = int(UserSettings.Get(group = 'projection', key = 'format',
                 precision = int(UserSettings.Get(group = 'projection', key = 'format',
@@ -236,7 +237,7 @@ class MapWindow(object):
                 updated = self._onMotion(self.lastEN, precision)
                 updated = self._onMotion(self.lastEN, precision)
 
 
             if not updated:
             if not updated:
-                self.parent.CoordinatesChanged()
+                self.frame.CoordinatesChanged()
         
         
         event.Skip()
         event.Skip()
 
 

+ 2 - 2
gui/wxpython/iclass/digit.py

@@ -28,7 +28,7 @@ except ImportError:
 
 
 class IClassVDigitWindow(VDigitWindow):
 class IClassVDigitWindow(VDigitWindow):
     """! Class similar to VDigitWindow but specialized for wxIClass."""
     """! Class similar to VDigitWindow but specialized for wxIClass."""
-    def __init__(self, parent, map):
+    def __init__(self, parent, map, frame):
         """!
         """!
         
         
         @a parent should has toolbar providing current class (category).
         @a parent should has toolbar providing current class (category).
@@ -36,7 +36,7 @@ class IClassVDigitWindow(VDigitWindow):
         @param parent gui parent
         @param parent gui parent
         @param map map renderer instance
         @param map map renderer instance
         """
         """
-        VDigitWindow.__init__(self, parent = parent, Map = map)
+        VDigitWindow.__init__(self, parent = parent, Map = map, frame = frame)
         
         
     def _onLeftDown(self, event):
     def _onLeftDown(self, event):
         action = self.toolbar.GetAction()
         action = self.toolbar.GetAction()

+ 2 - 2
gui/wxpython/iclass/frame.py

@@ -83,8 +83,8 @@ class IClassMapFrame(DoubleMapFrame):
                                 firstMap = Map(), secondMap = Map(),
                                 firstMap = Map(), secondMap = Map(),
                                 **kwargs)
                                 **kwargs)
         
         
-        self.firstMapWindow = IClassVDigitWindow(self, map = self.firstMap)
-        self.secondMapWindow = BufferedWindow(self, Map = self.secondMap)
+        self.firstMapWindow = IClassVDigitWindow(self, map = self.firstMap, frame = self)
+        self.secondMapWindow = BufferedWindow(self, Map = self.secondMap, frame = self)
         self.MapWindow = self.firstMapWindow # current by default
         self.MapWindow = self.firstMapWindow # current by default
         
         
         self._bindWindowsActivation()
         self._bindWindowsActivation()

+ 21 - 0
gui/wxpython/lmgr/frame.py

@@ -65,6 +65,7 @@ from lmgr.pyshell          import PyShellWindow
 from gui_core.forms        import GUI
 from gui_core.forms        import GUI
 from gcp.manager           import GCPWizard
 from gcp.manager           import GCPWizard
 from nviz.main             import haveNviz
 from nviz.main             import haveNviz
+from swipe.frame           import SwipeMapFrame
 
 
 class GMFrame(wx.Frame):
 class GMFrame(wx.Frame):
     """!Layer Manager frame with notebook widget for controlling GRASS
     """!Layer Manager frame with notebook widget for controlling GRASS
@@ -377,6 +378,26 @@ class GMFrame(wx.Frame):
         
         
         win.Show()
         win.Show()
 
 
+    def OnMapSwipe(self, event):
+        """!Launch Map Swipe"""
+        win = SwipeMapFrame(parent = self)
+
+        rasters = []
+        tree = self.GetLayerTree()
+        if tree:
+            for layer in tree.GetSelections():
+                if tree.GetPyData(layer)[0]['maplayer'].GetType() != 'raster':
+                    continue
+                rasters.append(tree.GetPyData(layer)[0]['maplayer'].GetName())
+
+        if len(rasters) >= 1:
+            win.SetFirstRaster(rasters[0])
+        if len(rasters) >= 2:
+            win.SetSecondRaster(rasters[1])
+
+        win.CentreOnScreen()
+        win.Show()
+
     def OnDone(self, cmd, returncode):
     def OnDone(self, cmd, returncode):
         """Command execution finised"""
         """Command execution finised"""
         if hasattr(self, "model"):
         if hasattr(self, "model"):

+ 4 - 4
gui/wxpython/mapdisp/frame.py

@@ -129,7 +129,7 @@ class MapFrame(SingleMapFrame):
         # Init map display (buffered DC & set default cursor)
         # Init map display (buffered DC & set default cursor)
         #
         #
         self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
         self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
-                                          Map = self.Map, tree = self.tree, lmgr = self._layerManager)
+                                          Map = self.Map, frame = self, tree = self.tree, lmgr = self._layerManager)
         # default is 2D display mode
         # default is 2D display mode
         self.MapWindow = self.MapWindow2D
         self.MapWindow = self.MapWindow2D
         self.MapWindow.SetCursor(self.cursors["default"])
         self.MapWindow.SetCursor(self.cursors["default"])
@@ -219,7 +219,7 @@ class MapFrame(SingleMapFrame):
         
         
         if not self.MapWindowVDigit:
         if not self.MapWindowVDigit:
             from vdigit.mapwindow import VDigitWindow
             from vdigit.mapwindow import VDigitWindow
-            self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
+            self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY, frame = self,
                                                 Map = self.Map, tree = self.tree,
                                                 Map = self.Map, tree = self.tree,
                                                 lmgr = self._layerManager)
                                                 lmgr = self._layerManager)
             self.MapWindowVDigit.Show()
             self.MapWindowVDigit.Show()
@@ -294,8 +294,8 @@ class MapFrame(SingleMapFrame):
         
         
         # create GL window
         # create GL window
         if not self.MapWindow3D:
         if not self.MapWindow3D:
-            self.MapWindow3D = GLWindow(self, id = wx.ID_ANY,
-                                             Map = self.Map, tree = self.tree, lmgr = self._layerManager)
+            self.MapWindow3D = GLWindow(self, id = wx.ID_ANY, frame = self,
+                                        Map = self.Map, tree = self.tree, lmgr = self._layerManager)
             self.MapWindow = self.MapWindow3D
             self.MapWindow = self.MapWindow3D
             self.MapWindow.SetCursor(self.cursors["default"])
             self.MapWindow.SetCursor(self.cursors["default"])
             
             

+ 55 - 54
gui/wxpython/mapdisp/mapwindow.py

@@ -51,11 +51,12 @@ class BufferedWindow(MapWindow, wx.Window):
     can also save the drawing to file by calling the
     can also save the drawing to file by calling the
     SaveToFile() method.
     SaveToFile() method.
     """
     """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None,
+    def __init__(self, parent, Map, frame,
+                 id = wx.ID_ANY, tree = None, lmgr = None,
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        MapWindow.__init__(self, parent, id, Map, tree, lmgr, **kwargs)
-        wx.Window.__init__(self, parent, id, style = style, **kwargs)
+        MapWindow.__init__(self, parent = parent, id = id, Map = Map,
+                           frame = frame, tree = tree, lmgr = lmgr, **kwargs)
+        wx.Window.__init__(self, parent = parent, id = id, style = style, **kwargs)
         
         
         # flags
         # flags
         self.resize = False # indicates whether or not a resize event has taken place
         self.resize = False # indicates whether or not a resize event has taken place
@@ -446,10 +447,10 @@ class BufferedWindow(MapWindow, wx.Window):
                     updatemap = False
                     updatemap = False
 
 
             # reposition checkbox in statusbar
             # reposition checkbox in statusbar
-            self.parent.StatusbarReposition()
+            self.frame.StatusbarReposition()
             
             
             # update statusbar
             # update statusbar
-            self.parent.StatusbarUpdate()
+            self.frame.StatusbarUpdate()
 
 
             if updatemap:
             if updatemap:
                 self.UpdateMap(render = True)
                 self.UpdateMap(render = True)
@@ -533,7 +534,7 @@ class BufferedWindow(MapWindow, wx.Window):
                 for key in self.imagedict.keys():
                 for key in self.imagedict.keys():
                     if self.imagedict[key]['id'] == overlay.id:
                     if self.imagedict[key]['id'] == overlay.id:
                         del self.imagedict[key]
                         del self.imagedict[key]
-
+                
                 self.imagedict[img] = { 'id' : overlay.id,
                 self.imagedict[img] = { 'id' : overlay.id,
                                         'layer' : overlay }
                                         'layer' : overlay }
                 imgs.append(img)
                 imgs.append(img)
@@ -587,9 +588,9 @@ class BufferedWindow(MapWindow, wx.Window):
         # initialize process bar (only on 'render')
         # initialize process bar (only on 'render')
         #
         #
         if render or renderVector:
         if render or renderVector:
-            self.parent.GetProgressBar().Show()
-            if self.parent.GetProgressBar().GetRange() > 0:
-                self.parent.GetProgressBar().SetValue(1)
+            self.frame.GetProgressBar().Show()
+            if self.frame.GetProgressBar().GetRange() > 0:
+                self.frame.GetProgressBar().SetValue(1)
         
         
         #
         #
         # render background image if needed
         # render background image if needed
@@ -606,16 +607,16 @@ class BufferedWindow(MapWindow, wx.Window):
             if render:
             if render:
                 # update display size
                 # update display size
                 self.Map.ChangeMapSize(self.GetClientSize())
                 self.Map.ChangeMapSize(self.GetClientSize())
-                if self.parent.GetProperty('resolution'):
+                if self.frame.GetProperty('resolution'):
                     # use computation region resolution for rendering
                     # use computation region resolution for rendering
                     windres = True
                     windres = True
                 else:
                 else:
                     windres = False
                     windres = False
                 
                 
-                self.mapfile = self.Map.Render(force = True, mapWindow = self.parent,
+                self.mapfile = self.Map.Render(force = True, mapWindow = self.frame,
                                                windres = windres)
                                                windres = windres)
             else:
             else:
-                self.mapfile = self.Map.Render(force = False, mapWindow = self.parent)
+                self.mapfile = self.Map.Render(force = False, mapWindow = self.frame)
             
             
         except GException, e:
         except GException, e:
             GError(message = e.value)
             GError(message = e.value)
@@ -700,20 +701,20 @@ class BufferedWindow(MapWindow, wx.Window):
             self.mouse['use'] = 'pointer'
             self.mouse['use'] = 'pointer'
             self.mouse['box'] = 'point'
             self.mouse['box'] = 'point'
             self.mouse['end'] = [0, 0]
             self.mouse['end'] = [0, 0]
-            self.SetCursor(self.parent.cursors["default"])
+            self.SetCursor(self.frame.cursors["default"])
             
             
         stop = time.clock()
         stop = time.clock()
         
         
         #
         #
         # hide process bar
         # hide process bar
         #
         #
-        self.parent.GetProgressBar().Hide()
+        self.frame.GetProgressBar().Hide()
 
 
         #
         #
         # update statusbar 
         # update statusbar 
         #
         #
         ### self.Map.SetRegion()
         ### self.Map.SetRegion()
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
         
         
         
         
         Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
         Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
@@ -1042,7 +1043,7 @@ class BufferedWindow(MapWindow, wx.Window):
         self.UpdateMap()
         self.UpdateMap()
         
         
         # update statusbar
         # update statusbar
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
         
         
         self.Refresh()
         self.Refresh()
         self.processMouse = True
         self.processMouse = True
@@ -1158,7 +1159,7 @@ class BufferedWindow(MapWindow, wx.Window):
             self.UpdateMap(render = True)
             self.UpdateMap(render = True)
             
             
             # update statusbar
             # update statusbar
-            self.parent.StatusbarUpdate()
+            self.frame.StatusbarUpdate()
             
             
         elif self.mouse["use"] == "query":
         elif self.mouse["use"] == "query":
             # querying
             # querying
@@ -1173,15 +1174,15 @@ class BufferedWindow(MapWindow, wx.Window):
                     nVectors += 1
                     nVectors += 1
             
             
             if isRaster or nVectors > 1:
             if isRaster or nVectors > 1:
-                self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
+                self.frame.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
             else:
             else:
-                self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
+                self.frame.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
                 # clear temp canvas
                 # clear temp canvas
                 self.UpdateMap(render = False, renderVector = False)
                 self.UpdateMap(render = False, renderVector = False)
             
             
         elif self.mouse["use"] == "queryVector":
         elif self.mouse["use"] == "queryVector":
             # editable mode for vector map layers
             # editable mode for vector map layers
-            self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
+            self.frame.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
             
             
             # clear temp canvas
             # clear temp canvas
             self.UpdateMap(render = False, renderVector = False)
             self.UpdateMap(render = False, renderVector = False)
@@ -1189,24 +1190,24 @@ class BufferedWindow(MapWindow, wx.Window):
         elif self.mouse["use"] in ["measure", "profile"]:
         elif self.mouse["use"] in ["measure", "profile"]:
             # measure or profile
             # measure or profile
             if self.mouse["use"] == "measure":
             if self.mouse["use"] == "measure":
-                self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
+                self.frame.MeasureDist(self.mouse['begin'], self.mouse['end'])
             
             
             self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
             self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
             self.ClearLines(pdc = self.pdcTmp)
             self.ClearLines(pdc = self.pdcTmp)
             self.DrawLines(pdc = self.pdcTmp)
             self.DrawLines(pdc = self.pdcTmp)
         
         
         elif self.mouse["use"] == "pointer" and \
         elif self.mouse["use"] == "pointer" and \
-                not self.parent.IsStandalone() and \
-                self.parent.GetLayerManager().gcpmanagement:
+                not self.frame.IsStandalone() and \
+                self.frame.GetLayerManager().gcpmanagement:
             # -> GCP manager
             # -> GCP manager
-            if self.parent.GetToolbar('gcpdisp'):
+            if self.frame.GetToolbar('gcpdisp'):
                 coord = self.Pixel2Cell(self.mouse['end'])
                 coord = self.Pixel2Cell(self.mouse['end'])
-                if self.parent.MapWindow == self.parent.SrcMapWindow:
+                if self.frame.MapWindow == self.frame.SrcMapWindow:
                     coordtype = 'source'
                     coordtype = 'source'
                 else:
                 else:
                     coordtype = 'target'
                     coordtype = 'target'
                 
                 
-                self.parent.GetLayerManager().gcpmanagement.SetGCPData(coordtype, coord, self, confirm = True)
+                self.frame.GetLayerManager().gcpmanagement.SetGCPData(coordtype, coord, self, confirm = True)
                 self.UpdateMap(render = False, renderVector = False)
                 self.UpdateMap(render = False, renderVector = False)
             
             
         elif self.mouse["use"] == "pointer" and \
         elif self.mouse["use"] == "pointer" and \
@@ -1228,10 +1229,10 @@ class BufferedWindow(MapWindow, wx.Window):
             
             
         elif self.mouse['use'] == 'legend':
         elif self.mouse['use'] == 'legend':
             self.ResizeLegend(self.mouse["begin"], self.mouse["end"])
             self.ResizeLegend(self.mouse["begin"], self.mouse["end"])
-            self.parent.dialogs['legend'].FindWindowByName("resize").SetValue(False)
+            self.frame.dialogs['legend'].FindWindowByName("resize").SetValue(False)
             self.Map.GetOverlay(1).SetActive(True)
             self.Map.GetOverlay(1).SetActive(True)
-            self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
-            self.parent.MapWindow.mouse['use'] = 'pointer'
+            self.frame.MapWindow.SetCursor(self.frame.cursors["default"])
+            self.frame.MapWindow.mouse['use'] = 'pointer'
             
             
             self.UpdateMap()
             self.UpdateMap()
             
             
@@ -1249,7 +1250,7 @@ class BufferedWindow(MapWindow, wx.Window):
             self.mouse['box'] = 'point'
             self.mouse['box'] = 'point'
             self.mouse['end'] = [0, 0]
             self.mouse['end'] = [0, 0]
             self.Refresh()
             self.Refresh()
-            self.SetCursor(self.parent.cursors["default"])
+            self.SetCursor(self.frame.cursors["default"])
         
         
         elif self.mouse["use"] != "profile" or \
         elif self.mouse["use"] != "profile" or \
                 (self.mouse['use'] != 'pointer' and \
                 (self.mouse['use'] != 'pointer' and \
@@ -1264,11 +1265,11 @@ class BufferedWindow(MapWindow, wx.Window):
             # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
             # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
             if self.dragid > 100:
             if self.dragid > 100:
                 self.currtxtid = self.dragid
                 self.currtxtid = self.dragid
-                self.parent.OnAddText(None)
+                self.frame.OnAddText(None)
             elif self.dragid == 0:
             elif self.dragid == 0:
-                self.parent.OnAddBarscale(None)
+                self.frame.OnAddBarscale(None)
             elif self.dragid == 1:
             elif self.dragid == 1:
-                self.parent.OnAddLegend(None)
+                self.frame.OnAddLegend(None)
         
         
     def OnRightDown(self, event):
     def OnRightDown(self, event):
         """!Right mouse button pressed
         """!Right mouse button pressed
@@ -1318,18 +1319,18 @@ class BufferedWindow(MapWindow, wx.Window):
         self.UpdateMap(render = True)
         self.UpdateMap(render = True)
         
         
         # update statusbar
         # update statusbar
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
         
         
     def OnMouseEnter(self, event):
     def OnMouseEnter(self, event):
         """!Mouse entered window and no mouse buttons were pressed
         """!Mouse entered window and no mouse buttons were pressed
         """
         """
-        if not self.parent.IsStandalone() and \
-                self.parent.GetLayerManager().gcpmanagement:
-            if self.parent.GetToolbar('gcpdisp'):
-                if not self.parent.MapWindow == self:
-                    self.parent.MapWindow = self
-                    self.parent.Map = self.Map
-                    self.parent.UpdateActive(self)
+        if not self.frame.IsStandalone() and \
+                self.frame.GetLayerManager().gcpmanagement:
+            if self.frame.GetToolbar('gcpdisp'):
+                if not self.frame.MapWindow == self:
+                    self.frame.MapWindow = self
+                    self.frame.Map = self.Map
+                    self.frame.UpdateActive(self)
                     # needed for wingrass
                     # needed for wingrass
                     self.SetFocus()
                     self.SetFocus()
         else:
         else:
@@ -1502,8 +1503,8 @@ class BufferedWindow(MapWindow, wx.Window):
             self.Map.region['center_northing'] = cn
             self.Map.region['center_northing'] = cn
             self.Map.region['ewres'] = (newreg['e'] - newreg['w']) / self.Map.width
             self.Map.region['ewres'] = (newreg['e'] - newreg['w']) / self.Map.width
             self.Map.region['nsres'] = (newreg['n'] - newreg['s']) / self.Map.height
             self.Map.region['nsres'] = (newreg['n'] - newreg['s']) / self.Map.height
-            if not self.parent.HasProperty('alignExtent') or \
-                    self.parent.GetProperty('alignExtent'):
+            if not self.frame.HasProperty('alignExtent') or \
+                    self.frame.GetProperty('alignExtent'):
                 self.Map.AlignExtentFromDisplay()
                 self.Map.AlignExtentFromDisplay()
             else:
             else:
                 for k in ('n', 's', 'e', 'w'):
                 for k in ('n', 's', 'e', 'w'):
@@ -1530,7 +1531,7 @@ class BufferedWindow(MapWindow, wx.Window):
         
         
         # disable tool if stack is empty
         # disable tool if stack is empty
         if len(self.zoomhistory) < 2: # disable tool
         if len(self.zoomhistory) < 2: # disable tool
-            toolbar = self.parent.GetMapToolbar()
+            toolbar = self.frame.GetMapToolbar()
             toolbar.Enable('zoomBack', enable = False)
             toolbar.Enable('zoomBack', enable = False)
         
         
         # zoom to selected region
         # zoom to selected region
@@ -1541,7 +1542,7 @@ class BufferedWindow(MapWindow, wx.Window):
         self.UpdateMap()
         self.UpdateMap()
         
         
         # update statusbar
         # update statusbar
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
 
 
     def ZoomHistory(self, n, s, e, w):
     def ZoomHistory(self, n, s, e, w):
         """!Manages a list of last 10 zoom extents
         """!Manages a list of last 10 zoom extents
@@ -1569,7 +1570,7 @@ class BufferedWindow(MapWindow, wx.Window):
         else:
         else:
             enable = False
             enable = False
         
         
-        toolbar = self.parent.GetMapToolbar()
+        toolbar = self.frame.GetMapToolbar()
         
         
         toolbar.Enable('zoomBack', enable)
         toolbar.Enable('zoomBack', enable)
         
         
@@ -1626,7 +1627,7 @@ class BufferedWindow(MapWindow, wx.Window):
         if render:
         if render:
             self.UpdateMap()
             self.UpdateMap()
         
         
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
         
         
     def ZoomToWind(self):
     def ZoomToWind(self):
         """!Set display geometry to match computational region
         """!Set display geometry to match computational region
@@ -1639,7 +1640,7 @@ class BufferedWindow(MapWindow, wx.Window):
         
         
         self.UpdateMap()
         self.UpdateMap()
         
         
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
 
 
     def ZoomToDefault(self):
     def ZoomToDefault(self):
         """!Set display geometry to match default region settings
         """!Set display geometry to match default region settings
@@ -1652,7 +1653,7 @@ class BufferedWindow(MapWindow, wx.Window):
         
         
         self.UpdateMap()
         self.UpdateMap()
         
         
-        self.parent.StatusbarUpdate()
+        self.frame.StatusbarUpdate()
     
     
     
     
     def GoTo(self, e, n):
     def GoTo(self, e, n):
@@ -1798,7 +1799,7 @@ class BufferedWindow(MapWindow, wx.Window):
         dEast  = (e2 - e1)
         dEast  = (e2 - e1)
         dNorth = (n2 - n1)
         dNorth = (n2 - n1)
         
         
-        if self.parent.Map.projinfo['proj'] == 'll' and haveCtypes:
+        if self.frame.Map.projinfo['proj'] == 'll' and haveCtypes:
             dist = gislib.G_distance(e1, n1, e2, n2)
             dist = gislib.G_distance(e1, n1, e2, n2)
         else:
         else:
             dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
             dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
@@ -1811,7 +1812,7 @@ class BufferedWindow(MapWindow, wx.Window):
 
 
     def RegisterMouseEventHandler(self, event, handler, cursor = None):
     def RegisterMouseEventHandler(self, event, handler, cursor = None):
         """!Calls UpdateTools to manage connected toolbars"""
         """!Calls UpdateTools to manage connected toolbars"""
-        self.parent.UpdateTools(None)
+        self.frame.UpdateTools(None)
         MapWindow.RegisterMouseEventHandler(self, event, handler, cursor)
         MapWindow.RegisterMouseEventHandler(self, event, handler, cursor)
 
 
     def UnregisterMouseEventHandler(self, event, handler):
     def UnregisterMouseEventHandler(self, event, handler):
@@ -1819,10 +1820,10 @@ class BufferedWindow(MapWindow, wx.Window):
         MapWindow.UnregisterMouseEventHandler(self, event, handler)
         MapWindow.UnregisterMouseEventHandler(self, event, handler)
         
         
         # sets pointer mode
         # sets pointer mode
-        toolbar = self.parent.toolbars['map']
+        toolbar = self.frame.toolbars['map']
         toolbar.action['id'] = vars(toolbar)["pointer"]
         toolbar.action['id'] = vars(toolbar)["pointer"]
         toolbar.OnTool(None)
         toolbar.OnTool(None)
-        self.parent.OnPointer(event = None)
+        self.frame.OnPointer(event = None)
         
         
     def RegisterGraphicsToDraw(self, graphicsType, setStatusFunc = None, drawFunc = None):
     def RegisterGraphicsToDraw(self, graphicsType, setStatusFunc = None, drawFunc = None):
         """! Method allows to register graphics to draw.
         """! Method allows to register graphics to draw.

+ 7 - 0
gui/wxpython/mapdisp/statusbar.py

@@ -33,12 +33,16 @@ This program is free software under the GNU General Public License
 
 
 import wx
 import wx
 
 
+from wx.lib.newevent import NewEvent
+
 from core          import utils
 from core          import utils
 from core.gcmd     import GMessage, RunCommand
 from core.gcmd     import GMessage, RunCommand
 from core.settings import UserSettings
 from core.settings import UserSettings
 
 
 from grass.script  import core as grass
 from grass.script  import core as grass
 
 
+wxAutoRender, EVT_AUTO_RENDER = NewEvent()
+
 class SbException:
 class SbException:
     """! Exception class used in SbManager and SbItems"""
     """! Exception class used in SbManager and SbItems"""
     def __init__(self, message):
     def __init__(self, message):
@@ -366,6 +370,9 @@ class SbRender(SbItem):
         
         
     def OnToggleRender(self, event):
     def OnToggleRender(self, event):
         # (other items should call self.mapFrame.IsAutoRendered())
         # (other items should call self.mapFrame.IsAutoRendered())
+        event = wxAutoRender(state = self.GetValue())
+        wx.PostEvent(self.mapFrame, event)
+        
         if self.GetValue():
         if self.GetValue():
             self.mapFrame.OnRender(None)
             self.mapFrame.OnRender(None)
 
 

+ 3 - 3
gui/wxpython/nviz/mapwindow.py

@@ -67,13 +67,13 @@ class NvizThread(Thread):
 
 
 class GLWindow(MapWindow, glcanvas.GLCanvas):
 class GLWindow(MapWindow, glcanvas.GLCanvas):
     """!OpenGL canvas for Map Display Window"""
     """!OpenGL canvas for Map Display Window"""
-    def __init__(self, parent, id = wx.ID_ANY,
+    def __init__(self, parent, id = wx.ID_ANY, frame = None,
                  Map = None, tree = None, lmgr = None):
                  Map = None, tree = None, lmgr = None):
         self.parent = parent # MapFrame
         self.parent = parent # MapFrame
         
         
         glcanvas.GLCanvas.__init__(self, parent, id)
         glcanvas.GLCanvas.__init__(self, parent, id)
-        MapWindow.__init__(self, parent, id, 
-                           Map, tree, lmgr)
+        MapWindow.__init__(self, parent = parent, id = id, frame = frame,
+                           Map = Map, tree = tree, lmgr = lmgr)
         self.Hide()
         self.Hide()
         
         
         self.init = False
         self.init = False

+ 62 - 0
gui/wxpython/swipe/dialogs.py

@@ -0,0 +1,62 @@
+"""!
+@package swipe.dialogs
+
+@brief Dialogs used in Map Swipe
+
+Classes:
+ - dialogs::SwipeMapDialog
+
+(C) 2006-2012 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+@author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import wx
+
+from core               import globalvar
+from gui_core.dialogs   import ElementDialog
+from gui_core           import gselect
+
+class SwipeMapDialog(ElementDialog):
+    """!Dialog used to select raster maps"""
+    def __init__(self, parent, title = _("Select raster maps"), id =  wx.ID_ANY, first = None, second = None):
+        ElementDialog.__init__(self, parent, title, label = _("Name of first raster map:"))
+
+        self.element = gselect.Select(parent = self.panel, type = 'raster',
+                                      size = globalvar.DIALOG_GSELECT_SIZE)
+        
+        self.element2 = gselect.Select(parent = self.panel, type = 'raster',
+                                       size = globalvar.DIALOG_GSELECT_SIZE)
+        
+        self.PostInit()
+        
+        if first:
+            self.element.SetValue(first)
+        if second:
+            self.element2.SetValue(second)
+            
+        self._layout()
+        self.SetMinSize(self.GetSize())
+
+    def _layout(self):
+        """!Do layout"""
+        self.dataSizer.Add(self.element, proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+ 
+        self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                         label = _("Name of second raster map:")), proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+
+        self.dataSizer.Add(self.element2, proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+       
+        self.panel.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+    def GetValues(self):
+        """!Get raster maps"""
+        return (self.GetElement(), self.element2.GetValue())
+

+ 460 - 0
gui/wxpython/swipe/frame.py

@@ -0,0 +1,460 @@
+import os
+import sys
+import  wx
+import time
+if __name__ == "__main__":
+    sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
+
+import grass.script as grass
+
+from gui_core.mapdisp   import DoubleMapFrame
+from core.render        import Map, MapLayer
+from mapdisp            import statusbar as sb
+from core.debug         import Debug
+from mapdisp.statusbar  import EVT_AUTO_RENDER
+
+from swipe.toolbars  import SwipeMapToolbar, SwipeMainToolbar
+from swipe.mapwindow import SwipeBufferedWindow, EVT_MOTION
+from swipe.dialogs   import SwipeMapDialog
+
+
+class SwipeMapFrame(DoubleMapFrame):
+    def __init__(self, parent  = None, title = _("Map Swipe"), name = "swipe", **kwargs):
+        DoubleMapFrame.__init__(self, parent = parent, title = title, name = name,
+                                firstMap = Map(), secondMap = Map(), **kwargs)
+        Debug.msg (1, "SwipeMapFrame.__init__()")
+        #
+        # Add toolbars
+        #
+        toolbars = ['swipeMap', 'swipeMain']
+        if sys.platform == 'win32':
+            self.AddToolbar(toolbars.pop(1))
+            toolbars.reverse()
+        else:
+            self.AddToolbar(toolbars.pop(0))
+        for toolb in toolbars:
+            self.AddToolbar(toolb)
+
+        #
+        # create widgets
+        #
+        self.splitter = MapSplitter(parent = self, id = wx.ID_ANY)
+
+        self.sliderH = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
+        self.sliderV = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_VERTICAL)
+        
+        self.firstMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.firstMap, frame = self)
+        self.secondMapWindow = SwipeBufferedWindow(parent = self.splitter, Map = self.secondMap, frame = self)
+        self.MapWindow = self.firstMapWindow # current by default
+        self.firstMap.region = self.secondMap.region
+        self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
+
+        self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
+
+        self._addPanes()
+        self._bindWindowsActivation()
+    
+        self._mgr.GetPane('sliderV').Hide()
+        self._mgr.GetPane('sliderH').Show()
+        self.slider = self.sliderH
+
+        self.InitStatusbar()
+
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(EVT_AUTO_RENDER, self.OnAutoRenderChanged)
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+        self.SetSize((800, 600))
+        
+        self._mgr.Update()
+
+        self.rasters = {'first': None, 'second': None}
+
+        # default action in map toolbar
+        self.OnPan(event = None)
+
+        self.resize = False
+
+        wx.CallAfter(self.CallAfterInit)
+
+    def CallAfterInit(self):
+        self.InitSliderBindings()
+        self.OnSelectRasters(event = None)
+        
+    def InitStatusbar(self):
+        """!Init statusbar (default items)."""
+        # items for choice
+        self.statusbarItems = [sb.SbCoordinates,
+                               sb.SbRegionExtent,
+                               sb.SbCompRegionExtent,
+                               sb.SbShowRegion,
+                               sb.SbAlignExtent,
+                               sb.SbResolution,
+                               sb.SbDisplayGeometry,
+                               sb.SbMapScale,
+                               sb.SbGoTo,
+                               sb.SbProjection]
+        
+        # create statusbar and its manager
+        statusbar = self.CreateStatusBar(number = 4, style = 0)
+        statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
+        
+        # fill statusbar manager
+        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
+        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
+        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
+        
+        self.statusbarManager.Update()
+
+    def ResetSlider(self):
+        if self.splitter.GetSplitMode() == wx.SPLIT_VERTICAL:
+            size = self.splitter.GetSize()[0]
+        else:
+            size = self.splitter.GetSize()[1]
+        self.slider.SetRange(0, size)
+        self.slider.SetValue(self.splitter.GetSashPosition())
+
+
+    def InitSliderBindings(self):
+        self.sliderH.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
+        self.sliderH.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
+        self.sliderV.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
+        self.sliderV.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
+        self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
+        self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
+
+
+    def OnSliderPositionChanging(self, event):
+        """!Slider changes its position, sash must be moved too."""
+        Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanging()")
+
+        self.GetFirstWindow().movingSash = True
+        self.GetSecondWindow().movingSash = True
+        pos = event.GetPosition()
+        if pos > 0:
+            self.splitter.SetSashPosition(pos)
+            self.splitter.OnSashChanging(None)
+
+    def OnSliderPositionChanged(self, event):
+        """!Slider position changed, sash must be moved too."""
+        Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanged()")
+
+        self.splitter.SetSashPosition(event.GetPosition())
+        self.splitter.OnSashChanged(None)
+
+    def OnSashChanging(self, event):
+        """!Sash position is changing, slider must be moved too."""
+        Debug.msg (5, "SwipeMapFrame.OnSashChanging()")
+
+        self.slider.SetValue(self.splitter.GetSashPosition())
+        event.Skip()
+
+    def OnSashChanged(self, event):
+        """!Sash position changed, slider must be moved too."""
+        Debug.msg (5, "SwipeMapFrame.OnSashChanged()")
+
+        self.OnSashChanging(event)
+        event.Skip()
+
+    def OnSize(self, event):
+        Debug.msg (4, "SwipeMapFrame.OnSize()")
+        self.resize = time.clock()
+        w1 = self.GetFirstWindow()
+        w2 = self.GetSecondWindow()
+
+        sizeAll = self.splitter.GetSize()
+        w1.SetClientSize(sizeAll)
+        w2.SetClientSize(sizeAll)
+        
+        w1.OnSize(event)
+        w2.OnSize(event)
+
+    def OnIdle(self, event):
+        if self.resize and time.clock() - self.resize > 0.2:
+            self.ResetSlider()
+            self.resize = False
+
+    def OnAutoRenderChanged(self, event):
+        """!Auto rendering state changed."""
+        style = self.splitter.GetWindowStyle()
+        style ^= wx.SP_LIVE_UPDATE
+        self.splitter.SetWindowStyle(style)
+
+    def AddToolbar(self, name):
+        """!Add defined toolbar to the window
+        
+        Currently known toolbars are:
+         - 'swipeMap'          - basic map toolbar
+         - 'swipeMain'         - swipe functionality
+        """
+        if name == "swipeMap":
+            self.toolbars[name] = SwipeMapToolbar(self)
+            self._mgr.AddPane(self.toolbars[name],
+                      wx.aui.AuiPaneInfo().
+                      Name(name).Caption(_("Map Toolbar")).
+                      ToolbarPane().Top().
+                      LeftDockable(False).RightDockable(False).
+                      BottomDockable(False).TopDockable(True).
+                      CloseButton(False).Layer(2).Row(1).
+                      BestSize((self.toolbars[name].GetBestSize())))
+
+        if name == "swipeMain":
+            self.toolbars[name] = SwipeMainToolbar(self)
+
+            self._mgr.AddPane(self.toolbars[name],
+                      wx.aui.AuiPaneInfo().
+                      Name(name).Caption(_("Main Toolbar")).
+                      ToolbarPane().Top().
+                      LeftDockable(False).RightDockable(False).
+                      BottomDockable(False).TopDockable(True).
+                      CloseButton(False).Layer(2).Row(1).
+                      BestSize((self.toolbars[name].GetBestSize())))
+
+    def _addPanes(self):
+        """!Add splitter window and sliders to aui manager"""
+        # splitter window
+        self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
+                  Name('splitter').CaptionVisible(False).PaneBorder(True).
+                  Dockable(False).Floatable(False).CloseButton(False).
+                  Center().Layer(1).BestSize((self.splitter.GetBestSize())))
+
+        # sliders
+        self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
+                  Name('sliderH').CaptionVisible(False).PaneBorder(False).
+                  CloseButton(False).Gripper(True).GripperTop(False).
+                  BottomDockable(True).TopDockable(True).
+                  LeftDockable(False).RightDockable(False).
+                  Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))
+
+        self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
+                  Name('sliderV').CaptionVisible(False).PaneBorder(False).
+                  CloseButton(False).Gripper(True).GripperTop(True).
+                  BottomDockable(False).TopDockable(False).
+                  LeftDockable(True).RightDockable(True).
+                  Right().Layer(1).BestSize((self.sliderV.GetBestSize())))
+
+    def UpdateRegion(self):
+        """!
+        Rerender the second window
+        when the region of the first changed.
+        """
+        Debug.msg(3, "SwipeMapFrame.UpdateRegion()")
+
+        if self.GetWindow() == self.GetSecondWindow():
+            self.Render(self.GetFirstWindow())
+        else:
+            self.Render(self.GetSecondWindow())
+
+    def OnZoomToMap(self, event):
+        """!
+        Set display extents to match selected raster (including NULLs)
+        or vector map.
+        """
+        self.GetFirstWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
+        self.GetSecondWindow().ZoomToMap(layers = self.Map.GetListOfLayers())
+        # needed again, don't know why
+        self.firstMap.region = self.secondMap.region
+
+    def OnZoomBack(self, event):
+        self.GetFirstWindow().ZoomBack()
+        self.secondMap.region = self.firstMap.region
+        self.Render(self.GetSecondWindow())
+
+
+    def OnSelectRasters(self, event):
+        """!Choose raster maps and rerender."""
+        dlg = SwipeMapDialog(self, first = self.rasters['first'], second = self.rasters['second'])
+        if dlg.ShowModal() == wx.ID_OK:
+            maps = dlg.GetValues()
+            raster1 = grass.find_file(name = maps[0], element = 'cell')
+            raster2 = grass.find_file(name = maps[1], element = 'cell')
+            self.SetFirstRaster(name = maps[0])
+            self.SetSecondRaster(name = maps[1])
+
+        dlg.Destroy()
+        self.OnRender(event = None)
+
+    def SetFirstRaster(self, name):
+        """!Set raster map to first Map"""
+        raster = grass.find_file(name = name, element = 'cell')
+        if raster['fullname']:
+            self.rasters['first'] = raster['fullname']
+            self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
+            self.OnZoomToMap(event = None)
+
+    def SetSecondRaster(self, name):
+        """!Set raster map to second Map"""
+        raster = grass.find_file(name = name, element = 'cell')
+        if raster['fullname']:
+            self.rasters['second'] = raster['fullname']
+            self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
+            self.OnZoomToMap(event = None)
+
+    def SetLayer(self, name, mapInstance):
+        """!Sets layer in Map.
+        
+        @param name layer (raster) name
+        """
+        Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
+        
+        self.rasters['first'] = name
+        # this simple application enables to keep only one raster
+        mapInstance.DeleteAllLayers()
+        cmdlist = ['d.rast', 'map=%s' % name]
+        # add layer to Map instance (core.render)
+        newLayer = mapInstance.AddLayer(type = 'raster', command = cmdlist, l_active = True,
+                                          name = name, l_hidden = False, l_opacity = 1.0,
+                                          l_render = True)
+
+    def OnSwitchWindows(self, event):
+        """!Switch windows position."""
+        Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
+
+        splitter = self.splitter
+        w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
+        splitter.ReplaceWindow(w1, w2)
+        splitter.ReplaceWindow(w2, w1)
+        # self.OnSize(None)
+        splitter.OnSashChanged(None)
+
+    def OnSwitchOrientation(self, event):
+        """!Switch orientation of the sash."""
+        Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
+
+        splitter = self.splitter
+        splitter.Unsplit()
+        if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
+            splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
+            self.slider = self.sliderH
+            self._mgr.GetPane('sliderH').Show()
+            self._mgr.GetPane('sliderV').Hide()
+        else:
+            splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
+            self.slider = self.sliderV
+            self._mgr.GetPane('sliderV').Show()
+            self._mgr.GetPane('sliderH').Hide()
+        self._mgr.Update()
+        splitter.OnSashChanged(None)
+        self.OnSize(None)
+
+    def GetMapToolbar(self):
+        """!Returns toolbar with zooming tools"""
+        return self.toolbars['swipeMap']
+
+    def IsStandalone(self):
+        if parent:
+            return False
+
+        return True
+
+
+class MapSplitter(wx.SplitterWindow):
+    """!Splitter window for displaying two maps"""
+    def __init__(self, parent, id):
+        wx.SplitterWindow.__init__(self, parent = parent, id = id,
+                                   style = wx.SP_LIVE_UPDATE
+                                   )
+        Debug.msg(2, "MapSplitter.__init__()")
+        
+        self.sashWidthMin = 1
+        self.sashWidthMax = 10
+        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
+        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
+        
+        wx.CallAfter(self.Init)
+
+    def Init(self):
+        self.OnSashChanged(evt = None)
+        self.SetMinimumPaneSize(0)
+        self.SetSashSize(self.sashWidthMin)
+
+    # def OnMotion(self, event):
+    #     w = self.GetSashSize()
+    #     w1, w2 = self.GetWindow1(), self.GetWindow2()
+    #     if self.SashHitTest(event.GetX(), event.GetY(), tolerance = 20):
+    #         if w == self.sashWidthMin:
+    #             self.SetSashSize(self.sashWidthMax)
+    #             self.SetNeedUpdating(True)
+    #             w1.movingSash = True
+    #             w2.movingSash = True
+    #         else:
+    #             w1.movingSash = False
+    #             w1.movingSash = False
+    #     else:
+    #         if w == self.sashWidthMax:
+    #             self.SetSashSize(self.sashWidthMin)
+    #             self.SetNeedUpdating(True)
+    #             w1.movingSash = True
+    #             w2.movingSash = True
+    #         else:
+    #             w1.movingSash = False
+    #             w2.movingSash = False
+
+    #     event.Skip()
+
+    def OnSashChanged(self, evt):
+        Debug.msg(5, "MapSplitter.OnSashChanged()")
+
+        w1, w2 = self.GetWindow1(), self.GetWindow2()
+        w1.movingSash = False
+        w2.movingSash = False
+        
+        wx.CallAfter(self.SashChanged)
+
+    def SashChanged(self):
+        Debug.msg(5, "MapSplitter.SashChanged()")
+
+        w1, w2 = self.GetWindow1(), self.GetWindow2() 
+        w1.SetImageCoords((0, 0))
+        if self.GetSplitMode() == wx.SPLIT_VERTICAL:
+            w = w1.GetSize()[0]
+            w2.SetImageCoords((-w, 0))
+        else:
+            h = w1.GetSize()[1]
+            w2.SetImageCoords((0, -h))
+
+        w1.UpdateMap(render = False, renderVector = False)
+        w2.UpdateMap(render = False, renderVector = False)
+
+        pos = self.GetSashPosition()
+        self.last = pos
+
+    def OnSashChanging(self, event):
+        Debug.msg(5, "MapSplitter.OnSashChanging()")
+
+        if not (self.GetWindowStyle() & wx.SP_LIVE_UPDATE):
+            if event:
+                event.Skip()
+            return
+
+        pos = self.GetSashPosition()
+        dpos = pos - self.last
+        self.last = pos
+        if self.GetSplitMode() == wx.SPLIT_VERTICAL:
+            dx = -dpos
+            dy = 0
+        else:
+            dx = 0
+            dy = -dpos
+        self.GetWindow2().TranslateImage(dx, dy)
+
+        self.GetWindow1().movingSash = True
+        self.GetWindow2().movingSash = True
+
+
+def main():
+    import gettext
+    
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    app = wx.PySimpleApp()
+    wx.InitAllImageHandlers()
+
+    frame = SwipeMapFrame()
+    frame.Show()
+    app.MainLoop()
+
+
+if __name__ == '__main__':
+    main()

+ 188 - 0
gui/wxpython/swipe/mapwindow.py

@@ -0,0 +1,188 @@
+"""!
+@package swipe.mapwindow
+
+@brief Map Swipe map window.
+
+Classes:
+ - mapwindow::SwipeBufferedWindow
+ - mapwindow::_MouseEvent
+
+(C) 2006-2012 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+@author Anna Kratochvilova <kratochanna gmail.com>
+
+Class _MouseEvent taken from wxPython FloatCanvas source code (Christopher Barker).
+"""
+
+import time
+import wx
+
+from core.debug import Debug
+from mapdisp.mapwindow import BufferedWindow
+
+
+EVT_MY_MOUSE_EVENTS = wx.NewEventType()
+EVT_MY_MOTION = wx.NewEventType()
+EVT_MOUSE_EVENTS = wx.PyEventBinder(EVT_MY_MOUSE_EVENTS)
+EVT_MOTION = wx.PyEventBinder(EVT_MY_MOTION)
+
+
+class SwipeBufferedWindow(BufferedWindow):
+    """!A subclass of BufferedWindow class. 
+
+    Enables to draw the image translated.
+    Special mouse events with changed coordinates are used.
+    """
+    def __init__(self, parent, Map, frame,
+                 tree = None, lmgr = None, **kwargs):
+        BufferedWindow.__init__(self, parent = parent, Map = Map, frame = frame, tree = tree, lmgr = lmgr, **kwargs)
+        Debug.msg(2, "SwipeBufferedWindow.__init__()")
+
+        self.specialSize = super(SwipeBufferedWindow, self).GetClientSize()
+        self.specialCoords = [0, 0]
+        self.imageId = 99
+        self.movingSash = False
+
+    def _bindMouseEvents(self):
+        """!Binds wx mouse events and custom mouse events"""
+        wx.EVT_MOUSE_EVENTS(self, self._mouseActions)
+        wx.EVT_MOTION(self, self._mouseMotion)
+        self.Bind(EVT_MOTION, self.OnMotion)
+        self.Bind(EVT_MOUSE_EVENTS, self.MouseActions)
+        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
+
+    def _RaiseMouseEvent(self, Event, EventType):
+         """!This is called in various other places to raise a Mouse Event
+         """
+         Debug.msg(5, "SwipeBufferedWindow._RaiseMouseEvent()")
+
+        # this computes the new coordinates from the mouse coords.
+         x, y = Event.GetPosition()
+         pt = x - self.GetImageCoords()[0], y - self.GetImageCoords()[1]
+         evt = _MouseEvent(EventType, Event, self.GetId(), pt)
+         self.GetEventHandler().ProcessEvent(evt)
+         # this skip was not in the original code but is needed here
+         Event.Skip()
+
+    def _mouseActions(self, event):
+        self._RaiseMouseEvent(event, EVT_MY_MOUSE_EVENTS)
+
+    def _mouseMotion(self, event):
+        self._RaiseMouseEvent(event, EVT_MY_MOTION)
+
+    def GetClientSize(self):
+        """!Overriden method which returns simulated window size.
+        """
+        return self.specialSize
+
+    def SetClientSize(self, size):
+        """!Overriden method which sets simulated window size.
+        """
+        Debug.msg(3, "SwipeBufferedWindow.SetClientSize(): size = %s" % size)
+        self.specialSize = size
+
+    def GetImageCoords(self):
+        """!Returns coordinates of rendered image"""
+        return self.specialCoords
+
+    def SetImageCoords(self, coords):
+        """!Sets coordinates of rendered image"""
+        Debug.msg(3, "SwipeBufferedWindow.SetImageCoords(): coords = %s, %s" % (coords[0], coords[1]))
+        self.specialCoords = coords
+
+    def OnSize(self, event):
+        """!Calls superclass's OnSize method only when needed"""
+        Debug.msg(5, "SwipeBufferedWindow.OnSize()")
+        if not self.movingSash:
+            super(SwipeBufferedWindow, self).OnSize(event)
+
+    def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
+        super(SwipeBufferedWindow, self).ZoomToMap(layers, ignoreNulls, render)
+        self.frame.UpdateRegion()
+
+    def ZoomBack(self):
+        """!Zoom last (previously stored position)
+        """
+        super(SwipeBufferedWindow, self).ZoomBack()
+        self.frame.UpdateRegion()
+
+    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0]):
+        """!Draws image (map) with translated coordinates.
+        """
+        Debug.msg(2, "SwipeBufferedWindow.Draw()")
+
+        if pdctype == 'image':
+            coords = self.GetImageCoords()
+
+        return super(SwipeBufferedWindow, self).Draw(pdc, img, drawid, pdctype, coords)
+        
+    def TranslateImage(self, dx, dy):
+        """!Translate image and redraw.
+        """
+        Debug.msg(5, "SwipeBufferedWindow.TranslateImage(): dx = %s, dy = %s" % (dx, dy))
+
+        self.pdc.TranslateId(self.imageId, dx, dy)
+        self.Refresh()
+        
+
+    def MouseActions(self, event):
+        """!Handle mouse events and if needed let parent frame know"""
+        super(SwipeBufferedWindow, self).MouseActions(event)
+        if event.GetWheelRotation() != 0 or \
+           event.LeftUp() or \
+           event.MiddleUp():
+
+            self.frame.UpdateRegion()
+
+        event.Skip()
+        
+    def MouseDraw(self, pdc = None, begin = None, end = None):
+        """!Overriden method to recompute coordinates back to original values
+        so that e.g. drawing of zoom box is done properly"""
+        Debug.msg(5, "SwipeBufferedWindow.MouseDraw()")
+
+        offsetX, offsetY = self.GetImageCoords()
+        begin = (self.mouse['begin'][0] + offsetX, self.mouse['begin'][1] + offsetY)
+        end = (self.mouse['end'][0] + offsetX, self.mouse['end'][1] + offsetY)
+        super(SwipeBufferedWindow, self).MouseDraw(pdc, begin, end)
+
+
+class _MouseEvent(wx.PyCommandEvent):
+    """!
+    This event class takes a regular wxWindows mouse event as a parameter, 
+    and wraps it so that there is access to all the original methods. This 
+    is similar to subclassing, but you can't subclass a wxWindows event.
+
+    The goal is to be able to it just like a regular mouse event.
+
+    Difference is that it is a CommandEvent, which propagates up the 
+    window hierarchy until it is handled.
+    """
+
+    def __init__(self, EventType, NativeEvent, WinID, changed = None):
+        Debug.msg(5, "_MouseEvent:__init__()")
+
+        wx.PyCommandEvent.__init__(self)
+
+        self.SetEventType(EventType)
+        self._NativeEvent = NativeEvent
+        self.changed = changed
+
+    def GetPosition(self):
+        return wx.Point(*self.changed)
+
+    def GetPositionTuple(self):
+        return self.changed
+
+    def GetX(self):
+        return self.changed[0]
+        
+    def GetY(self):
+        return self.changed[1]
+
+    # this delegates all other attributes to the native event.
+    def __getattr__(self, name):
+        return getattr(self._NativeEvent, name)

+ 123 - 0
gui/wxpython/swipe/toolbars.py

@@ -0,0 +1,123 @@
+"""!
+@package swipe.toolbars
+
+@brief Map Swipe toolbars and icons.
+
+Classes:
+ - toolbars::swipeMapToolbar
+ - toolbars::swipeMainToolbar
+
+(C) 2006-2012 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+@author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import wx
+
+from gui_core.toolbars import BaseToolbar, BaseIcons
+from icons.icon import MetaIcon
+
+swipeIcons = {
+        'tools': MetaIcon(img = 'tools', label = _('Tools')),
+        }
+
+class SwipeMapToolbar(BaseToolbar):
+    """!Map toolbar (to control map zoom and rendering)
+    """
+    def __init__(self, parent):
+        """!Map toolbar constructor
+        """
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+
+        # realize the toolbar
+        self.Realize()
+        
+        self.action = { 'id' : self.pan }
+        self.defaultAction = { 'id' : self.pan,
+                               'bind' : self.parent.OnPan }
+        
+        self.EnableTool(self.zoomBack, False)
+        
+    def _toolbarData(self):
+        """!Returns toolbar data (name, icon, handler)"""
+        # BaseIcons are a set of often used icons. It is possible
+        # to reuse icons in ./trunk/gui/icons/grass or add new ones there.
+        icons = BaseIcons
+        return self._getToolbarData((("displaymap", icons["display"],
+                                      self.parent.OnDraw),
+                                     ("rendermap", icons["render"],
+                                      self.parent.OnRender),
+                                     ("erase", icons["erase"],
+                                      self.parent.OnErase),
+                                     (None, ), # creates separator
+                                     ("pan", icons["pan"],
+                                      self.parent.OnPan,
+                                      wx.ITEM_CHECK), # toggle tool
+                                     ("zoomIn", icons["zoomIn"],
+                                      self.parent.OnZoomIn,
+                                      wx.ITEM_CHECK),
+                                     ("zoomOut", icons["zoomOut"],
+                                      self.parent.OnZoomOut,
+                                      wx.ITEM_CHECK),
+                                     (None, ),
+                                     ("zoomBack", icons["zoomBack"],
+                                      self.parent.OnZoomBack),
+                                     ("zoomToMap", icons["zoomExtent"],
+                                      self.parent.OnZoomToMap),
+                                    ))
+                                    
+    def SetActiveMap(self, index):
+        """!Set currently selected map.
+        Unused, needed because of DoubleMapFrame API.
+        """
+        pass
+
+class SwipeMainToolbar(BaseToolbar):
+    """!Toolbar with tools related to application functionality
+    """
+    def __init__(self, parent):
+        """!Toolbar constructor
+        """
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = swipeIcons
+        return self._getToolbarData((("addRaster", BaseIcons['addRast'],
+                                      self.parent.OnSelectRasters),
+                                     (None, ),
+                                     ("tools", swipeIcons['tools'],
+                                      self.OnToolMenu)
+                                    ))
+
+    def OnToolMenu(self, event):
+        """!Menu for additional tools"""
+        point = wx.GetMousePosition()
+        toolMenu = wx.Menu()
+        
+        for label, itype, handler, desc in (
+            (_("Switch orientation"),
+             wx.ITEM_NORMAL, self.parent.OnSwitchOrientation, "switchOrientation"),
+            (_("Switch maps"),
+             wx.ITEM_NORMAL, self.parent.OnSwitchWindows, "switchMaps")):
+            # Add items to the menu
+            item = wx.MenuItem(parentMenu = toolMenu, id = wx.ID_ANY,
+                               text = label,
+                               kind = itype)
+            toolMenu.AppendItem(item)
+            self.parent.GetWindow().Bind(wx.EVT_MENU, handler, item)
+        
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.parent.GetWindow().PopupMenu(toolMenu)
+        toolMenu.Destroy()

+ 4 - 4
gui/wxpython/vdigit/mapwindow.py

@@ -28,11 +28,11 @@ from vdigit.dialogs import VDigitCategoryDialog, VDigitZBulkDialog, VDigitDuplic
 class VDigitWindow(BufferedWindow):
 class VDigitWindow(BufferedWindow):
     """!A Buffered window extended for vector digitizer.
     """!A Buffered window extended for vector digitizer.
     """
     """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None,
+    def __init__(self, parent, Map, frame,
+                 id = wx.ID_ANY, tree = None, lmgr = None,
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        BufferedWindow.__init__(self, parent, id, Map, tree, lmgr,
-                                style, **kwargs)
+        BufferedWindow.__init__(self, parent = parent, id = id, Map = Map,
+                                frame = frame, tree = tree, lmgr = lmgr, style = style, **kwargs)
         
         
         self.pdcVector = wx.PseudoDC()
         self.pdcVector = wx.PseudoDC()
         self.toolbar   = self.parent.GetToolbar('vdigit')
         self.toolbar   = self.parent.GetToolbar('vdigit')

+ 16 - 1
gui/wxpython/wxpythonlib.dox

@@ -36,6 +36,7 @@ vector digitizer or georectification tool are also available.
  - \ref psmap
  - \ref psmap
  - \ref locWizard
  - \ref locWizard
  - \ref plot
  - \ref plot
+ - \ref swipe
  - \ref other
  - \ref other
 - \ref devel
 - \ref devel
 - \ref seeAlso
 - \ref seeAlso
@@ -476,7 +477,21 @@ available in GRASS 5 and GRASS 6.
  - toolbars::IClassToolbar
  - toolbars::IClassToolbar
  - toolbars::IClassMapManagerToolbar
  - toolbars::IClassMapManagerToolbar
  - toolbars::IClassMiscToolbar
  - toolbars::IClassMiscToolbar
- 
+
+\subsection swipe Map Swipe
+
+- swipe::frame
+ - frame::SwipeMapFrame
+ - frame::MapSplitter
+- swipe::mapwindow
+ - mapwindow::SwipeBufferedWindow
+ - mapwindow::_MouseEvent
+- swipe::dialogs
+ - dialogs::SwipeMapDialog
+- swipe::toolbars
+ - toolbars::SwipeMapToolbar
+ - toolbars::SwipeMainToolbar
+
 \subsection other Other GUI modules
 \subsection other Other GUI modules
 
 
 - modules::colorrules
 - modules::colorrules

+ 6 - 0
gui/wxpython/xml/menudata.xml

@@ -742,6 +742,12 @@
 	  <handler>OnPsMap</handler>
 	  <handler>OnPsMap</handler>
 	  <command>ps.map</command>
 	  <command>ps.map</command>
 	</menuitem>
 	</menuitem>
+	<menuitem>
+	  <label>Map Swipe</label>
+	  <help>Launch Map Swipe</help>
+	  <keywords>visualization,raster</keywords>
+	  <handler>OnMapSwipe</handler>
+	</menuitem>
 	<separator />
 	<separator />
 	<menuitem>
 	<menuitem>
 	  <label>Launch script</label>
 	  <label>Launch script</label>