[GRASS-SVN] r68923 - in grass/trunk/gui/wxpython: core gui_core lmgr mapdisp mapwin nviz

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Jul 9 16:28:30 PDT 2016


Author: annakrat
Date: 2016-07-09 16:28:30 -0700 (Sat, 09 Jul 2016)
New Revision: 68923

Modified:
   grass/trunk/gui/wxpython/core/render.py
   grass/trunk/gui/wxpython/gui_core/forms.py
   grass/trunk/gui/wxpython/lmgr/frame.py
   grass/trunk/gui/wxpython/mapdisp/frame.py
   grass/trunk/gui/wxpython/mapdisp/toolbars.py
   grass/trunk/gui/wxpython/mapwin/base.py
   grass/trunk/gui/wxpython/mapwin/buffered.py
   grass/trunk/gui/wxpython/mapwin/decorations.py
   grass/trunk/gui/wxpython/nviz/mapwindow.py
   grass/trunk/gui/wxpython/nviz/wxnviz.py
Log:
wxGUI: rewrited handling of decorations (legend, barscale), now multiple legends are possible

Modified: grass/trunk/gui/wxpython/core/render.py
===================================================================
--- grass/trunk/gui/wxpython/core/render.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/core/render.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -364,6 +364,7 @@
         self.thread = gThread()
 
         self.updateProgress = Signal('RenderLayerMgr.updateProgress')
+        self.renderingFailed = Signal('RenderLayerMgr.renderingFailed')
 
         self._startTime = None
         self._render_env = env
@@ -389,14 +390,16 @@
 
         self._startTime = time.time()
         self.thread.Run(callable=self._render, cmd=cmd_render, env=env_cmd,
-                        ondone=self.OnRenderDone)
+                        ondone=self.OnRenderDone, userdata={'cmd': cmd})
         self.layer.forceRender = False
 
     def _render(self, cmd, env):
-        try:
-            return grass.run_command(cmd[0], env=env, **cmd[1])
-        except CalledModuleError as e:
-            return 1
+        p = grass.start_command(cmd[0], env=env, stderr=grass.PIPE, **cmd[1])
+        stdout, stderr = p.communicate()
+        if p.returncode:
+            return stderr
+        else:
+            return None
 
     def Abort(self):
         """Abort rendering process"""
@@ -419,13 +422,14 @@
 
         Emits updateProcess
         """
-        Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): ret=%d time=%f" %
+        Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): err=%s time=%f" %
                   (self.layer, event.ret, time.time() - self._startTime))
-        if event.ret != 0:
-            try:
-                os.remove(self.layer.mapfile)
-            except:
-                pass
+        if event.ret is not None:
+            cmd = cmdtuple_to_list(event.userdata['cmd'])
+            self.renderingFailed.emit(cmd=cmd, error=event.ret)
+            # don't remove layer if overlay, we need to keep the old one
+            if self.layer.type != 'overlay':
+                try_remove(self.layer.mapfile)
 
         self.updateProgress.emit(layer=self.layer)
 
@@ -443,6 +447,7 @@
 
         self.updateMap = Signal('RenderMapMgr.updateMap')
         self.updateProgress = Signal('RenderMapMgr.updateProgress')
+        self.renderingFailed = Signal('RenderMapMgr.renderingFailed')
         self.renderDone = Signal('RenderMapMgr.renderDone')
         self.renderDone.connect(self.OnRenderDone)
 
@@ -519,6 +524,25 @@
 
         return env
 
+    def RenderOverlays(self, force=False):
+        """Render only overlays
+
+        :param bool force: force rendering all map layers
+        """
+        if self._rendering:
+            Debug.msg(
+                1, "RenderMapMgr().RenderOverlays(): cancelled (already rendering)")
+            return
+
+        wx.BeginBusyCursor()
+        self._rendering = True
+
+        env = self.GetRenderEnv()
+        self._init(env)
+        # no layer composition afterwards
+        if self._renderLayers(env, force, overlaysOnly=True) == 0:
+            self.renderDone.emit()
+
     def Render(self, force=False, windres=False):
         """Render map composition
 
@@ -535,7 +559,7 @@
 
         env = self.GetRenderEnv(windres)
         self._init(env)
-        if self._renderLayers(env, force, windres) == 0:
+        if self._renderLayers(env, force) == 0:
             self.renderDone.emit()
 
     def OnRenderDone(self):
@@ -652,7 +676,10 @@
                 'progresVal'] == self.progressInfo['range']:
             self.renderDone.emit()
 
+    def RenderingFailed(self, cmd, error):
+        self.renderingFailed.emit(cmd=cmd, error=error)
 
+
 class Map(object):
 
     def __init__(self, gisrc=None):
@@ -1413,6 +1440,7 @@
                     string=True))))
         if renderMgr:
             renderMgr.updateProgress.connect(self.renderMgr.ReportProgress)
+            renderMgr.renderingFailed.connect(self.renderMgr.RenderingFailed)
         overlay.forceRender = render
 
         return overlay
@@ -1511,9 +1539,7 @@
 
     def RenderOverlays(self, force):
         """Render overlays only (for nviz)"""
-        for layer in self.overlays:
-            if force or layer.forceRender:
-                layer.Render()
+        self.renderMgr.RenderOverlays(force)
 
     def AbortAllThreads(self):
         """Abort all layers threads e. g. donwloading data"""

Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/gui_core/forms.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -873,7 +873,7 @@
                                           'MapWindow'):
             # display decorations and
             # pressing OK or cancel after setting layer properties
