Jelajahi Sumber

wxGUI: refactoring overlays (legend, barscale)

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@54909 15284696-431f-4ddb-bdfa-cd5b030d7da7
Anna Petrášová 12 tahun lalu
induk
melakukan
b4a8e5dd31

+ 69 - 109
gui/wxpython/gui_core/dialogs.py

@@ -513,29 +513,34 @@ class SavedRegion(wx.Dialog):
         """!Return region name"""
         """!Return region name"""
         return self.wind
         return self.wind
     
     
+DECOR_DIALOG_LEGEND = 0
+DECOR_DIALOG_BARSCALE = 1
+
 class DecorationDialog(wx.Dialog):
 class DecorationDialog(wx.Dialog):
     """!Controls setting options and displaying/hiding map overlay
     """!Controls setting options and displaying/hiding map overlay
     decorations
     decorations
     """
     """
-    def __init__(self, parent, ovlId, title, cmd, name = None,
-                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE,
-                 checktxt = '', ctrltxt = ''):
+    def __init__(self, parent, title, overlayController,
+                 ddstyle, **kwargs):
         
         
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, **kwargs)
         
         
-        self.ovlId   = ovlId   # PseudoDC id
-        self.cmd     = cmd
-        self.name    = name    # overlay name
         self.parent  = parent  # MapFrame
         self.parent  = parent  # MapFrame
+        self._overlay = overlayController
+        self._ddstyle = ddstyle
         
         
         sizer = wx.BoxSizer(wx.VERTICAL)
         sizer = wx.BoxSizer(wx.VERTICAL)
         
         
         box = wx.BoxSizer(wx.HORIZONTAL)
         box = wx.BoxSizer(wx.HORIZONTAL)
-        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY, label = checktxt)
-        if self.parent.Map.GetOverlay(self.ovlId) is None:
-            self.chkbox.SetValue(True)
+        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY)
+        self.chkbox.SetValue(True)
+
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
+            self.chkbox.SetLabel("Show legend")
         else:
         else:
-            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
+            self.chkbox.SetLabel("Show scale and North arrow")
+
+
         box.Add(item = self.chkbox, proportion = 0,
         box.Add(item = self.chkbox, proportion = 0,
                 flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
                 flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
         sizer.Add(item = box, proportion = 0,
         sizer.Add(item = box, proportion = 0,
@@ -546,24 +551,29 @@ class DecorationDialog(wx.Dialog):
         box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
         box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
         sizer.Add(item = box, proportion = 0,
         sizer.Add(item = box, proportion = 0,
                   flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
                   flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        if self.name == 'legend':
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
             box = wx.BoxSizer(wx.HORIZONTAL)
             box = wx.BoxSizer(wx.HORIZONTAL)
-            resize = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
-            resize.SetToolTipString(_("Click and drag on the map display to set legend"
-                                        " size and position and then press OK"))
-            resize.SetName('resize')
-            resize.Disable()
-            box.Add(item = resize, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
+            self.resizeBtn = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
+            self.resizeBtn.SetToolTipString(_("Click and drag on the map display to set legend "
+                                              "size and position and then press OK"))
+            self.resizeBtn.Disable()
+            self.resizeBtn.Bind(wx.EVT_TOGGLEBUTTON, self.OnResize)
+            box.Add(item = self.resizeBtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
             sizer.Add(item = box, proportion = 0,
             sizer.Add(item = box, proportion = 0,
                       flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
                       flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
 
 
         box = wx.BoxSizer(wx.HORIZONTAL)
         box = wx.BoxSizer(wx.HORIZONTAL)
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
+            labelText = _("Drag legend object with mouse in pointer mode to position.\n"
+                          "Double-click to change options.\n"
+                          "Define raster map name for legend in properties dialog.")
+        else:
+            labelText = _("Drag scale object with mouse in pointer mode to position.\n"
+                          "Double-click to change options.")
+
         label = wx.StaticText(parent = self, id = wx.ID_ANY,
         label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = _("Drag %s with mouse in pointer mode to position.\n"
-                                      "Double-click to change options." % ctrltxt))
-        if self.name == 'legend':
-            label.SetLabel(label.GetLabel() + _('\nDefine raster map name for legend in '
-                                                'properties dialog.'))
+                              label = labelText)
+
         box.Add(item = label, proportion = 0,
         box.Add(item = label, proportion = 0,
                 flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
                 flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
         sizer.Add(item = box, proportion = 0,
         sizer.Add(item = box, proportion = 0,
@@ -578,8 +588,7 @@ class DecorationDialog(wx.Dialog):
 
 
         self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
         self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
         self.btnOK.SetDefault()
         self.btnOK.SetDefault()
-        if self.name == 'legend':
-            self.btnOK.Enable(False)
+        self.btnOK.Enable(self._ddstyle != DECOR_DIALOG_LEGEND)
         btnsizer.AddButton(self.btnOK)
         btnsizer.AddButton(self.btnOK)
 
 
         btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
         btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
@@ -592,70 +601,40 @@ class DecorationDialog(wx.Dialog):
         #
         #
         # bindings
         # bindings
         #
         #
-        self.Bind(wx.EVT_BUTTON,   self.OnOptions, optnbtn)
-        if self.name == 'legend':
-            self.Bind(wx.EVT_TOGGLEBUTTON,   self.OnResize, resize)
-        self.Bind(wx.EVT_BUTTON,   self.OnCancel,  btnCancel)
-        self.Bind(wx.EVT_BUTTON,   self.OnOK,      self.btnOK)
+        optnbtn.Bind(wx.EVT_BUTTON, self.OnOptions)
+        btnCancel.Bind(wx.EVT_BUTTON, lambda evt: self.CloseDialog())
+        self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
 
 
         self.SetSizer(sizer)
         self.SetSizer(sizer)
         sizer.Fit(self)
         sizer.Fit(self)
 
 
-        # create overlay if doesn't exist
-        self._createOverlay()
-        
-        if len(self.parent.MapWindow.overlays[self.ovlId]['cmd']) > 1:
-            if name == 'legend':
-                mapName, found = GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd'])
-                if found:
-                    # enable 'OK' and 'Resize' button
-                    self.btnOK.Enable()
-                    if not self.parent.IsPaneShown('3d'):
-                        self.FindWindowByName('resize').Enable()
-                    
-                    # set title
-                    self.SetTitle(_('Legend of raster map <%s>') % \
-                                      mapName)
-            
-        
-    def _createOverlay(self):
-        """!Creates overlay"""
-        if not self.parent.GetMap().GetOverlay(self.ovlId):
-            self.newOverlay = self.parent.Map.AddOverlay(id = self.ovlId, ltype = self.name,
-                                                         command = self.cmd,
-                                                         active = False, render = False, hidden = True)
-            prop = { 'layer' : self.newOverlay,
-                     'params' : None,
-                     'propwin' : None,
-                     'cmd' : self.cmd,
-                     'coords': (0, 0),
-                     'pdcType': 'image' }
-            self.parent.MapWindow2D.overlays[self.ovlId] = prop
-            if self.parent.MapWindow3D:
-                self.parent.MapWindow3D.overlays[self.ovlId] = prop
-                
-        else:
-            if self.parent.MapWindow.overlays[self.ovlId]['propwin'] == None:
-                return
+        mapName, found = GetLayerNameFromCmd(self._overlay.cmd)
+        if found:
+            # enable 'OK' and 'Resize' button
+            self.btnOK.Enable()
+            if not self.parent.IsPaneShown('3d'):
+                self.resizeBtn.Enable()
             
             
-            self.parent.MapWindow.overlays[self.ovlId]['propwin'].get_dcmd = self.GetOptData
+            # set title
+            self.SetTitle(_('Legend of raster map <%s>') % \
+                              mapName)
         
         
     def OnOptions(self, event):
     def OnOptions(self, event):
         """!Sets option for decoration map overlays
         """!Sets option for decoration map overlays
         """
         """
-        if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None:
+        if self._overlay.propwin is None:
             # build properties dialog
             # build properties dialog
-            GUI(parent = self.parent).ParseCommand(cmd = self.cmd,
-                                                   completed = (self.GetOptData, self.name, ''))
+            GUI(parent = self.parent).ParseCommand(cmd = self._overlay.cmd,
+                                                   completed = (self.GetOptData, self._overlay.name, ''))
             
             
         else:
         else:
-            if self.parent.MapWindow.overlays[self.ovlId]['propwin'].IsShown():
-                self.parent.MapWindow.overlays[self.ovlId]['propwin'].SetFocus()
+            if self._overlay.propwin.IsShown():
+                self._overlay.propwin.SetFocus()
             else:
             else:
-                self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
+                self._overlay.propwin.Show()
         
         
     def OnResize(self, event):
     def OnResize(self, event):
-        if self.FindWindowByName('resize').GetValue(): 
+        if event.GetInt(): 
             self.parent.SwitchTool(self.parent.toolbars['map'], event)
             self.parent.SwitchTool(self.parent.toolbars['map'], event)
             self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
             self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
             self.parent.MapWindow.mouse['use'] = 'legend'
             self.parent.MapWindow.mouse['use'] = 'legend'
@@ -665,21 +644,18 @@ class DecorationDialog(wx.Dialog):
             self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
             self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
             self.parent.MapWindow.mouse['use'] = 'pointer'
             self.parent.MapWindow.mouse['use'] = 'pointer'
             
             
-    def OnCancel(self, event):
-        """!Cancel dialog"""
-        if self.name == 'legend' and self.FindWindowByName('resize').GetValue():
-            self.FindWindowByName('resize').SetValue(False)
+    def CloseDialog(self):
+        """!Hide dialog"""
+        if self._ddstyle == DECOR_DIALOG_LEGEND and self.resizeBtn.GetValue():
+            self.resizeBtn.SetValue(False)
             self.OnResize(None)
             self.OnResize(None)
-            
-        self.parent.dialogs['barscale'] = None
-        if event and hasattr(self, 'newOverlay'):
-            self.parent.Map.DeleteOverlay(self.newOverlay)
-        self.Destroy()
+
+        self.Hide()
 
 
     def OnOK(self, event):
     def OnOK(self, event):
         """!Button 'OK' pressed"""
         """!Button 'OK' pressed"""
         # enable or disable overlay
         # enable or disable overlay
-        self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
+        self._overlay.Show(self.chkbox.IsChecked())
         
         
         # update map
         # update map
         if self.parent.IsPaneShown('3d'):
         if self.parent.IsPaneShown('3d'):
@@ -687,36 +663,20 @@ class DecorationDialog(wx.Dialog):
         
         
         self.parent.MapWindow.UpdateMap()
         self.parent.MapWindow.UpdateMap()
         
         
-        # close dialog
-        self.OnCancel(None)
+        # hide dialog
+        self.CloseDialog()
         
         
     def GetOptData(self, dcmd, layer, params, propwin):
     def GetOptData(self, dcmd, layer, params, propwin):
         """!Process decoration layer data"""
         """!Process decoration layer data"""
-        # update layer data
-        if params:
-            self.parent.MapWindow.overlays[self.ovlId]['params'] = params
         if dcmd:
         if dcmd:
-            self.parent.MapWindow.overlays[self.ovlId]['cmd'] = dcmd
-        self.parent.MapWindow.overlays[self.ovlId]['propwin'] = propwin
+            self._overlay.cmd = dcmd
+        self._overlay.propwin = propwin
+        if params:
+            self.btnOK.Enable()
+            if self._ddstyle == DECOR_DIALOG_LEGEND and not self.parent.IsPaneShown('3d'):
+                self.resizeBtn.Enable()
+
 
 
-        # change parameters for item in layers list in render.Map
-        # "Use mouse..." (-m) flag causes GUI freeze and is pointless here, trac #119
-        
-        try:
-            self.parent.MapWindow.overlays[self.ovlId]['cmd'].remove('-m')
-        except ValueError:
-            pass
-            
-        self.parent.Map.ChangeOverlay(id = self.ovlId, ltype = self.name,
-                                      command = self.parent.MapWindow.overlays[self.ovlId]['cmd'],
-                                      active = self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive(),
-                                      render = False, hidden = True)
-        if  self.name == 'legend':
-            if params and not self.btnOK.IsEnabled():
-                self.btnOK.Enable()
-                if not self.parent.IsPaneShown('3d'):
-                    self.FindWindowByName('resize').Enable()
-            
 class TextLayerDialog(wx.Dialog):
 class TextLayerDialog(wx.Dialog):
     """
     """
     Controls setting options and displaying/hiding map overlay decorations
     Controls setting options and displaying/hiding map overlay decorations

+ 8 - 2
gui/wxpython/lmgr/frame.py

@@ -609,9 +609,15 @@ class GMFrame(wx.Frame):
             return
             return
         
         
         if layertype == 'barscale':
         if layertype == 'barscale':
-            self.GetMapDisplay().OnAddBarscale(None)
+            if len(command) > 1:
+                self.GetMapDisplay().AddBarscale(cmd = command, showDialog = False)
+            else:
+                self.GetMapDisplay().AddBarscale(showDialog = True)
         elif layertype == 'rastleg':
         elif layertype == 'rastleg':
-            self.GetMapDisplay().OnAddLegend(None)
+            if len(command) > 1:
+                self.GetMapDisplay().AddLegend(cmd = command, showDialog = False)
+            else:
+                self.GetMapDisplay().AddLegend(showDialog = True)
         elif layertype == 'redraw':
         elif layertype == 'redraw':
             self.GetMapDisplay().OnRender(None)
             self.GetMapDisplay().OnRender(None)
         else:
         else:

+ 78 - 56
gui/wxpython/mapdisp/frame.py

@@ -43,11 +43,13 @@ from mapdisp.gprint     import PrintOptions
 from core.gcmd          import GError, GMessage
 from core.gcmd          import GError, GMessage
 from dbmgr.dialogs      import DisplayAttributesDialog
 from dbmgr.dialogs      import DisplayAttributesDialog
 from core.utils         import ListOfCatsToRange, GetLayerNameFromCmd
 from core.utils         import ListOfCatsToRange, GetLayerNameFromCmd
-from gui_core.dialogs   import GetImageHandlers, ImageSizeDialog, DecorationDialog, TextLayerDialog
+from gui_core.dialogs   import GetImageHandlers, ImageSizeDialog, DecorationDialog, TextLayerDialog, \
+                               DECOR_DIALOG_LEGEND, DECOR_DIALOG_BARSCALE
 from core.debug         import Debug
 from core.debug         import Debug
 from core.settings      import UserSettings
 from core.settings      import UserSettings
 from gui_core.mapdisp   import SingleMapFrame
 from gui_core.mapdisp   import SingleMapFrame
 from mapdisp.mapwindow  import BufferedWindow
 from mapdisp.mapwindow  import BufferedWindow
+from mapdisp.overlays   import LegendController, BarscaleController
 from modules.histogram  import HistogramFrame
 from modules.histogram  import HistogramFrame
 from wxplot.histogram   import Histogram2Frame
 from wxplot.histogram   import Histogram2Frame
 from wxplot.profile     import ProfileFrame
 from wxplot.profile     import ProfileFrame
@@ -127,11 +129,19 @@ class MapFrame(SingleMapFrame):
         
         
         self.statusbarManager.Update()
         self.statusbarManager.Update()
 
 
+        # init decoration objects
+        self.decorations = {}
+        self.legend = LegendController(self.Map)
+        self.barscale = BarscaleController(self.Map)
+        self.decorations[self.legend.id] = self.legend
+        self.decorations[self.barscale.id] = self.barscale
+
         #
         #
         # Init map display (buffered DC & set default cursor)
         # Init map display (buffered DC & set default cursor)
         #
         #
         self.MapWindow2D = BufferedWindow(self, giface = self._giface, id = wx.ID_ANY,
         self.MapWindow2D = BufferedWindow(self, giface = self._giface, id = wx.ID_ANY,
-                                          Map = self.Map, frame = self, tree = self.tree, lmgr = self._layerManager)
+                                          Map = self.Map, frame = self, tree = self.tree,
+                                          lmgr = self._layerManager, overlays = self.decorations)
         # 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"])
@@ -1117,68 +1127,80 @@ class MapFrame(SingleMapFrame):
         win.Refresh()
         win.Refresh()
         win.Update()
         win.Update()
        
        
-    def OnAddBarscale(self, event):
+    def AddBarscale(self, cmd = None, showDialog = True):
         """!Handler for scale/arrow map decoration menu selection.
         """!Handler for scale/arrow map decoration menu selection.
         """
         """
-        if self.dialogs['barscale']:
+        if cmd:
+            self.barscale.cmd = cmd
+
+        if not showDialog:
+            self.barscale.Show()
+            self.MapWindow.UpdateMap()
             return
             return
-        self.SwitchTool(self.toolbars['map'], event)
-        
-        id = 0 # unique index for overlay layer
-
-        # If location is latlon, only display north arrow (scale won't work)
-        #        proj = self.Map.projinfo['proj']
-        #        if proj == 'll':
-        #            barcmd = 'd.barscale -n'
-        #        else:
-        #            barcmd = 'd.barscale'
-
-        # decoration overlay control dialog
-        self.dialogs['barscale'] = \
-            DecorationDialog(parent = self, title = _('Scale and North arrow'),
-                             size = (350, 200),
-                             style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                             cmd = ['d.barscale', 'at=0,95'],
-                             ovlId = id,
-                             name = 'barscale',
-                             checktxt = _("Show/hide scale and North arrow"),
-                             ctrltxt = _("scale object"))
-
-        self.dialogs['barscale'].CentreOnParent()
-        ### dialog cannot be show as modal - in the result d.barscale is not selectable
-        ### self.dialogs['barscale'].ShowModal()
-        self.dialogs['barscale'].Show()
+
+        # Decoration overlay control dialog
+        if self.dialogs['barscale']:
+            if self.dialogs['barscale'].IsShown():
+                self.dialogs['barscale'].SetFocus()
+            else:
+                self.dialogs['barscale'].Show()
+        else:
+            # If location is latlon, only display north arrow (scale won't work)
+            #        proj = self.Map.projinfo['proj']
+            #        if proj == 'll':
+            #            barcmd = 'd.barscale -n'
+            #        else:
+            #            barcmd = 'd.barscale'
+
+            # decoration overlay control dialog
+            self.dialogs['barscale'] = \
+                DecorationDialog(parent = self, title = _('Scale and North arrow'),
+                                     overlayController = self.barscale,
+                                     ddstyle = DECOR_DIALOG_BARSCALE,
+                                     size = (350, 200),
+                                     style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE)
+
+            self.dialogs['barscale'].CentreOnParent()
+            ### dialog cannot be show as modal - in the result d.barscale is not selectable
+            ### self.dialogs['barscale'].ShowModal()
+            self.dialogs['barscale'].Show()
         self.MapWindow.mouse['use'] = 'pointer'
         self.MapWindow.mouse['use'] = 'pointer'
 
 
-    def OnAddLegend(self, event):
+    def AddLegend(self, cmd = None, showDialog = True):
         """!Handler for legend map decoration menu selection.
         """!Handler for legend map decoration menu selection.
         """
         """
-        if self.dialogs['legend']:
+        if cmd:
+            self.legend.cmd = cmd
+        else:
+            layers = self._giface.GetLayerList().GetSelectedLayers()
+            for layer in layers:
+                if layer.type == 'raster':
+                    self.legend.cmd.append('map=%s' % layer.maplayer.name)
+                    break
+
+        if not showDialog:
+            self.legend.Show()
+            self.MapWindow.UpdateMap()
             return
             return
-        
-        id = 1 # index for overlay layer in render
-        
-        cmd = ['d.legend', 'at=5,50,2,5']
-        
-        if self.tree and self.tree.layer_selected and \
-                self.tree.GetLayerInfo(self.tree.layer_selected, key = 'type') == 'raster':
-            cmd.append('map=%s' % self.tree.GetLayerInfo(self.tree.layer_selected, key = 'maplayer').name)
-        
+
         # Decoration overlay control dialog
         # Decoration overlay control dialog
-        self.dialogs['legend'] = \
-            DecorationDialog(parent = self, title = ('Legend'),
-                             size = (350, 200),
-                             style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                             cmd = cmd,
-                             ovlId = id,
-                             name = 'legend',
-                             checktxt = _("Show/hide legend"),
-                             ctrltxt = _("legend object")) 
-            
-        self.dialogs['legend'].CentreOnParent() 
-        ### dialog cannot be show as modal - in the result d.legend is not selectable
-        ### self.dialogs['legend'].ShowModal()
-        self.dialogs['legend'].Show()
+        if self.dialogs['legend']:
+            if self.dialogs['legend'].IsShown():
+                self.dialogs['legend'].SetFocus()
+            else:
+                self.dialogs['legend'].Show()
+        else:
+            self.dialogs['legend'] = \
+                DecorationDialog(parent = self, title = _("Legend"),
+                                 overlayController = self.legend,
+                                 ddstyle = DECOR_DIALOG_LEGEND,
+                                 size = (350, 200),
+                                 style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE)
+
+            self.dialogs['legend'].CentreOnParent() 
+            ### dialog cannot be show as modal - in the result d.legend is not selectable
+            ### self.dialogs['legend'].ShowModal()
+            self.dialogs['legend'].Show()
         self.MapWindow.mouse['use'] = 'pointer'
         self.MapWindow.mouse['use'] = 'pointer'
         
         
     def OnAddText(self, event):
     def OnAddText(self, event):
@@ -1376,6 +1398,6 @@ class MapFrame(SingleMapFrame):
         if self.dialogs['legend']:
         if self.dialogs['legend']:
             if hasattr(event ,'GetEventObject'):
             if hasattr(event ,'GetEventObject'):
                 if event.GetEventObject().GetId() == \
                 if event.GetEventObject().GetId() == \
-                        self.dialogs['legend'].FindWindowByName('resize').GetId():
+                        self.dialogs['legend'].resizeBtn.GetId():
                     return
                     return
             self.dialogs['legend'].FindWindowByName('resize').SetValue(0)
             self.dialogs['legend'].FindWindowByName('resize').SetValue(0)

+ 14 - 35
gui/wxpython/mapdisp/mapwindow.py

@@ -56,7 +56,7 @@ class BufferedWindow(MapWindow, wx.Window):
     SaveToFile() method.
     SaveToFile() method.
     """
     """
     def __init__(self, parent, giface, Map, frame,
     def __init__(self, parent, giface, Map, frame,
-                 id = wx.ID_ANY, tree = None, lmgr = None,
+                 id = wx.ID_ANY, tree = None, lmgr = None, overlays = None,
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
         MapWindow.__init__(self, parent = parent, giface = giface, Map = Map,
         MapWindow.__init__(self, parent = parent, giface = giface, Map = Map,
                            frame = frame, **kwargs)
                            frame = frame, **kwargs)
@@ -94,7 +94,7 @@ class BufferedWindow(MapWindow, wx.Window):
         self.mapfile = None   # image file to be rendered
         self.mapfile = None   # image file to be rendered
         self.img     = None   # wx.Image object (self.mapfile)
         self.img     = None   # wx.Image object (self.mapfile)
         # decoration overlays
         # decoration overlays
-        self.overlays = {}
+        self.overlays = overlays
         # images and their PseudoDC ID's for painting and dragging
         # images and their PseudoDC ID's for painting and dragging
         self.imagedict = {}   
         self.imagedict = {}   
         self.select = {}      # selecting/unselecting decorations for dragging
         self.select = {}      # selecting/unselecting decorations for dragging
@@ -505,10 +505,10 @@ class BufferedWindow(MapWindow, wx.Window):
             # draw any active and defined overlays
             # draw any active and defined overlays
             if self.imagedict[img]['layer'].IsActive():
             if self.imagedict[img]['layer'].IsActive():
                 id = self.imagedict[img]['id']
                 id = self.imagedict[img]['id']
-                coords = int(ratio[0] * self.overlays[id]['coords'][0]),\
-                         int(ratio[1] * self.overlays[id]['coords'][1])
+                coords = int(ratio[0] * self.overlays[id].coords[0]),\
+                         int(ratio[1] * self.overlays[id].coords[1])
                 self.Draw(self.pdc, img = img, drawid = id,
                 self.Draw(self.pdc, img = img, drawid = id,
-                          pdctype = self.overlays[id]['pdcType'], coords = coords)
+                          pdctype = self.overlays[id].pdcType, coords = coords)
                           
                           
         # redraw text labels
         # redraw text labels
         for id in self.textdict.keys():
         for id in self.textdict.keys():
@@ -682,7 +682,7 @@ class BufferedWindow(MapWindow, wx.Window):
             if self.imagedict[img]['layer'].IsActive():
             if self.imagedict[img]['layer'].IsActive():
                 id = self.imagedict[img]['id']
                 id = self.imagedict[img]['id']
                 self.Draw(self.pdc, img = img, drawid = id,
                 self.Draw(self.pdc, img = img, drawid = id,
-                          pdctype = self.overlays[id]['pdcType'], coords = self.overlays[id]['coords'])
+                          pdctype = self.overlays[id].pdcType, coords = self.overlays[id].coords)
         
         
         for id in self.textdict.keys():
         for id in self.textdict.keys():
             self.Draw(self.pdc, img = self.textdict[id], drawid = id,
             self.Draw(self.pdc, img = self.textdict[id], drawid = id,
@@ -1216,7 +1216,7 @@ class BufferedWindow(MapWindow, wx.Window):
             # end drag of overlay decoration
             # end drag of overlay decoration
             
             
             if self.dragid < 99 and self.dragid in self.overlays:
             if self.dragid < 99 and self.dragid in self.overlays:
-                self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
+                self.overlays[self.dragid].coords = self.pdc.GetIdBounds(self.dragid)
             elif self.dragid > 100 and self.dragid in self.textdict:
             elif self.dragid > 100 and self.dragid in self.textdict:
                 self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
                 self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
             else:
             else:
@@ -1225,9 +1225,10 @@ class BufferedWindow(MapWindow, wx.Window):
             self.currtxtid = None
             self.currtxtid = None
             
             
         elif self.mouse['use'] == 'legend':
         elif self.mouse['use'] == 'legend':
-            self.ResizeLegend(self.mouse["begin"], self.mouse["end"])
-            self.frame.dialogs['legend'].FindWindowByName("resize").SetValue(False)
-            self.Map.GetOverlay(1).SetActive(True)
+            self.frame.dialogs['legend'].resizeBtn.SetValue(False)
+            screenSize = self.GetClientSizeTuple()
+            self.overlays[1].ResizeLegend(self.mouse["begin"], self.mouse["end"], screenSize)
+
             self.frame.MapWindow.SetCursor(self.frame.cursors["default"])
             self.frame.MapWindow.SetCursor(self.frame.cursors["default"])
             self.frame.MapWindow.mouse['use'] = 'pointer'
             self.frame.MapWindow.mouse['use'] = 'pointer'
             
             
@@ -1264,9 +1265,9 @@ class BufferedWindow(MapWindow, wx.Window):
                 self.currtxtid = self.dragid
                 self.currtxtid = self.dragid
                 self.frame.OnAddText(None)
                 self.frame.OnAddText(None)
             elif self.dragid == 0:
             elif self.dragid == 0:
-                self.frame.OnAddBarscale(None)
+                self.frame.AddBarscale()
             elif self.dragid == 1:
             elif self.dragid == 1:
-                self.frame.OnAddLegend(None)
+                self.frame.AddLegend()
         
         
     def OnRightDown(self, event):
     def OnRightDown(self, event):
         """!Right mouse button pressed
         """!Right mouse button pressed
@@ -1423,29 +1424,7 @@ class BufferedWindow(MapWindow, wx.Window):
         y = (n - north) / res
         y = (n - north) / res
         
         
         return (x, y)
         return (x, y)
-    
-    def ResizeLegend(self, begin, end):
-        w = abs(begin[0] - end[0])
-        h = abs(begin[1] - end[1])
-        if begin[0] < end[0]:
-            x = begin[0]
-        else:
-            x = end[0]
-        if begin[1] < end[1]:
-            y = begin[1]
-        else:
-            y = end[1]
-        screenSize = self.GetClientSizeTuple()
-        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
-              (screenSize[1] - y) / float(screenSize[1]) * 100,
-              x / float(screenSize[0]) * 100,
-              (x + w) / float(screenSize[0]) * 100]
-        for i, subcmd in enumerate(self.overlays[1]['cmd']):
-            if subcmd.startswith('at='):
-                self.overlays[1]['cmd'][i] = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
-        self.Map.ChangeOverlay(1, True, command = self.overlays[1]['cmd'])
-        self.overlays[1]['coords'] = (0,0)
-        
+
     def Zoom(self, begin, end, zoomtype):
     def Zoom(self, begin, end, zoomtype):
         """!Calculates new region while (un)zoom/pan-ing
         """!Calculates new region while (un)zoom/pan-ing
         """
         """

+ 154 - 0
gui/wxpython/mapdisp/overlays.py

@@ -0,0 +1,154 @@
+"""!
+@package mapdisp.overlays
+
+@brief Map display overlays - barscale and legend
+
+Classes:
+ - overlays::OverlayController
+ - overlays::BarscaleController
+ - overlays::LegendController
+
+(C) 2006-2013 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 OverlayController(object):
+    """!Base class for decorations (barscale, legend) controller."""
+    def __init__(self, renderer):
+        self._renderer = renderer
+        self._overlay = None
+        self._coords = [0, 0]
+        self._pdcType = 'image'
+        self._propwin = None
+        self._defaultAt = ''
+
+    def SetCmd(self, cmd):
+        hasAt = False
+        for i in cmd:
+            if i.startswith("at="):
+                hasAt = True
+                break
+        if not hasAt:
+            cmd.append(self._defaultAt)
+        self._cmd = cmd
+
+    def GetCmd(self):
+        return self._cmd
+
+    cmd = property(fset = SetCmd, fget = GetCmd)
+
+    def SetCoords(self, coords):
+        self._coords = list(coords)
+
+    def GetCoords(self):
+        return self._coords
+
+    coords = property(fset = SetCoords, fget = GetCoords)
+
+    def GetPdcType(self):
+        return self._pdcType
+
+    pdcType = property(fget = GetPdcType)
+
+    def GetName(self):
+        return self._name
+
+    name = property(fget = GetName)
+
+    def GetId(self):
+        return self._id
+
+    id = property(fget = GetId)
+
+    def GetPropwin(self):
+        return self._propwin
+
+    def SetPropwin(self, win):
+        self._propwin = win
+
+    propwin = property(fget = GetPropwin, fset = SetPropwin)
+
+    def GetLayer(self):
+        return self._overlay
+
+    layer = property(fget = GetLayer)
+
+    def IsShown(self):
+        if self._overlay and self._overlay.IsActive():
+            return True
+        return False
+
+    def Show(self, show = True):
+        """!Activate or deactivate overlay."""
+        if show:
+            if not self._overlay:
+                self._add()
+            self._overlay.SetActive(True)
+            self._update()
+        else:
+            self.Hide()
+
+
+    def Hide(self):
+        if self._overlay:
+            self._overlay.SetActive(False)
+
+    def _add(self):
+        self._overlay = self._renderer.AddOverlay(id = self._id, ltype = self._name,
+                                                  command = self.cmd, active = False,
+                                                  render = False, hidden = True)
+        # check if successfull
+
+    def _update(self):
+        self._renderer.ChangeOverlay(id = self._id, command = self._cmd,
+                                     render = True)
+
+
+class BarscaleController(OverlayController):
+    def __init__(self, renderer):
+        OverlayController.__init__(self, renderer)
+        self._id = 0
+        self._name = 'barscale'
+        self._defaultAt = 'at=0,95'
+        self._cmd = ['d.barscale', self._defaultAt]
+
+
+class LegendController(OverlayController):
+    def __init__(self, renderer):
+        OverlayController.__init__(self, renderer)
+        self._id = 1
+        self._name = 'legend'
+        # TODO: synchronize with d.legend?
+        self._defaultAt = 'at=5,50,2,5'
+        self._cmd = ['d.legend', self._defaultAt]
+
+    def ResizeLegend(self, begin, end, screenSize):
+        """!Resize legend according to given bbox coordinates."""
+        w = abs(begin[0] - end[0])
+        h = abs(begin[1] - end[1])
+        if begin[0] < end[0]:
+            x = begin[0]
+        else:
+            x = end[0]
+        if begin[1] < end[1]:
+            y = begin[1]
+        else:
+            y = end[1]
+        
+        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
+              (screenSize[1] - y) / float(screenSize[1]) * 100,
+              x / float(screenSize[0]) * 100,
+              (x + w) / float(screenSize[0]) * 100]
+        atStr = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
+
+        for i, subcmd in enumerate(self._cmd):
+            if subcmd.startswith('at='):
+                self._cmd[i] = atStr
+                break
+
+        self._coords = [0, 0]
+        self.Show()

+ 3 - 3
gui/wxpython/mapdisp/toolbars.py

@@ -249,11 +249,11 @@ class MapToolbar(BaseToolbar):
         """
         """
         if self.parent.IsPaneShown('3d'):
         if self.parent.IsPaneShown('3d'):
             self._onMenu(((MapIcons["addNorthArrow"], self.parent.OnAddArrow),
             self._onMenu(((MapIcons["addNorthArrow"], self.parent.OnAddArrow),
-                          (MapIcons["addLegend"],     self.parent.OnAddLegend),
+                          (MapIcons["addLegend"],     lambda evt: self.parent.AddLegend()),
                           (MapIcons["addText"],       self.parent.OnAddText)))
                           (MapIcons["addText"],       self.parent.OnAddText)))
         else:
         else:
-            self._onMenu(((MapIcons["addBarscale"], self.parent.OnAddBarscale),
-                          (MapIcons["addLegend"],   self.parent.OnAddLegend),
+            self._onMenu(((MapIcons["addBarscale"], lambda evt: self.parent.AddBarscale()),
+                          (MapIcons["addLegend"],   lambda evt: self.parent.AddLegend()),
                           (MapIcons["addText"],     self.parent.OnAddText)))
                           (MapIcons["addText"],     self.parent.OnAddText)))
         
         
     def ExitToolbars(self):
     def ExitToolbars(self):

+ 13 - 14
gui/wxpython/nviz/mapwindow.py

@@ -390,15 +390,15 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
         """!Estimates legend size for dragging"""
         """!Estimates legend size for dragging"""
         size = None
         size = None
         if 1 in self.overlays:
         if 1 in self.overlays:
-            for param in self.overlays[1]['cmd'][1:]:
+            for param in self.overlays[1].cmd[1:]:
                 if param.startswith("at="):
                 if param.startswith("at="):
                     size = map(int, param.split("=")[-1].split(','))
                     size = map(int, param.split("=")[-1].split(','))
                     break
                     break
         if size:
         if size:
             wSize = self.GetClientSizeTuple()
             wSize = self.GetClientSizeTuple()
             x, y = size[2]/100. * wSize[0], wSize[1] - (size[1]/100. * wSize[1])
             x, y = size[2]/100. * wSize[0], wSize[1] - (size[1]/100. * wSize[1])
-            x += self.overlays[1]['coords'][0]
-            y += self.overlays[1]['coords'][1]
+            x += self.overlays[1].coords[0]
+            y += self.overlays[1].coords[1]
             w = (size[3] - size[2])/100. * wSize[0]
             w = (size[3] - size[2])/100. * wSize[0]
             h = (size[1] - size[0])/100. * wSize[1]
             h = (size[1] - size[0])/100. * wSize[1]
             
             
@@ -445,7 +445,7 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
         for texture in self.imagelist:
         for texture in self.imagelist:
             # inactive overlays, remove text labels
             # inactive overlays, remove text labels
             if texture.GetId() < 100:
             if texture.GetId() < 100:
-                if not self.overlays[texture.GetId()]['layer'].IsActive():
+                if not self.overlays[texture.GetId()].IsShown():
                     texture.SetActive(False)
                     texture.SetActive(False)
                 else:
                 else:
                     texture.SetActive(True)
                     texture.SetActive(True)
@@ -455,19 +455,18 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
                     
                     
         # update images (only legend so far)
         # update images (only legend so far)
         for oid, overlay in self.overlays.iteritems():
         for oid, overlay in self.overlays.iteritems():
-            layer = overlay['layer']
-            if not layer.IsActive() or oid == 0: # 0 for barscale
+            if not overlay.IsShown() or oid == 0: # 0 for barscale
                 continue
                 continue
             if oid not in [t.GetId() for t in self.imagelist]: # new
             if oid not in [t.GetId() for t in self.imagelist]: # new
-                self.CreateTexture(overlay = layer)
+                self.CreateTexture(overlay = overlay.layer)
             else:
             else:
                 for t in self.imagelist:
                 for t in self.imagelist:
                     if t.GetId() == oid: # check if it is the same
                     if t.GetId() == oid: # check if it is the same
-                        if not t.Corresponds(layer):
+                        if not t.Corresponds(overlay):
                             self.imagelist.remove(t)
                             self.imagelist.remove(t)
-                            t = self.CreateTexture(overlay = layer)
+                            t = self.CreateTexture(overlay = overlay.layer)
                         # always set coordinates, needed for synchr. 2D and 3D modes
                         # always set coordinates, needed for synchr. 2D and 3D modes
-                        t.SetCoords(overlay['coords'])
+                        t.SetCoords(overlay.coords)
 
 
                     
                     
         # update text labels
         # update text labels
@@ -488,7 +487,7 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
         """!Create texture from overlay image or from textdict"""
         """!Create texture from overlay image or from textdict"""
         if overlay: # legend  
         if overlay: # legend  
             texture = wxnviz.ImageTexture(filepath = overlay.mapfile, overlayId = overlay.id,
             texture = wxnviz.ImageTexture(filepath = overlay.mapfile, overlayId = overlay.id,
-                                          coords = list(self.overlays[overlay.id]['coords']),
+                                          coords = list(self.overlays[overlay.id].coords),
                                           cmd = overlay.GetCmd())
                                           cmd = overlay.GetCmd())
             if overlay.id == 1: # legend
             if overlay.id == 1: # legend
                 texture.SetBounds(self.GetLegendRect())
                 texture.SetBounds(self.GetLegendRect())
@@ -788,8 +787,8 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
                 dx = self.mouse['end'][0] - self.mouse['begin'][0]
                 dx = self.mouse['end'][0] - self.mouse['begin'][0]
                 dy = self.mouse['end'][1] - self.mouse['begin'][1]
                 dy = self.mouse['end'][1] - self.mouse['begin'][1]
                 if self.dragid < 99:
                 if self.dragid < 99:
-                    coords = self.overlays[self.dragid]['coords']
-                    self.overlays[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
+                    coords = self.overlays[self.dragid].coords
+                    self.overlays[self.dragid].coords = [coords[0] + dx, coords[1] + dy]
                 else: # text
                 else: # text
                     coords = self.textdict[self.dragid]['coords']
                     coords = self.textdict[self.dragid]['coords']
                     self.textdict[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
                     self.textdict[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
@@ -833,7 +832,7 @@ class GLWindow(MapWindow, glcanvas.GLCanvas):
         self.dragid = self.FindObjects(pos[0], pos[1], self.hitradius)
         self.dragid = self.FindObjects(pos[0], pos[1], self.hitradius)
         
         
         if self.dragid == 1:
         if self.dragid == 1:
-            self.parent.OnAddLegend(None)
+            self.parent.AddLegend()
         elif self.dragid > 100:
         elif self.dragid > 100:
             self.parent.OnAddText(None)
             self.parent.OnAddText(None)
         else:
         else: