123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- """!
- @package example.frame
- @brief Example tool for displaying raster map and related information
- Classes:
- - frame::ExampleMapFrame
- - frame::ExampleInfoTextManager
- (C) 2011-2014 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 Anna Petrasova <kratochanna gmail.com>
- """
- import os
- import sys
- import wx
- # this enables to run application standalone (> python example/frame.py )
- if __name__ == "__main__":
- sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
- # i18n is taken care of in the grass library code.
- # 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 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 toolbars import ExampleMapToolbar, ExampleMiscToolbar, ExampleMainToolbar
- from 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
- # are used in nviz, vdigit, iclass gui modules.
- # from ctypes import *
- # try:
- # from grass.lib.raster import *
- # haveExample = True
- # errMsg = ''
- # except ImportError as e:
- # haveExample = False
- # errMsg = _("Loading raster lib failed.\n%s") % e
- class ExampleMapFrame(SingleMapFrame):
- """! Main frame 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).
- @see IClassMapFrame in iclass.frame
- """
- def __init__(self, parent, giface, title=_("Example Tool"),
- toolbars=["MiscToolbar", "MapToolbar", "MainToolbar"],
- size=(800, 600), name='exampleWindow', **kwargs):
- """!Map Frame 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__(self, parent=parent, title=title,
- name=name, Map=Map(), **kwargs)
- # Place debug message where appropriate
- # 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__()")
- #
- # Add toolbars to aui manager
- #
- toolbarsCopy = toolbars[:]
- # workaround to have the same toolbar order on all platforms
- if sys.platform == 'win32':
- toolbarsCopy.reverse()
- for toolbar in toolbarsCopy:
- self.AddToolbar(toolbar)
- self.mapWindowProperties = MapWindowProperties()
- self.mapWindowProperties.setValuesFromUserSettings()
- self.mapWindowProperties.autoRenderChanged.connect(
- lambda value: self.OnRender(None) if value else None)
- #
- # Add statusbar
- #
- # choose items in statusbar choice, which makes sense for your application
- self.statusbarItems = [sb.SbCoordinates,
- sb.SbRegionExtent,
- sb.SbCompRegionExtent,
- sb.SbShowRegion,
- sb.SbAlignExtent,
- sb.SbResolution,
- sb.SbDisplayGeometry,
- sb.SbMapScale,
- 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()
- # create map window
- self.MapWindow = BufferedMapWindow(parent=self, Map=self.GetMap(),
- properties=self.mapWindowProperties, giface=self)
- self._setUpMapWindow(self.MapWindow)
- self.MapWindow.InitZoomHistory()
- # create whatever you want, here it is a widget for displaying raster info
- self.info = ExampleInfoTextManager(self)
- # add map window (and other widgets) to aui manager
- self._addPanes()
- self._mgr.Update()
- # initialize variables related to your application functionality
- self.InitVariables()
- # default action
- self.GetMapToolbar().SelectDefault()
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
- self.SetSize(size)
- def __del__(self):
- """!Destructor deletes temporary region"""
- gcore.del_temp_region()
- def OnCloseWindow(self, event):
- """!Destroy frame"""
- 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
- self.statitistics = dict()
- # use WIND_OVERRIDE region not to affect current region
- gcore.use_temp_region()
- def _addPanes(self):
- """!Add mapwindow (and other widgets) to aui manager"""
- window = self.GetWindow()
- name = "mainWindow"
- self._mgr.AddPane(window, wx.aui.AuiPaneInfo().
- Name(name).CentrePane().
- Dockable(False).CloseButton(False).DestroyOnClose(True).
- Layer(0))
- window = self.info.GetControl()
- name = "infoText"
- self._mgr.AddPane(window, wx.aui.AuiPaneInfo().
- Name(name).Caption(_("Raster Info")).MinSize((250, -1)).
- Dockable(True).CloseButton(False).
- Layer(0).Left())
- def AddToolbar(self, name):
- """!Add defined toolbar to the window
- Currently known toolbars are:
- - 'ExampleMapToolbar' - basic map toolbar
- - 'ExampleMainToolbar' - toolbar with application specific tools
- - 'ExampleMiscToolbar' - toolbar with common tools (help, quit, ...)
- """
- # see wx.aui.AuiPaneInfo documentation for understanding all options
- if name == "MapToolbar":
- self.toolbars[name] = ExampleMapToolbar(self, self._toolSwitcher)
- self._mgr.AddPane(self.toolbars[name],
- wx.aui.AuiPaneInfo().
- Name(name).Caption(_("Map Toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(1).Row(1).
- BestSize((self.toolbars[name].GetBestSize())))
- if name == "MiscToolbar":
- self.toolbars[name] = ExampleMiscToolbar(self)
- self._mgr.AddPane(self.toolbars[name],
- wx.aui.AuiPaneInfo().
- Name(name).Caption(_("Misc Toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(1).Row(1).
- BestSize((self.toolbars[name].GetBestSize())))
- if name == "MainToolbar":
- self.toolbars[name] = ExampleMainToolbar(self)
- self._mgr.AddPane(self.toolbars[name],
- wx.aui.AuiPaneInfo().
- Name(name).Caption(_("Main Toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(1).Row(1).
- BestSize((self.toolbars[name].GetBestSize())))
- def GetMapToolbar(self):
- """!Returns toolbar with zooming tools"""
- return self.toolbars['MapToolbar']
- def OnHelp(self, event):
- """!Show help page"""
- RunCommand('g.manual', entry='wxGUI.Example')
- def OnSelectRaster(self, event):
- """!Opens dialog to select raster map"""
- dlg = ExampleMapDialog(self)
- if dlg.ShowModal() == wx.ID_OK:
- raster = gcore.find_file(name=dlg.GetRasterMap(), element='cell')
- if raster['fullname']:
- self.SetLayer(name=raster['fullname'])
- else:
- # show user that the map name is incorrect
- GError(parent=self,
- message=_("Raster map <{raster}> not found").format(raster=dlg.GetRasterMap()))
- dlg.Destroy()
- def SetLayer(self, name):
- """!Sets layer in Map and updates statistics.
- @param name layer (raster) name
- """
- Debug.msg (3, "ExampleMapFrame.SetLayer(): name=%s" % name)
- # this simple application enables to keep only one raster
- self.GetMap().DeleteAllLayers()
- cmdlist = ['d.rast', 'map=%s' % name]
- # add layer to Map instance (core.render)
- newLayer = self.GetMap().AddLayer(ltype='raster', command=cmdlist, active=True,
- name=name, hidden=False, opacity=1.0,
- render=True)
- self.GetWindow().ZoomToMap(layers=[newLayer, ], render=True)
- self.currentRaster = name
- # change comp. region to match new raster, so that the statistics
- # are computed for the entire raster
- RunCommand('g.region',
- rast=self.currentRaster,
- parent=self)
- self.UpdateStatistics()
- def ComputeStatitistics(self):
- """!Computes statistics for raster map using 'r.univar' module.
- @return statistic in form of dictionary
- """
- # RunCommand enables to run GRASS module
- res = RunCommand('r.univar', # module name
- flags='g', # command flags
- map=self.currentRaster, # module parameters
- read=True) # get command output
- return gcore.parse_key_val(res, val_type=float)
- def UpdateStatistics(self):
- """!Upadate statistic information.
- Called after changing raster map.
- """
- stats = self.ComputeStatitistics()
- self.info.WriteStatistics(name=self.currentRaster, statDict=stats)
- class ExampleInfoTextManager:
- """!Class for displaying information.
- Wrraper for wx.TextCtrl.
- """
- def __init__(self, parent):
- """!Creates wx.TextCtrl for displaying information.
- """
- self.textCtrl = wx.TextCtrl(parent, id=wx.ID_ANY,
- style=wx.TE_MULTILINE | wx.TE_RICH2 | wx.TE_READONLY)
- self.textCtrl.SetInsertionPoint(0)
- self.font = self.textCtrl.GetFont()
- def GetControl(self):
- """!Returns control itself."""
- return self.textCtrl
- def _setStyle(self, style):
- """!Sets default style of textCtrl.
- @param style "title"/"value"
- """
- if style == "title":
- self.font.SetWeight(wx.FONTWEIGHT_BOLD)
- elif style == "value":
- self.font.SetWeight(wx.FONTWEIGHT_NORMAL)
- else:
- return
- self.textCtrl.SetDefaultStyle(wx.TextAttr(font=self.font))
- def _writeLine(self, title, value):
- """!Formats text (key, value pair) with styles."""
- self._setStyle("title")
- self.textCtrl.AppendText("%s: " % title)
- self._setStyle("value")
- self.textCtrl.AppendText("%.2f\n" % value)
- def _writeRasterTitle(self, name):
- """!Writes title."""
- self._setStyle("title")
- self.textCtrl.AppendText("%s\n\n" % name)
- def WriteStatistics(self, name, statDict):
- """!Write and format information about raster map
- @param name raster map name
- @param statDict dictionary containing information
- """
- self.GetControl().Clear()
- self._writeRasterTitle(name=name)
- for key, value in statDict.iteritems():
- self._writeLine(title=key, value=value)
|