Browse Source

wxGUI: Move SbMask widget to main window/layer manager statusbar (#2089)

Co-authored-by: Anna Petrasova <kratochanna@gmail.com>
Linda Kladivova 3 years ago
parent
commit
251bce4254

+ 13 - 3
gui/wxpython/core/gconsole.py

@@ -371,8 +371,6 @@ class GConsole(wx.EvtHandler):
         # Signal when some map is created or updated by a module.
         # attributes: name: map name, ltype: map type,
         self.mapCreated = Signal("GConsole.mapCreated")
-        # emitted when map display should be re-render
-        self.updateMap = Signal("GConsole.updateMap")
         # emitted when log message should be written
         self.writeLog = Signal("GConsole.writeLog")
         # emitted when command log message should be written
@@ -788,7 +786,19 @@ class GConsole(wx.EvtHandler):
                                 element=prompt,
                             )
         if name == "r.mask":
-            self.updateMap.emit()
+            action = "new"
+            for p in task.get_options()["flags"]:
+                if p.get("name") == "r" and p.get("value"):
+                    action = "delete"
+            gisenv = grass.gisenv()
+            self._giface.grassdbChanged.emit(
+                grassdb=gisenv["GISDBASE"],
+                location=gisenv["LOCATION_NAME"],
+                mapset=gisenv["MAPSET"],
+                action=action,
+                map="MASK",
+                element="raster",
+            )
 
         event.Skip()
 

+ 0 - 1
gui/wxpython/gui_core/forms.py

@@ -570,7 +570,6 @@ class TaskFrame(wx.Frame):
         self._gconsole = self.notebookpanel._gconsole
         if self._gconsole:
             self._gconsole.mapCreated.connect(self.OnMapCreated)
-            self._gconsole.updateMap.connect(lambda: self._giface.updateMap.emit())
         self.goutput = self.notebookpanel.goutput
         if self.goutput:
             self.goutput.showNotification.connect(

+ 3 - 6
gui/wxpython/gui_core/mapdisp.py

@@ -321,8 +321,8 @@ class MapPanelBase(wx.Panel):
         # create statusbar and its manager
         statusbar = wx.StatusBar(self, id=wx.ID_ANY)
         statusbar.SetMinHeight(24)
-        statusbar.SetFieldsCount(4)
-        statusbar.SetStatusWidths([-5, -2, -1, -1])
+        statusbar.SetFieldsCount(3)
+        statusbar.SetStatusWidths([-6, -2, -1])
         self.statusbarManager = sb.SbManager(mapframe=self, statusbar=statusbar)
 
         # fill statusbar manager
@@ -330,10 +330,7 @@ class MapPanelBase(wx.Panel):
             statusbarItems, mapframe=self, statusbar=statusbar
         )
         self.statusbarManager.AddStatusbarItem(
-            sb.SbMask(self, statusbar=statusbar, position=2)
-        )
-        self.statusbarManager.AddStatusbarItem(
-            sb.SbRender(self, statusbar=statusbar, position=3)
+            sb.SbRender(self, statusbar=statusbar, position=2)
         )
         self.statusbarManager.Update()
         return statusbar

+ 23 - 1
gui/wxpython/lmgr/frame.py

@@ -62,6 +62,7 @@ from gui_core.menu import Menu as GMenu
 from core.debug import Debug
 from lmgr.toolbars import LMWorkspaceToolbar, LMToolsToolbar
 from lmgr.toolbars import LMMiscToolbar, LMNvizToolbar, DisplayPanelToolbar
+from lmgr.statusbar import SbMain
 from lmgr.workspace import WorkspaceManager
 from lmgr.pyshell import PyShellWindow
 from lmgr.giface import (
@@ -152,7 +153,7 @@ class GMFrame(wx.Frame):
 
         # create widgets
         self._createMenuBar()
-        self.statusbar = self.CreateStatusBar(number=1)
+        self.statusbar = SbMain(parent=self, giface=self._giface)
         self.notebook = self._createNotebook()
         self._createDataCatalog(self.notebook)
         self._createDisplay(self.notebook)
@@ -199,6 +200,23 @@ class GMFrame(wx.Frame):
             )
 
         self._auimgr.GetPane("toolbarNviz").Hide()
