From b9e393ef4e3e060eb456b5c3c6b3a583b5d1bc49 Mon Sep 17 00:00:00 2001 From: Linda Kladivova <49241681+lindakladivova@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:24:37 +0100 Subject: [PATCH] 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. --- doc/gui/wxpython/example/README | 10 +- doc/gui/wxpython/example/frame.py | 111 ++++--- doc/gui/wxpython/example/g.gui.example.py | 36 ++- gui/wxpython/gcp/manager.py | 79 ++++- gui/wxpython/gcp/mapdisplay.py | 10 +- gui/wxpython/gui_core/mapdisp.py | 158 +++++----- gui/wxpython/iclass/frame.py | 71 ++++- gui/wxpython/iclass/g.gui.iclass.py | 11 +- gui/wxpython/image2target/ii2t_manager.py | 77 ++++- gui/wxpython/image2target/ii2t_mapdisplay.py | 14 +- gui/wxpython/lmgr/frame.py | 300 +++++++++++-------- gui/wxpython/lmgr/layertree.py | 30 +- gui/wxpython/main_window/frame.py | 19 +- gui/wxpython/mapdisp/frame.py | 82 +++-- gui/wxpython/mapdisp/main.py | 91 ++++-- gui/wxpython/mapswipe/frame.py | 69 +++-- gui/wxpython/mapswipe/g.gui.mapswipe.py | 12 +- gui/wxpython/mapswipe/toolbars.py | 2 +- gui/wxpython/photo2image/ip2i_manager.py | 80 ++++- gui/wxpython/photo2image/ip2i_mapdisplay.py | 19 +- gui/wxpython/rdigit/g.gui.rdigit.py | 49 ++- gui/wxpython/vdigit/g.gui.vdigit.py | 50 +++- gui/wxpython/vdigit/preferences.py | 2 +- 23 files changed, 914 insertions(+), 468 deletions(-) diff --git a/doc/gui/wxpython/example/README b/doc/gui/wxpython/example/README index c5b21047140..ca55b0f5c9b 100644 --- a/doc/gui/wxpython/example/README +++ b/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. diff --git a/doc/gui/wxpython/example/frame.py b/doc/gui/wxpython/example/frame.py index 03b812ffe41..636497a101b 100644 --- a/doc/gui/wxpython/example/frame.py +++ b/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 @@ # 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 @@ # 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 @@ def __init__( 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 @@ def __init__( # 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 @@ def __init__( # # choose items in statusbar choice, which makes sense for your application - self.statusbarItems = [ + statusbarItems = [ sb.SbCoordinates, sb.SbRegionExtent, sb.SbCompRegionExtent, @@ -121,24 +122,7 @@ def __init__( 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 @@ def __init__( self.GetMapToolbar().SelectDefault() self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.SetSize(size) @@ -173,20 +156,10 @@ def __del__(self): 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 @@ def _addPanes(self): .Left(), ) + # statusbar + self.AddStatusbarPane() + def AddToolbar(self, name): """!Add defined toolbar to the window @@ -234,7 +210,8 @@ def AddToolbar(self, name): """ # 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 @@ def AddToolbar(self, name): ) 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 @@ def AddToolbar(self, name): ) 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 @@ def SetLayer(self, name): @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 @@ def UpdateStatistics(self): 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. diff --git a/doc/gui/wxpython/example/g.gui.example.py b/doc/gui/wxpython/example/g.gui.example.py index c73f397c1f5..9c04d659458 100644 --- a/doc/gui/wxpython/example/g.gui.example.py +++ b/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 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() diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 0ee93d297a5..762292c3e1c 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -9,7 +9,8 @@ - manager::LocationPage - manager::GroupPage - manager::DispMapPage - - manager::GCP + - manager::GCPPanel + - manager::GCPDisplay - manager::GCPList - manager::VectGroup - manager::EditGCP @@ -52,9 +53,10 @@ 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 @@ def __init__(self, parent, giface): # # 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 @@ def GetSelectTargetRasterExtraItems(self): 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 @@ def __init__( 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 @@ def __init__( 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 @@ def ReloadGCPs(self, event): 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 @@ def OnSize(self, event): """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 @@ def OnIdle(self, event): 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, diff --git a/gui/wxpython/gcp/mapdisplay.py b/gui/wxpython/gcp/mapdisplay.py index 6604ae1275c..e7596e5e984 100644 --- a/gui/wxpython/gcp/mapdisplay.py +++ b/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 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 @@ 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 @@ def __init__( :param kwargs: wx.Frame attribures """ - SingleMapFrame.__init__( + SingleMapPanel.__init__( self, parent=parent, giface=giface, @@ -220,7 +220,7 @@ def __init__( 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) diff --git a/gui/wxpython/gui_core/mapdisp.py b/gui/wxpython/gui_core/mapdisp.py index 5bd7c493028..a6cffe58500 100644 --- a/gui/wxpython/gui_core/mapdisp.py +++ b/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 @@ @author Anna Kratochvilova """ -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 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 @@ def __init__( parent=None, id=wx.ID_ANY, title="", - style=wx.DEFAULT_FRAME_STYLE, auimgr=None, name="", **kwargs, @@ -76,28 +73,15 @@ def __init__( :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 @@ def __init__( 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 @@ def _initMap(self, Map): % "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 @@ def OnSize(self, event): # 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 @@ def GetPPM(self): 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 @@ def GetMapScale(self, map=None): 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 @@ def GetMapScale(self, map=None): 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 @@ def GetToolbar(self, name): 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 @@ def OnZoomToDefault(self, event): 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 @@ def __init__( giface=None, id=wx.ID_ANY, title="", - style=wx.DEFAULT_FRAME_STYLE, Map=None, auimgr=None, name="", @@ -535,18 +509,16 @@ def __init__( :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 @@ def OnRender(self, event): 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 @@ def __init__( parent=None, id=wx.ID_ANY, title=None, - style=wx.DEFAULT_FRAME_STYLE, firstMap=None, secondMap=None, auimgr=None, @@ -622,17 +593,15 @@ def __init__( :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 @@ def ActivateSecondMap(self, event=None): 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 @@ def OnDraw(self, event): 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() diff --git a/gui/wxpython/iclass/frame.py b/gui/wxpython/iclass/frame.py index 789e1ba6fa6..7082b026fb0 100644 --- a/gui/wxpython/iclass/frame.py +++ b/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.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 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 @@ def __init__( """ :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 @@ def __init__( # 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 @@ def __init__( wx.CallAfter(self.AddTrainingAreaMap) - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.Bind(wx.EVT_SIZE, self.OnSize) self.SendSizeEvent() @@ -478,7 +479,7 @@ def _addPaneMapWindow(self, name, position): def OnUpdateActive(self, event): """ .. todo:: - move to DoubleMapFrame? + move to DoubleMapPanel? """ if self.GetMapToolbar().GetActiveMap() == 0: self.MapWindow = self.firstMapWindow @@ -495,7 +496,7 @@ def OnUpdateActive(self, event): def UpdateActive(self, win): """ .. todo:: - move to DoubleMapFrame? + move to DoubleMapPanel? """ mapTb = self.GetMapToolbar() # optionally disable tool zoomback tool @@ -506,13 +507,13 @@ def UpdateActive(self, win): 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 @@ def GetCurrentCategoryIdx(self): 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 @@ def GetMapManagers(self): 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 @@ def SetAlias(self, original, alias): 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() diff --git a/gui/wxpython/iclass/g.gui.iclass.py b/gui/wxpython/iclass/g.gui.iclass.py index fa51094b6aa..a452754bfb9 100755 --- a/gui/wxpython/iclass/g.gui.iclass.py +++ b/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: diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index d1c82997501..d99d47b1b71 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -9,7 +9,8 @@ - manager::LocationPage - manager::GroupPage - manager::DispMapPage - - manager::GCP + - manager::GCPPanel + - manager::GCPDisplay - manager::GCPList - manager::VectGroup - manager::EditGCP @@ -57,9 +58,10 @@ 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 @@ def __init__(self, parent, giface): # # 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 @@ def OnEnterPage(self, event=None): 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 @@ def __init__( 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 @@ def __init__( 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 @@ def ReloadGCPs(self, event): 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 @@ def OnSize(self, event): """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 @@ def OnIdle(self, event): 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, diff --git a/gui/wxpython/image2target/ii2t_mapdisplay.py b/gui/wxpython/image2target/ii2t_mapdisplay.py index 46f3be97d91..c8972242e82 100644 --- a/gui/wxpython/image2target/ii2t_mapdisplay.py +++ b/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 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 @@ 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 @@ def __init__( :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 @@ def __init__( 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) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index b202f188adb..f8c3d255ed1 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -64,7 +64,11 @@ 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 @@ def show_menu_errors(messages): # 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 @@ def _createPythonShell(self, parent): 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 @@ def OnPsMap(self, event=None, cmd=None): 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 @@ def OnIClass(self, event=None, cmd=None): 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 @@ def OnIClass(self, event=None, cmd=None): ) 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 @@ def OnShowAttributeTable(self, event, selection=None): # 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 diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index ca3e66b2f19..e2d18560064 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -36,7 +36,6 @@ 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 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 @@ def __init__( self, parent, giface, + createNewMapDisplay, id=wx.ID_ANY, style=wx.SUNKEN_BORDER, ctstyle=CT.TR_HAS_BUTTONS @@ -110,15 +109,11 @@ def __init__( 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 @@ def __init__( 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)) diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 23e2869970d..7df530c55b4 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -798,9 +798,15 @@ def OnPsMap(self, event=None, cmd=None): 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 @@ def OnIClass(self, event=None, cmd=None): 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 @@ def OnIClass(self, event=None, cmd=None): ) 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() diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index eeb685d7153..48fac59784e 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -7,7 +7,7 @@ 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 @@ @author Michael Barton @author Jachym Cepicky @author Martin Landa -@author Vaclav Petras (SingleMapFrame, handlers support) -@author Anna Kratochvilova (SingleMapFrame) +@author Vaclav Petras (SingleMapPanel, handlers support) +@author Anna Kratochvilova (SingleMapPanel) @author Stepan Turek (handlers support) """ @@ -36,7 +36,7 @@ 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 @@ 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 @@ def __init__( :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 @@ def __init__( # 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 @@ def __init__( # # Bind various events # - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.Bind(wx.EVT_SIZE, self.OnSize) # @@ -962,7 +961,7 @@ def PrintMenu(self, event): 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 @@ def OnCloseWindow(self, event, askIfSaveWorkspace=True): """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 @@ def OnZoomToMap(self, event): """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 @@ def QuitVDigit(self): """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() diff --git a/gui/wxpython/mapdisp/main.py b/gui/wxpython/mapdisp/main.py index a602e1d1c48..14f931a2967 100644 --- a/gui/wxpython/mapdisp/main.py +++ b/gui/wxpython/mapdisp/main.py @@ -7,8 +7,9 @@ - mapdisp::DMonMap - mapdisp::Layer - mapdisp::LayerList + - mapdisp::StandaloneMapDisplayGrassInterface - mapdisp::DMonGrassInterface - - mapdisp::DMonFrame + - mapdisp::DMonDisplay - mapdisp::MapApp Usage: @@ -22,8 +23,8 @@ @author Michael Barton @author Jachym Cepicky @author Martin Landa -@author Vaclav Petras (MapFrameBase) -@author Anna Kratochvilova (MapFrameBase) +@author Vaclav Petras (MapPanelBase) +@author Anna Kratochvilova (MapPanelBase) """ from __future__ import print_function @@ -52,7 +53,8 @@ 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 @@ def __init__(self, mapframe): 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 @@ def OnSize(self, event): 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 @@ def OnInit(self): return True - def CreateMapFrame(self, name, decorations=True): + def CreateMapDisplay(self, name, decorations=True): toolbars = [] if decorations: toolbars.append("map") @@ -511,24 +545,27 @@ def CreateMapFrame(self, name, decorations=True): 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 @@ def CreateMapFrame(self, name, decorations=True): ), ) - 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 @@ def watcher(self): 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 @@ def GetMapFrame(self): 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() diff --git a/gui/wxpython/mapswipe/frame.py b/gui/wxpython/mapswipe/frame.py index aaa4edc9428..a55cbcb2d37 100644 --- a/gui/wxpython/mapswipe/frame.py +++ b/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 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 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.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 @@ def __init__( secondMap=Map(), **kwargs, ) - Debug.msg(1, "SwipeMapFrame.__init__()") + Debug.msg(1, "SwipeMapPanel.__init__()") # # Add toolbars # @@ -119,7 +122,6 @@ def __init__( 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 @@ def TrackCursor(self, event): 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 @@ def InitSliderBindings(self): 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 @@ def OnSliderPositionChanging(self, event): 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 @@ def SetLayer(self, name, mapInstance): :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 @@ def SetLayer(self, name, mapInstance): 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 @@ def SaveToFile(self, event): 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 @@ def OnCloseWindow(self, event): 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""" diff --git a/gui/wxpython/mapswipe/g.gui.mapswipe.py b/gui/wxpython/mapswipe/g.gui.mapswipe.py index 76c17323438..c887be2548d 100755 --- a/gui/wxpython/mapswipe/g.gui.mapswipe.py +++ b/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) diff --git a/gui/wxpython/mapswipe/toolbars.py b/gui/wxpython/mapswipe/toolbars.py index 7882f252066..d425310f3e1 100644 --- a/gui/wxpython/mapswipe/toolbars.py +++ b/gui/wxpython/mapswipe/toolbars.py @@ -76,7 +76,7 @@ def _toolbarData(self): def SetActiveMap(self, index): """Set currently selected map. - Unused, needed because of DoubleMapFrame API. + Unused, needed because of DoubleMapPanel API. """ pass diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 677da10e3e0..e61f07a22aa 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -7,7 +7,8 @@ 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 @@ 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 @@ def __init__( # # 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 @@ def OnGLMFocus(self, event): 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 @@ def __init__( 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 @@ def __init__( 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 @@ def ReloadGCPs(self, event): 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 @@ def OnSize(self, event): """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 @@ def OnIdle(self, event): 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, diff --git a/gui/wxpython/photo2image/ip2i_mapdisplay.py b/gui/wxpython/photo2image/ip2i_mapdisplay.py index b25754e3f39..f512a635f5f 100644 --- a/gui/wxpython/photo2image/ip2i_mapdisplay.py +++ b/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 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 @@ 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 @@ def __init__( ): """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 @@ def __init__( :param kwargs: wx.Frame attribures """ - SingleMapFrame.__init__( + SingleMapPanel.__init__( self, parent=parent, giface=giface, @@ -224,7 +218,7 @@ def __init__( 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 @@ def _setUpMapWindow(self, mapWindow): def AddToolbar(self, name): """Add defined toolbar to the window - Currently known toolbars are: - 'map' - basic map toolbar - 'gcpdisp' - GCP Manager, Display diff --git a/gui/wxpython/rdigit/g.gui.rdigit.py b/gui/wxpython/rdigit/g.gui.rdigit.py index 9bc4aa15a3b..005def54636 100755 --- a/gui/wxpython/rdigit/g.gui.rdigit.py +++ b/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 __init__( 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 OnMapCreated(self, name, ltype): 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() diff --git a/gui/wxpython/vdigit/g.gui.vdigit.py b/gui/wxpython/vdigit/g.gui.vdigit.py index b114076f4cd..72ffe75585a 100644 --- a/gui/wxpython/vdigit/g.gui.vdigit.py +++ b/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 __init__(self, vectorMap): 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 __init__(self, vectorMap): 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() diff --git a/gui/wxpython/vdigit/preferences.py b/gui/wxpython/vdigit/preferences.py index 3bc731aac82..39ec892e3cf 100644 --- a/gui/wxpython/vdigit/preferences.py +++ b/gui/wxpython/vdigit/preferences.py @@ -38,7 +38,7 @@ def __init__( 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