-            if self.task.name in ['d.barscale', 'd.legend', 'd.northarrow', 'd.histogram'] \
+            if self.task.name in ['d.barscale', 'd.legend', 'd.northarrow', 'd.histogram', 'd.text'] \
                     or len(self.parent.GetLayerInfo(self.layer, key='cmd')) >= 1:
                 self.Hide()
             # canceled layer with nothing set

Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/lmgr/frame.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -651,10 +651,10 @@
         Also close associated map display
         """
 
-        if UserSettings.Get(group='manager', key='askOnQuit',
-                            subkey='enabled') and self.workspaceChanged:
-            maptree = self.GetLayerTree()
-
+        # save changes in the workspace
+        maptree = self.GetLayerTree()
+        if  self.workspaceChanged and UserSettings.Get(
+                group='manager', key='askOnQuit', subkey='enabled'):
             if self.workspaceFile:
                 message = _("Do you want to save changes in the workspace?")
             else:
@@ -749,9 +749,9 @@
 
         if layertype == 'barscale':
             if len(command) > 1:
-                self.GetMapDisplay().AddBarscale(cmd=command, showDialog=False)
+                self.GetMapDisplay().AddBarscale(cmd=command)
             else:
-                self.GetMapDisplay().AddBarscale(showDialog=True)
+                self.GetMapDisplay().AddBarscale()
         elif layertype == 'rastleg':
             if len(command) > 1:
                 self.GetMapDisplay().AddLegend(cmd=command, showDialog=False)
@@ -759,9 +759,14 @@
                 self.GetMapDisplay().AddLegend(showDialog=True)
         elif layertype == 'northarrow':
             if len(command) > 1:
-                self.GetMapDisplay().AddArrow(cmd=command, showDialog=False)
+                self.GetMapDisplay().AddArrow(cmd=command)
             else:
-                self.GetMapDisplay().AddArrow(showDialog=True)
+                self.GetMapDisplay().AddArrow()
+        elif layertype == 'text':
+            if len(command) > 1:
+                self.GetMapDisplay().AddDtext(cmd=command)
+            else:
+                self.GetMapDisplay().AddDtext()
         elif layertype == 'redraw':
             self.GetMapDisplay().OnRender(None)
         elif layertype == 'export':
@@ -1485,6 +1490,8 @@
                         mapdisplay[i].AddBarscale(overlay['cmd'])
                     if overlay['cmd'][0] == "d.northarrow":
                         mapdisplay[i].AddArrow(overlay['cmd'])
+                    if overlay['cmd'][0] == "d.text":
+                        mapdisplay[i].AddDtext(overlay['cmd'])
 
             # avoid double-rendering when loading workspace
             # mdisp.MapWindow2D.UpdateMap()
@@ -2421,10 +2428,10 @@
             self.Destroy()
             return
 
-        # save changes in the workspace
-        maptree = self.GetLayerTree()
-        if self.workspaceChanged and UserSettings.Get(
-                group='manager', key='askOnQuit', subkey='enabled'):
+        if UserSettings.Get(group='manager', key='askOnQuit',
+                            subkey='enabled') and self.workspaceChanged:
+            maptree = self.GetLayerTree()
+
             if self.workspaceFile:
                 message = _("Do you want to save changes in the workspace?")
             else:

Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -43,8 +43,8 @@
 from mapwin.base import MapWindowProperties
 from gui_core.query import QueryDialog, PrepareQueryResults
 from mapwin.buffered import BufferedMapWindow
-from mapwin.decorations import TextLayerDialog, \
-    LegendController, BarscaleController, ArrowController
+from mapwin.decorations import LegendController, BarscaleController, \
+    ArrowController, DtextController
 from modules.histogram import HistogramFrame
 from wxplot.histogram import HistogramPlotFrame
 from wxplot.profile import ProfileFrame
@@ -128,12 +128,7 @@
 
         # init decoration objects
         self.decorations = {}
-        self.legend = LegendController(self.Map, self._giface)
-        self.barscale = BarscaleController(self.Map, self._giface)
-        self.arrow = ArrowController(self.Map, self._giface)
-        self.decorations[self.legend.id] = self.legend
-        self.decorations[self.barscale.id] = self.barscale
-        self.decorations[self.arrow.id] = self.arrow
+        self._decorationWindows = {}
 
         self.mapWindowProperties.autoRenderChanged.connect(
             lambda value:
@@ -147,12 +142,8 @@
             properties=self.mapWindowProperties, overlays=self.decorations)
         self.MapWindow2D.mapQueried.connect(self.Query)
         self.MapWindow2D.overlayActivated.connect(self._activateOverlay)
-        self.MapWindow2D.overlayHidden.connect(self._hideOverlay)
-        self.MapWindow2D.overlayHidden.connect(self._hideOverlay)
-        for overlay in (self.legend, self.barscale, self.arrow):
-            overlay.overlayChanged.connect(
-                lambda: self.MapWindow2D.UpdateMap(
-                    render=False, renderVector=False))
+        self.MapWindow2D.overlayRemoved.connect(self._removeOverlay)
+        self.MapWindow2D.overlayRemoved.connect(self._removeOverlay)
         self._setUpMapWindow(self.MapWindow2D)
 
         self.MapWindow2D.mouseHandlerUnregistered.connect(self.ResetPointer)
@@ -254,6 +245,8 @@
 
         #
         self.Map.GetRenderMgr().updateProgress.connect(self.statusbarManager.SetProgress)
+        self.Map.GetRenderMgr().renderingFailed.connect(lambda cmd, error: self._giface.WriteError(
+            _("Failed to run command '{command}'. Details:\n{error}").format(command=' '.join(cmd), error=error)))
 
     def GetMapWindow(self):
         return self.MapWindow
@@ -414,8 +407,7 @@
             self.MapWindow3D.ResetViewHistory()
             self.MapWindow3D.UpdateView(None)
             self.MapWindow3D.overlayActivated.connect(self._activateOverlay)
-            self.MapWindow3D.overlayHidden.connect(self._hideOverlay)
-            self.legend.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
+            self.MapWindow3D.overlayRemoved.connect(self._removeOverlay)
         else:
             self._switchMapWindow(self.MapWindow3D)
             os.environ['GRASS_REGION'] = self.Map.SetRegion(
@@ -432,10 +424,14 @@
 
             self.MapWindow3D.ResetViewHistory()
 
+        # connect signals for updating overlays
+        for overlay in self.decorations.values():
+            overlay.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
+        self.Map.GetRenderMgr().renderDone.connect(self.MapWindow3D._onUpdateOverlays)
+
         self._giface.updateMap.disconnect(self.MapWindow2D.UpdateMap)
         self._giface.updateMap.connect(self.MapWindow3D.UpdateMap)
         self.MapWindow3D.overlays = self.MapWindow2D.overlays
-        self.MapWindow3D.textdict = self.MapWindow2D.textdict
         # update overlays needs to be called after because getClientSize
         # is called during update and it must give reasonable values
         wx.CallAfter(self.MapWindow3D.UpdateOverlays)
@@ -479,13 +475,16 @@
         self.ending3dMode.emit()
         try:
             self.MapWindow2D.overlays = self.MapWindow3D.overlays
-            self.MapWindow2D.textdict = self.MapWindow3D.textdict
         except AttributeError:
             pass
         # TODO: here we end because self.MapWindow3D is None for a while
         self._giface.updateMap.disconnect(self.MapWindow3D.UpdateMap)
         self._giface.updateMap.connect(self.MapWindow2D.UpdateMap)
-        self.legend.overlayChanged.disconnect(self.MapWindow3D.UpdateOverlays)
+        # disconnect overlays
+        for overlay in self.decorations.values():
+            overlay.overlayChanged.disconnect(self.MapWindow3D.UpdateOverlays)
+        self.Map.GetRenderMgr().renderDone.disconnect(self.MapWindow3D._onUpdateOverlays)
+        self.MapWindow3D.ClearTextures()
 
         self.MapWindow.UpdateMap()
         self._mgr.Update()
@@ -1195,113 +1194,60 @@
 
         :param overlayId: id of overlay
         """
-        if overlayId > 100:
-            self.OnAddText(None)
-        elif overlayId == 0:
-            self.AddLegend(cmd=self.legend.cmd, showDialog=True)
-        elif overlayId == 1:
-            self.AddBarscale(showDialog=True)
-        elif overlayId == 2:
-            self.AddArrow(showDialog=True)
+        dlg = self.decorations[overlayId].dialog
+        if dlg.IsShown():
+            dlg.SetFocus()
+            dlg.Raise()
+        else:
+            dlg.Show()
 
-    def _hideOverlay(self, overlayId):
+    def _removeOverlay(self, overlayId):
         """Hide overlay.
 
         :param overlayId: id of overlay
         """
-        self.decorations[overlayId].Hide()
+        del self._decorationWindows[self.decorations[overlayId].dialog]
+        self.decorations[overlayId].Remove()
+        del self.decorations[overlayId]
 
-    def AddBarscale(self, cmd=None, showDialog=None):
+    def AddBarscale(self, cmd=None):
         """Handler for scale bar map decoration menu selection."""
         if self.IsPaneShown('3d'):
             self.MapWindow3D.SetDrawScalebar((70, 70))
             return
 
-        if self.barscale.IsShown() and showDialog is None:
-            self.barscale.Hide()
-            return
-
         if cmd:
-            self.barscale.cmd = cmd
+            show = False
+        else:
+            show = True
+            cmd = ['d.barscale']
 
-        if not showDialog:
-            self.barscale.Show()
-            return
-
         # Decoration overlay control dialog
-        if self.barscale.dialog:
-            if self.barscale.dialog.IsShown():
-                self.barscale.dialog.SetFocus()
-                self.barscale.dialog.Raise()
-            else:
-                self.barscale.dialog.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'
+        GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+            cmd, completed=(self.GetOptData, None, None))
 
-            # decoration overlay control dialog
-            GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
-                self.barscale.cmd, completed=(self.barscale.GetOptData, None, None))
-
         self.MapWindow.mouse['use'] = 'pointer'
 
     def AddLegend(self, cmd=None, showDialog=None):
         """Handler for legend map decoration menu selection."""
-        if self.legend.IsShown() and showDialog is None:
-            self.legend.Hide()
-            return
+
         if cmd:
-            self.legend.cmd = cmd
+            show = False
         else:
+            show = True
+            cmd = ['d.legend']
             layers = self._giface.GetLayerList().GetSelectedLayers()
             for layer in layers:
                 if layer.type == 'raster':
-                    isMap = False
-                    # replace map
-                    for i, legendParam in enumerate(self.legend.cmd[1:]):
-                        idx = i + 1
-                        param_val = legendParam.split('=')
-                        if len(param_val) != 2:
-                            continue
-                        param, val = param_val
-                        if param == 'raster':
-                            self.legend.cmd[idx] = 'raster={rast}'.format(
-                                rast=layer.maplayer.name)
-                            isMap = True
-                        elif param in ('use', 'range'):
-                            # clear range or use to avoid problems
-                            del self.legend.cmd[idx]
-
-                    if not isMap:  # for the first time
-                        self.legend.cmd.append(
-                            'raster=%s' %
-                            layer.maplayer.name)
+                    cmd.append('raster={rast}'.format(rast=layer.maplayer.name))
                     break
 
-        if not showDialog and self.legend.CmdIsValid():
-            self.legend.Show()
-            return
+        GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+            cmd, completed=(self.GetOptData, None, None))
 
-        # Decoration overlay control dialog
-        # always create new one to avoid problem when switching between maps
-        if self.legend.dialog:
-            if self.legend.dialog.IsShown():
-                self.legend.dialog.SetFocus()
-                self.legend.dialog.Raise()
-            else:
-                self.legend.dialog.Destroy()
-                self.legend.dialog = None
-        if not self.legend.dialog:
-            GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
-                self.legend.cmd, completed=(self.legend.GetOptData, None, None))
-
         self.MapWindow.mouse['use'] = 'pointer'
 
-    def AddArrow(self, cmd=None, showDialog=None):
+    def AddArrow(self, cmd=None):
         """Handler for north arrow menu selection."""
         if self.IsPaneShown('3d'):
             # here was opening of appearance page of nviz notebook
@@ -1310,96 +1256,68 @@
             self.MapWindow3D.SetDrawArrow((70, 70))
             return
 
-        if self.arrow.IsShown() and showDialog is None:
-            self.arrow.Hide()
-            return
         if cmd:
-            self.arrow.cmd = cmd
+            show = False
+        else:
+            show = True
+            cmd = ['d.northarrow']
 
-        if not showDialog:
-            self.arrow.Show()
-            return
-
         # Decoration overlay control dialog
-        if self.arrow.dialog:
-            if self.arrow.dialog.IsShown():
-                self.arrow.dialog.SetFocus()
-                self.arrow.dialog.Raise()
-            else:
-                self.arrow.dialog.Show()
-        else:
-            GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
-                self.arrow.cmd, completed=(self.arrow.GetOptData, None, None))
+        GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+            cmd, completed=(self.GetOptData, None, None))
 
         self.MapWindow.mouse['use'] = 'pointer'
 
-    def OnAddText(self, event):
-        """Handler for text decoration menu selection.
-        """
-        if self.MapWindow.dragid > -1:
-            id = self.MapWindow.dragid
-            self.MapWindow.dragid = -1
+    def AddDtext(self, cmd=None):
+        """Handler for d.text menu selection."""
+        if cmd:
+            show = False
         else:
-            # index for overlay layer in render
-            if len(self.MapWindow.textdict.keys()) > 0:
-                id = max(self.MapWindow.textdict.keys()) + 1
-            else:
-                id = 101
+            show = True
+            cmd = ['d.text']
 
-        self.dialogs['text'] = TextLayerDialog(parent=self, ovlId=id,
-                                               title=_('Add text layer'),
-                                               size=(400, 200))
-        self.dialogs['text'].CenterOnParent()
+        # Decoration overlay control dialog
+        GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+            cmd, completed=(self.GetOptData, None, None))
 
-        # If OK button pressed in decoration control dialog
-        if self.dialogs['text'].ShowModal() == wx.ID_OK:
-            text = self.dialogs['text'].GetValues()['text']
-            active = self.dialogs['text'].GetValues()['active']
+        self.MapWindow.mouse['use'] = 'pointer'
 
-            # delete object if it has no text or is not active
-            if text == '' or active == False:
-                try:
-                    self.MapWindow2D.pdc.ClearId(id)
-                    self.MapWindow2D.pdc.RemoveId(id)
-                    del self.MapWindow.textdict[id]
-                    if self.IsPaneShown('3d'):
-                        self.MapWindow3D.UpdateOverlays()
-                        self.MapWindow.UpdateMap()
-                    else:
-                        self.MapWindow2D.UpdateMap(
-                            render=False, renderVector=False)
-                except:
-                    pass
-                return
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """Called after options are set through module dialog.
 
-            self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
+        :param dcmd: resulting command
+        :param layer: not used
+        :param params: module parameters (not used)
+        :param propwin: dialog window
+        """
 
-            if self.IsPaneShown('3d'):
-                self.MapWindow3D.UpdateOverlays()
-                self.MapWindow3D.UpdateMap()
-            else:
-                self.MapWindow2D.pdc.ClearId(id)
-                self.MapWindow2D.pdc.SetId(id)
-                self.MapWindow2D.UpdateMap(render=False, renderVector=False)
+        if not dcmd:
+            return
+        if propwin in self._decorationWindows:
+            overlay = self._decorationWindows[propwin]
+        else:
+            cmd = dcmd[0]
+            if cmd == 'd.northarrow':
+                overlay = ArrowController(self.Map, self._giface)
+            elif cmd == 'd.barscale':
+                overlay = BarscaleController(self.Map, self._giface)
+            elif cmd == 'd.legend':
+                overlay = LegendController(self.Map, self._giface)
+            elif cmd == 'd.text':
+                overlay = DtextController(self.Map, self._giface)
 
-        self.MapWindow.mouse['use'] = 'pointer'
+            self.decorations[overlay.id] = overlay
+            overlay.overlayChanged.connect(lambda: self.MapWindow2D.UpdateMap(
+                                           render=False, renderVector=False))
+            if self.MapWindow3D:
+                overlay.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
 
-    def GetOptData(self, dcmd, type, params, propwin):
-        """Callback method for decoration overlay command generated by
-        dialog created in menuform.py
-        """
-        # Reset comand and rendering options in render.Map. Always render decoration.
-        # Showing/hiding handled by PseudoDC
-        self.Map.ChangeOverlay(
-            ovltype=type,
-            type='overlay',
-            name='',
-            command=dcmd,
-            active=True,
-            render=False)
-        self.params[type] = params
-        self.propwin[type] = propwin
+            overlay.dialog = propwin
+            self._decorationWindows[propwin] = overlay
 
