Browse Source

wxGUI: Single-Window GUI: Integrate new map display wx.Panels into a AuiNotebook center pane #1735 (#1732)

Linda Kladivova 3 years ago
parent
commit
0537933d1c
1 changed files with 190 additions and 144 deletions
  1. 190 144
      gui/wxpython/main_window/frame.py

+ 190 - 144
gui/wxpython/main_window/frame.py

@@ -69,7 +69,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 MapPanel
 from datacatalog.catalog import DataCatalog
 from gui_core.forms import GUI
 from gui_core.wrap import Menu, TextEntryDialog
@@ -151,8 +155,8 @@ class GMFrame(wx.Frame):
 
         # set pane sizes according to the full screen size of the primary monitor
         size = wx.Display().GetGeometry().GetSize()
-        self.PANE_BEST_SIZE = tuple(t / 5 for t in size)
-        self.PANE_MIN_SIZE = tuple(t / 10 for t in size)
+        self.PANE_BEST_SIZE = tuple(t / 3 for t in size)
+        self.PANE_MIN_SIZE = tuple(t / 7 for t in size)
 
         # create widgets and build panes
         self.CreateMenuBar()
@@ -290,6 +294,22 @@ class GMFrame(wx.Frame):
             return self._auimgr.GetPane(name).IsShown()
         return False
 
+    def _createMapNotebook(self):
+        """Create Map Display notebook"""
+        # create the notebook off-window to avoid flicker
+        client_size = self.GetClientSize()
+        notebook_style = (
+            aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
+        )
+        self.mapnotebook = aui.AuiNotebook(
+            self,
+            -1,
+            wx.Point(client_size.x, client_size.y),
+            wx.Size(430, 200),
+            agwStyle=notebook_style,
+        )
+        self.mapnotebook.SetArtProvider(aui.AuiDefaultTabArt())
+
     def _createDataCatalog(self, parent):
         """Initialize Data Catalog widget"""
         self.datacatalog = DataCatalog(parent=parent, giface=self._giface)
@@ -360,21 +380,152 @@ class GMFrame(wx.Frame):
         else:
             self.pyshell = None
 
-    def _createMapDisplay(self, parent):
-        """Set up Map Display"""
-        # blank panel for testing
-        self.mapdisplay = wx.Panel(parent=parent)
+    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
+        )
+        self.notebookLayers.AddPage(page=self.pg_panel, text=name, select=True)
+        self.currentPage = self.notebookLayers.GetCurrentPage()
+        self.currentPageNum = self.notebookLayers.GetSelection()
+
+        def CreateNewMapDisplay(layertree):
+            """Callback function which creates a new Map Display window
+            :param layertree: layer tree object
+            :return: reference to mapdisplay instance
+            """
+            # create instance of Map Display interface
+            self._gifaceForDisplay = LayerManagerGrassInterfaceForMapDisplay(
+                self._giface, layertree
+            )
+
+            # create Map Display
+            mapdisplay = MapPanel(
+                parent=self.mapnotebook,
+                giface=self._gifaceForDisplay,
+                id=wx.ID_ANY,
+                tree=layertree,
+                lmgr=self,
+                Map=layertree.Map,
+                title=name,
+                size=globalvar.MAP_WINDOW_SIZE,
+            )
+            # add map display panel to notebook and make it current
+            self.mapnotebook.AddPage(mapdisplay, name)
+            self.mapnotebook.SetSelection(self.currentPageNum)
+
+            # set map display properties
+            self._setUpMapDisplay(mapdisplay)
+
+            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(self.GetLayerTree(), proportion=1, flag=wx.EXPAND, border=1)
+        self.currentPage.SetSizer(cb_boxsizer)
+        cb_boxsizer.Fit(self.GetLayerTree())
+        self.currentPage.Layout()
+        self.GetLayerTree().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.Bind(
+            wx.EVT_ACTIVATE,
+            lambda event, page=self.currentPage: self._onMapDisplayFocus(page),
+        )
+
+        mapdisplay.starting3dMode.connect(
+            lambda firstTime, mapDisplayPage=self.currentPage: self._onStarting3dMode(
+                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 BuildPanes(self):
         """Build panes - toolbars as well as panels"""
 
         # initialize all main widgets
+        self._createMapNotebook()
         self._createDataCatalog(parent=self)
         self._createDisplay(parent=self)
         self._createSearchModule(parent=self)
         self._createConsole(parent=self)
         self._createPythonShell(parent=self)
-        self._createMapDisplay(parent=self)
         self.toolbars = {
             "workspace": LMWorkspaceToolbar(parent=self),
             "tools": LMToolsToolbar(parent=self),
@@ -416,8 +567,8 @@ class GMFrame(wx.Frame):
             )
 
         self._auimgr.AddPane(
-            self.mapdisplay,
-            aui.AuiPaneInfo().Name("map display").CenterPane().PaneBorder(True),
+            self.mapnotebook,
+            aui.AuiPaneInfo().Name("map display content").CenterPane().PaneBorder(True),
         )
 
         self._auimgr.AddPane(
@@ -552,17 +703,28 @@ class GMFrame(wx.Frame):
             ("toolbarWorkspace", "toolbarTools", "toolbarMisc", "toolbarNviz")
         ):
             self._auimgr.GetPane(toolbar).Row(1).Position(pos)
-        self._auimgr.Update()
 
         # create nviz tools tab
         self.nviz = NvizToolWindow(
-            parent=self.notebook, tree=self.GetLayerTree(), display=self.GetMapDisplay()
+            parent=self, tree=self.GetLayerTree(), display=self.GetMapDisplay()
         )
-        idx = self.notebook.GetPageIndexByName("layers")
-        self.notebook.InsertNBPage(
-            index=idx + 1, page=self.nviz, text=_("3D view"), name="nviz"
+        self._auimgr.AddPane(
+            self.nviz,
+            aui.AuiPaneInfo()
+            .Name("nviz")
+            .Caption("3D view")
+            .Left()
+            .Layer(1)
+            .Position(3)
+            .BestSize(self.PANE_BEST_SIZE)
+            .MinSize(self.PANE_MIN_SIZE)
+            .CloseButton(False)
+            .MinimizeButton(True)
+            .MaximizeButton(True),
         )
-        self.notebook.SetSelectionByName("nviz")
+
+        self._auimgr.GetPane("nviz").Show()
+        self._auimgr.Update()
 
         # this is a bit strange here since a new window is created everytime
         if not firstTime:
@@ -573,8 +735,6 @@ class GMFrame(wx.Frame):
         """Remove nviz notebook page"""
         # if more mapwindow3D were possible, check here if nb page should be
         # removed
-        self.notebook.SetSelectionByName("layers")
-        self.notebook.DeleteNBPage("nviz")
 
         # hide toolbar
         self._auimgr.GetPane("toolbarNviz").Hide()
@@ -582,6 +742,8 @@ class GMFrame(wx.Frame):
             ("toolbarWorkspace", "toolbarTools", "toolbarMisc")
         ):
             self._auimgr.GetPane(toolbar).Row(1).Position(pos)
+        self._auimgr.DetachPane(self.nviz)
+        self.nviz.Destroy()
         self._auimgr.Update()
 
     def OnLocationWizard(self, event):
@@ -723,8 +885,7 @@ class GMFrame(wx.Frame):
         self.currentPage = self.notebookLayers.GetCurrentPage()
         self.currentPageNum = self.notebookLayers.GetSelection()
         try:
-            self.GetMapDisplay().SetFocus()
-            self.GetMapDisplay().Raise()
+            self.mapnotebook.SetSelection(self.GetMapDisplayIndex())
         except Exception:
             pass
 
@@ -744,6 +905,7 @@ class GMFrame(wx.Frame):
 
         maptree = self.notebookLayers.GetPage(event.GetSelection()).maptree
         maptree.GetMapDisplay().CleanUp()
+        self.mapnotebook.DeletePage(self.GetMapDisplayIndex())
         maptree.Close(True)
 
         self.currentPage = None
@@ -756,6 +918,7 @@ class GMFrame(wx.Frame):
         self.notebookLayers.Unbind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING)
         self.notebookLayers.DeletePage(page_index)
         self.notebookLayers.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.OnCBPageClosing)
