[GRASS-SVN] r58197 - in grass/trunk/gui: icons/grass wxpython/core wxpython/gui_core wxpython/mapswipe
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Nov 11 14:39:36 PST 2013
Author: annakrat
Date: 2013-11-11 14:39:35 -0800 (Mon, 11 Nov 2013)
New Revision: 58197
Added:
grass/trunk/gui/icons/grass/layer-down.png
grass/trunk/gui/icons/grass/layer-edit.png
grass/trunk/gui/icons/grass/layer-up.png
grass/trunk/gui/wxpython/core/layerlist.py
grass/trunk/gui/wxpython/gui_core/simplelmgr.py
Modified:
grass/trunk/gui/wxpython/gui_core/forms.py
grass/trunk/gui/wxpython/mapswipe/dialogs.py
grass/trunk/gui/wxpython/mapswipe/frame.py
grass/trunk/gui/wxpython/mapswipe/toolbars.py
Log:
wxGUI/mapswipe: added possibility to display multiple raster/vector maps; reusable SimpleLayerManager created
Added: grass/trunk/gui/icons/grass/layer-down.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/icons/grass/layer-down.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/trunk/gui/icons/grass/layer-edit.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/icons/grass/layer-edit.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/trunk/gui/icons/grass/layer-up.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/icons/grass/layer-up.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/trunk/gui/wxpython/core/layerlist.py
===================================================================
--- grass/trunk/gui/wxpython/core/layerlist.py (rev 0)
+++ grass/trunk/gui/wxpython/core/layerlist.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -0,0 +1,371 @@
+# -*- coding: utf-8 -*-
+"""!
+ at package core.layerlist
+
+ at brief Non GUI classes for layer management (so far used for class simplelmgr only)
+
+Classes:
+ - layerlist::LayerList
+ - layerlist::Layer
+ - layerlist::LayerListToRendererConverter
+
+(C) 2013 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.
+
+ at author Anna Petrasova (kratochanna gmail.com)
+"""
+
+from grass.script import core as gcore
+
+
+class LayerList(object):
+ """!Non GUI class managing list of layers.
+
+ It provides API for handling layers. In the future,
+ a non GUI class (e.g. named LayerTree) which includes this API,
+ should be used for Layer Manager.
+ """
+ def __init__(self):
+ self._list = []
+
+ def GetSelectedLayers(self, activeOnly=True):
+ """!Returns list of selected layers.
+
+ @param activeOnly return only active layers
+ """
+ layers = []
+ for layer in self._list:
+ if layer.IsSelected():
+ if activeOnly and layer.IsActive():
+ layers.append(layer)
+ else:
+ layers.append(layer)
+ return layers
+
+ def GetSelectedLayer(self, activeOnly=False):
+ """!Returns selected layer or None when there is no selected layer.
+
+ @param activeOnly return only active layers
+ """
+ layers = self.GetSelectedLayers(activeOnly)
+ if layers:
+ return layers[0]
+ return None
+
+ def GetActiveLayers(self):
+ """!Returns list of active layers."""
+ return [layer for layer in self._list if layer.IsActive()]
+
+ def GetLayersByTypes(self, mapTypes):
+ """!Returns layers by types.
+
+ @param mapTypes list of types
+ """
+ layers = []
+ for layer in self._list:
+ if layer.mapType in mapTypes:
+ layers.append(layer)
+ return layers
+
+ def AddNewLayer(self, name, mapType, cmd, active=True, hidden=False,
+ opacity=100, label=None, pos=0):
+ """!Creates new layer and adds it to the list (insert to the first position).
+
+ @param ltype layer type (raster, vector, 3d-raster, ...)
+ @param cmd command (given as a list)
+ @param active if True layer is active
+ @param hidden if True layer is hidden
+ @param opacity layer opacity level (0 - 100)
+ @param name layer name (set automatically from cmd)
+ @param label layer label (set automatically from name)
+ @param pos add layer to position
+ """
+ layer = Layer()
+ layer.hidden = hidden
+ layer.mapType = mapType
+ layer.cmd = cmd
+ layer.active = active
+ layer.opacity = opacity
+ layer.name = name
+ if label:
+ layer.label = label
+
+ self._list.insert(pos, layer)
+ return layer
+
+ def AddLayer(self, layer):
+ """!Adds a layer to the layer list.
+ """
+ self._list.insert(0, layer)
+
+ def InsertLayer(self, index, layer):
+ """!Adds a layer to the layer list.
+ """
+ self._list.insert(index, layer)
+
+ def RemoveLayer(self, layer):
+ """!Removes layer."""
+ self._list.remove(layer)
+
+ def GetLayerByData(self, key, value):
+ """!Returns layer with specified.
+
+ @note Returns only one layer. This might change.
+
+ @warning Avoid using this method, it might be removed in the future.
+ """
+ raise NotImplementedError()
+
+ def GetLayerIndex(self, layer):
+ """!Get index of layer."""
+ return self._list.index(layer)
+
+ def MoveLayerUp(self, layer):
+ """!Moves layer up (1 step)."""
+ idx = self._list.index(layer)
+ if idx > 0:
+ lr = self._list.pop(idx)
+ self._list.insert(idx - 1, lr)
+
+ def MoveLayerDown(self, layer):
+ """!Moves layer down (1 step)."""
+ idx = self._list.index(layer)
+ if idx < len(self._list) - 1:
+ lr = self._list.pop(idx)
+ self._list.insert(idx + 1, lr)
+
+ def __iter__(self):
+ for layer in self._list:
+ yield layer
+
+ def __getitem__(self, index):
+ return self._list[index]
+
+ def __len__(self):
+ return len(self._list)
+
+ def __str__(self):
+ text = ''
+ for layer in self._list:
+ text += str(layer.name) + '\n'
+ return text
+
+
+class Layer(object):
+ """!Object representing layer.
+
+ Properties of the object are checked during setting.
+ Map types can be extended if needed.
+
+ >>> layer = Layer()
+ >>> layer.selected = True
+ >>> layer.IsSelected()
+ True
+ >>> layer.opacity = 0.1
+ Traceback (most recent call last):
+ ...
+ ValueError: Opacity must be an integer between 0 and 100, not 0.1.
+ >>> layer.name = 'blablabla'
+ Traceback (most recent call last):
+ ...
+ ValueError: To set layer name, the type of layer must be specified.
+ >>> layer.mapType = 'rast'
+ >>> layer.name = 'blablabla'
+ Traceback (most recent call last):
+ ...
+ ValueError: Map <blablabla> not found.
+ """
+ def __init__(self):
+ self._mapType = None
+ self._name = None
+ self._label = None
+ self._cmd = None
+ self._opacity = 1
+
+ self._selected = False
+ self._active = True
+ self._hidden = False
+ self._initialized = False
+
+ self._mapTypes = ['rast', 'vect', 'rast3d']
+ self._internalTypes = {'rast': 'cell',
+ 'vect': 'vect',
+ 'rast3d': 'grid3'}
+
+ def GetName(self):
+ return self._name
+
+ def SetName(self, name):
+ """!Sets name of the layer.
+
+ It checks the name of the layer by g.findfile
+ (raises ValueError if map does not exist).
+ Therefore map type has to be set first.
+ """
+ if not self.hidden:
+ fullName = name.split('@')
+ if len(fullName) == 1:
+ if self._mapType is None:
+ raise ValueError("To set layer name, the type of layer must be specified.")
+
+ res = gcore.find_file(name=fullName,
+ element=self._internalTypes[self._mapType])
+ if not res['mapset']:
+ raise ValueError("Map <{name}> not found.".format(name=name))
+ self._name = name + '@' + res['mapset']
+ else:
+ self._name = name
+ self.label = name
+
+ name = property(fget=GetName, fset=SetName)
+
+ def GetLabel(self):
+ return self._label
+
+ def SetLabel(self, label):
+ self._label = label
+
+ label = property(fget=GetLabel, fset=SetLabel)
+
+ def GetCmd(self):
+ return self._cmd
+
+ def SetCmd(self, cmd):
+ self._cmd = cmd
+
+ cmd = property(fget=GetCmd, fset=SetCmd)
+
+ def GetMapType(self):
+ return self._mapType
+
+ def SetMapType(self, mapType):
+ """!Sets map type of the layer.
+
+ @param mapType can be 'rast', 'vect', 'rast3'
+ """
+ if mapType not in self._mapTypes:
+ raise ValueError("Wrong map type used: {mtype}".format(mtype=mapType))
+
+ self._mapType = mapType
+
+ mapType = property(fget=GetMapType, fset=SetMapType)
+
+ def GetOpacity(self):
+ """!Returns opacity value.
+
+ @return opacity as integer between 0 and 100
+ """
+ return int(self._opacity * 100)
+
+ def SetOpacity(self, opacity):
+ """!Sets opacity of the layer.
+
+ @param opacity integer between 0 and 100
+ """
+ if not (0 <= opacity <= 100) or opacity != int(opacity):
+ raise ValueError("Opacity must be an integer between 0 and 100, not {op}.".format(op=opacity))
+ self._opacity = opacity / 100.
+
+ opacity = property(fget=GetOpacity, fset=SetOpacity)
+
+ def Select(self, select=True):
+ self._selected = select
+
+ def IsSelected(self):
+ return self._selected
+
+ selected = property(fget=IsSelected, fset=Select)
+
+ def IsActive(self):
+ return self._active
+
+ def Activate(self, active=True):
+ """!Sets if layer is active (checked)."""
+ self._active = active
+
+ active = property(fget=IsActive, fset=Activate)
+
+ def IsHidden(self):
+ return self._hidden
+
+ def Hide(self, hide=True):
+ """!Sets if layer is hidden."""
+ self._hidden = hide
+
+ hidden = property(fget=IsHidden, fset=Hide)
+
+
+class LayerListToRendererConverter:
+ """!Help class for converting LayerList layers into renderer list (Map)"""
+ def __init__(self, renderer):
+ """!
+
+ @param layerList instance of LayerList
+ @param renderer instance of Map
+ """
+ self._renderer = renderer
+
+ def _getRendererLayer(self, index):
+ """!Returns corresponding layer of renderer."""
+ rLayers = self._renderer.GetListOfLayers()
+ index = len(rLayers) - index - 1
+ return rLayers[index]
+
+ def ConvertAll(self, layerList):
+ """!Removes all layers in Map and adds new layers form layerList.
+ It's not meant for continuous update because everything is rerendered.
+ """
+ self._renderer.DeleteAllLayers()
+ for layer in reversed(layerList):
+ self.AddLayer(index=-1, layer=layer)
+
+ def ChangeLayerOpacity(self, index, layer):
+ """!Changes layer opacity in renderer."""
+ rLayer = self._getRendererLayer(index)
+ self._renderer.ChangeLayer(rLayer, opacity=layer.opacity / 100.)
+
+ def ChangeLayerCmd(self, index, layer):
+ """!Changes layer cmd in renderer."""
+ rLayer = self._getRendererLayer(index)
+ self._renderer.ChangeLayer(rLayer, command=layer.cmd)
+
+ def ChangeLayerActive(self, index, layer):
+ """!Changes layer active state in renderer."""
+ rLayer = self._getRendererLayer(index)
+ self._renderer.ChangeLayer(rLayer, active=layer.active)
+
+ def MoveLayerUp(self, index):
+ """!Moves layer up in renderer."""
+ rLayers = self._renderer.GetListOfLayers()
+ index = len(rLayers) - index - 1
+ rLayer = rLayers.pop(index)
+ rLayers.insert(index + 1, rLayer)
+ self._renderer.SetLayers(rLayers)
+
+ def MoveLayerDown(self, index):
+ """!Moves layer down in renderer."""
+ rLayers = self._renderer.GetListOfLayers()
+ index = len(rLayers) - index - 1
+ rLayer = rLayers.pop(index)
+ rLayers.insert(index - 1, rLayer)
+ self._renderer.SetLayers(rLayers)
+
+ def AddLayer(self, index, layer):
+ """!Adds layer to renderer (prepends)."""
+ mapType = None
+ if layer.mapType == 'rast':
+ mapType = 'raster'
+ elif layer.mapType == 'vect':
+ mapType = 'vector'
+ elif layer.mapType == 'rast3d':
+ mapType = '3d-raster'
+ self._renderer.AddLayer(ltype=mapType, command=layer.cmd,
+ name=layer.name, active=layer.active,
+ hidden=False, opacity=layer.opacity / 100.,
+ render=True, pos=-1)
+
+ def RemoveLayer(self, index):
+ """!Removes layer from renderer."""
+ self._renderer.DeleteLayer(self._getRendererLayer(index))
Property changes on: grass/trunk/gui/wxpython/core/layerlist.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py 2013-11-11 22:23:51 UTC (rev 58196)
+++ grass/trunk/gui/wxpython/gui_core/forms.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -751,7 +751,7 @@
self.dialogClosing.emit()
if self.get_dcmd and \
self.parent and \
- self.parent.GetName() in ('LayerTree',
+ self.parent.GetName() in ('LayerTree', 'SimpleLayerManager',
'MapWindow'):
# display decorations and
# pressing OK or cancel after setting layer properties
Added: grass/trunk/gui/wxpython/gui_core/simplelmgr.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/simplelmgr.py (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/simplelmgr.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -0,0 +1,422 @@
+# -*- coding: utf-8 -*-
+"""!
+ at package gui_core.simplelmgr
+
+ at brief GUI class for simple layer management.
+
+Classes:
+ - simplelmgr::SimpleLayerManager
+ - simplelmgr::SimpleLmgrToolbar
+
+(C) 2013 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.
+
+ at author Anna Petrasova (kratochanna gmail.com)
+"""
+import os
+import sys
+
+# adding a path to wxGUI modules
+if __name__ == '__main__':
+ WXGUIBASE = os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython')
+ if WXGUIBASE not in sys.path:
+ sys.path.append(WXGUIBASE)
+import wx
+import wx.aui
+
+from grass.pydispatch.signal import Signal
+
+from gui_core.toolbars import BaseToolbar, BaseIcons
+from icons.icon import MetaIcon
+from gui_core.forms import GUI
+from gui_core.dialogs import SetOpacityDialog
+from core.utils import GetLayerNameFromCmd
+from core.gcmd import GError
+from core.layerlist import LayerList
+
+SIMPLE_LMGR_RASTER = 1
+SIMPLE_LMGR_VECTOR = 2
+SIMPLE_LMGR_RASTER3D = 4
+SIMPLE_LMGR_TB_TOP = 8
+SIMPLE_LMGR_TB_BOTTOM = 16
+SIMPLE_LMGR_TB_LEFT = 32
+SIMPLE_LMGR_TB_RIGHT = 64
+
+
+class SimpleLayerManager(wx.Panel):
+ """!Simple layer manager class provides similar functionality to
+ Layertree, but it's just list, not tree."""
+ def __init__(self, parent, layerList,
+ lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT):
+ wx.Panel.__init__(self, parent=parent, name='SimpleLayerManager')
+
+ self._style = lmgrStyle
+ self._layerList = layerList
+ self._checkList = wx.CheckListBox(self, style=wx.LB_EXTENDED)
+ # dialog windows held separately
+ self._dialogs = {}
+ self._toolbar = SimpleLmgrToolbar(self, lmgrStyle=self._style)
+
+ self._auimgr = wx.aui.AuiManager(self)
+
+ # needed in order not to change selection when moving layers
+ self._blockSelectionChanged = False
+
+ self._checkList.Bind(wx.EVT_LISTBOX, lambda evt: self._selectionChanged())
+ self._checkList.Bind(wx.EVT_LISTBOX_DCLICK, self.OnLayerChangeProperties)
+ self._checkList.Bind(wx.EVT_CHECKLISTBOX, self.OnLayerChecked)
+
+ # signal emitted when somethin in layer list changes
+ self.opacityChanged = Signal('SimpleLayerManager.opacityChanged')
+ self.cmdChanged = Signal('SimpleLayerManager.cmdChanged')
+ self.layerAdded = Signal('SimpleLayerManager.layerAdded')
+ self.layerRemoved = Signal('SimpleLayerManager.layerRemoved')
+ self.layerActivated = Signal('SimpleLayerManager.layerActivated')
+ self.layerMovedUp = Signal('SimpleLayerManager.layerMovedUp')
+ self.layerMovedDown = Signal('SimpleLayerManager.layerMovedDown')
+ # emitted by any change (e.g. for rerendering)
+ self.anyChange = Signal('SimpleLayerManager.layerChange')
+
+ self._layout()
+ self.SetMinSize((200, -1))
+
+ def _layout(self):
+ self._auimgr.AddPane(self._checkList,
+ wx.aui.AuiPaneInfo().
+ Name("checklist").
+ CenterPane().
+ CloseButton(False).
+ BestSize((self._checkList.GetBestSize())))
+ paneInfo = wx.aui.AuiPaneInfo(). \
+ Name("toolbar").Caption(_("Toolbar")).ToolbarPane(). \
+ CloseButton(False).Layer(1).Gripper(False). \
+ BestSize((self._toolbar.GetBestSize()))
+ if self._style & SIMPLE_LMGR_TB_LEFT:
+ paneInfo.Left()
+ elif self._style & SIMPLE_LMGR_TB_RIGHT:
+ paneInfo.Right()
+ elif self._style & SIMPLE_LMGR_TB_TOP:
+ paneInfo.Top()
+ else:
+ paneInfo.Bottom()
+
+ self._auimgr.AddPane(self._toolbar, paneInfo)
+ self._auimgr.Update()
+
+ def _selectionChanged(self):
+ """!Selection was changed externally,
+ updates selection info in layers."""
+ if self._blockSelectionChanged:
+ return
+ selected = self._checkList.GetSelections()
+ for i, layer in enumerate(self._layerList):
+ layer.Select(i in selected)
+
+ def OnLayerChecked(self, event):
+ """!Layer was (un)checked, update layer's info."""
+ checkedIdxs = self._checkList.GetChecked()
+ for i, layer in enumerate(self._layerList):
+ if i in checkedIdxs and not layer.IsActive():
+ layer.Activate()
+ self.layerActivated.emit(index=i, layer=layer)
+ elif i not in checkedIdxs and layer.IsActive():
+ layer.Activate(False)
+ self.layerActivated.emit(index=i, layer=layer)
+ self.anyChange.emit()
+ event.Skip()
+
+ def OnAddRaster(self, event):
+ """!Opens d.rast dialog and adds layer.
+ Dummy layer is added first."""
+ cmd = ['d.rast']
+ layer = self.AddRaster(name='', cmd=cmd, hidden=True, dialog=None)
+ GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, layer, ''))
+ event.Skip()
+
+ def OnAddVector(self, event):
+ """!Opens d.vect dialog and adds layer.
+ Dummy layer is added first."""
+ cmd = ['d.vect']
+ layer = self.AddVector(name='', cmd=cmd, hidden=True, dialog=None)
+ GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, layer, ''))
+ event.Skip()
+
+ def OnAddRast3d(self, event):
+ """!Opens d.rast3d dialog and adds layer.
+ Dummy layer is added first."""
+ cmd = ['d.rast3d']
+ layer = self.AddRast3d(name='', cmd=cmd, hidden=True, dialog=None)
+ GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, layer, ''))
+ event.Skip()
+
+ def OnRemove(self, event):
+ """!Removes selected layers from list."""
+ layers = self._layerList.GetSelectedLayers(activeOnly=False)
+ for layer in layers:
+ self.layerRemoved.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
+ self._layerList.RemoveLayer(layer)
+ if self._dialogs[layer]:
+ self._dialogs[layer].Destroy()
+ self._update()
+ self.anyChange.emit()
+ event.Skip()
+
+ def OnLayerUp(self, event):
+ """!Moves selected layers one step up.
+
+ Note: not completely correct for multiple layers."""
+ layers = self._layerList.GetSelectedLayers()
+ self._blockSelectionChanged = True
+ for layer in layers:
+ idx = self._layerList.GetLayerIndex(layer)
+ if idx > 0:
+ self.layerMovedUp.emit(index=idx, layer=layer)
+ self._layerList.MoveLayerUp(layer)
+ self._update()
+ self._blockSelectionChanged = False
+ self.anyChange.emit()
+ event.Skip()
+
+ def OnLayerDown(self, event):
+ """!Moves selected layers one step down.
+
+ Note: not completely correct for multiple layers."""
+ layers = self._layerList.GetSelectedLayers()
+ self._blockSelectionChanged = True
+ for layer in layers:
+ idx = self._layerList.GetLayerIndex(layer)
+ if idx < len(self._layerList) - 1:
+ self.layerMovedDown.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
+ self._layerList.MoveLayerDown(layer)
+ self._update()
+ self._blockSelectionChanged = False
+ self.anyChange.emit()
+ event.Skip()
+
+ def OnLayerChangeProperties(self, event):
+ """Opens module dialog to edit layer command."""
+ layers = self._layerList.GetSelectedLayers()
+ if not layers or len(layers) > 1:
+ return
+ self._layerChangeProperties(layers[0])
+ event.Skip()
+
+ def _layerChangeProperties(self, layer):
+ """!Opens new module dialog or recycles it."""
+ dlg = self._dialogs[layer]
+ if dlg is not None:
+ if dlg.IsShown():
+ dlg.Raise()
+ dlg.SetFocus()
+ else:
+ dlg.Show()
+ else:
+ GUI(parent=self, giface=None,
+ modal=False).ParseCommand(cmd=layer.cmd,
+ completed=(self.GetOptData, layer, ''))
+
+ def OnLayerChangeOpacity(self, event):
+ """!Opacity of a layer is changing."""
+ layers = self._layerList.GetSelectedLayers()
+ if not layers or len(layers) > 1:
+ return
+ layer = layers[0]
+ dlg = SetOpacityDialog(self, opacity=layer.opacity,
+ title=_("Set opacity of <%s>") % layer.name)
+ dlg.applyOpacity.connect(lambda value:
+ self._setLayerOpacity(layer, value))
+ dlg.CentreOnParent()
+
+ if dlg.ShowModal() == wx.ID_OK:
+ self._setLayerOpacity(layer, dlg.GetOpacity())
+ dlg.Destroy()
+ event.Skip()
+
+ def _setLayerOpacity(self, layer, value):
+ """!Sets layer's opacity.'"""
+ # * 100 to be compatible, should be changes everywhere to 0-100 range
+ layer.opacity = int(value * 100)
+ self._update()
+ self.opacityChanged.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
+ self.anyChange.emit()
+
+ def _update(self):
+ """!Updates checklistbox according to layerList structure."""
+ items = []
+ active = []
+ selected = []
+ for layer in self._layerList:
+ if layer.opacity < 100:
+ items.append("{name} (opacity {opacity}%)".format(name=layer.name,
+ opacity=layer.opacity))
+ else:
+ items.append(layer.name)
+ active.append(layer.IsActive())
+ selected.append(layer.IsSelected())
+
+ self._checkList.SetItems(items)
+ for i, check in enumerate(active):
+ self._checkList.Check(i, check)
+
+ for i, layer in enumerate(self._layerList):
+ if selected[i]:
+ self._checkList.Select(i)
+ else:
+ self._checkList.Deselect(i)
+
+ def GetOptData(self, dcmd, layer, params, propwin):
+ """!Handler for module dialogs."""
+ if dcmd:
+ layer.cmd = dcmd
+ self._dialogs[layer] = propwin
+ layer.selected = True
+ mapName, found = GetLayerNameFromCmd(dcmd)
+ if found:
+ try:
+ if layer.hidden:
+ layer.hidden = False
+ signal = self.layerAdded
+ else:
+ signal = self.cmdChanged
+
+ layer.name = mapName
+ signal.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
+ except ValueError, e:
+ self._layerList.RemoveLayer(layer)
+ GError(parent=self,
+ message=str(e),
+ showTraceback=False)
+
+ self._update()
+ self.anyChange.emit()
+
+ def AddRaster(self, name, cmd, hidden, dialog):
+ """!Ads new raster layer."""
+ layer = self._layerList.AddNewLayer(name=name, mapType='rast',
+ active=True,
+ cmd=cmd, hidden=hidden)
+ self._dialogs[layer] = dialog
+ return layer
+
+ def AddRast3d(self, name, cmd, hidden, dialog):
+ """!Ads new raster3d layer."""
+ layer = self._layerList.AddNewLayer(name=name, mapType='rast3d',
+ active=True,
+ cmd=cmd, hidden=hidden)
+ self._dialogs[layer] = dialog
+ return layer
+
+ def AddVector(self, name, cmd, hidden, dialog):
+ """!Ads new vector layer."""
+ layer = self._layerList.AddNewLayer(name=name, mapType='vect',
+ active=True,
+ cmd=cmd, hidden=hidden)
+ self._dialogs[layer] = dialog
+ return layer
+
+ def GetLayerInfo(self, layer, key):
+ """!Just for compatibility, should be removed in the future"""
+ value = getattr(layer, key)
+ # hack to return empty list, required in OnCancel in forms
+ # not sure why it should be empty
+ if key == 'cmd' and len(value) == 1:
+ return []
+ return value
+
+ def Delete(self, layer):
+ """!Just for compatibility, should be removed in the future"""
+ self._layerList.RemoveLayer(layer)
+ if self._dialogs[layer]:
+ self._dialogs[layer].Destroy()
+
+
+class SimpleLmgrToolbar(BaseToolbar):
+ """!Toolbar of simple layer manager.
+
+ Style of the toolbar can be changed (horizontal,
+ vertical, which map types to include).
+ """
+ def __init__(self, parent, lmgrStyle):
+ """!Toolbar constructor
+ """
+ self._style = lmgrStyle
+ if lmgrStyle & (SIMPLE_LMGR_TB_LEFT | SIMPLE_LMGR_TB_RIGHT):
+ direction = wx.TB_VERTICAL
+ else:
+ direction = wx.TB_HORIZONTAL
+ BaseToolbar.__init__(self, parent, style=wx.NO_BORDER | direction)
+
+ self.InitToolbar(self._toolbarData())
+
+ # realize the toolbar
+ self.Realize()
+
+ def _toolbarData(self):
+ """!Toolbar data"""
+ data = [('edit', icons['edit'],
+ self.parent.OnLayerChangeProperties),
+ ('remove', icons['remove'],
+ self.parent.OnRemove),
+ (None, ),
+ ('up', icons['up'],
+ self.parent.OnLayerUp),
+ ('down', icons['down'],
+ self.parent.OnLayerDown),
+ (None, ),
+ ('opacity', icons['opacity'],
+ self.parent.OnLayerChangeOpacity),
+ ]
+ if self._style & SIMPLE_LMGR_RASTER3D:
+ data.insert(0, ('addRaster3d', icons['addRast3d'],
+ self.parent.OnAddRast3d))
+ if self._style & SIMPLE_LMGR_VECTOR:
+ data.insert(0, ('addVector', BaseIcons['addVect'],
+ self.parent.OnAddVector))
+ if self._style & SIMPLE_LMGR_RASTER:
+ data.insert(0, ('addRaster', BaseIcons['addRast'],
+ self.parent.OnAddRaster))
+
+ return self._getToolbarData(data)
+
+
+icons = {
+ 'remove': MetaIcon(img='layer-remove',
+ label=_("Remove"),
+ desc=_("Remove selected map(s) from list")),
+ 'up': MetaIcon(img='layer-up',
+ label=_("Layer up"),
+ desc=_("Move selected layer(s) up")),
+ 'down': MetaIcon(img='layer-down',
+ label=_("Layer down"),
+ desc=_("Move selected layer(s) down")),
+ 'edit': MetaIcon(img='layer-edit',
+ label=_("Edit layer properties"),
+ desc=_("Edit layer properties")),
+ 'opacity': MetaIcon(img='layer-opacity',
+ label=_("Change opacity"),
+ desc=_("Change layer opacity")),
+ 'addRast3d': MetaIcon(img='layer-raster3d-add',
+ label=_("Add 3D raster map layer"),
+ desc=_("Add 3D raster map layer")),
+ }
+
+
+class TestFrame(wx.Frame):
+ def __init__(self, parent):
+ wx.Frame.__init__(self, parent=parent)
+ SimpleLayerManager(parent=self, layerList=LayerList())
+
+
+def test():
+ app = wx.App()
+ frame = TestFrame(None)
+ frame.Show()
+ app.MainLoop()
+
+if __name__ == '__main__':
+ test()
Property changes on: grass/trunk/gui/wxpython/gui_core/simplelmgr.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/trunk/gui/wxpython/mapswipe/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/mapswipe/dialogs.py 2013-11-11 22:23:51 UTC (rev 58196)
+++ grass/trunk/gui/wxpython/mapswipe/dialogs.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -6,70 +6,204 @@
Classes:
- dialogs::SwipeMapDialog
-(C) 2012 by the GRASS Development Team
+(C) 2013 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.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
+import copy
import wx
from core import globalvar
from core.utils import _
-from gui_core.dialogs import SimpleDialog
from gui_core import gselect
from gui_core.widgets import SimpleValidator
from core.gcmd import GMessage
+from core.layerlist import LayerList
+from gui_core.simplelmgr import SimpleLayerManager, SIMPLE_LMGR_RASTER, \
+ SIMPLE_LMGR_VECTOR, SIMPLE_LMGR_TB_LEFT, SIMPLE_LMGR_TB_RIGHT
-class SwipeMapDialog(SimpleDialog):
- """!Dialog used to select raster maps"""
- def __init__(self, parent, title = _("Select raster maps"), first = None, second = None):
- SimpleDialog.__init__(self, parent, title)
+from grass.pydispatch.signal import Signal
- self.element1 = gselect.Select(parent = self.panel, type = 'raster',
- size = globalvar.DIALOG_GSELECT_SIZE,
- validator = SimpleValidator(callback = self.ValidatorCallback))
-
- self.element2 = gselect.Select(parent = self.panel, type = 'raster',
- size = globalvar.DIALOG_GSELECT_SIZE,
- validator = SimpleValidator(callback = self.ValidatorCallback))
-
- self.element1.SetFocus()
+
+class SwipeMapDialog(wx.Dialog):
+ """!Dialog used to select maps.
+
+ There are two modes - simple (only two raster maps),
+ or two layer lists.
+ """
+ def __init__(self, parent, title=_("Select raster maps"),
+ first=None, second=None,
+ firstLayerList=None, secondLayerList=None):
+
+ wx.Dialog.__init__(self, parent=parent, title=title,
+ style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE)
+
+ if firstLayerList is None:
+ self._firstLayerList = LayerList()
+ else:
+ self._firstLayerList = copy.deepcopy(firstLayerList)
+ if secondLayerList is None:
+ self._secondLayerList = LayerList()
+ else:
+ self._secondLayerList = copy.deepcopy(secondLayerList)
+
+ self._firstPanel = self._createSimplePanel()
+ self._secondPanel = self._createAdvancedPanel()
+
+ self.btnSwitch = wx.Button(self)
+ self.btnCancel = wx.Button(self, id=wx.ID_CANCEL)
+ self.btnApply = wx.Button(self, id=wx.ID_APPLY)
+ self.btnOK = wx.Button(self, id=wx.ID_OK)
+ self.btnOK.SetDefault()
+
+ self.btnSwitch.Bind(wx.EVT_BUTTON, self.OnSwitchMode)
+ self.btnApply.Bind(wx.EVT_BUTTON, lambda evt: self._apply())
+ self.btnOK.Bind(wx.EVT_BUTTON, lambda evt: self._ok())
+ self.btnCancel.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
+ self.Bind(wx.EVT_CLOSE, lambda evt: self.Hide())
+
+ self.applyChanges = Signal('SwipeMapDialog.applyChanges')
+
if first:
- self.element1.SetValue(first)
+ self._firstRaster.SetValue(first)
if second:
- self.element2.SetValue(second)
-
+ self._secondRaster.SetValue(second)
+
self._layout()
- self.SetMinSize(self.GetSize())
def _layout(self):
"""!Do layout"""
- self.dataSizer.Add(wx.StaticText(self.panel, id = wx.ID_ANY,
- label = _("Name of top/left raster map:")),
- proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
- self.dataSizer.Add(self.element1, proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 1)
-
- self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
- label = _("Name of bottom/right raster map:")), proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 1)
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ self._switchSizer = wx.BoxSizer()
+ self._switchSizer.Add(self._firstPanel, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ self._switchSizer.Add(self._secondPanel, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ mainSizer.Add(self._switchSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL)
- self.dataSizer.Add(self.element2, proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 1)
-
- self.panel.SetSizer(self.sizer)
- self.sizer.Fit(self)
+ self.btnSizer = wx.StdDialogButtonSizer()
+ self.btnSizer.AddButton(self.btnCancel)
+ self.btnSizer.AddButton(self.btnOK)
+ self.btnSizer.AddButton(self.btnApply)
+ self.btnSizer.Realize()
+ mainSizer.Add(item=self.btnSwitch, proportion=0,
+ flag=wx.ALL | wx.ALIGN_LEFT, border=5)
+ mainSizer.Add(item=self.btnSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+ self.mainSizer = mainSizer
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+ self._switchMode(simple=True)
+
+ def _createSimplePanel(self):
+ panel = wx.Panel(self)
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ self._firstRaster = gselect.Select(parent=panel, type='raster',
+ size=globalvar.DIALOG_GSELECT_SIZE,
+ validator=SimpleValidator(callback=self.ValidatorCallback))
+
+ self._secondRaster = gselect.Select(parent=panel, type='raster',
+ size=globalvar.DIALOG_GSELECT_SIZE,
+ validator=SimpleValidator(callback=self.ValidatorCallback))
+ sizer.Add(wx.StaticText(panel, label=_("Name of top/left raster map:")),
+ proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
+ sizer.Add(self._firstRaster, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=1)
+ sizer.Add(wx.StaticText(panel, label=_("Name of bottom/right raster map:")),
+ proportion=0, flag=wx.EXPAND | wx.ALL, border=1)
+ sizer.Add(self._secondRaster, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=1)
+
+ self._firstRaster.SetFocus()
+
+ panel.SetSizer(sizer)
+ sizer.Fit(panel)
+
+ return panel
+
+ def _createAdvancedPanel(self):
+ panel = wx.Panel(self)
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self._firstLmgr = SimpleLayerManager(parent=panel, layerList=self._firstLayerList,
+ lmgrStyle=SIMPLE_LMGR_RASTER |
+ SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT)
+ self._secondLmgr = SimpleLayerManager(parent=panel, layerList=self._secondLayerList,
+ lmgrStyle=SIMPLE_LMGR_RASTER |
+ SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_RIGHT)
+ sizer.Add(self._firstLmgr, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
+ sizer.Add(self._secondLmgr, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
+ panel.SetSizer(sizer)
+ sizer.Fit(panel)
+
+ return panel
+
+ def _switchMode(self, simple):
+ if simple:
+ self._switchSizer.Show(self._firstPanel, show=True, recursive=True)
+ self._switchSizer.Show(self._secondPanel, show=False, recursive=True)
+ self.btnSwitch.SetLabel(_("Switch to advanced mode"))
+ self.btnCancel.SetLabel(_("Cancel"))
+ else:
+ self._switchSizer.Show(self._firstPanel, show=False, recursive=True)
+ self._switchSizer.Show(self._secondPanel, show=True, recursive=True)
+ self.btnSwitch.SetLabel(_("Switch to simple mode"))
+ self.btnCancel.SetLabel(_("Close"))
+
+ self.Freeze() # doesn't do anything (at least on Ubuntu)
+ self.btnSizer.Show(self.btnApply, simple)
+ self.btnSizer.Show(self.btnOK, simple)
+ self.btnSizer.Layout()
+ self._switchSizer.Layout()
+ self.Fit()
+ self.Thaw()
+
+ self.applyChanges.emit()
+
+ def OnSwitchMode(self, event):
+ if self._switchSizer.IsShown(self._secondPanel):
+ self._switchMode(simple=True)
+ else:
+ self._switchMode(simple=False)
+
def ValidatorCallback(self, win):
- if win == self.element1.GetTextCtrl():
- GMessage(parent = self, message = _("Name of the first map is missing."))
+ if self._switchSizer.IsShown(self._secondPanel):
+ return
+
+ if win == self._firstRaster.GetTextCtrl():
+ GMessage(parent=self, message=_("Name of the first map is missing."))
else:
- GMessage(parent = self, message = _("Name of the second map is missing."))
+ GMessage(parent=self, message=_("Name of the second map is missing."))
+ def _ok(self):
+ self._apply()
+ self.Close()
+
+ def _apply(self):
+ # TODO check if not empty
+ self.applyChanges.emit()
+
def GetValues(self):
"""!Get raster maps"""
- return (self.element1.GetValue(), self.element2.GetValue())
+ if self.IsSimpleMode():
+ return (self._firstRaster.GetValue(), self._secondRaster.GetValue())
+ else:
+ return (self._firstLayerList, self._secondLayerList)
+ def IsSimpleMode(self):
+ if self._switchSizer.IsShown(self._firstPanel):
+ return True
+ return False
+
+ def GetFirstSimpleLmgr(self):
+ return self._firstLmgr
+
+ def GetSecondSimpleLmgr(self):
+ return self._secondLmgr
Modified: grass/trunk/gui/wxpython/mapswipe/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapswipe/frame.py 2013-11-11 22:23:51 UTC (rev 58196)
+++ grass/trunk/gui/wxpython/mapswipe/frame.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -29,6 +29,7 @@
from core.debug import Debug
from core.gcmd import GError, GMessage
from core.utils import _
+from core.layerlist import LayerListToRendererConverter
from mapswipe.toolbars import SwipeMapToolbar, SwipeMainToolbar, SwipeMiscToolbar
from mapswipe.mapwindow import SwipeBufferedWindow
@@ -97,6 +98,8 @@
self.rasters = {'first': None, 'second': None}
+ self._inputDialog = None
+
# default action in map toolbar
self.GetMapToolbar().SelectDefault()
@@ -143,7 +146,7 @@
self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
self.splitter.Init()
if not (self.rasters['first'] and self.rasters['second']):
- self.OnSelectRasters(event = None)
+ self.OnSelectLayers(event=None)
def InitStatusbar(self):
"""!Init statusbar (default items)."""
@@ -336,28 +339,66 @@
self.secondMap.region = self.firstMap.region
self.Render(self.GetSecondWindow())
- def OnSelectRasters(self, event):
- """!Choose raster maps and rerender."""
- dlg = SwipeMapDialog(self, first = self.rasters['first'], second = self.rasters['second'])
- dlg.CentreOnParent()
- if dlg.ShowModal() == wx.ID_OK:
- maps = dlg.GetValues()
- res1 = self.SetFirstRaster(name = maps[0])
- res2 = self.SetSecondRaster(name = maps[1])
+ def OnSelectLayers(self, event):
+ if self._inputDialog is None:
+ dlg = SwipeMapDialog(self, first=self.rasters['first'],
+ second=self.rasters['second'],
+ firstLayerList=None, secondLayerList=None)
+ dlg.applyChanges.connect(self.OnApplyInputChanges)
+ # connect to convertor object to convert to Map
+ # store reference to convertor is needed otherwise it would be discarded
+ self._firstConverter = self._connectSimpleLmgr(dlg.GetFirstSimpleLmgr(),
+ self.GetFirstMap())
+ self._secondConverter = self._connectSimpleLmgr(dlg.GetSecondSimpleLmgr(),
+ self.GetSecondMap())
+ self._inputDialog = dlg
+ dlg.CentreOnParent()
+ dlg.Show()
+ else:
+ if self._inputDialog.IsShown():
+ self._inputDialog.Raise()
+ self._inputDialog.SetFocus()
+ else:
+ self._inputDialog.Show()
- if not (res1 and res2):
+ def _connectSimpleLmgr(self, lmgr, renderer):
+ converter = LayerListToRendererConverter(renderer)
+ lmgr.opacityChanged.connect(converter.ChangeLayerOpacity)
+ lmgr.cmdChanged.connect(converter.ChangeLayerCmd)
+ lmgr.layerAdded.connect(converter.AddLayer)
+ lmgr.layerRemoved.connect(converter.RemoveLayer)
+ lmgr.layerActivated.connect(converter.ChangeLayerActive)
+ lmgr.layerMovedUp.connect(converter.MoveLayerUp)
+ lmgr.layerMovedDown.connect(converter.MoveLayerDown)
+ lmgr.anyChange.connect(self._simpleLmgrChanged)
+ return converter
+
+ def _simpleLmgrChanged(self):
+ if self.IsAutoRendered():
+ self.OnRender(event=None)
+
+ def OnApplyInputChanges(self):
+ first, second = self._inputDialog.GetValues()
+ if self._inputDialog.IsSimpleMode():
+ self.rasters['first'], self.rasters['second'] = first, second
+ res1 = self.SetFirstRaster(name=self.rasters['first'])
+ res2 = self.SetSecondRaster(name=self.rasters['second'])
+ if not (res1 and res2) and first and second:
message = ''
if not res1:
- message += _("Map <%s> not found. ") % maps[0]
+ message += _("Map <%s> not found. ") % self.rasters['first']
if not res2:
- message += _("Map <%s> not found.") % maps[1]
- GError(parent = self, message = message)
- dlg.Destroy()
- self.SetRasterNames()
+ message += _("Map <%s> not found.") % self.rasters['second']
+ GError(parent = self, message = message)
+ return
self.ZoomToMap()
+ else:
+ LayerListToRendererConverter(self.GetFirstMap()).ConvertAll(first)
+ LayerListToRendererConverter(self.GetSecondMap()).ConvertAll(second)
- dlg.Destroy()
- self.OnRender(event = None)
+ self.SetRasterNames()
+ if self.IsAutoRendered():
+ self.OnRender(event=None)
def SetFirstRaster(self, name):
"""!Set raster map to first Map"""
@@ -551,10 +592,14 @@
self.SendSizeEvent()
def SetRasterNames(self):
- if self.rasters['first']:
- self.GetFirstWindow().SetRasterNameText(self.rasters['first'], 101)
- if self.rasters['second']:
- self.GetSecondWindow().SetRasterNameText(self.rasters['second'], 102)
+ if self._inputDialog.IsSimpleMode():
+ if self.rasters['first']:
+ self.GetFirstWindow().SetRasterNameText(self.rasters['first'], 101)
+ if self.rasters['second']:
+ self.GetSecondWindow().SetRasterNameText(self.rasters['second'], 102)
+ else:
+ self.GetFirstWindow().SetRasterNameText('', 101)
+ self.GetSecondWindow().SetRasterNameText('', 102)
def GetMapToolbar(self):
"""!Returns toolbar with zooming tools"""
Modified: grass/trunk/gui/wxpython/mapswipe/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/mapswipe/toolbars.py 2013-11-11 22:23:51 UTC (rev 58196)
+++ grass/trunk/gui/wxpython/mapswipe/toolbars.py 2013-11-11 22:39:35 UTC (rev 58197)
@@ -118,7 +118,7 @@
def _toolbarData(self):
"""!Toolbar data"""
return self._getToolbarData((("addRaster", swipeIcons['addRast'],
- self.parent.OnSelectRasters),
+ self.parent.OnSelectLayers),
(None, ),
("tools", swipeIcons['tools'],
self.OnToolMenu)
More information about the grass-commit
mailing list