+        overlay.cmd = dcmd
+        overlay.Show()
+
     def OnZoomToMap(self, event):
         """Set display extents to match selected raster (including
         NULLs) or vector map.

Modified: grass/trunk/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/toolbars.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/mapdisp/toolbars.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -32,11 +32,11 @@
                        label=_('Select vector feature(s)'),
                        desc=_('Select features interactively from vector map')),
     'addBarscale': MetaIcon(img='scalebar-add',
-                            label=_('Show/hide scale bar')),
+                            label=_('Add scale bar')),
     'addLegend': MetaIcon(img='legend-add',
-                          label=_('Show/hide legend')),
+                          label=_('Add legend')),
     'addNorthArrow': MetaIcon(img='north-arrow-add',
-                              label=_('Show/hide north arrow')),
+                              label=_('Add north arrow')),
     'analyze': MetaIcon(img='layer-raster-analyze',
                         label=_('Analyze map'),
                         desc=_('Measuring, profiling, histogramming, ...')),
@@ -49,7 +49,7 @@
     'scatter': MetaIcon(img='layer-raster-profile',
                         label=_("Create bivariate scatterplot of raster maps")),
     'addText': MetaIcon(img='text-add',
-                        label=_('Add text layer')),
+                        label=_('Add text')),
     'histogram': MetaIcon(img='layer-raster-histogram',
                           label=_('Create histogram of raster map')),
     'vnet': MetaIcon(img='vector-tools',
@@ -271,10 +271,10 @@
               lambda evt: self.parent.AddLegend()),
              (MapIcons["addBarscale"],
               lambda evt: self.parent.AddBarscale()),
-                (MapIcons["addNorthArrow"],
-                 lambda evt: self.parent.AddArrow()),
-                (MapIcons["addText"],
-                 self.parent.OnAddText)))
+             (MapIcons["addNorthArrow"],
+              lambda evt: self.parent.AddArrow()),
+             (MapIcons["addText"],
+              lambda evt: self.parent.AddDtext())))
 
     def ExitToolbars(self):
         if self.parent.GetToolbar('vdigit'):

Modified: grass/trunk/gui/wxpython/mapwin/base.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/base.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/mapwin/base.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -125,7 +125,7 @@
         # emitted after double click in pointer mode on legend, text, scalebar
         self.overlayActivated = Signal('MapWindow.overlayActivated')
         # emitted when overlay should be hidden
-        self.overlayHidden = Signal('MapWindow.overlayHidden')
+        self.overlayRemoved = Signal('MapWindow.overlayRemoved')
 
         # mouse attributes -- position on the screen, begin and end of
         # dragging, and type of drawing

Modified: grass/trunk/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/buffered.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/mapwin/buffered.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -160,15 +160,12 @@
         self.img = None   # wx.Image object (self.mapfile)
         # decoration overlays
         self.overlays = overlays
-        self._overlayNames = {
-            0: _("legend"),
-            1: _("scale bar"),
-            2: _("north arrow")}
         # images and their PseudoDC ID's for painting and dragging
         self.imagedict = {}
         self.select = {}      # selecting/unselecting decorations for dragging
         self.textdict = {}    # text, font, and color indexed by id
 
+
         # zoom objects
         self.zoomhistory = []  # list of past zoom extents
         self.currzoom = 0  # current set of extents in zoom history being used
@@ -274,27 +271,20 @@
 
         pos = self.ScreenToClient(event.GetPosition())
         idlist = self.pdc.FindObjects(pos[0], pos[1], self.hitradius)
-        separator = True
-        if idlist and idlist[0] in (0, 1, 2):  # legend, scale bar, north arrow
-            if separator:
-                menu.AppendSeparator()
-                separator = False
-            self._hide = wx.NewId()
+        if self.overlays and idlist and [i for i in idlist if i in self.overlays.keys()]:  # legend, scale bar, north arrow, dtext
+            menu.AppendSeparator()
+            removeId = wx.NewId()
             self.Bind(wx.EVT_MENU,
-                      lambda evt: self.overlayHidden.emit(overlayId=idlist[0]),
-                      id=self._hide)
-            menu.Append(
-                self._hide,
-                _("Hide {overlay}").format(
-                    overlay=self._overlayNames[
-                        idlist[0]]))
+                      lambda evt: self.overlayRemoved.emit(overlayId=idlist[0]),
+                      id=removeId)
+            menu.Append(removeId, self.overlays[idlist[0]].removeLabel)
 
-            if idlist[0] == 0:
-                self._resizeLegend = wx.NewId()
+            if self.overlays[idlist[0]].name == 'legend':
+                resizeLegendId = wx.NewId()
                 self.Bind(wx.EVT_MENU,
                           lambda evt: self.overlays[idlist[0]].StartResizing(),
-                          id=self._resizeLegend)
-                menu.Append(self._resizeLegend, _("Resize legend"))
+                          id=resizeLegendId)
+                menu.Append(resizeLegendId, _("Resize legend"))
         self.PopupMenu(menu)
         menu.Destroy()
 
@@ -1071,20 +1061,22 @@
 
         if isinstance(r, list):
             r = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100:  # text dragging
+        if id in self.textdict:  # text dragging
             rtop = (r[0], r[1] - r[3], r[2], r[3])
             r = r.Union(rtop)
             rleft = (r[0] - r[2], r[1], r[2], r[3])
             r = r.Union(rleft)
+
         self.pdc.TranslateId(id, dx, dy)
 
         r2 = self.pdc.GetIdBounds(id)
         if isinstance(r2, list):
             r2 = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100:  # text
+        if id in self.textdict:  # text
             self.textdict[id]['bbox'] = r2
             self.textdict[id]['coords'][0] += dx
             self.textdict[id]['coords'][1] += dy
+
         r = r.Union(r2)
         r.Inflate(4, 4)
         self.RefreshRect(r, False)
@@ -1514,6 +1506,7 @@
                 idlist.remove(99)
             if idlist != []:
                 self.dragid = idlist[0]  # drag whatever is on top
+
         else:
             pass
         coords = self.Pixel2Cell(self.mouse['begin'])
@@ -1561,13 +1554,12 @@
                 self.dragid >= 0):
             # end drag of overlay decoration
 
-            if self.dragid < 99 and self.dragid in self.overlays:
+            if self.overlays and self.dragid in self.overlays:
                 self.overlays[
                     self.dragid].coords = self.pdc.GetIdBounds(
                     self.dragid)
-            elif self.dragid > 100 and self.dragid in self.textdict:
-                self.textdict[self.dragid][
-                    'bbox'] = self.pdc.GetIdBounds(self.dragid)
+            elif self.dragid in self.textdict:
+                self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
             else:
                 pass
             self.dragid = None
@@ -1689,6 +1681,13 @@
                 self.digit:
             self._onMouseMoving(event)
 
+        pos = event.GetPosition()
+        idlist = self.pdc.FindObjects(pos[0], pos[1], self.hitradius)
+        if self.overlays and idlist and [i for i in idlist if i in self.overlays.keys()]:  # legend, scale bar, north arrow, dtext
+            self.SetToolTipString("Double click in Pointer mode to set object"
+                                  " properties,\nright click to remove")
+        else:
+            self.SetToolTip(None)
         event.Skip()
 
     def OnCopyCoordinates(self, event):

Modified: grass/trunk/gui/wxpython/mapwin/decorations.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/decorations.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/mapwin/decorations.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -22,7 +22,6 @@
 from core.utils import _
 
 import wx
-from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
 
 from grass.pydispatch.signal import Signal
 try:
@@ -32,12 +31,6 @@
     hasPIL = False
 
 
-class OverlayId:
-    legendId = 0
-    barscaleId = 1
-    arrowId = 2
-
-
 class OverlayController(object):
 
     """Base class for decorations (barscale, legend) controller."""
@@ -52,7 +45,8 @@
         self._defaultAt = ''
         self._cmd = None   # to be set by user
         self._name = None  # to be defined by subclass
-        self._id = None    # to be defined by subclass
+        self._removeLabel = None  # to be defined by subclass
+        self._id = wx.NewId()
         self._dialog = None
 
         # signals that overlay or its visibility changed
@@ -97,6 +91,11 @@
 
     name = property(fget=GetName)
 
+    def GetRemoveLabel(self):
+        return self._removeLabel
+
+    removeLabel = property(fget=GetRemoveLabel)
+
     def GetId(self):
         return self._id
 
@@ -145,22 +144,12 @@
             self._overlay.SetActive(False)
         self.overlayChanged.emit()
 
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """Called after options are set through module dialog.
+    def Remove(self):
+        if self._dialog:
+            self._dialog.Destroy()
+        self._renderer.DeleteOverlay(self._overlay)
+        self.overlayChanged.emit()
 