+        self.mapnotebook.DeletePage(page_index)
 
     def RunSpecialCmd(self, command):
         """Run command from command line, check for GUI wrappers"""
@@ -884,7 +1047,7 @@ class GMFrame(wx.Frame):
         :param bool onlyCurrent: True to return only active mapdisplay
                                  False for list of all mapdisplays
 
-        :return: MapFrame instance (or list)
+        :return: MapPanel instance (or list)
         :return: None no mapdisplay selected
         """
         if onlyCurrent:
@@ -903,6 +1066,11 @@ class GMFrame(wx.Frame):
         """Get all (open) map displays"""
         return self.GetMapDisplay(onlyCurrent=False)
 
+    def GetMapDisplayIndex(self):
+        """Get the index of the currently active map display tab.
+        Can be different than index of related layertree."""
+        return self.mapnotebook.GetPageIndex(self.GetMapDisplay())
+
     def GetLogWindow(self):
         """Gets console for command output and messages"""
         return self._gconsole
@@ -1404,8 +1572,7 @@ class GMFrame(wx.Frame):
         if dlg.ShowModal() == wx.ID_OK:
             name = dlg.GetValue()
             self.notebookLayers.SetPageText(page=self.currentPageNum, text=name)
-            mapdisplay = self.GetMapDisplay()
-            mapdisplay.SetTitle(name)
+            self.mapnotebook.SetPageText(page_idx=self.GetMapDisplayIndex(), text=name)
         dlg.Destroy()
 
     def OnRasterRules(self, event):
@@ -1697,109 +1864,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)
-        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(self.GetLayerTree(), proportion=1, flag=wx.EXPAND, border=1)
-        self.currentPage.SetSizer(cb_boxsizer)
-        cb_boxsizer.Fit(self.GetLayerTree())
-        self.currentPage.Layout()
-        self.GetLayerTree().Layout()
-
-        mapdisplay = self.currentPage.maptree.mapdisplay
-        mapdisplay.Bind(
-            wx.EVT_ACTIVATE,
-            lambda event, page=self.currentPage: self._onMapDisplayFocus(page),
-        )
-        mapdisplay.starting3dMode.connect(
-            lambda firstTime, mapDisplayPage=self.currentPage: self._onStarting3dMode(
-                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 Exception:
-                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
@@ -1937,9 +2001,6 @@ class GMFrame(wx.Frame):
             )
         )
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnAddVector(self, event):
         """Add vector map to the current layer tree"""
         # start new map display if no display is available
@@ -1961,9 +2022,6 @@ class GMFrame(wx.Frame):
             )
         )
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnAddVectorTheme(self, event):
         """Add thematic vector map to the current layer tree"""
         self.GetLayerTree().AddLayer("thememap")
@@ -1989,9 +2047,6 @@ class GMFrame(wx.Frame):
             )
         )
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnAddRaster3D(self, event):
         """Add 3D raster map to the current layer tree"""
         self.GetLayerTree().AddLayer("raster_3d")
@@ -2049,9 +2104,6 @@ class GMFrame(wx.Frame):
 
         self.GetLayerTree().AddLayer("command")
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnAddGroup(self, event):
         """Add layer group"""
         # start new map display if no display is available
@@ -2060,9 +2112,6 @@ class GMFrame(wx.Frame):
 
         self.GetLayerTree().AddLayer("group")
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnAddGrid(self, event):
         """Add grid map layer to the current layer tree"""
         self.GetLayerTree().AddLayer("grid")
@@ -2083,9 +2132,6 @@ class GMFrame(wx.Frame):
 
         self.GetLayerTree().AddLayer("labels")
 
-        # show map display
-        self.GetMapDisplay().Show()
-
     def OnShowRegionExtent(self, event):
         """Add vector labels map layer to the current layer tree"""
         # start new map display if no display is available