+
+        # Add statusbar
+        self._auimgr.AddPane(
+            self.statusbar.GetWidget(),
+            wx.aui.AuiPaneInfo()
+            .Bottom()
+            .MinSize(30, 30)
+            .Fixed()
+            .Name("statusbar")
+            .CloseButton(False)
+            .DestroyOnClose(True)
+            .ToolbarPane()
+            .Dockable(False)
+            .PaneBorder(False)
+            .Gripper(False),
+        )
+
         # bindings
         self.Bind(wx.EVT_CLOSE, self.OnCloseWindowOrExit)
         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
@@ -329,6 +347,10 @@ class GMFrame(wx.Frame):
             return self._auimgr.GetPane(name).IsShown()
         return False
 
+    def SetStatusText(self, *args):
+        """Overide SbMain statusbar method"""
+        self.statusbar.SetStatusText(*args)
+
     def _createNotebook(self):
         """Initialize notebook widget"""
         if sys.platform == "win32":

+ 146 - 0
gui/wxpython/lmgr/statusbar.py

@@ -0,0 +1,146 @@
+"""
+@package frame.statusbar
+
+@brief Classes for main window statusbar management
+
+Classes:
+ - statusbar::SbMain
+ - statusbar::SbMask
+
+(C) 2022 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 Linda Kladivova <lindakladivova gmail.com>
+@author Anna Petrasova <kratochanna gmail.com>
+@author Vaclav Petras <wenzeslaus gmail.com>
+"""
+
+import wx
+
+import grass.script as gs
+
+from core.gcmd import RunCommand
+from gui_core.wrap import Button
+
+
+class SbMain:
+    """Statusbar for main window."""
+
+    def __init__(self, parent, giface):
+        self.parent = parent
+        self.giface = giface
+        self.widget = wx.StatusBar(self.parent, id=wx.ID_ANY)
+        self.widget.SetMinHeight(24)
+        self.widget.SetFieldsCount(2)
+        self.widget.SetStatusWidths([-1, 100])
+        self.mask = SbMask(self.widget, self.giface)
+        self.widget.Bind(wx.EVT_SIZE, self.OnSize)
+        self._repositionStatusbar()
+
+    def GetWidget(self):
+        """Returns underlying widget.
+
+        :return: widget or None if doesn't exist
+        """
+        return self.widget
+
+    def _repositionStatusbar(self):
+        """Reposition widgets in main window statusbar"""
+        rect1 = self.GetWidget().GetFieldRect(1)
+        rect1.x += 1
+        rect1.y += 1
+        self.mask.GetWidget().SetRect(rect1)
+
+    def Refresh(self):
+        """Refresh statusbar. So far it refreshes just a mask."""
+        self.mask.Refresh()
+
+    def OnSize(self, event):
+        """Adjust main window statusbar on changing size"""
+        self._repositionStatusbar()
+
+    def SetStatusText(self, *args):
+        """Overide wx.StatusBar method"""
+        self.GetWidget().SetStatusText(*args)
+
+
+class SbMask:
+    """Button to show whether mask is activated and remove mask with
+    left mouse click
+    """
+
+    def __init__(self, parent, giface):
+        self.name = "mask"
+        self.mask_layer = "MASK"
+        self.parent = parent
+        self.giface = giface
+        self.widget = Button(
+            parent=parent, id=wx.ID_ANY, label=_(self.mask_layer), style=wx.NO_BORDER
+        )
+        self.widget.Bind(wx.EVT_BUTTON, self.OnRemoveMask)
+        self.widget.SetForegroundColour(wx.Colour(255, 0, 0))
+        self.widget.SetToolTip(tip=_("Left mouse click to remove the MASK"))
+        self.giface.currentMapsetChanged.connect(self.Refresh)
+        self.giface.grassdbChanged.connect(self._dbChanged)
+        self.Refresh()
+
+    def _dbChanged(self, map=None, newname=None):
+        if map == self.mask_layer or newname == self.mask_layer:
+            self.Refresh()
+            self.giface.updateMap.emit()
+
+    def Show(self):
+        """Invokes showing of underlying widget.
+
+        In derived classes it can do what is appropriate for it,
+        e.g. showing text on statusbar (only).
+        """
+        self.widget.Show()
+
+    def Hide(self):
+        self.widget.Hide()
+
+    def SetValue(self, value):
+        self.widget.SetValue(value)
+
+    def GetValue(self):
+        return self.widget.GetValue()
+
+    def GetWidget(self):
+        """Returns underlying widget.
+
+        :return: widget or None if doesn't exist
+        """
+        return self.widget
+
+    def Refresh(self):
+        """Show mask in the statusbar if mask file found"""
+        if gs.find_file(
+            name=self.mask_layer, element="cell", mapset=gs.gisenv()["MAPSET"]
+        )["name"]:
+            self.Show()
+        else:
+            self.Hide()
+
+    def OnRemoveMask(self, event):
+        dlg = wx.MessageDialog(
+            self.parent,
+            message=_("Are you sure that you want to remove the MASK?"),
+            caption=_("Remove MASK"),
+            style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION,
+        )
+        if dlg.ShowModal() != wx.ID_YES:
+            dlg.Destroy()
+            return
+        RunCommand("r.mask", flags="r")
+        gisenv = gs.gisenv()
+        self.giface.grassdbChanged.emit(
+            grassdb=gisenv["GISDBASE"],
+            location=gisenv["LOCATION_NAME"],
+            mapset=gisenv["MAPSET"],
+            map=self.mask_layer,
+            action="delete",
+            element="raster",
+        )