-        :param dcmd: resulting command
-        :param layer: not used
-        :param params: module parameters (not used)
-        :param propwin: dialog window
-        """
-        if not dcmd:
-            return
-
-        self._cmd = dcmd
-        self._dialog = propwin
-
-        self.Show()
-
     def _add(self):
         self._overlay = self._renderer.AddOverlay(
             id=self._id,
@@ -189,6 +178,7 @@
                     "Please install Python Imaging Library (PIL)\n"
                     "for better control of legend and other decorations."))
             return 0, 0
+
         for param in self._cmd:
             if not param.startswith('at'):
                 continue
@@ -199,12 +189,35 @@
             return x, y
 
 
+class DtextController(OverlayController):
+
+    def __init__(self, renderer, giface):
+        OverlayController.__init__(self, renderer, giface)
+        self._name = 'text'
+        self._removeLabel = _("Remove text")
+        self._defaultAt = 'at=50,50'
+        self._cmd = ['d.text', self._defaultAt]
+
+    def CmdIsValid(self):
+        inputs = 0
+        for param in self._cmd[1:]:
+            param = param.split('=')
+            if len(param) == 1:
+                inputs += 1
+            else:
+                if param[0] == 'text' and len(param) == 2:
+                    inputs += 1
+        if inputs >= 1:
+            return True
+        return False
+
+
 class BarscaleController(OverlayController):
 
     def __init__(self, renderer, giface):
         OverlayController.__init__(self, renderer, giface)
-        self._id = OverlayId.barscaleId
         self._name = 'barscale'
+        self._removeLabel = _("Remove scale bar")
         # different from default because the reference point is not in the
         # middle
         self._defaultAt = 'at=0,98'
@@ -215,8 +228,8 @@
 
     def __init__(self, renderer, giface):
         OverlayController.__init__(self, renderer, giface)
-        self._id = OverlayId.arrowId
         self._name = 'arrow'
+        self._removeLabel = _("Remove north arrow")
         # different from default because the reference point is not in the
         # middle
         self._defaultAt = 'at=85.0,25.0'
@@ -227,8 +240,8 @@
 
     def __init__(self, renderer, giface):
         OverlayController.__init__(self, renderer, giface)
-        self._id = OverlayId.legendId
         self._name = 'legend'
+        self._removeLabel = _("Remove legend")
         # TODO: synchronize with d.legend?
         self._defaultAt = 'at=5,50,7,10'
         self._cmd = ['d.legend', self._defaultAt]
@@ -313,202 +326,3 @@
         self._giface.GetMapDisplay().GetMapToolbar().SelectDefault()
         # redraw
         self.overlayChanged.emit()
-
-
-class TextLayerDialog(wx.Dialog):
-    """!Controls setting options and displaying/hiding map overlay decorations
-    """
-
-    def __init__(self, parent, ovlId, title, name='text', size=wx.DefaultSize,
-                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-
-        wx.Dialog.__init__(
-            self,
-            parent=parent,
-            id=wx.ID_ANY,
-            title=title,
-            style=style,
-            size=size)
-
-        self.ovlId = ovlId
-        self.parent = parent
-
-        if self.ovlId in self.parent.MapWindow.textdict.keys():
-            self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
-            self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
-            self.currClr = self.parent.MapWindow.textdict[self.ovlId]['color']
-            self.currRot = self.parent.MapWindow.textdict[
-                self.ovlId]['rotation']
-            self.currCoords = self.parent.MapWindow.textdict[
-                self.ovlId]['coords']
-            self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
-        else:
-            self.currClr = wx.BLACK
-            self.currText = ''
-            self.currFont = self.GetFont()
-            self.currRot = 0.0
-            self.currCoords = [10, 10]
-            self.currBB = wx.Rect()
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.GridBagSizer(vgap=5, hgap=5)
-
-        # show/hide
-        self.chkbox = wx.CheckBox(parent=self, id=wx.ID_ANY,
-                                  label=_('Show text object'))
-        if self.parent.Map.GetOverlay(self.ovlId) is None:
-            self.chkbox.SetValue(True)
-        else:
-            self.chkbox.SetValue(
-                self.parent.MapWindow.overlays[
-                    self.ovlId]['layer'].IsActive())
-        box.Add(item=self.chkbox, span=(1, 2),
-                pos=(0, 0))
-
-        # text entry
-        box.Add(
-            item=wx.StaticText(
-                parent=self,
-                id=wx.ID_ANY,
-                label=_("Text:")),
-            flag=wx.ALIGN_CENTER_VERTICAL,
-            pos=(
-                1,
-                0))
-
-        self.textentry = ExpandoTextCtrl(
-            parent=self, id=wx.ID_ANY, value="", size=(300, -1))
-        self.textentry.SetFont(self.currFont)
-        self.textentry.SetForegroundColour(self.currClr)
-        self.textentry.SetValue(self.currText)
-        # get rid of unneeded scrollbar when text box first opened
-        self.textentry.SetClientSize((300, -1))
-
-        box.Add(item=self.textentry,
-                flag=wx.EXPAND,
-                pos=(1, 1))
-
-        # rotation
-        box.Add(
-            item=wx.StaticText(
-                parent=self,
-                id=wx.ID_ANY,
-                label=_("Rotation:")),
-            flag=wx.ALIGN_CENTER_VERTICAL,
-            pos=(
-                2,
-                0))
-        self.rotation = wx.SpinCtrl(
-            parent=self, id=wx.ID_ANY, value="", pos=(
-                30, 50), size=(
-                75, -1), style=wx.SP_ARROW_KEYS)
-        self.rotation.SetRange(-360, 360)
-        self.rotation.SetValue(int(self.currRot))
-        box.Add(item=self.rotation,
-                flag=wx.ALIGN_RIGHT,
-                pos=(2, 1))
-
-        # font
-        box.Add(
-            item=wx.StaticText(
-                parent=self,
-                id=wx.ID_ANY,
-                label=_("Font:")),
-            flag=wx.ALIGN_CENTER_VERTICAL,
-            pos=(
-                3,
-                0))
-        fontbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set font"))
-        box.Add(item=fontbtn,
-                flag=wx.ALIGN_RIGHT,
-                pos=(3, 1))
-
-        box.AddGrowableCol(1)
-        box.AddGrowableRow(1)
-        self.sizer.Add(item=box, proportion=1,
-                       flag=wx.ALL | wx.EXPAND, border=10)
-
-        # note
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        label = wx.StaticText(
-            parent=self, id=wx.ID_ANY, label=_(
-                "Drag text with mouse in pointer mode "
-                "to position.\nDouble-click to change options"))
-        box.Add(item=label, proportion=0,
-                flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
-        self.sizer.Add(
-            item=box, proportion=0, flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL |
-            wx.ALIGN_CENTER | wx.ALL, border=5)
-
-        line = wx.StaticLine(parent=self, id=wx.ID_ANY,
-                             size=(20, -1), style=wx.LI_HORIZONTAL)
-        self.sizer.Add(item=line, proportion=0,
-                       flag=wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border=5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(parent=self, id=wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(parent=self, id=wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        self.sizer.Add(item=btnsizer, proportion=0,
-                       flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-
-        self.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-        # bindings
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
-        self.Bind(wx.EVT_BUTTON, self.OnSelectFont, fontbtn)
-        self.Bind(wx.EVT_TEXT, self.OnText, self.textentry)
-        self.Bind(wx.EVT_SPINCTRL, self.OnRotation, self.rotation)
-
-        self.SetMinSize((400, 230))
-
-    def OnRefit(self, event):
-        """Resize text entry to match text"""
-        self.sizer.Fit(self)
-
-    def OnText(self, event):
-        """Change text string"""
-        self.currText = event.GetString()
-
-    def OnRotation(self, event):
-        """Change rotation"""
-        self.currRot = event.GetInt()
-
-        event.Skip()
-
-    def OnSelectFont(self, event):
-        """Change font"""
-        data = wx.FontData()
-        data.EnableEffects(True)
-        data.SetColour(self.currClr)         # set colour
-        data.SetInitialFont(self.currFont)
-
-        dlg = wx.FontDialog(self, data)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            data = dlg.GetFontData()
-            self.currFont = data.GetChosenFont()
-            self.currClr = data.GetColour()
-
-            self.textentry.SetFont(self.currFont)
-            self.textentry.SetForegroundColour(self.currClr)
-
-            self.Layout()
-
-        dlg.Destroy()
-
-    def GetValues(self):
-        """Get text properties"""
-        return {'text': self.currText,
-                'font': self.currFont,
-                'color': self.currClr,
-                'rotation': self.currRot,
-                'coords': self.currCoords,
-                'active': self.chkbox.IsChecked()}

Modified: grass/trunk/gui/wxpython/nviz/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/nviz/mapwindow.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/nviz/mapwindow.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -160,7 +160,6 @@
         self.imagelist = []
         self.overlay = wx.Overlay()
         #self.pdc = wx.PseudoDC()
-        self.textdict = {}
         self.dragid = -1
         self.hitradius = 5
         # layer manager toolwindow
@@ -473,125 +472,36 @@
             if texture.IsActive():
                 texture.Draw()
 
-    def GetLegendRect(self):
-        """Estimates legend size for dragging"""
-        size = None
-        if 0 in self.overlays:
-            for param in self.overlays[0].cmd[1:]:
-                if param.startswith("at="):
-                    size = map(float, param.split("=")[-1].split(','))
-                    break
-        if size:
-            wSize = self.GetClientSizeTuple()
-            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]
-            w = (size[3] - size[2]) / 100. * wSize[0]
-            h = (size[1] - size[0]) / 100. * wSize[1]
-
-            rect = wx.Rect(x, y, w, h)
-            return rect
-
-        return wx.Rect()
-
-    def DrawTextImage(self, textDict, relCoords):
-        """Draw overlay text"""
-        bmp = wx.EmptyBitmap(textDict['bbox'][2], textDict['bbox'][3])
-        memDC = wx.MemoryDC()
-        memDC.SelectObject(bmp)
-
-        mask = self.view['background']['color']
-        if mask == textDict['color']:
-            mask = wx.WHITE
-        memDC.SetBackground(wx.Brush(mask))
-        memDC.Clear()
-        memDC.SetFont(textDict['font'])
-        memDC.SetTextForeground(textDict['color'])
-        if textDict['rotation'] == 0:
-            memDC.DrawText(textDict['text'], 0, 0)
-        else:
-            memDC.DrawRotatedText(textDict['text'], relCoords[0], relCoords[1],
-                                  textDict['rotation'])
-        bmp.SetMaskColour(mask)
-        memDC.DrawBitmap(bmp, 0, 0, 1)
-
-        filename = grass.tempfile(create=False) + '.png'
-        bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
-        memDC.SelectObject(wx.NullBitmap)
-
-        return filename
-
     def UpdateOverlays(self):
-        """Converts rendered overlay files and text labels to wx.Image
-            and then to textures so that they can be rendered by OpenGL.
-            Updates self.imagelist"""
+        """Renders overlays (legend, text).
+        Once this is done _onUpdateOverlays is called"""
         self.Map.ChangeMapSize(self.GetClientSize())
         self.Map.RenderOverlays(force=True)
 
-        # delete textures
-        for texture in self.imagelist:
-            # inactive overlays, remove text labels
-            if texture.GetId() < 100:
-                if not self.overlays[texture.GetId()].IsShown():
-                    texture.SetActive(False)
-                else:
-                    texture.SetActive(True)
-            else:  # text label
-                if texture.GetId() not in self.textdict:
-                    self.imagelist.remove(texture)
-
-        # update images (only legend so far)
+    def _onUpdateOverlays(self):
+        """Converts rendered overlay files and text labels to wx.Image
+            and then to textures so that they can be rendered by OpenGL.
+            Updates self.imagelist"""
+        # update images (legend and text)
         for oid, overlay in self.overlays.iteritems():
-            if not overlay.IsShown() or oid in (1, 2):  # 0 for barscale
+            if not overlay.IsShown() or overlay.name in ('barscale', 'northarrow'):
                 continue
             if oid not in [t.GetId() for t in self.imagelist]:  # new
-                self.CreateTexture(overlay=overlay.layer)
+                self.CreateTexture(overlay=overlay)
             else:
                 for t in self.imagelist:
                     if t.GetId() == oid:  # check if it is the same
                         if not t.Corresponds(overlay):
                             self.imagelist.remove(t)
-                            t = self.CreateTexture(overlay=overlay.layer)
+                            t = self.CreateTexture(overlay=overlay)
 
-        # update text labels
-        for textId in self.textdict.keys():
-            if textId not in [t.GetId() for t in self.imagelist]:  # new
-                self.CreateTexture(textId=textId)
-            else:
-                for t in self.imagelist:
-                    if t.GetId() == textId:  # check if it is the same
-                        self.textdict[textId]['bbox'] = t.textDict['bbox']
-                        if not t.Corresponds(self.textdict[textId]):
-                            self.imagelist.remove(t)
-                            t = self.CreateTexture(textId=textId)
-                        # always set coordinates, needed for synchr. 2D and 3D
-                        # modes
-                        t.SetCoords(self.textdict[textId]['coords'])
         self.Refresh()
 
-    def CreateTexture(self, overlay=None, textId=None):
-        """Create texture from overlay image or from textdict"""
-        if overlay:  # legend
-            texture = wxnviz.ImageTexture(
-                filepath=overlay.mapfile,
-                overlayId=overlay.id,
-                coords=list(
-                    self.overlays[
-                        overlay.id].coords),
-                cmd=overlay.GetCmd())
-            if overlay.id == 0:  # legend
-                texture.SetBounds(self.GetLegendRect())
-        else:  # text
-            coords, bbox, relCoords = self.TextBounds(self.textdict[textId])
-            self.textdict[textId]['coords'] = coords
-            self.textdict[textId]['bbox'] = bbox
-            file = self.DrawTextImage(self.textdict[textId], relCoords)
-            texture = wxnviz.TextTexture(
-                filepath=file, overlayId=textId, coords=coords,
-                textDict=self.textdict[textId])
-            bbox.OffsetXY(*relCoords)
-            texture.SetBounds(bbox)
+    def CreateTexture(self, overlay):
+        """Create texture from overlay image"""
+        texture = wxnviz.ImageTexture(
+                filepath=overlay.layer.mapfile, overlayId=overlay.id,
+                coords=list(overlay.coords), cmd=overlay.GetCmd())
 
         if not texture.textureId:  # texture too big
             GMessage(
@@ -605,6 +515,9 @@
 
         return texture
 
+    def ClearTextures(self):
+        self.imagelist = []
+
     def FindObjects(self, mouseX, mouseY, radius):
         """Find object which was clicked on"""
         for texture in self.imagelist:
@@ -783,11 +696,12 @@
             self.SetDrawScalebar((pos[0], size[1] - pos[1]))
 
         if self.mouse['use'] == 'pointer':
-            # get decoration or text id
+            # get decoration id
             self.dragid = self.FindObjects(
                 self.mouse['tmp'][0],
                 self.mouse['tmp'][1],
                 self.hitradius)
+
         if self.mouse['use'] == 'fly':
             if not self.timerFly.IsRunning():
                 self.timerFly.Start(self.fly['interval'])
@@ -895,17 +809,11 @@
             if self.dragid >= 0:
                 dx = self.mouse['end'][0] - self.mouse['begin'][0]
                 dy = self.mouse['end'][1] - self.mouse['begin'][1]
-                if self.dragid < 99:
+                if self.dragid in self.overlays:
                     coords = self.overlays[self.dragid].coords
                     self.overlays[
                         self.dragid].coords = [
                         coords[0] + dx, coords[1] + dy]
-                else:  # text
-                    coords = self.textdict[self.dragid]['coords']
-                    self.textdict[
-                        self.dragid]['coords'] = [
-                        coords[0] + dx,
-                        coords[1] + dy]
                 self.dragid = -1
                 self.render['quick'] = False
                 self.Refresh(False)
@@ -2764,13 +2672,6 @@
         """
         self.lmgr.nviz.OnResetView(None)
 
