瀏覽代碼

wxGUI: refactoring: Map Display inheriting from wx.Panel (#1675)

Map Display GUI logic is being changed. For purposes of the Single-Window GUI, MapFrameBase was replaced by MapPanelBase. It subsequently influeced all GUI tools which had been build based on MapFrameBase.
All these tools had to be adapted for new wx.Panel based solution.
Linda Kladivova 3 年之前
父節點
當前提交
2f94d78a66

+ 7 - 3
doc/gui/wxpython/example/README

@@ -55,10 +55,14 @@ a few more things to be done.
 
     def OnExample(self, event):
         """!Launch ExampleTool"""
-        from example.frame import ExampleMapFrame
-        win = ExampleMapFrame(parent=self, giface=self._giface)
+        from example.frame import ExampleMapDisplay
+
+        frame = wx.Frame(
+        parent=None, size=globalvar.MAP_WINDOW_SIZE, title=_("Example Tool")
+        )
+        win = ExampleMapDisplay(parent=frame, giface=self._giface)
         win.CentreOnScreen()
-        
+
         win.Show()
 
 7. Run make again.

+ 62 - 49
doc/gui/wxpython/example/frame.py

@@ -4,7 +4,8 @@
 @brief Example tool for displaying raster map and related information
 
 Classes:
- - frame::ExampleMapFrame
+ - frame::ExampleMapPanel
+ - frame::ExampleMapDisplay
  - frame::ExampleInfoTextManager
 
 (C) 2011-2014 by the GRASS Development Team
@@ -27,16 +28,17 @@ if __name__ == "__main__":
 # So we need to import it before any of the GUI code.
 from grass.script import core as gcore
 
-from gui_core.mapdisp import SingleMapFrame
+from gui_core.mapdisp import SingleMapPanel, FrameMixin
 from mapwin.buffered import BufferedMapWindow
 from mapwin.base import MapWindowProperties
 from mapdisp import statusbar as sb
 from core.render import Map
 from core.debug import Debug
 from core.gcmd import RunCommand, GError
+from core import globalvar
 
-from toolbars import ExampleMapToolbar, ExampleMiscToolbar, ExampleMainToolbar
-from dialogs import ExampleMapDialog
+from example.toolbars import ExampleMapToolbar, ExampleMiscToolbar, ExampleMainToolbar
+from example.dialogs import ExampleMapDialog
 
 # It is possible to call grass library functions (in C) directly via ctypes
 # however this is less stable. Example is available in trunk/doc/python/, ctypes
@@ -52,13 +54,13 @@ from dialogs import ExampleMapDialog
 #     errMsg = _("Loading raster lib failed.\n%s") % e
 
 
-class ExampleMapFrame(SingleMapFrame):
-    """! Main frame of example tool.
+class ExampleMapPanel(SingleMapPanel):
+    """! Main panel of example tool.
 
-    Inherits from SingleMapFrame, so map is displayed in one map widow.
-    In case two map windows are needed, use DoubleMapFrame from (gui_core.mapdisp).
+    Inherits from SingleMapPanel, so map is displayed in one map widow.
+    In case two map windows are needed, use DoubleMapPanel from (gui_core.mapdisp).
 
-    @see IClassMapFrame in iclass.frame
+    @see IClassMapPanel in iclass.frame
     """
 
     def __init__(
@@ -71,14 +73,13 @@ class ExampleMapFrame(SingleMapFrame):
         name="exampleWindow",
         **kwargs,
     ):
-        """!Map Frame constructor
+        """!Map Panel constructor
 
         @param parent (no parent is expected)
         @param title window title
         @param toolbars list of active toolbars (default value represents all toolbars)
-        @param size default size
         """
-        SingleMapFrame.__init__(
+        SingleMapPanel.__init__(
             self, parent=parent, title=title, name=name, Map=Map(), **kwargs
         )
 
@@ -86,7 +87,7 @@ class ExampleMapFrame(SingleMapFrame):
         # and set debug level from 1 to 5 (higher to lower level functions).
         # To enable debug mode write:
         # > g.gisenv set=WX_DEBUG=5
-        Debug.msg(1, "ExampleMapFrame.__init__()")
+        Debug.msg(1, "ExampleMapPanel.__init__()")
 
         #
         # Add toolbars to aui manager
@@ -109,7 +110,7 @@ class ExampleMapFrame(SingleMapFrame):
         #
 
         # choose items in statusbar choice, which makes sense for your application
-        self.statusbarItems = [
+        statusbarItems = [
             sb.SbCoordinates,
             sb.SbRegionExtent,
             sb.SbCompRegionExtent,
@@ -121,24 +122,7 @@ class ExampleMapFrame(SingleMapFrame):
             sb.SbGoTo,
             sb.SbProjection,
         ]
-
-        # create statusbar and its manager
-        statusbar = self.CreateStatusBar(number=4, style=0)
-        statusbar.SetStatusWidths([-5, -2, -1, -1])
-        self.statusbarManager = sb.SbManager(mapframe=self, statusbar=statusbar)
-
-        # fill statusbar manager
-        self.statusbarManager.AddStatusbarItemsByClass(
-            self.statusbarItems, mapframe=self, statusbar=statusbar
-        )
-        self.statusbarManager.AddStatusbarItem(
-            sb.SbMask(self, statusbar=statusbar, position=2)
-        )
-        self.statusbarManager.AddStatusbarItem(
-            sb.SbRender(self, statusbar=statusbar, position=3)
-        )
-
-        self.statusbarManager.Update()
+        self.statusbar = self.CreateStatusbar(statusbarItems)
 
         # create map window
         self.MapWindow = BufferedMapWindow(
@@ -164,7 +148,6 @@ class ExampleMapFrame(SingleMapFrame):
         self.GetMapToolbar().SelectDefault()
 
         self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
         self.SetSize(size)
 
@@ -173,20 +156,10 @@ class ExampleMapFrame(SingleMapFrame):
         gcore.del_temp_region()
 
     def OnCloseWindow(self, event):
-        """!Destroy frame"""
+        """!Destroy panel"""
+        self._mgr.UnInit()
         self.Destroy()
 
-    def IsStandalone(self):
-        """!Check if application is standalone.
-
-        Standalone application can work without parent.
-        Parent can be e.g. Layer Manager.
-        """
-        if self.parent:
-            return False
-
-        return True
-
     def InitVariables(self):
         """!Initialize any variables nneded by application"""
         self.currentRaster = None
@@ -224,6 +197,9 @@ class ExampleMapFrame(SingleMapFrame):
             .Left(),
         )
 
+        # statusbar
+        self.AddStatusbarPane()
+
     def AddToolbar(self, name):
         """!Add defined toolbar to the window
 
@@ -234,7 +210,8 @@ class ExampleMapFrame(SingleMapFrame):
         """
         # see wx.aui.AuiPaneInfo documentation for understanding all options
         if name == "MapToolbar":
-            self.toolbars[name] = ExampleMapToolbar(self, self._toolSwitcher)
+            if "MapToolbar" not in self.toolbars:
+                self.toolbars[name] = ExampleMapToolbar(self, self._toolSwitcher)
 
             self._mgr.AddPane(
                 self.toolbars[name],
@@ -254,7 +231,8 @@ class ExampleMapFrame(SingleMapFrame):
             )
 
         if name == "MiscToolbar":
-            self.toolbars[name] = ExampleMiscToolbar(self)
+            if "MiscToolbar" not in self.toolbars:
+                self.toolbars[name] = ExampleMiscToolbar(self)
 
             self._mgr.AddPane(
                 self.toolbars[name],
@@ -274,7 +252,8 @@ class ExampleMapFrame(SingleMapFrame):
             )
 
         if name == "MainToolbar":
-            self.toolbars[name] = ExampleMainToolbar(self)
+            if "MainToolbar" not in self.toolbars:
+                self.toolbars[name] = ExampleMainToolbar(self)
 
             self._mgr.AddPane(
                 self.toolbars[name],
@@ -325,7 +304,7 @@ class ExampleMapFrame(SingleMapFrame):
 
         @param name layer (raster) name
         """
-        Debug.msg(3, "ExampleMapFrame.SetLayer(): name=%s" % name)
+        Debug.msg(3, "ExampleMapPanel.SetLayer(): name=%s" % name)
 
         # this simple application enables to keep only one raster
         self.GetMap().DeleteAllLayers()
@@ -378,6 +357,40 @@ class ExampleMapFrame(SingleMapFrame):
         self.info.WriteStatistics(name=self.currentRaster, statDict=stats)
 
 
+class ExampleMapDisplay(FrameMixin, ExampleMapPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, **kwargs):
+
+        # init map panel
+        ExampleMapPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bindings
+        parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class ExampleInfoTextManager:
     """!Class for displaying information.
 

+ 24 - 12
doc/gui/wxpython/example/g.gui.example.py

@@ -19,7 +19,7 @@
 ############################################################################
 
 # %module
-# % description: Example GUI application which displays raster map and further information
+# % description: Example GUI app which displays raster map and further information
 # % keyword: example
 # % keyword: GUI
 # % keyword: raster
@@ -31,7 +31,6 @@
 
 import os
 import sys
-import wx
 
 
 # i18n is taken care of in the grass library code.
@@ -43,15 +42,21 @@ if __name__ == "__main__":
     if wxbase not in sys.path:
         sys.path.append(wxbase)
 
-from core.globalvar import CheckWxVersion
-from core.giface import StandaloneGrassInterface
-from core.utils import GuiModuleMain
-from core.settings import UserSettings
-from example.frame import ExampleMapFrame
-
 
 def main():
     options, flags = gcore.parser()
+
+    import wx
+
+    from grass.script.setup import set_gui_path
+
+    set_gui_path()
+
+    from core.globalvar import CheckWxVersion, MAP_WINDOW_SIZE
+    from core.giface import StandaloneGrassInterface
+    from core.settings import UserSettings
+    from example.frame import ExampleMapDisplay
+
     if options["input"]:
         map_name = gcore.find_file(name=options["input"], element="cell")["fullname"]
         if not map_name:
@@ -72,10 +77,17 @@ def main():
         wx.InitAllImageHandlers()
 
     # show main frame
-    giface = StandaloneGrassInterface()
-    frame = ExampleMapFrame(parent=None, giface=giface)
+    frame = wx.Frame(
+        parent=None, size=MAP_WINDOW_SIZE, title=_("Example Tool - GRASSGIS")
+    )
+    frame = ExampleMapDisplay(
+        parent=frame,
+        giface=StandaloneGrassInterface(),
+    )
     if options["input"]:
-        giface.WriteLog(_("Loading raster map <{raster}>...").format(raster=map_name))
+        frame.giface.WriteLog(
+            _("Loading raster map <{raster}>...").format(raster=map_name)
+        )
         frame.SetLayer(map_name)
 
     frame.Show()
@@ -83,4 +95,4 @@ def main():
 
 
 if __name__ == "__main__":
-    GuiModuleMain(main)
+    main()

+ 64 - 15
gui/wxpython/gcp/manager.py

@@ -9,7 +9,8 @@ Classes:
  - manager::LocationPage
  - manager::GroupPage
  - manager::DispMapPage
- - manager::GCP
+ - manager::GCPPanel
+ - manager::GCPDisplay
  - manager::GCPList
  - manager::VectGroup
  - manager::EditGCP
@@ -52,9 +53,10 @@ from core import utils
 from core.render import Map
 from gui_core.gselect import Select, LocationSelect, MapsetSelect
 from gui_core.dialogs import GroupDialog
+from gui_core.mapdisp import FrameMixin
 from core.gcmd import RunCommand, GMessage, GError, GWarning
 from core.settings import UserSettings
-from gcp.mapdisplay import MapFrame
+from gcp.mapdisplay import MapPanel
 from core.giface import Notification
 from gui_core.wrap import (
     SpinCtrl,
@@ -289,22 +291,32 @@ class GCPWizard(object):
             #
             # start GCP Manager
             #
-            self.gcpmgr = GCP(
-                self.parent,
+            # create superior Map Display frame
+            mapframe = wx.Frame(
+                parent=None,
+                id=wx.ID_ANY,
+                size=globalvar.MAP_WINDOW_SIZE,
+                style=wx.DEFAULT_FRAME_STYLE,
+                title=name,
+            )
+
+            # create GCP manager
+            gcpmgr = GCPDisplay(
+                parent=mapframe,
                 giface=self._giface,
                 grwiz=self,
-                size=globalvar.MAP_WINDOW_SIZE,
-                toolbars=["gcpdisp"],
+                id=wx.ID_ANY,
                 Map=self.SrcMap,
                 lmgr=self.parent,
+                title=name,
             )
 
             # load GCPs
-            self.gcpmgr.InitMapDisplay()
-            self.gcpmgr.CenterOnScreen()
-            self.gcpmgr.Show()
+            gcpmgr.InitMapDisplay()
+            gcpmgr.CenterOnScreen()
+            gcpmgr.Show()
             # need to update AUI here for wingrass
-            self.gcpmgr._mgr.Update()
+            gcpmgr._mgr.Update()
         else:
             self.Cleanup()
 
@@ -1025,7 +1037,7 @@ class DispMapPage(TitledPage):
         return {self.web_servc_lyrs_root_node_name: self.GetWebServiceLayers().keys()}
 
 
-class GCP(MapFrame, ColumnSorterMixin):
+class GCPPanel(MapPanel, ColumnSorterMixin):
     """
     Manages ground control points for georectifying. Calculates RMS statistics.
     Calls i.rectify or v.rectify to georectify map.
@@ -1053,7 +1065,7 @@ class GCP(MapFrame, ColumnSorterMixin):
             self.show_target = True
 
         # wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
-        MapFrame.__init__(
+        MapPanel.__init__(
             self,
             parent=parent,
             giface=self._giface,
@@ -1236,7 +1248,6 @@ class GCP(MapFrame, ColumnSorterMixin):
         self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_IDLE, self.OnIdle)
-        self.Bind(wx.EVT_CLOSE, self.OnQuit)
 
         self.SetSettings()
 
@@ -1687,7 +1698,7 @@ class GCP(MapFrame, ColumnSorterMixin):
             targetMapWin.UpdateMap(render=False, renderVector=False)
 
     def OnFocus(self, event):
-        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
+        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapPanel?
         # self.grwiz.SwitchEnv('source')
         pass
 
@@ -2366,7 +2377,7 @@ class GCP(MapFrame, ColumnSorterMixin):
         """Adjust Map Windows after GCP Map Display has been resized"""
         # re-render image on idle
         self.resize = grass.clock()
-        super(MapFrame, self).OnSize(event)
+        super(MapPanel, self).OnSize(event)
 
     def OnIdle(self, event):
         """GCP Map Display resized, adjust Map Windows"""
@@ -2389,6 +2400,44 @@ class GCP(MapFrame, ColumnSorterMixin):
         pass
 
 
+class GCPDisplay(FrameMixin, GCPPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, grwiz, id, lmgr, Map, title, **kwargs):
+        # init map panel
+        GCPPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            grwiz=grwiz,
+            id=id,
+            lmgr=lmgr,
+            Map=Map,
+            title=title,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bind to frame
+        parent.Bind(wx.EVT_CLOSE, self.OnQuit)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class GCPList(ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
     def __init__(
         self,

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

@@ -5,7 +5,7 @@
 for various display management functions, one for manipulating GCPs.
 
 Classes:
-- mapdisplay::MapFrame
+- mapdisplay::MapPanel
 
 (C) 2006-2011 by the GRASS Development Team
 
@@ -27,7 +27,7 @@ from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
 from mapdisp.gprint import PrintOptions
 from core.gcmd import GMessage
 from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
-from gui_core.mapdisp import SingleMapFrame
+from gui_core.mapdisp import SingleMapPanel
 from gui_core.wrap import Menu
 from mapwin.buffered import BufferedMapWindow
 from mapwin.base import MapWindowProperties
@@ -39,7 +39,7 @@ import gcp.statusbar as sbgcp
 cmdfilename = None
 
 
-class MapFrame(SingleMapFrame):
+class MapPanel(SingleMapPanel):
     """Main frame for map display window. Drawing takes place in
     child double buffered drawing window.
     """
@@ -66,7 +66,7 @@ class MapFrame(SingleMapFrame):
         :param kwargs: wx.Frame attribures
         """
 
-        SingleMapFrame.__init__(
+        SingleMapPanel.__init__(
             self,
             parent=parent,
             giface=giface,
@@ -220,7 +220,7 @@ class MapFrame(SingleMapFrame):
         self.statusbarManager.Update()
 
     def _setUpMapWindow(self, mapWindow):
-        # TODO: almost the same implementation as for MapFrameBase (only names differ)
+        # TODO: almost the same implementation as for MapPanelBase (only names differ)
         # enable or disable zoom history tool
         mapWindow.zoomHistoryAvailable.connect(
             lambda: self.GetMapToolbar().Enable("zoomback", enable=True)

+ 89 - 69
gui/wxpython/gui_core/mapdisp.py

@@ -4,9 +4,9 @@
 @brief Base classes for Map display window
 
 Classes:
- - mapdisp::MapFrameBase
- - mapdisp::SingleMapFrame
- - mapdisp::DoubleMapFrame
+ - mapdisp::MapPanelBase
+ - mapdisp::SingleMapPanel
+ - mapdisp::DoubleMapPanel
 
 (C) 2009-2014 by the GRASS Development Team
 
@@ -19,13 +19,11 @@ This program is free software under the GNU General Public License
 @author Anna Kratochvilova <kratochanna gmail.com>
 """
 
-import os
 import sys
 import six
 
 import wx
 
-from core import globalvar
 from core.debug import Debug
 from gui_core.toolbars import ToolSwitcher
 from gui_core.wrap import NewId
@@ -34,7 +32,7 @@ from mapdisp import statusbar as sb
 from grass.script import core as grass
 
 
-class MapFrameBase(wx.Frame):
+class MapPanelBase(wx.Panel):
     """Base class for map display window
 
     Derived class must use (create and initialize) \c statusbarManager
@@ -50,7 +48,7 @@ class MapFrameBase(wx.Frame):
     It is expected that derived class will call _setUpMapWindow().
 
     Derived class can has one or more map windows (and map renders)
-    but implementation of MapFrameBase expects that one window and
+    but implementation of MapPanelBase expects that one window and
     one map will be current.
     Current instances of map window and map renderer should be returned
     by methods GetWindow() and GetMap() respectively.
@@ -63,7 +61,6 @@ class MapFrameBase(wx.Frame):
         parent=None,
         id=wx.ID_ANY,
         title="",
-        style=wx.DEFAULT_FRAME_STYLE,
         auimgr=None,
         name="",
         **kwargs,
@@ -76,28 +73,15 @@ class MapFrameBase(wx.Frame):
         :param parent: gui parent
         :param id: wx id
         :param title: window title
-        :param style: \c wx.Frame style
         :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
         :param auimgr: AUI manager (if \c None, wx.aui.AuiManager is used)
-        :param name: frame name
-        :param kwargs: arguments passed to \c wx.Frame
+        :param name: panel name
+        :param kwargs: arguments passed to \c wx.Panel
         """
 
         self.parent = parent
 
-        wx.Frame.__init__(self, parent, id, title, style=style, name=name, **kwargs)
-
-        #
-        # set the size & system icon
-        #
-        self.SetClientSize(self.GetSize())
-        self.iconsize = (16, 16)
-
-        self.SetIcon(
-            wx.Icon(
-                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
-            )
-        )
+        wx.Panel.__init__(self, parent, id, **kwargs)
 
         # toolbars
         self.toolbars = {}
@@ -116,23 +100,22 @@ class MapFrameBase(wx.Frame):
         self._toolSwitcher = ToolSwitcher()
         self._toolSwitcher.toggleToolChanged.connect(self._onToggleTool)
 
-        self._initShortcuts()
-
-    def _initShortcuts(self):
-
-        # set accelerator table (fullscreen, close window)
-        shortcuts_table = (
-            (self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11),
+        # set accelerator table
+        self.shortcuts_table = [
             (self.OnCloseWindow, wx.ACCEL_CTRL, ord("W")),
             (self.OnRender, wx.ACCEL_CTRL, ord("R")),
             (self.OnRender, wx.ACCEL_NORMAL, wx.WXK_F5),
-        )
+        ]
+
+        self._initShortcuts()
+
+    def _initShortcuts(self):
+        """init shortcuts to acceleration table"""
         accelTable = []
-        for handler, entry, kdb in shortcuts_table:
+        for handler, entry, kdb in self.shortcuts_table:
             wxId = NewId()
             self.Bind(wx.EVT_MENU, handler, id=wxId)
             accelTable.append((entry, kdb, wxId))
-
         self.SetAcceleratorTable(wx.AcceleratorTable(accelTable))
 
     def _initMap(self, Map):
@@ -143,13 +126,13 @@ class MapFrameBase(wx.Frame):
                 % "g.region"
             )
 
-        Debug.msg(2, "MapFrame._initMap():")
+        Debug.msg(2, "MapPanel._initMap():")
         Map.ChangeMapSize(self.GetClientSize())
         Map.region = Map.GetRegion()  # g.region -upgc
         # self.Map.SetRegion() # adjust region to match display window
 
     def _resize(self):
-        Debug.msg(1, "MapFrame._resize():")
+        Debug.msg(1, "MapPanel_resize():")
         wm, hw = self.MapWindow.GetClientSize()
         wf, hf = self.GetSize()
         dw = wf - wm
@@ -168,14 +151,6 @@ class MapFrameBase(wx.Frame):
         # update statusbar
         self.StatusbarUpdate()
 
-    def OnFullScreen(self, event):
-        """!Switch fullscreen mode, hides also toolbars"""
-        for toolbar in self.toolbars:
-            self._mgr.GetPane(self.toolbars[toolbar]).Show(self.IsFullScreen())
-        self._mgr.Update()
-        self.ShowFullScreen(not self.IsFullScreen())
-        event.Skip()
-
     def OnCloseWindow(self, event):
         self.Destroy()
 
@@ -218,7 +193,7 @@ class MapFrameBase(wx.Frame):
 
         Debug.msg(
             4,
-            "MapFrameBase.GetPPM(): size: px=%d,%d mm=%f,%f "
+            "MapPanelBase.GetPPM(): size: px=%d,%d mm=%f,%f "
             "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f"
             % (
                 dpSizePx[0],
@@ -273,7 +248,7 @@ class MapFrameBase(wx.Frame):
         widthCm = region["cols"] / ppm[0] * 100
 
         Debug.msg(
-            4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" % (widthCm, heightCm)
+            4, "MapPanel.GetMapScale(): width_cm=%f, height_cm=%f" % (widthCm, heightCm)
         )
 
         xscale = (region["e"] - region["w"]) / (region["cols"] / ppm[0])
@@ -282,7 +257,7 @@ class MapFrameBase(wx.Frame):
 
         Debug.msg(
             3,
-            "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f"
+            "MapPanel.GetMapScale(): xscale=%f, yscale=%f -> scale=%f"
             % (xscale, yscale, scale),
         )
 
@@ -321,7 +296,7 @@ class MapFrameBase(wx.Frame):
     def StatusbarUpdate(self):
         """Update statusbar content"""
         if self.statusbarManager:
-            Debug.msg(5, "MapFrameBase.StatusbarUpdate()")
+            Debug.msg(5, "MapPanelBase.StatusbarUpdate()")
             self.statusbarManager.Update()
 
     def IsAutoRendered(self):
@@ -506,10 +481,10 @@ class MapFrameBase(wx.Frame):
         self.MapWindow.ZoomToDefault()
 
 
-class SingleMapFrame(MapFrameBase):
-    """Frame with one map window.
+class SingleMapPanel(MapPanelBase):
+    """Panel with one map window.
 
-    It is base class for frames which needs only one map.
+    It is base class for panels which needs only one map.
 
     Derived class should have \c self.MapWindow or
     it has to override GetWindow() methods.
@@ -524,7 +499,6 @@ class SingleMapFrame(MapFrameBase):
         giface=None,
         id=wx.ID_ANY,
         title="",
-        style=wx.DEFAULT_FRAME_STYLE,
         Map=None,
         auimgr=None,
         name="",
@@ -535,18 +509,16 @@ class SingleMapFrame(MapFrameBase):
         :param parent: gui parent
         :param id: wx id
         :param title: window title
-        :param style: \c wx.Frame style
         :param map: instance of render.Map
-        :param name: frame name
-        :param kwargs: arguments passed to MapFrameBase
+        :param name: panel name
+        :param kwargs: arguments passed to MapPanelBase
         """
 
-        MapFrameBase.__init__(
+        MapPanelBase.__init__(
             self,
             parent=parent,
             id=id,
             title=title,
-            style=style,
             auimgr=auimgr,
             name=name,
             **kwargs,
@@ -580,10 +552,10 @@ class SingleMapFrame(MapFrameBase):
         self.StatusbarUpdate()
 
 
-class DoubleMapFrame(MapFrameBase):
-    """Frame with two map windows.
+class DoubleMapPanel(MapPanelBase):
+    """Panel with two map windows.
 
-    It is base class for frames which needs two maps.
+    It is base class for panels which needs two maps.
     There is no primary and secondary map. Both maps are equal.
     However, one map is current.
 
@@ -597,8 +569,8 @@ class DoubleMapFrame(MapFrameBase):
     (when using class or when writing class itself).
 
     .. todo:
-        Use it in GCP manager (probably changes to both DoubleMapFrame
-        and GCP MapFrame will be necessary).
+        Use it in GCP manager (probably changes to both DoubleMapPanel
+        and GCP MapPanel will be necessary).
     """
 
     def __init__(
@@ -606,7 +578,6 @@ class DoubleMapFrame(MapFrameBase):
         parent=None,
         id=wx.ID_ANY,
         title=None,
-        style=wx.DEFAULT_FRAME_STYLE,
         firstMap=None,
         secondMap=None,
         auimgr=None,
@@ -622,17 +593,15 @@ class DoubleMapFrame(MapFrameBase):
         :param parent: gui parent
         :param id: wx id
         :param title: window title
-        :param style: \c wx.Frame style
-        :param name: frame name
-        :param kwargs: arguments passed to MapFrameBase
+        :param name: panel name
+        :param kwargs: arguments passed to MapPanelBase
         """
 
-        MapFrameBase.__init__(
+        MapPanelBase.__init__(
             self,
             parent=parent,
             id=id,
             title=title,
-            style=style,
             auimgr=auimgr,
             name=name,
             **kwargs,
@@ -724,7 +693,6 @@ class DoubleMapFrame(MapFrameBase):
     def SetBindRegions(self, on):
         """Set or unset binding display regions."""
         self._bindRegions = on
-
         if on:
             if self.MapWindow == self.firstMapWindow:
                 self.firstMapWindow.zoomChanged.connect(self.OnZoomChangedFirstMap)
@@ -812,3 +780,55 @@ class DoubleMapFrame(MapFrameBase):
     def Draw(self, mapToDraw):
         """Re-display current map composition"""
         mapToDraw.UpdateMap(render=False)
+
+
+class FrameMixin:
+    """Mixin class for wx.Panel that provides methods standardly
+    used on wx.Frame widget"""
+
+    def Show(self):
+        self.GetParent().Show()
+
+    def SetTitle(self, name):
+        self.GetParent().SetTitle(name)
+
+    def Raise(self):
+        self.GetParent().Raise()
+
+    def SetFocus(self):
+        self.GetParent().SetFocus()
+
+    def CenterOnScreen(self):
+        self.GetParent().CenterOnScreen()
+
+    def CentreOnScreen(self):
+        self.GetParent().CentreOnScreen()
+
+    def IsFullScreen(self):
+        return self.GetParent().IsFullScreen()
+
+    def IsIconized(self):
+        self.GetParent().IsIconized()
+
+    def Maximize(self):
+        self.GetParent().Maximize()
+
+    def ShowFullScreen(self, show):
+        for toolbar in self.toolbars.keys():
+            self._mgr.GetPane(self.toolbars[toolbar]).Show(self.IsFullScreen())
+        if self.statusbar:
+            self._mgr.GetPane("statusbar").Show(self.IsFullScreen())
+        self._mgr.Update()
+
+        self.GetParent().ShowFullScreen(show)
+
+    def OnFullScreen(self, event):
+        """!Switches frame to fullscreen mode, hides toolbars and statusbar"""
+        self.ShowFullScreen(not self.IsFullScreen())
+        event.Skip()
+
+    def BindToFrame(self, *args):
+        self.GetParent().Bind(*args)
+
+    def Destroy(self):
+        self.GetParent().Destroy()

+ 55 - 16
gui/wxpython/iclass/frame.py

@@ -5,7 +5,8 @@
 for spectral signature analysis.
 
 Classes:
- - frame::IClassMapFrame
+ - frame::IClassMapPanel
+ - frame::IClassMapDisplay
  - frame::MapManager
 
 (C) 2006-2013 by the GRASS Development Team
@@ -42,7 +43,8 @@ from mapdisp import statusbar as sb
 from mapdisp.main import StandaloneMapDisplayGrassInterface
 from mapwin.buffered import BufferedMapWindow
 from vdigit.toolbars import VDigitToolbar
-from gui_core.mapdisp import DoubleMapFrame
+from gui_core.mapdisp import DoubleMapPanel, FrameMixin
+from core import globalvar
 from core.render import Map
 from core.gcmd import RunCommand, GMessage, GError
 from gui_core.dialogs import SetOpacityDialog
@@ -70,7 +72,7 @@ from iclass.plots import PlotPanel
 from grass.pydispatch.signal import Signal
 
 
-class IClassMapFrame(DoubleMapFrame):
+class IClassMapPanel(DoubleMapPanel):
     """wxIClass main frame
 
     It has two map windows one for digitizing training areas and one for
@@ -94,10 +96,10 @@ class IClassMapFrame(DoubleMapFrame):
         """
         :param parent: (no parent is expected)
         :param title: window title
-        :param toolbars: dictionary of active toolbars (defalult value represents all toolbars)
+        :param toolbars: dictionary of active toolbars (default value represents all toolbars)
         :param size: default size
         """
-        DoubleMapFrame.__init__(
+        DoubleMapPanel.__init__(
             self,
             parent=parent,
             title=title,
@@ -153,8 +155,8 @@ class IClassMapFrame(DoubleMapFrame):
         # Signals
         #
 
-        self.groupSet = Signal("IClassMapFrame.groupSet")
-        self.categoryChanged = Signal("IClassMapFrame.categoryChanged")
+        self.groupSet = Signal("IClassMapPanel.groupSet")
+        self.categoryChanged = Signal("IClassMapPanel.categoryChanged")
 
         self.InitStatistics()
 
@@ -213,7 +215,6 @@ class IClassMapFrame(DoubleMapFrame):
 
         wx.CallAfter(self.AddTrainingAreaMap)
 
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
         self.Bind(wx.EVT_SIZE, self.OnSize)
 
         self.SendSizeEvent()
@@ -478,7 +479,7 @@ class IClassMapFrame(DoubleMapFrame):
     def OnUpdateActive(self, event):
         """
         .. todo::
-            move to DoubleMapFrame?
+            move to DoubleMapPanel?
         """
         if self.GetMapToolbar().GetActiveMap() == 0:
             self.MapWindow = self.firstMapWindow
@@ -495,7 +496,7 @@ class IClassMapFrame(DoubleMapFrame):
     def UpdateActive(self, win):
         """
         .. todo::
-            move to DoubleMapFrame?
+            move to DoubleMapPanel?
         """
         mapTb = self.GetMapToolbar()
         # optionally disable tool zoomback tool
@@ -506,13 +507,13 @@ class IClassMapFrame(DoubleMapFrame):
         self.StatusbarUpdate()
 
     def ActivateFirstMap(self, event=None):
-        DoubleMapFrame.ActivateFirstMap(self, event)
+        DoubleMapPanel.ActivateFirstMap(self, event)
         self.GetMapToolbar().Enable(
             "zoomBack", enable=(len(self.MapWindow.zoomhistory) > 1)
         )
 
     def ActivateSecondMap(self, event=None):
-        DoubleMapFrame.ActivateSecondMap(self, event)
+        DoubleMapPanel.ActivateSecondMap(self, event)
         self.GetMapToolbar().Enable(
             "zoomBack", enable=(len(self.MapWindow.zoomhistory) > 1)
         )
@@ -1361,17 +1362,17 @@ class IClassMapFrame(DoubleMapFrame):
 
     def OnZoomIn(self, event):
         """Enable zooming for plots"""
-        super(IClassMapFrame, self).OnZoomIn(event)
+        super(IClassMapPanel, self).OnZoomIn(event)
         self.plotPanel.EnableZoom(type=1)
 
     def OnZoomOut(self, event):
         """Enable zooming for plots"""
-        super(IClassMapFrame, self).OnZoomOut(event)
+        super(IClassMapPanel, self).OnZoomOut(event)
         self.plotPanel.EnableZoom(type=-1)
 
     def OnPan(self, event):
         """Enable panning for plots"""
-        super(IClassMapFrame, self).OnPan(event)
+        super(IClassMapPanel, self).OnPan(event)
         self.plotPanel.EnablePan()
 
     def OnPointer(self, event):
@@ -1391,6 +1392,39 @@ class IClassMapFrame(DoubleMapFrame):
         return self.trainingMapManager, self.previewMapManager
 
 
+class IClassMapDisplay(FrameMixin, IClassMapPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, **kwargs):
+        # init map panel
+        IClassMapPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bindings
+        parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class MapManager:
     """Class for managing map renderer.
 
@@ -1589,7 +1623,12 @@ class MapManager:
 def test():
     app = wx.App()
 
-    frame = IClassMapFrame()
+    frame = wx.Frame(
+        parent=None,
+        size=globalvar.MAP_WINDOW_SIZE,
+        title=_("Supervised Classification Tool"),
+    )
+    frame = IClassMapDisplay(parent=frame)
     frame.Show()
     app.MainLoop()
 

+ 8 - 3
gui/wxpython/iclass/g.gui.iclass.py

@@ -64,7 +64,8 @@ def main():
     set_gui_path()
 
     from core.settings import UserSettings
-    from iclass.frame import IClassMapFrame
+    from core import globalvar
+    from iclass.frame import IClassMapDisplay
 
     group_name = subgroup_name = map_name = trainingmap_name = None
 
@@ -104,11 +105,15 @@ def main():
     app = wx.App()
 
     # show main frame
-    frame = IClassMapFrame(
+    frame = wx.Frame(
         parent=None,
-        giface=None,
+        size=globalvar.MAP_WINDOW_SIZE,
         title=_("Supervised Classification Tool - GRASS GIS"),
     )
+    frame = IClassMapDisplay(
+        parent=frame,
+        giface=None,
+    )
     if not flags["m"]:
         frame.CenterOnScreen()
     if group_name:

+ 62 - 15
gui/wxpython/image2target/ii2t_manager.py

@@ -9,7 +9,8 @@ Classes:
  - manager::LocationPage
  - manager::GroupPage
  - manager::DispMapPage
- - manager::GCP
+ - manager::GCPPanel
+ - manager::GCPDisplay
  - manager::GCPList
  - manager::VectGroup
  - manager::EditGCP
@@ -57,9 +58,10 @@ from core import utils
 from core.render import Map
 from gui_core.gselect import Select, LocationSelect, MapsetSelect
 from gui_core.dialogs import GroupDialog
+from gui_core.mapdisp import FrameMixin
 from core.gcmd import RunCommand, GMessage, GError, GWarning
 from core.settings import UserSettings
-from gcp.mapdisplay import MapFrame
+from gcp.mapdisplay import MapPanel
 from core.giface import Notification
 from gui_core.wrap import (
     SpinCtrl,
@@ -296,22 +298,30 @@ class GCPWizard(object):
             #
             # start GCP Manager
             #
-            self.gcpmgr = GCP(
-                self.parent,
+            # create superior Map Display frame
+            mapframe = wx.Frame(
+                parent=None,
+                id=wx.ID_ANY,
+                size=globalvar.MAP_WINDOW_SIZE,
+                style=wx.DEFAULT_FRAME_STYLE,
+                title=name,
+            )
+            gcpmgr = GCPDisplay(
+                parent=mapframe,
                 giface=self._giface,
                 grwiz=self,
-                size=globalvar.MAP_WINDOW_SIZE,
-                toolbars=["gcpdisp"],
+                id=wx.ID_ANY,
                 Map=self.SrcMap,
                 lmgr=self.parent,
+                title=name,
             )
 
             # load GCPs
-            self.gcpmgr.InitMapDisplay()
-            self.gcpmgr.CenterOnScreen()
-            self.gcpmgr.Show()
+            gcpmgr.InitMapDisplay()
+            gcpmgr.CenterOnScreen()
+            gcpmgr.Show()
             # need to update AUI here for wingrass
-            self.gcpmgr._mgr.Update()
+            gcpmgr._mgr.Update()
         else:
             self.Cleanup()
 
@@ -990,7 +1000,7 @@ class DispMapPage(TitledPage):
             wx.FindWindowById(wx.ID_FORWARD).Enable(True)
 
 
-class GCP(MapFrame, ColumnSorterMixin):
+class GCPPanel(MapPanel, ColumnSorterMixin):
     """
     Manages ground control points for georectifying. Calculates RMS statistics.
     Calls i.ortho.rectify or v.rectify to georectify map.
@@ -1018,7 +1028,7 @@ class GCP(MapFrame, ColumnSorterMixin):
             self.show_target = True
 
         # wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
-        MapFrame.__init__(
+        MapPanel.__init__(
             self,
             parent=parent,
             giface=self._giface,
@@ -1209,7 +1219,6 @@ class GCP(MapFrame, ColumnSorterMixin):
         self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_IDLE, self.OnIdle)
-        self.Bind(wx.EVT_CLOSE, self.OnQuit)
 
         self.SetSettings()
 
@@ -1701,7 +1710,7 @@ class GCP(MapFrame, ColumnSorterMixin):
             targetMapWin.UpdateMap(render=False, renderVector=False)
 
     def OnFocus(self, event):
-        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
+        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapPanel?
         # self.grwiz.SwitchEnv('source')
         pass
 
@@ -2291,7 +2300,7 @@ class GCP(MapFrame, ColumnSorterMixin):
         """Adjust Map Windows after GCP Map Display has been resized"""
         # re-render image on idle
         self.resize = grass.clock()
-        super(MapFrame, self).OnSize(event)
+        super(MapPanel, self).OnSize(event)
 
     def OnIdle(self, event):
         """GCP Map Display resized, adjust Map Windows"""
@@ -2314,6 +2323,44 @@ class GCP(MapFrame, ColumnSorterMixin):
         pass
 
 
+class GCPDisplay(FrameMixin, GCPPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, grwiz, id, lmgr, Map, title, **kwargs):
+        # init map panel
+        GCPPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            grwiz=grwiz,
+            id=id,
+            lmgr=lmgr,
+            Map=Map,
+            title=title,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bind to frame
+        parent.Bind(wx.EVT_CLOSE, self.OnQuit)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class GCPList(ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
     def __init__(
         self,

+ 7 - 7
gui/wxpython/image2target/ii2t_mapdisplay.py

@@ -5,7 +5,7 @@
 for various display management functions, one for manipulating GCPs.
 
 Classes:
-- mapdisplay::MapFrame
+- mapdisplay::MapPanel
 
 (C) 2006-2011 by the GRASS Development Team
 
@@ -27,7 +27,7 @@ from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
 from mapdisp.gprint import PrintOptions
 from core.gcmd import GMessage
 from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
-from gui_core.mapdisp import SingleMapFrame
+from gui_core.mapdisp import SingleMapPanel
 from gui_core.wrap import Menu
 from mapwin.buffered import BufferedMapWindow
 from mapwin.base import MapWindowProperties
@@ -39,8 +39,8 @@ import gcp.statusbar as sbgcp
 cmdfilename = None
 
 
-class MapFrame(SingleMapFrame):
-    """Main frame for map display window. Drawing takes place in
+class MapPanel(SingleMapPanel):
+    """Main panel for map display window. Drawing takes place in
     child double buffered drawing window.
     """
 
@@ -63,10 +63,10 @@ class MapFrame(SingleMapFrame):
         :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
         :param map: instance of render.Map
         :param auimgs: AUI manager
-        :param kwargs: wx.Frame attribures
+        :param kwargs: wx.Panel attribures
         """
 
-        SingleMapFrame.__init__(
+        SingleMapPanel.__init__(
             self,
             parent=parent,
             giface=giface,
@@ -225,7 +225,7 @@ class MapFrame(SingleMapFrame):
         self.statusbarManager.Update()
 
     def _setUpMapWindow(self, mapWindow):
-        # TODO: almost the same implementation as for MapFrameBase (only names differ)
+        # TODO: almost the same implementation as for MapPanelBase (only names differ)
         # enable or disable zoom history tool
         mapWindow.zoomHistoryAvailable.connect(
             lambda: self.GetMapToolbar().Enable("zoomback", enable=True)

+ 174 - 126
gui/wxpython/lmgr/frame.py

@@ -64,7 +64,11 @@ from lmgr.toolbars import LMWorkspaceToolbar, LMToolsToolbar
 from lmgr.toolbars import LMMiscToolbar, LMNvizToolbar, DisplayPanelToolbar
 from lmgr.workspace import WorkspaceManager
 from lmgr.pyshell import PyShellWindow
-from lmgr.giface import LayerManagerGrassInterface
+from lmgr.giface import (
+    LayerManagerGrassInterface,
+    LayerManagerGrassInterfaceForMapDisplay,
+)
+from mapdisp.frame import MapDisplay
 from datacatalog.catalog import DataCatalog
 from gui_core.forms import GUI
 from gui_core.wrap import Menu, TextEntryDialog
@@ -249,9 +253,9 @@ class GMFrame(wx.Frame):
             # start default initial display
             self.NewDisplay(show=False)
 
-        # show map display widnow
+        # show map display window
         # -> OnSize() -> UpdateMap()
-        for mapdisp in self.GetMapDisplay(onlyCurrent=False):
+        for mapdisp in self.GetAllMapDisplays():
             mapdisp.Show()
 
         # redirect stderr to log area
@@ -405,6 +409,158 @@ class GMFrame(wx.Frame):
         else:
             self.pyshell = None
 
+    def OnNewDisplay(self, event=None):
+        """Create new layer tree and map display window instance"""
+        self.NewDisplay()
+
+    def NewDisplay(self, name=None, show=True):
+        """Create new layer tree structure and associated map display and
+        add it to display notebook tab
+        :param name: name of new map display window
+        :param show: show map display window if True
+        """
+        Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.displayIndex)
+        if not name:
+            name = _("Map Display {number}").format(number=self.displayIndex + 1)
+
+        # make a new page in the bookcontrol for the layer tree (on page 0 of
+        # the notebook)
+        self.pg_panel = wx.Panel(
+            self.notebookLayers, id=wx.ID_ANY, style=wx.BORDER_NONE
+        )
+        # create display toolbar
+        dmgrToolbar = DisplayPanelToolbar(guiparent=self.pg_panel, parent=self)
+        # add page to notebook
+        self.notebookLayers.AddPage(page=self.pg_panel, text=name, select=True)
+        self.currentPage = self.notebookLayers.GetCurrentPage()
+
+        def CreateNewMapDisplay(layertree):
+            """Callback function which creates a new Map Display window
+            :param layertree: layer tree object
+            :param name: name of new map display window
+            :return: reference to mapdisplay instance
+            """
+            # count map display frame position
+            pos = wx.Point((self.displayIndex + 1) * 25, (self.displayIndex + 1) * 25)
+
+            # create superior Map Display frame
+            mapframe = wx.Frame(
+                layertree,
+                id=wx.ID_ANY,
+                pos=pos,
+                size=globalvar.MAP_WINDOW_SIZE,
+                style=wx.DEFAULT_FRAME_STYLE,
+                title=name,
+            )
+
+            # create instance of Map Display interface
+            self._gifaceForDisplay = LayerManagerGrassInterfaceForMapDisplay(
+                self._giface, layertree
+            )
+            # create Map Display
+            mapdisplay = MapDisplay(
+                parent=mapframe,
+                giface=self._gifaceForDisplay,
+                id=wx.ID_ANY,
+                size=globalvar.MAP_WINDOW_SIZE,
+                tree=layertree,
+                lmgr=self,
+                idx=self.displayIndex,
+                Map=layertree.Map,
+                title=name,
+            )
+
+            # set map display properties
+            self._setUpMapDisplay(mapdisplay)
+
+            # show map display if requested
+            if show:
+                mapdisplay.Show()
+            return mapdisplay
+
+        # create layer tree (tree control for managing GIS layers)  and put on
+        # new notebook page and new map display frame
+        self.currentPage.maptree = LayerTree(
+            parent=self.currentPage,
+            giface=self._giface,
+            createNewMapDisplay=CreateNewMapDisplay,
+            id=wx.ID_ANY,
+            pos=wx.DefaultPosition,
+            size=wx.DefaultSize,
+            style=wx.TR_HAS_BUTTONS
+            | wx.TR_LINES_AT_ROOT
+            | wx.TR_HIDE_ROOT
+            | wx.TR_DEFAULT_STYLE
+            | wx.NO_BORDER
+            | wx.FULL_REPAINT_ON_RESIZE,
+            lmgr=self,
+            notebook=self.notebookLayers,
+            title=name,
+        )
+
+        # layout for controls
+        cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
+        cb_boxsizer.Add(dmgrToolbar, proportion=0, flag=wx.EXPAND)
+        cb_boxsizer.Add(self.GetLayerTree(), proportion=1, flag=wx.EXPAND, border=1)
+        self.currentPage.SetSizer(cb_boxsizer)
+        self.currentPage.Fit()
+        self.currentPage.Layout()
+
+        self.displayIndex += 1
+
+        return self.GetMapDisplay()
+
+    def _setUpMapDisplay(self, mapdisplay):
+        """Set up Map Display properties"""
+        page = self.currentPage
+
+        def CanCloseDisplay(askIfSaveWorkspace):
+            """Callback to check if user wants to close display"""
+            pgnum = self.notebookLayers.GetPageIndex(page)
+            name = self.notebookLayers.GetPageText(pgnum)
+            caption = _("Close Map Display {}").format(name)
+            if not askIfSaveWorkspace or (
+                askIfSaveWorkspace and self.workspace_manager.CanClosePage(caption)
+            ):
+                return pgnum
+            return None
+
+        mapdisplay.canCloseDisplayCallback = CanCloseDisplay
+
+        # bind various events
+        mapdisplay.BindToFrame(
+            wx.EVT_ACTIVATE,
+            lambda event, page=self.currentPage: self._onMapDisplayFocus(page),
+        )
+
+        mapdisplay.starting3dMode.connect(
+            lambda firstTime, mapDisplayPage=self.currentPage: self._onMapDisplayStarting3dMode(
+                mapDisplayPage
+            )
+        )
+        mapdisplay.starting3dMode.connect(self.AddNvizTools)
+        mapdisplay.ending3dMode.connect(self.RemoveNvizTools)
+        mapdisplay.closingDisplay.connect(self._closePageNoEvent)
+
+        # set default properties
+        mapdisplay.SetProperties(
+            render=UserSettings.Get(
+                group="display", key="autoRendering", subkey="enabled"
+            ),
+            mode=UserSettings.Get(
+                group="display", key="statusbarMode", subkey="selection"
+            ),
+            alignExtent=UserSettings.Get(
+                group="display", key="alignExtent", subkey="enabled"
+            ),
+            constrainRes=UserSettings.Get(
+                group="display", key="compResolution", subkey="enabled"
+            ),
+            showCompExtent=UserSettings.Get(
+                group="display", key="showCompExtent", subkey="enabled"
+            ),
+        )
+
     def _addPagesToNotebook(self):
         """Add pages to notebook widget"""
         # add 'data catalog' widget to main notebook page
@@ -570,9 +726,15 @@ class GMFrame(wx.Frame):
 
     def OnMapSwipe(self, event=None, cmd=None):
         """Launch Map Swipe. See OnIClass documentation"""
-        from mapswipe.frame import SwipeMapFrame
+        from mapswipe.frame import SwipeMapDisplay
 
-        win = SwipeMapFrame(parent=self, giface=self._giface)
+        frame = wx.Frame(
+            parent=None, size=globalvar.MAP_WINDOW_SIZE, title=_("Map Swipe Tool")
+        )
+        win = SwipeMapDisplay(
+            parent=frame,
+            giface=self._giface,
+        )
 
         rasters = []
         tree = self.GetLayerTree()
@@ -1442,7 +1604,7 @@ class GMFrame(wx.Frame):
             This documentation is actually documentation of some
             component related to gui_core/menu.py file.
         """
-        from iclass.frame import IClassMapFrame, haveIClass, errMsg
+        from iclass.frame import IClassMapDisplay, haveIClass, errMsg
 
         if not haveIClass:
             GError(
@@ -1451,7 +1613,12 @@ class GMFrame(wx.Frame):
             )
             return
 
-        win = IClassMapFrame(parent=self)
+        frame = wx.Frame(
+            parent=None,
+            size=globalvar.MAP_WINDOW_SIZE,
+            title=_("Supervised Classification Tool"),
+        )
+        win = IClassMapDisplay(parent=frame, giface=self._giface)
         win.CentreOnScreen()
 
         win.Show()
@@ -1651,125 +1818,6 @@ class GMFrame(wx.Frame):
         # show ATM window
         dbmanager.Show()
 
-    def OnNewDisplay(self, event=None):
-        """Create new layer tree and map display instance"""
-        self.NewDisplay()
-
-    def NewDisplay(self, name=None, show=True):
-        """Create new layer tree, which will
-        create an associated map display frame
-
-        :param name: name of new map display
-        :param show: show map display window if True
-
-        :return: reference to mapdisplay intance
-        """
-        Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.displayIndex)
-
-        # make a new page in the bookcontrol for the layer tree (on page 0 of
-        # the notebook)
-        self.pg_panel = wx.Panel(self.notebookLayers, id=wx.ID_ANY, style=wx.EXPAND)
-        # create display toolbar
-        dmgrToolbar = DisplayPanelToolbar(guiparent=self.pg_panel, parent=self)
-
-        if name:
-            dispName = name
-        else:
-            dispName = _("Map Display {number}").format(number=self.displayIndex + 1)
-        self.notebookLayers.AddPage(page=self.pg_panel, text=dispName, select=True)
-        self.currentPage = self.notebookLayers.GetCurrentPage()
-
-        # create layer tree (tree control for managing GIS layers)  and put on
-        # new notebook page
-        self.currentPage.maptree = LayerTree(
-            self.currentPage,
-            giface=self._giface,
-            id=wx.ID_ANY,
-            pos=wx.DefaultPosition,
-            size=wx.DefaultSize,
-            style=wx.TR_HAS_BUTTONS
-            | wx.TR_LINES_AT_ROOT
-            | wx.TR_HIDE_ROOT
-            | wx.TR_DEFAULT_STYLE
-            | wx.NO_BORDER
-            | wx.FULL_REPAINT_ON_RESIZE,
-            idx=self.displayIndex,
-            lmgr=self,
-            notebook=self.notebookLayers,
-            showMapDisplay=show,
-            title=dispName,
-        )
-
-        # layout for controls
-        cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
-        cb_boxsizer.Add(dmgrToolbar, proportion=0, flag=wx.EXPAND)
-        cb_boxsizer.Add(self.GetLayerTree(), proportion=1, flag=wx.EXPAND, border=1)
-        self.currentPage.SetSizer(cb_boxsizer)
-        self.currentPage.Fit()
-        self.currentPage.Layout()
-        page = self.currentPage
-
-        def CanCloseDisplay(askIfSaveWorkspace):
-            """Callback to check if user wants to close display"""
-            pgnum = self.notebookLayers.GetPageIndex(page)
-            name = self.notebookLayers.GetPageText(pgnum)
-            caption = _("Close Map Display {}").format(name)
-            if not askIfSaveWorkspace or (
-                askIfSaveWorkspace and self.workspace_manager.CanClosePage(caption)
-            ):
-                return pgnum
-            return None
-
-        mapdisplay = self.currentPage.maptree.mapdisplay
-        mapdisplay.canCloseDisplayCallback = CanCloseDisplay
-        mapdisplay.Bind(
-            wx.EVT_ACTIVATE,
-            lambda event, page=self.currentPage: self._onMapDisplayFocus(page),
-        )
-        mapdisplay.starting3dMode.connect(
-            lambda firstTime, mapDisplayPage=self.currentPage: self._onMapDisplayStarting3dMode(
-                mapDisplayPage
-            )
-        )
-        mapdisplay.starting3dMode.connect(self.AddNvizTools)
-        mapdisplay.ending3dMode.connect(self.RemoveNvizTools)
-        mapdisplay.closingDisplay.connect(self._closePageNoEvent)
-
-        # use default window layout
-        if UserSettings.Get(group="general", key="defWindowPos", subkey="enabled"):
-            dim = UserSettings.Get(group="general", key="defWindowPos", subkey="dim")
-            idx = 4 + self.displayIndex * 4
-            try:
-                x, y = map(int, dim.split(",")[idx : idx + 2])
-                w, h = map(int, dim.split(",")[idx + 2 : idx + 4])
-                self.GetMapDisplay().SetPosition((x, y))
-                self.GetMapDisplay().SetSize((w, h))
-            except:
-                pass
-
-        # set default properties
-        mapdisplay.SetProperties(
-            render=UserSettings.Get(
-                group="display", key="autoRendering", subkey="enabled"
-            ),
-            mode=UserSettings.Get(
-                group="display", key="statusbarMode", subkey="selection"
-            ),
-            alignExtent=UserSettings.Get(
-                group="display", key="alignExtent", subkey="enabled"
-            ),
-            constrainRes=UserSettings.Get(
-                group="display", key="compResolution", subkey="enabled"
-            ),
-            showCompExtent=UserSettings.Get(
-                group="display", key="showCompExtent", subkey="enabled"
-            ),
-        )
-
-        self.displayIndex += 1
-
-        return self.GetMapDisplay()
-
     def _onMapDisplayFocus(self, notebookLayerPage):
         """Changes bookcontrol page to page associated with display."""
         # moved from mapdisp/frame.py

+ 2 - 28
gui/wxpython/lmgr/layertree.py

@@ -36,7 +36,6 @@ from grass.script import utils as gutils
 from core import globalvar
 from gui_core.dialogs import SqlQueryFrame, SetOpacityDialog, TextEntryDialog
 from gui_core.forms import GUI
-from mapdisp.frame import MapFrame
 from core.render import Map
 from core.utils import GetLayerNameFromCmd, ltype2command
 from core.debug import Debug
@@ -46,7 +45,6 @@ from core.gcmd import GWarning, GError, RunCommand
 from icons.icon import MetaIcon
 from gui_core.widgets import MapValidator
 from gui_core.wrap import Menu, GenBitmapButton, TextCtrl, NewId
-from lmgr.giface import LayerManagerGrassInterfaceForMapDisplay
 
 
 TREE_ITEM_HEIGHT = 25
@@ -95,6 +93,7 @@ class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
         self,
         parent,
         giface,
+        createNewMapDisplay,
         id=wx.ID_ANY,
         style=wx.SUNKEN_BORDER,
         ctstyle=CT.TR_HAS_BUTTONS
@@ -110,15 +109,11 @@ class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
         if "style" in kwargs:
             ctstyle |= kwargs["style"]
             del kwargs["style"]
-        self.displayIndex = kwargs["idx"]
-        del kwargs["idx"]
         self.lmgr = kwargs["lmgr"]
         del kwargs["lmgr"]
         # GIS Manager notebook for layer tree
         self.notebook = kwargs["notebook"]
         del kwargs["notebook"]
-        showMapDisplay = kwargs["showMapDisplay"]
-        del kwargs["showMapDisplay"]
 
         self._giface = giface
         self.treepg = parent  # notebook page holding layer tree
@@ -158,28 +153,7 @@ class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
         self._setGradient()
 
         # init associated map display
-        pos = wx.Point((self.displayIndex + 1) * 25, (self.displayIndex + 1) * 25)
-        self._gifaceForDisplay = LayerManagerGrassInterfaceForMapDisplay(
-            self._giface, self
-        )
-        self.mapdisplay = MapFrame(
-            self,
-            giface=self._gifaceForDisplay,
-            id=wx.ID_ANY,
-            pos=pos,
-            size=globalvar.MAP_WINDOW_SIZE,
-            style=wx.DEFAULT_FRAME_STYLE,
-            tree=self,
-            lmgr=self.lmgr,
-            Map=self.Map,
-            title=title,
-        )
-
-        # show new display
-        if showMapDisplay is True:
-            self.mapdisplay.Show()
-            self.mapdisplay.Refresh()
-            self.mapdisplay.Update()
+        self.mapdisplay = createNewMapDisplay(layertree=self)
 
         self.root = self.AddRoot(_("Map Layers"))
         self.SetPyData(self.root, (None, None))

+ 15 - 4
gui/wxpython/main_window/frame.py

@@ -798,9 +798,15 @@ class GMFrame(wx.Frame):
 
     def OnMapSwipe(self, event=None, cmd=None):
         """Launch Map Swipe. See OnIClass documentation"""
-        from mapswipe.frame import SwipeMapFrame
+        from mapswipe.frame import SwipeMapDisplay
 
-        win = SwipeMapFrame(parent=self, giface=self._giface)
+        frame = wx.Frame(
+            parent=None, size=globalvar.MAP_WINDOW_SIZE, title=_("Map Swipe Tool")
+        )
+        win = SwipeMapDisplay(
+            parent=frame,
+            giface=self._giface,
+        )
 
         rasters = []
         tree = self.GetLayerTree()
@@ -1652,7 +1658,7 @@ class GMFrame(wx.Frame):
             This documentation is actually documentation of some
             component related to gui_core/menu.py file.
         """
-        from iclass.frame import IClassMapFrame, haveIClass, errMsg
+        from iclass.frame import IClassMapDisplay, haveIClass, errMsg
 
         if not haveIClass:
             GError(
@@ -1661,7 +1667,12 @@ class GMFrame(wx.Frame):
             )
             return
 
-        win = IClassMapFrame(parent=self, giface=self._giface)
+        frame = wx.Frame(
+            parent=None,
+            size=globalvar.MAP_WINDOW_SIZE,
+            title=_("Supervised Classification Tool"),
+        )
+        win = IClassMapDisplay(parent=frame, giface=self._giface)
         win.CentreOnScreen()
 
         win.Show()

+ 65 - 17
gui/wxpython/mapdisp/frame.py

@@ -7,7 +7,7 @@ functions, and additional toolbars (vector digitizer, 3d view).
 Can be used either from Layer Manager or as d.mon backend.
 
 Classes:
- - mapdisp::MapFrame
+ - mapdisp::MapPanel
 
 (C) 2006-2016 by the GRASS Development Team
 
@@ -17,8 +17,8 @@ This program is free software under the GNU General Public License
 @author Michael Barton
 @author Jachym Cepicky
 @author Martin Landa <landa.martin gmail.com>
-@author Vaclav Petras <wenzeslaus gmail.com> (SingleMapFrame, handlers support)
-@author Anna Kratochvilova <kratochanna gmail.com> (SingleMapFrame)
+@author Vaclav Petras <wenzeslaus gmail.com> (SingleMapPanel, handlers support)
+@author Anna Kratochvilova <kratochanna gmail.com> (SingleMapPanel)
 @author Stepan Turek <stepan.turek seznam.cz> (handlers support)
 """
 
@@ -36,7 +36,7 @@ from core.utils import ListOfCatsToRange, GetLayerNameFromCmd
 from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
 from core.debug import Debug
 from core.settings import UserSettings
-from gui_core.mapdisp import SingleMapFrame
+from gui_core.mapdisp import SingleMapPanel, FrameMixin
 from mapwin.base import MapWindowProperties
 from gui_core.query import QueryDialog, PrepareQueryResults
 from mapwin.buffered import BufferedMapWindow
@@ -63,8 +63,8 @@ import grass.script as grass
 from grass.pydispatch.signal import Signal
 
 
-class MapFrame(SingleMapFrame):
-    """Main frame for map display window. Drawing takes place in
+class MapPanel(SingleMapPanel):
+    """Main panel for map display window. Drawing takes place in
     child double buffered drawing window.
     """
 
@@ -91,10 +91,10 @@ class MapFrame(SingleMapFrame):
         :param lmgr: Layer Manager
         :param map: instance of render.Map
         :param auimgr: AUI manager
-        :param name: frame name
-        :param kwargs: wx.Frame attributes
+        :param name: panel name
+        :param kwargs: wx.Panel attributes
         """
-        SingleMapFrame.__init__(
+        SingleMapPanel.__init__(
             self,
             parent=parent,
             title=title,
@@ -119,16 +119,16 @@ class MapFrame(SingleMapFrame):
 
         # Emitted when starting (switching to) 3D mode.
         # Parameter firstTime specifies if 3D was already actived.
-        self.starting3dMode = Signal("MapFrame.starting3dMode")
+        self.starting3dMode = Signal("MapPanel.starting3dMode")
 
         # Emitted when ending (switching from) 3D mode.
-        self.ending3dMode = Signal("MapFrame.ending3dMode")
+        self.ending3dMode = Signal("MapPanel.ending3dMode")
 
         # Emitted when closing display by closing its window.
-        self.closingDisplay = Signal("MapFrame.closingDisplay")
+        self.closingDisplay = Signal("MapPanel.closingDisplay")
 
         # Emitted when closing display by closing its window.
-        self.closingVNETDialog = Signal("MapFrame.closingVNETDialog")
+        self.closingVNETDialog = Signal("MapPanel.closingVNETDialog")
 
         # properties are shared in other objects, so defining here
         self.mapWindowProperties = MapWindowProperties()
@@ -226,7 +226,6 @@ class MapFrame(SingleMapFrame):
         #
         # Bind various events
         #
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
         self.Bind(wx.EVT_SIZE, self.OnSize)
 
         #
@@ -962,7 +961,7 @@ class MapFrame(SingleMapFrame):
     def CleanUp(self):
         """Clean up before closing map display.
         End digitizer/nviz."""
-        Debug.msg(2, "MapFrame.CleanUp()")
+        Debug.msg(2, "MapPanel.CleanUp()")
         self.Map.Clean()
         # close edited map and 3D tools properly
         if self.GetToolbar("vdigit"):
@@ -980,7 +979,7 @@ class MapFrame(SingleMapFrame):
         """Window closed.
         Also close associated layer tree page
         """
-        Debug.msg(2, "MapFrame.OnCloseWindow()")
+        Debug.msg(2, "MapPanel.OnCloseWindow()")
         if self.canCloseDisplayCallback:
             pgnum = self.canCloseDisplayCallback(askIfSaveWorkspace=askIfSaveWorkspace)
             if pgnum is not None:
@@ -1491,7 +1490,7 @@ class MapFrame(SingleMapFrame):
         """Set display extents to match selected raster (including
         NULLs) or vector map.
         """
-        Debug.msg(3, "MapFrame.OnZoomToMap()")
+        Debug.msg(3, "MapPanel.OnZoomToMap()")
         self.MapWindow.ZoomToMap(layers=None)
 
     def OnZoomToRaster(self, event):
@@ -1702,3 +1701,52 @@ class MapFrame(SingleMapFrame):
         """Quit VDigit"""
         # disable the toolbar
         self.RemoveToolbar("vdigit", destroy=True)
+
+
+class MapDisplay(FrameMixin, MapPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, id, tree, lmgr, idx, Map, title, **kwargs):
+        # init map panel
+        MapPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            id=id,
+            tree=tree,
+            lmgr=lmgr,
+            Map=Map,
+            title=title,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+        # use default frame window layout
+        if UserSettings.Get(group="general", key="defWindowPos", subkey="enabled"):
+            dim = UserSettings.Get(group="general", key="defWindowPos", subkey="dim")
+            idx = 4 + idx * 4
+            try:
+                x, y = map(int, dim.split(",")[idx : idx + 2])
+                w, h = map(int, dim.split(",")[idx + 2 : idx + 4])
+                parent.SetPosition((x, y))
+                parent.SetSize((w, h))
+            except Exception:
+                pass
+
+        # bindings
+        parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()

+ 64 - 27
gui/wxpython/mapdisp/main.py

@@ -7,8 +7,9 @@ Classes:
  - mapdisp::DMonMap
  - mapdisp::Layer
  - mapdisp::LayerList
+ - mapdisp::StandaloneMapDisplayGrassInterface
  - mapdisp::DMonGrassInterface
- - mapdisp::DMonFrame
+ - mapdisp::DMonDisplay
  - mapdisp::MapApp
 
 Usage:
@@ -22,8 +23,8 @@ This program is free software under the GNU General Public License
 @author Michael Barton
 @author Jachym Cepicky
 @author Martin Landa <landa.martin gmail.com>
-@author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
-@author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
+@author Vaclav Petras <wenzeslaus gmail.com> (MapPanelBase)
+@author Anna Kratochvilova <kratochanna gmail.com> (MapPanelBase)
 """
 
 from __future__ import print_function
@@ -52,7 +53,8 @@ from core import utils  # noqa: E402
 from core.giface import StandaloneGrassInterface  # noqa: E402
 from core.gcmd import RunCommand  # noqa: E402
 from core.render import Map, MapLayer, RenderMapMgr  # noqa: E402
-from mapdisp.frame import MapFrame  # noqa: E402
+from mapdisp.frame import MapPanel  # noqa: E402
+from gui_core.mapdisp import FrameMixin  # noqa: E402
 from core.debug import Debug  # noqa: E402
 from core.settings import UserSettings  # noqa: E402
 
@@ -464,13 +466,35 @@ class DMonGrassInterface(StandaloneMapDisplayGrassInterface):
         StandaloneMapDisplayGrassInterface.__init__(self, mapframe)
 
 
-class DMonFrame(MapFrame):
-    def OnZoomToMap(self, event):
-        layers = self.MapWindow.GetMap().GetListOfLayers()
-        self.MapWindow.ZoomToMap(layers=layers)
+class DMonDisplay(FrameMixin, MapPanel):
+    """Map display for wrapping map panel with d.mon mathods and frame methods"""
+
+    def __init__(self, parent, giface, id, Map, title, toolbars, statusbar):
+        # init map panel
+        MapPanel.__init__(
+            self,
+            parent=parent,
+            id=id,
+            title=title,
+            Map=Map,
+            giface=giface,
+            toolbars=toolbars,
+            statusbar=statusbar,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bindings
+        parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
-    def OnSize(self, event):
-        super(DMonFrame, self).OnSize(event)
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
 
         # update env file
         width, height = self.MapWindow.GetClientSize()
@@ -482,6 +506,16 @@ class DMonFrame(MapFrame):
             else:
                 print(line.rstrip("\n"))
 
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+    def OnZoomToMap(self, event):
+        layers = self.MapWindow.GetMap().GetListOfLayers()
+        self.MapWindow.ZoomToMap(layers=layers)
+
 
 class MapApp(wx.App):
     def OnInit(self):
@@ -492,7 +526,7 @@ class MapApp(wx.App):
 
         return True
 
-    def CreateMapFrame(self, name, decorations=True):
+    def CreateMapDisplay(self, name, decorations=True):
         toolbars = []
         if decorations:
             toolbars.append("map")
@@ -511,24 +545,27 @@ class MapApp(wx.App):
         else:
             self.Map = None
 
-        self.mapFrm = DMonFrame(
-            parent=None,
+        mapframe = wx.Frame(
+            None, id=wx.ID_ANY, size=monSize, style=wx.DEFAULT_FRAME_STYLE, title=name
+        )
+
+        self.mapDisplay = DMonDisplay(
+            parent=mapframe,
             id=wx.ID_ANY,
             title=name,
             Map=self.Map,
             giface=self._giface,
-            size=monSize,
             toolbars=toolbars,
             statusbar=decorations,
         )
 
         # FIXME: hack to solve dependency
-        self._giface._mapframe = self.mapFrm
+        self._giface._mapframe = self.mapDisplay
 
-        self.mapFrm.GetMapWindow().SetAlwaysRenderEnabled(False)
+        self.mapDisplay.GetMapWindow().SetAlwaysRenderEnabled(False)
 
         # set default properties
-        self.mapFrm.SetProperties(
+        self.mapDisplay.SetProperties(
             render=UserSettings.Get(
                 group="display", key="autoRendering", subkey="enabled"
             ),
@@ -546,15 +583,15 @@ class MapApp(wx.App):
             ),
         )
 
-        self.Map.saveToFile.connect(lambda cmd: self.mapFrm.DOutFile(cmd))
-        self.Map.dToRast.connect(lambda cmd: self.mapFrm.DToRast(cmd))
+        self.Map.saveToFile.connect(lambda cmd: self.mapDisplay.DOutFile(cmd))
+        self.Map.dToRast.connect(lambda cmd: self.mapDisplay.DToRast(cmd))
         self.Map.query.connect(
-            lambda ltype, maps: self.mapFrm.SetQueryLayersAndActivate(
+            lambda ltype, maps: self.mapDisplay.SetQueryLayersAndActivate(
                 ltype=ltype, maps=maps
             )
         )
 
-        return self.mapFrm
+        return self.mapDisplay
 
     def OnExit(self):
         if __name__ == "__main__":
@@ -590,15 +627,15 @@ class MapApp(wx.App):
             if currentCmdFileTime > self.cmdTimeStamp:
                 self.timer.Stop()
                 self.cmdTimeStamp = currentCmdFileTime
-                self.mapFrm.GetMap().GetLayersFromCmdFile()
+                self.mapDisplay.GetMap().GetLayersFromCmdFile()
                 self.timer.Start(mtime)
         except OSError as e:
             grass.warning("%s" % e)
             self.timer.Stop()
 
-    def GetMapFrame(self):
-        """Get Map Frame instance"""
-        return self.mapFrm
+    def GetMapDisplay(self):
+        """Get Map Display instance"""
+        return self.mapDisplay
 
 
 if __name__ == "__main__":
@@ -633,8 +670,8 @@ if __name__ == "__main__":
 
     start = time.time()
     gmMap = MapApp(0)
-    mapFrame = gmMap.CreateMapFrame(monName, monDecor)
-    mapFrame.Show()
+    mapDisplay = gmMap.CreateMapDisplay(monName, monDecor)
+    mapDisplay.Show()
     Debug.msg(1, "WxMonitor started in %.6f sec" % (time.time() - start))
 
     gmMap.MainLoop()

+ 52 - 17
gui/wxpython/mapswipe/frame.py

@@ -4,7 +4,9 @@
 @brief Map Swipe Frame
 
 Classes:
- - dialogs::SwipeMapDialog
+ - frame::SwipeMapPanel
+ - frame::SwipeMapDisplay
+ - frame::MapSplitter
 
 (C) 2012 by the GRASS Development Team
 
@@ -19,7 +21,7 @@ import wx
 
 import grass.script as grass
 
-from gui_core.mapdisp import DoubleMapFrame
+from gui_core.mapdisp import DoubleMapPanel, FrameMixin
 from gui_core.dialogs import GetImageHandlers
 from mapwin.base import MapWindowProperties
 from core.render import Map
@@ -27,6 +29,7 @@ from mapdisp import statusbar as sb
 from core.debug import Debug
 from core.gcmd import GError, GMessage
 from core.layerlist import LayerListToRendererConverter
+from core import globalvar
 from gui_core.query import QueryDialog, PrepareQueryResults
 
 from mapswipe.toolbars import SwipeMapToolbar, SwipeMainToolbar, SwipeMiscToolbar
@@ -34,11 +37,11 @@ from mapswipe.mapwindow import SwipeBufferedWindow
 from mapswipe.dialogs import SwipeMapDialog, PreferencesDialog
 
 
-class SwipeMapFrame(DoubleMapFrame):
+class SwipeMapPanel(DoubleMapPanel):
     def __init__(
         self, parent=None, giface=None, title=_("Map Swipe"), name="swipe", **kwargs
     ):
-        DoubleMapFrame.__init__(
+        DoubleMapPanel.__init__(
             self,
             parent=parent,
             title=title,
@@ -47,7 +50,7 @@ class SwipeMapFrame(DoubleMapFrame):
             secondMap=Map(),
             **kwargs,
         )
-        Debug.msg(1, "SwipeMapFrame.__init__()")
+        Debug.msg(1, "SwipeMapPanel.__init__()")
         #
         # Add toolbars
         #
@@ -119,7 +122,6 @@ class SwipeMapFrame(DoubleMapFrame):
 
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_IDLE, self.OnIdle)
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
         self.SetSize((800, 600))
 
@@ -156,14 +158,14 @@ class SwipeMapFrame(DoubleMapFrame):
 
     def ActivateFirstMap(self, event=None):
         """Switch tracking direction"""
-        super(SwipeMapFrame, self).ActivateFirstMap(event)
+        super(SwipeMapPanel, self).ActivateFirstMap(event)
 
         self.firstMapWindow.ClearLines()
         self.firstMapWindow.Refresh()
 
     def ActivateSecondMap(self, event=None):
         """Switch tracking direction"""
-        super(SwipeMapFrame, self).ActivateSecondMap(event)
+        super(SwipeMapPanel, self).ActivateSecondMap(event)
 
         self.secondMapWindow.ClearLines()
         self.secondMapWindow.Refresh()
@@ -193,7 +195,7 @@ class SwipeMapFrame(DoubleMapFrame):
 
     def OnSliderPositionChanging(self, event):
         """Slider changes its position, sash must be moved too."""
-        Debug.msg(5, "SwipeMapFrame.OnSliderPositionChanging()")
+        Debug.msg(5, "SwipeMapPanel.OnSliderPositionChanging()")
 
         self.GetFirstWindow().movingSash = True
         self.GetSecondWindow().movingSash = True
@@ -205,29 +207,29 @@ class SwipeMapFrame(DoubleMapFrame):
 
     def OnSliderPositionChanged(self, event):
         """Slider position changed, sash must be moved too."""
-        Debug.msg(5, "SwipeMapFrame.OnSliderPositionChanged()")
+        Debug.msg(5, "SwipeMapPanel.OnSliderPositionChanged()")
 
         self.splitter.SetSashPosition(event.GetPosition())
         self.splitter.OnSashChanged(None)
 
     def OnSashChanging(self, event):
         """Sash position is changing, slider must be moved too."""
-        Debug.msg(5, "SwipeMapFrame.OnSashChanging()")
+        Debug.msg(5, "SwipeMapPanel.OnSashChanging()")
 
         self.slider.SetValue(self.splitter.GetSashPosition())
         event.Skip()
 
     def OnSashChanged(self, event):
         """Sash position changed, slider must be moved too."""
-        Debug.msg(5, "SwipeMapFrame.OnSashChanged()")
+        Debug.msg(5, "SwipeMapPanel.OnSashChanged()")
 
         self.OnSashChanging(event)
         event.Skip()
 
     def OnSize(self, event):
-        Debug.msg(4, "SwipeMapFrame.OnSize()")
+        Debug.msg(4, "SwipeMapPanel.OnSize()")
         self.resize = grass.clock()
-        super(SwipeMapFrame, self).OnSize(event)
+        super(SwipeMapPanel, self).OnSize(event)
 
     def OnIdle(self, event):
         if self.resize and grass.clock() - self.resize > 0.2:
@@ -501,7 +503,7 @@ class SwipeMapFrame(DoubleMapFrame):
 
         :param name: layer (raster) name
         """
-        Debug.msg(3, "SwipeMapFrame.SetLayer(): name=%s" % name)
+        Debug.msg(3, "SwipeMapPanel.SetLayer(): name=%s" % name)
 
         # this simple application enables to keep only one raster
         mapInstance.DeleteAllLayers()
@@ -519,7 +521,7 @@ class SwipeMapFrame(DoubleMapFrame):
 
     def OnSwitchWindows(self, event):
         """Switch windows position."""
-        Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")
+        Debug.msg(3, "SwipeMapPanel.OnSwitchWindows()")
 
         splitter = self.splitter
         w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
@@ -639,7 +641,7 @@ class SwipeMapFrame(DoubleMapFrame):
 
     def OnSwitchOrientation(self, event):
         """Switch orientation of the sash."""
-        Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")
+        Debug.msg(3, "SwipeMapPanel.OnSwitchOrientation()")
 
         splitter = self.splitter
         splitter.Unsplit()
@@ -833,6 +835,39 @@ class SwipeMapFrame(DoubleMapFrame):
         self.Destroy()
 
 
+class SwipeMapDisplay(FrameMixin, SwipeMapPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, **kwargs):
+        # init map panel
+        SwipeMapPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bindings
+        parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class MapSplitter(wx.SplitterWindow):
     """Splitter window for displaying two maps"""
 

+ 9 - 3
gui/wxpython/mapswipe/g.gui.mapswipe.py

@@ -59,7 +59,8 @@ def main():
 
     from core.settings import UserSettings
     from core.giface import StandaloneGrassInterface
-    from mapswipe.frame import SwipeMapFrame
+    from core import globalvar
+    from mapswipe.frame import SwipeMapDisplay
 
     driver = UserSettings.Get(group="display", key="driver", subkey="type")
     if driver == "png":
@@ -79,11 +80,16 @@ def main():
 
     app = wx.App()
 
-    frame = SwipeMapFrame(
+    # show main frame
+    frame = wx.Frame(
         parent=None,
-        giface=StandaloneGrassInterface(),
+        size=globalvar.MAP_WINDOW_SIZE,
         title=_("Map Swipe Tool - GRASS GIS"),
     )
+    frame = SwipeMapDisplay(
+        parent=frame,
+        giface=StandaloneGrassInterface(),
+    )
 
     if first:
         frame.SetFirstRaster(first)

+ 1 - 1
gui/wxpython/mapswipe/toolbars.py

@@ -76,7 +76,7 @@ class SwipeMapToolbar(BaseToolbar):
 
     def SetActiveMap(self, index):
         """Set currently selected map.
-        Unused, needed because of DoubleMapFrame API.
+        Unused, needed because of DoubleMapPanel API.
         """
         pass
 

+ 64 - 16
gui/wxpython/photo2image/ip2i_manager.py

@@ -7,7 +7,8 @@ and click GCP creation
 
 Classes:
  - ip2i_manager::GCPWizard
- - ip2i_manager::GCP
+ - ip2i_manager::GCPPanel
+ - ip2i_manager::GCPDisplay
  - ip2i_manager::GCPList
  - ip2i_manager::EditGCP
  - ip2i_manager::GrSettingsDialog
@@ -41,9 +42,10 @@ import grass.script as grass
 from core import utils, globalvar
 from core.render import Map
 from gui_core.gselect import Select
+from gui_core.mapdisp import FrameMixin
 from core.gcmd import RunCommand, GMessage, GError, GWarning
 from core.settings import UserSettings
-from photo2image.ip2i_mapdisplay import MapFrame
+from photo2image.ip2i_mapdisplay import MapPanel
 from gui_core.wrap import (
     SpinCtrl,
     Button,
@@ -202,23 +204,32 @@ class GCPWizard(object):
         #
         # start GCP Manager
         #
-        self.gcpmgr = GCP(
-            self.parent,
+        # create superior Map Display frame
+        mapframe = wx.Frame(
+            parent=None,
+            id=wx.ID_ANY,
+            size=globalvar.MAP_WINDOW_SIZE,
+            style=wx.DEFAULT_FRAME_STYLE,
+            title=name,
+        )
+        gcpmgr = GCPDisplay(
+            parent=mapframe,
             giface=self._giface,
             grwiz=self,
-            size=globalvar.MAP_WINDOW_SIZE,
-            toolbars=["gcpdisp"],
+            id=wx.ID_ANY,
             Map=self.SrcMap,
             lmgr=self.parent,
+            title=name,
             camera=camera,
         )
 
         # load GCPs
-        self.gcpmgr.InitMapDisplay()
-        self.gcpmgr.CenterOnScreen()
-        self.gcpmgr.Show()
+        gcpmgr.InitMapDisplay()
+        gcpmgr.CenterOnScreen()
+        gcpmgr.Show()
         # need to update AUI here for wingrass
-        self.gcpmgr._mgr.Update()
+        gcpmgr._mgr.Update()
+
         self.SwitchEnv("target")
 
     def SetSrcEnv(self, location, mapset):
@@ -284,7 +295,7 @@ class GCPWizard(object):
         event.Skip()
 
 
-class GCP(MapFrame, ColumnSorterMixin):
+class GCPPanel(MapPanel, ColumnSorterMixin):
     """
     Manages ground control points for georectifying. Calculates RMS statistics.
     Calls i.rectify or v.rectify to georectify map.
@@ -314,8 +325,7 @@ class GCP(MapFrame, ColumnSorterMixin):
 
         self.camera = camera
 
-        # wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
-        MapFrame.__init__(
+        MapPanel.__init__(
             self,
             parent=parent,
             giface=self._giface,
@@ -586,7 +596,6 @@ class GCP(MapFrame, ColumnSorterMixin):
         self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_IDLE, self.OnIdle)
-        self.Bind(wx.EVT_CLOSE, self.OnQuit)
 
         self.SetSettings()
 
@@ -1035,7 +1044,7 @@ class GCP(MapFrame, ColumnSorterMixin):
             targetMapWin.UpdateMap(render=False)
 
     def OnFocus(self, event):
-        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
+        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapPanel?
         # self.grwiz.SwitchEnv('source')
         pass
 
@@ -1585,7 +1594,7 @@ class GCP(MapFrame, ColumnSorterMixin):
         """Adjust Map Windows after GCP Map Display has been resized"""
         # re-render image on idle
         self.resize = grass.clock()
-        super(MapFrame, self).OnSize(event)
+        super(MapPanel, self).OnSize(event)
 
     def OnIdle(self, event):
         """GCP Map Display resized, adjust Map Windows"""
@@ -1608,6 +1617,45 @@ class GCP(MapFrame, ColumnSorterMixin):
         pass
 
 
+class GCPDisplay(FrameMixin, GCPPanel):
+    """Map display for wrapping map panel with frame methods"""
+
+    def __init__(self, parent, giface, grwiz, id, lmgr, Map, title, camera, **kwargs):
+        # init map panel
+        GCPPanel.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            grwiz=grwiz,
+            id=id,
+            lmgr=lmgr,
+            Map=Map,
+            title=title,
+            camera=camera,
+            **kwargs,
+        )
+        # set system icon
+        parent.iconsize = (16, 16)
+        parent.SetIcon(
+            wx.Icon(
+                os.path.join(globalvar.ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO
+            )
+        )
+
+        # bind to frame
+        parent.Bind(wx.EVT_CLOSE, self.OnQuit)
+
+        # extend shortcuts and create frame accelerator table
+        self.shortcuts_table.append((self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11))
+        self._initShortcuts()
+
+        # add Map Display panel to Map Display frame
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self, proportion=1, flag=wx.EXPAND)
+        parent.SetSizer(sizer)
+        parent.Layout()
+
+
 class GCPList(ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
     def __init__(
         self,

+ 6 - 13
gui/wxpython/photo2image/ip2i_mapdisplay.py

@@ -1,17 +1,12 @@
 """
 @package photo2image.ip2i_mapdisplay
-
 @brief Display to manage ground control points with two toolbars, one
 for various display management functions, one for manipulating GCPs.
-
 Classes:
-- mapdisplay::MapFrame
-
+- mapdisplay::MapPanel
 (C) 2006-2011 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 Markus Metz
 """
 
@@ -27,7 +22,7 @@ from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
 from mapdisp.gprint import PrintOptions
 from core.gcmd import GMessage
 from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
-from gui_core.mapdisp import SingleMapFrame
+from gui_core.mapdisp import SingleMapPanel
 from gui_core.wrap import Menu
 from mapwin.buffered import BufferedMapWindow
 from mapwin.base import MapWindowProperties
@@ -39,8 +34,8 @@ import gcp.statusbar as sbgcp
 cmdfilename = None
 
 
-class MapFrame(SingleMapFrame):
-    """Main frame for map display window. Drawing takes place in
+class MapPanel(SingleMapPanel):
+    """Main panel for map display window. Drawing takes place in
     child double buffered drawing window.
     """
 
@@ -57,7 +52,6 @@ class MapFrame(SingleMapFrame):
     ):
         """Main map display window with toolbars, statusbar and
         DrawWindow
-
         :param giface: GRASS interface instance
         :param title: window title
         :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
@@ -66,7 +60,7 @@ class MapFrame(SingleMapFrame):
         :param kwargs: wx.Frame attribures
         """
 
-        SingleMapFrame.__init__(
+        SingleMapPanel.__init__(
             self,
             parent=parent,
             giface=giface,
@@ -224,7 +218,7 @@ class MapFrame(SingleMapFrame):
         self.statusbarManager.Update()
 
     def _setUpMapWindow(self, mapWindow):
-        # TODO: almost the same implementation as for MapFrameBase (only names differ)
+        # TODO: almost the same implementation as for MapPanelBase (only names differ)
         # enable or disable zoom history tool
         mapWindow.zoomHistoryAvailable.connect(
             lambda: self.GetMapToolbar().Enable("zoomback", enable=True)
@@ -236,7 +230,6 @@ class MapFrame(SingleMapFrame):
 
     def AddToolbar(self, name):
         """Add defined toolbar to the window
-
         Currently known toolbars are:
          - 'map'     - basic map toolbar
          - 'gcpdisp' - GCP Manager, Display

+ 39 - 10
gui/wxpython/rdigit/g.gui.rdigit.py

@@ -73,28 +73,44 @@ def main():
     set_gui_path()
 
     from core.render import Map
-    from mapdisp.frame import MapFrame
+    from core.globalvar import ICONDIR
+    from mapdisp.frame import MapPanel
+    from gui_core.mapdisp import FrameMixin
     from mapdisp.main import DMonGrassInterface
     from core.settings import UserSettings
 
     # define classes which needs imports as local
     # for longer definitions, a separate file would be a better option
-    class RDigitMapFrame(MapFrame):
+    class RDigitMapDisplay(FrameMixin, MapPanel):
+        """Map display for wrapping map panel with r.digit mathods and frame methods"""
+
         def __init__(
             self,
+            parent,
             new_map=None,
             base_map=None,
             edit_map=None,
             map_type=None,
         ):
-            MapFrame.__init__(
-                self,
-                parent=None,
-                Map=Map(),
-                giface=DMonGrassInterface(None),
-                title=_("Raster Digitizer - GRASS GIS"),
-                size=(850, 600),
+            MapPanel.__init__(
+                self, parent=parent, Map=Map(), giface=DMonGrassInterface(None)
+            )
+
+            # set system icon
+            parent.iconsize = (16, 16)
+            parent.SetIcon(
+                wx.Icon(os.path.join(ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO)
             )
+
+            # bindings
+            parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+            # extend shortcuts and create frame accelerator table
+            self.shortcuts_table.append(
+                (self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11)
+            )
+            self._initShortcuts()
+
             # this giface issue not solved yet, we must set mapframe afterwards
             self._giface._mapframe = self
             self._giface.mapCreated.connect(self.OnMapCreated)
@@ -126,6 +142,12 @@ def main():
             self.rdigit.quitDigitizer.disconnect(self.QuitRDigit)
             self.rdigit.quitDigitizer.connect(lambda: self.Close())
 
+            # add Map Display panel to Map Display frame
+            sizer = wx.BoxSizer(wx.VERTICAL)
+            sizer.Add(self, proportion=1, flag=wx.EXPAND)
+            parent.SetSizer(sizer)
+            parent.Layout()
+
         def _addLayer(self, name, ltype="raster"):
             """Add layer into map
 
@@ -208,7 +230,14 @@ def main():
         os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
 
     app = wx.App()
-    frame = RDigitMapFrame(**kwargs)
+    frame = wx.Frame(
+        None,
+        id=wx.ID_ANY,
+        size=(850, 600),
+        style=wx.DEFAULT_FRAME_STYLE,
+        title=_("Raster Digitizer - GRASS GIS"),
+    )
+    frame = RDigitMapDisplay(parent=frame, **kwargs)
     frame.Show()
 
     app.MainLoop()

+ 39 - 11
gui/wxpython/vdigit/g.gui.vdigit.py

@@ -52,7 +52,9 @@ def main():
     set_gui_path()
 
     from core.render import Map
-    from mapdisp.frame import MapFrame
+    from core.globalvar import ICONDIR
+    from mapdisp.frame import MapPanel
+    from gui_core.mapdisp import FrameMixin
     from mapdisp.main import DMonGrassInterface
     from core.settings import UserSettings
     from vdigit.main import haveVDigit, errorMsg
@@ -60,16 +62,29 @@ def main():
 
     # define classes which needs imports as local
     # for longer definitions, a separate file would be a better option
-    class VDigitMapFrame(MapFrame):
-        def __init__(self, vectorMap):
-            MapFrame.__init__(
-                self,
-                parent=None,
-                Map=Map(),
-                giface=DMonGrassInterface(None),
-                title=_("Vector Digitizer - GRASS GIS"),
-                size=(850, 600),
+    class VDigitMapDisplay(FrameMixin, MapPanel):
+        """Map display for wrapping map panel with v.digit mathods and frame methods"""
+
+        def __init__(self, parent, vectorMap):
+            MapPanel.__init__(
+                self, parent=parent, Map=Map(), giface=DMonGrassInterface(None)
+            )
+
+            # set system icon
+            parent.iconsize = (16, 16)
+            parent.SetIcon(
+                wx.Icon(os.path.join(ICONDIR, "grass_map.ico"), wx.BITMAP_TYPE_ICO)
+            )
+
+            # bindings
+            parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+            # extend shortcuts and create frame accelerator table
+            self.shortcuts_table.append(
+                (self.OnFullScreen, wx.ACCEL_NORMAL, wx.WXK_F11)
             )
+            self._initShortcuts()
+
             # this giface issue not solved yet, we must set mapframe aferwards
             self._giface._mapframe = self
             # load vector map
@@ -92,6 +107,12 @@ def main():
             self.toolbars["vdigit"].quitDigitizer.disconnect(self.QuitVDigit)
             self.toolbars["vdigit"].quitDigitizer.connect(lambda: self.Close())
 
+            # add Map Display panel to Map Display frame
+            sizer = wx.BoxSizer(wx.VERTICAL)
+            sizer.Add(self, proportion=1, flag=wx.EXPAND)
+            parent.SetSizer(sizer)
+            parent.Layout()
+
     if not haveVDigit:
         grass.fatal(_("Vector digitizer not available. %s") % errorMsg)
 
@@ -123,7 +144,14 @@ def main():
         os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
 
     app = wx.App()
-    frame = VDigitMapFrame(options["map"])
+    frame = wx.Frame(
+        None,
+        id=wx.ID_ANY,
+        size=(850, 600),
+        style=wx.DEFAULT_FRAME_STYLE,
+        title=_("Vector Digitizer - GRASS GIS"),
+    )
+    frame = VDigitMapDisplay(parent=frame, vectorMap=options["map"])
     frame.Show()
 
     app.MainLoop()

+ 1 - 1
gui/wxpython/vdigit/preferences.py

@@ -38,7 +38,7 @@ class VDigitSettingsDialog(wx.Dialog):
         wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
 
         self._giface = giface
-        self.parent = parent  # MapFrame
+        self.parent = parent  # MapPanel
         self.digit = self.parent.MapWindow.digit
 
         # notebook