+ 25 - 5
gui/wxpython/main_window/frame.py

@@ -67,6 +67,7 @@ from gui_core.menu import Menu as GMenu
 from core.debug import Debug
 from lmgr.toolbars import LMWorkspaceToolbar, LMToolsToolbar
 from lmgr.toolbars import LMMiscToolbar, LMNvizToolbar, DisplayPanelToolbar
+from lmgr.statusbar import SbMain
 from lmgr.workspace import WorkspaceManager
 from lmgr.pyshell import PyShellWindow
 from lmgr.giface import (
@@ -96,7 +97,7 @@ class GMFrame(wx.Frame):
         id=wx.ID_ANY,
         title=None,
         workspace=None,
-        size=globalvar.GM_WINDOW_SIZE,
+        size=wx.Display().GetGeometry().GetSize(),
         style=wx.DEFAULT_FRAME_STYLE,
         **kwargs,
     ):
@@ -107,6 +108,7 @@ class GMFrame(wx.Frame):
             self.baseTitle = _("GRASS GIS")
 
         self.iconsize = (16, 16)
+        self.size = size
 
         self.displayIndex = 0  # index value for map displays and layer trees
         self.currentPage = None  # currently selected page for layer tree notebook
@@ -154,13 +156,11 @@ class GMFrame(wx.Frame):
         self.dialogs["atm"] = list()
 
         # set pane sizes according to the full screen size of the primary monitor
