diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index 4de1fbb4fb3..56790203102 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -371,8 +371,6 @@ def __init__(self, guiparent=None, giface=None, ignoredCmdPattern=None): # 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 @@ def OnCmdDone(self, event): 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() diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index f24214f2a4c..df1650e61cc 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -570,7 +570,6 @@ def __init__( 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( diff --git a/gui/wxpython/gui_core/mapdisp.py b/gui/wxpython/gui_core/mapdisp.py index 0df29fc6335..f91e42deabd 100644 --- a/gui/wxpython/gui_core/mapdisp.py +++ b/gui/wxpython/gui_core/mapdisp.py @@ -321,8 +321,8 @@ def CreateStatusbar(self, statusbarItems): # 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 @@ def CreateStatusbar(self, statusbarItems): 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 diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 7d768210248..17d99daf8d5 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -62,6 +62,7 @@ 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 @@ def show_menu_errors(messages): # 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 @@ def show_menu_errors(messages): ) 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 @@ def IsPaneShown(self, name): 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": diff --git a/gui/wxpython/lmgr/statusbar.py b/gui/wxpython/lmgr/statusbar.py new file mode 100644 index 00000000000..f47eb71ddfb --- /dev/null +++ b/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 +@author Anna Petrasova +@author Vaclav Petras +""" + +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", + ) diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index dadcfb246ee..addd8270b6e 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -67,6 +67,7 @@ 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 @@ def __init__( 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 @@ def __init__( 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 @@ def show_menu_errors(messages): 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 @@ def IsPaneShown(self, name): 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 @@ -523,6 +527,7 @@ def BuildPanes(self): """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) @@ -574,6 +579,21 @@ def BuildPanes(self): aui.AuiPaneInfo().Name("map display content").CenterPane().PaneBorder(True), ) + 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() diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index 1122c4458dd..6e565ff65f1 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -14,7 +14,6 @@ - statusbar::SbMapScale - statusbar::SbGoTo - statusbar::SbProjection - - statusbar::SbMask - statusbar::SbTextItem - statusbar::SbDisplayGeometry - statusbar::SbCoordinates @@ -37,9 +36,7 @@ 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 @@ def Reposition(self): 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 @@ def Update(self): 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.