-    def TextBounds(self, textinfo):
-        """Return text boundary data
-
-        :param textinfo: text metadata (text, font, color, rotation)
-        """
-        return self.parent.MapWindow2D.TextBounds(textinfo, relcoords=True)
-
     def DisactivateWin(self):
         """Use when the class instance is hidden in MapFrame."""
         pass

Modified: grass/trunk/gui/wxpython/nviz/wxnviz.py
===================================================================
--- grass/trunk/gui/wxpython/nviz/wxnviz.py	2016-07-09 22:28:28 UTC (rev 68922)
+++ grass/trunk/gui/wxpython/nviz/wxnviz.py	2016-07-09 23:28:30 UTC (rev 68923)
@@ -49,7 +49,7 @@
 from grass.lib.raster import *
 
 from core.debug import Debug
-from core.utils import _
+from core.utils import _, autoCropImageFromFile
 import grass.script as grass
 
 log = None
@@ -2041,12 +2041,11 @@
         :param coords: image coordinates
         """
         self.path = filepath
-        self.image = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
-        self.width = self.image.GetWidth()
-        self.height = self.image.GetHeight()
+        self.image = autoCropImageFromFile(filepath)
+        self.width = self.orig_width = self.image.GetWidth()
+        self.height = self.orig_height = self.image.GetHeight()
         self.id = overlayId
-        self.coords = [0, 0]
-        self.bounds = wx.Rect()
+        self.coords = coords
         self.active = True
 
         # alpha needs to be initialized
@@ -2131,12 +2130,8 @@
             self.height,
             self.textureId)
 
-    def SetBounds(self, rect):
-        """Set Bounding Rectangle"""
-        self.bounds = rect
-
     def HitTest(self, x, y, radius):
-        copy = wx.Rect(*self.bounds)
+        copy = wx.Rect(self.coords[0], self.coords[1], self.orig_width, self.orig_height)
         copy.Inflate(radius, radius)
         return copy.ContainsXY(x, y)
 
@@ -2144,7 +2139,6 @@
         """Move texture on the screen"""
         self.coords[0] += dx
         self.coords[1] += dy
-        self.bounds.OffsetXY(dx, dy)
 
     def SetCoords(self, coords):
         """Set coordinates"""
@@ -2188,37 +2182,3 @@
 
     def Corresponds(self, item):
         return sorted(self.GetCmd()) == sorted(item.GetCmd())
-
-
-class TextTexture(Texture):
-    """Class representing OpenGL texture as a text label"""
-
-    def __init__(self, filepath, overlayId, coords, textDict):
-        """Load image to texture
-
-        :param filepath: path to image file
-        :param overlayId: id of overlay (101 and more for text)
-        :param coords: text coordinates
-        :param textDict: text properties
-        """
-        Texture.__init__(
-            self,
-            filepath=filepath,
-            overlayId=overlayId,
-            coords=coords)
-
-        self.textDict = textDict
-
-    def GetTextDict(self):
-        """Returns text properties."""
-        return self.textDict
-
-    def Corresponds(self, item):
-        t = self.GetTextDict()
-        for prop in t.keys():
-            if prop in ('coords', 'bbox'):
-                continue
-            if t[prop] != item[prop]:
-                return False
-
-        return True



More information about the grass-commit mailing list