-        size = wx.Display().GetGeometry().GetSize()
-        self.PANE_BEST_SIZE = tuple(t // 3 for t in size)
-        self.PANE_MIN_SIZE = tuple(t // 5 for t in size)
+        self.PANE_BEST_SIZE = tuple(t // 3 for t in self.size)
+        self.PANE_MIN_SIZE = tuple(t // 5 for t in self.size)
 
         # create widgets and build panes
         self.CreateMenuBar()
-        self.CreateStatusBar(number=1)
         self.BuildPanes()
         self.BindEvents()
 
@@ -270,6 +270,10 @@ class GMFrame(wx.Frame):
             return self._auimgr.GetPane(name).IsShown()
         return False
 
+    def SetStatusText(self, *args):
+        """Overide SbMain statusbar method"""
+        self.statusbar.SetStatusText(*args)
+
     def _createMapNotebook(self):
         """Create Map Display notebook"""
         # create the notebook off-window to avoid flicker
@@ -526,6 +530,7 @@ class GMFrame(wx.Frame):
         """Build panes - toolbars as well as panels"""
         self._auimgr.SetAutoNotebookTabArt(SimpleTabArt())
         # initialize all main widgets
+        self.statusbar = SbMain(parent=self, giface=self._giface)
         self._createMapNotebook()
         self._createDataCatalog(parent=self)
         self._createDisplay(parent=self)
@@ -578,6 +583,21 @@ class GMFrame(wx.Frame):
         )
 
         self._auimgr.AddPane(
+            self.statusbar.GetWidget(),
+            aui.AuiPaneInfo()
+            .Bottom()
+            .MinSize(30, 30)
+            .Fixed()
+            .Name("statusbar")
+            .CloseButton(False)
+            .DestroyOnClose(True)
+            .ToolbarPane()
+            .Dockable(False)
+            .PaneBorder(False)
+            .Gripper(False),
+        )
+
+        self._auimgr.AddPane(
             self.datacatalog,
             aui.AuiPaneInfo()
             .Name("datacatalog")

+ 2 - 51
gui/wxpython/mapdisp/statusbar.py

@@ -14,7 +14,6 @@ Classes:
  - statusbar::SbMapScale
  - statusbar::SbGoTo
  - statusbar::SbProjection
- - statusbar::SbMask
  - statusbar::SbTextItem
  - statusbar::SbDisplayGeometry
  - statusbar::SbCoordinates
@@ -37,9 +36,7 @@ import wx
 from core import utils
 from core.gcmd import RunCommand
 from core.settings import UserSettings
-from gui_core.wrap import Button, TextCtrl
-
-from grass.script import core as grass
+from gui_core.wrap import TextCtrl
 
 from grass.pydispatch.signal import Signal
 
@@ -281,9 +278,7 @@ class SbManager:
                 w, h = rect.width, rect.height + 1
                 if win == self.progressbar.GetWidget():
                     wWin = rect.width - 6
-                if idx == 2:  # mask
-                    x += 5
-                elif idx == 3:  # render
+                if idx == 2:  # render
                     x += 5
             win.SetPosition((x, y))
             win.SetSize((w, h))
@@ -892,50 +887,6 @@ class SbProjection(SbItem):
         self.mapFrame.StatusbarEnableLongHelp(False)
 
 
-class SbMask(SbItem):
-    """Button to show whether mask is activated and remove mask with
-    left mouse click
-    """
-
-    def __init__(self, mapframe, statusbar, position=0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = "mask"
-
-        self.widget = Button(
-            parent=self.statusbar, id=wx.ID_ANY, label=_("MASK"), style=wx.NO_BORDER
-        )
-        self.widget.Bind(wx.EVT_BUTTON, self.OnRemoveMask)
-        self.widget.SetForegroundColour(wx.Colour(255, 0, 0))
-        self.widget.SetToolTip(tip=_("Left mouse click to remove the MASK"))
-        self.widget.Hide()
-
-    def Update(self):
-        if grass.find_file(
-            name="MASK", element="cell", mapset=grass.gisenv()["MAPSET"]
-        )["name"]:
-            self.Show()
-        else:
-            self.Hide()
-
-    def OnRemoveMask(self, event):
-        if grass.find_file(
-            name="MASK", element="cell", mapset=grass.gisenv()["MAPSET"]
-        )["name"]:
-
-            dlg = wx.MessageDialog(
-                self.mapFrame,
-                message=_("Are you sure that you want to remove the MASK?"),
-                caption=_("Remove MASK"),
-                style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION,
-            )
-            if dlg.ShowModal() != wx.ID_YES:
-                dlg.Destroy()
-                return
-            RunCommand("r.mask", flags="r")
-            self.Hide()
-            self.mapFrame.OnRender(event=None)
-
-
 class SbTextItem(SbItem):
     """Base class for items without widgets.