[GRASS-SVN] r62792 - in grass/trunk/gui/wxpython: . core gui_core mapdisp mapwin rdigit vdigit
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Nov 17 20:00:51 PST 2014
Author: annakrat
Date: 2014-11-17 20:00:51 -0800 (Mon, 17 Nov 2014)
New Revision: 62792
Added:
grass/trunk/gui/wxpython/rdigit/
grass/trunk/gui/wxpython/rdigit/__init__.py
grass/trunk/gui/wxpython/rdigit/controller.py
grass/trunk/gui/wxpython/rdigit/dialogs.py
grass/trunk/gui/wxpython/rdigit/toolbars.py
Modified:
grass/trunk/gui/wxpython/Makefile
grass/trunk/gui/wxpython/core/render.py
grass/trunk/gui/wxpython/gui_core/toolbars.py
grass/trunk/gui/wxpython/mapdisp/frame.py
grass/trunk/gui/wxpython/mapdisp/toolbars.py
grass/trunk/gui/wxpython/mapwin/buffered.py
grass/trunk/gui/wxpython/mapwin/graphics.py
grass/trunk/gui/wxpython/vdigit/toolbars.py
Log:
wxGUI: raster digitizer added, enables drawing areas, lines, points and setting buffer for individual features [news]
Modified: grass/trunk/gui/wxpython/Makefile
===================================================================
--- grass/trunk/gui/wxpython/Makefile 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/Makefile 2014-11-18 04:00:51 UTC (rev 62792)
@@ -11,7 +11,7 @@
SRCFILES := $(wildcard icons/*.py scripts/*.py xml/*) \
$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* vdigit/* \
+ mapswipe/* modules/*.py nviz/*.py psmap/* rdigit/* rlisetup/* timeline/* vdigit/* \
vnet/*.py web_services/*.py wxplot/*.py iscatt/*.py tplot/*) \
gis_set.py gis_set_error.py wxgui.py README
@@ -20,7 +20,7 @@
PYDSTDIRS := $(patsubst %,$(DSTDIR)/%,animation core dbmgr gcp gmodeler \
gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
- mapswipe vdigit wxplot web_services rlisetup vnet timeline iscatt tplot)
+ mapswipe vdigit wxplot web_services rdigit rlisetup vnet timeline iscatt tplot)
DSTDIRS := $(patsubst %,$(DSTDIR)/%,icons scripts xml)
Modified: grass/trunk/gui/wxpython/core/render.py
===================================================================
--- grass/trunk/gui/wxpython/core/render.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/core/render.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -430,6 +430,8 @@
self.layerChanged = Signal('Map.layerChanged')
self.updateProgress = Signal('Map.updateProgress')
+ self.layerRemoved = Signal('Map:layerRemoved')
+ self.layerAdded = Signal('Map:layerAdded')
def GetProjInfo(self):
"""Get projection info"""
@@ -1034,6 +1036,8 @@
wx.EndBusyCursor()
+ self.layerAdded.emit(layer=layer)
+
return layer
def DeleteAllLayers(self, overlay = False):
@@ -1072,6 +1076,7 @@
os.remove(f)
list.remove(layer)
+ self.layerRemoved.emit(layer=layer)
return layer
return None
@@ -1123,6 +1128,7 @@
raise GException(_("Unable to render map layer <%s>.") %
layer.GetName())
+ self.layerChanged(layer=layer)
return layer
def ChangeOpacity(self, layer, opacity):
Modified: grass/trunk/gui/wxpython/gui_core/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/toolbars.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/gui_core/toolbars.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -324,6 +324,18 @@
del self._groups[group][tb]
break
+ def IsToolInGroup(self, tool, group):
+ """Checks whether a tool is in a specified group.
+
+ :param tool: tool id
+ :param group: name of group (e.g. 'mouseUse')
+ """
+ for group in self._toolsGroups[tool]:
+ for tb in self._groups[group]:
+ if tb.FindById(tool):
+ return True
+ return False
+
def ToolChanged(self, tool):
"""When any tool/button is pressed, other tools from group must be unchecked.
Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -343,7 +343,6 @@
self.OnFlyThrough, wx.ITEM_CHECK, 8),))
self._toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self.toolbars['map'],
tool=self.toolbars['map'].flyThrough)
- self.toolbars['map'].ChangeToolsDesc(mode2d = False)
# update status bar
self.statusbarManager.HideStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
@@ -477,7 +476,7 @@
# vector digitizer
elif name == "vdigit":
- self.toolbars['map'].combo.SetValue(_("Digitize"))
+ self.toolbars['map'].combo.SetValue(_("Vector digitizer"))
self._addToolbarVDigit()
if fixed:
@@ -504,8 +503,7 @@
self._mgr.GetPane('vdigit').Hide()
self._mgr.GetPane('2d').Show()
self._switchMapWindow(self.MapWindow2D)
-
- self.toolbars['map'].combo.SetValue(_("2D view"))
+
self.toolbars['map'].Enable2D(True)
self._mgr.Update()
@@ -772,7 +770,9 @@
self.toolbars['vdigit'].OnExit()
if self.IsPaneShown('3d'):
self.RemoveNviz()
-
+ if hasattr(self, 'rdigit') and self.rdigit:
+ self.rdigit.CleanUp()
+
if not self._layerManager:
self.Destroy()
elif self.page:
@@ -1435,3 +1435,58 @@
map_win.ActivateWin()
self.MapWindow = map_win
+
+ def AddRDigit(self):
+ """Adds raster digitizer: creates toolbar and digitizer controller,
+ binds events and signals."""
+ from rdigit.controller import RDigitController, EVT_UPDATE_PROGRESS
+ from rdigit.toolbars import RDigitToolbar
+
+ self.rdigit = RDigitController(self._giface,
+ mapWindow=self.GetMapWindow())
+ self.toolbars['rdigit'] = RDigitToolbar(parent=self, controller=self.rdigit,
+ toolSwitcher=self._toolSwitcher)
+ # connect signals
+ self.rdigit.newRasterCreated.connect(self.toolbars['rdigit'].NewRasterAdded)
+ self.rdigit.newRasterCreated.connect(lambda name: self._giface.mapCreated.emit(name=name, ltype='raster'))
+ self.rdigit.newFeatureCreated.connect(self.toolbars['rdigit'].UpdateCellValues)
+ self.rdigit.uploadMapCategories.connect(self.toolbars['rdigit'].UpdateCellValues)
+ self.rdigit.showNotification.connect(lambda text: self.SetStatusText(text, 0))
+ self.rdigit.quitDigitizer.connect(self.QuitRDigit)
+ self.rdigit.Bind(EVT_UPDATE_PROGRESS,
+ lambda evt: self.statusbarManager.SetProgress(evt.range, evt.value, evt.text))
+ rasters = self.GetMap().GetListOfLayers(ltype='raster', mapset=grass.gisenv()['MAPSET'])
+ self.toolbars['rdigit'].UpdateRasterLayers(rasters)
+ self.toolbars['rdigit'].SelectDefault()
+
+ self.GetMap().layerAdded.connect(self._updateRDigitLayers)
+ self.GetMap().layerRemoved.connect(self._updateRDigitLayers)
+ self.GetMap().layerChanged.connect(self._updateRDigitLayers)
+ self._mgr.AddPane(self.toolbars['rdigit'],
+ wx.aui.AuiPaneInfo().
+ Name("rdigit toolbar").Caption(_("Raster Digitizer Toolbar")).
+ ToolbarPane().Top().Row(1).
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).Floatable().
+ CloseButton(False).Layer(2).DestroyOnClose().
+ BestSize((self.toolbars['rdigit'].GetBestSize())))
+ self._mgr.Update()
+
+ self.rdigit.Start()
+
+ def _updateRDigitLayers(self, layer):
+ mapset = grass.gisenv()['MAPSET']
+ self.toolbars['rdigit'].UpdateRasterLayers(
+ rasters=self.GetMap().GetListOfLayers(ltype='raster', mapset=mapset))
+
+ def QuitRDigit(self):
+ """Calls digitizer cleanup, removes digitizer object and disconnects
+ signals from Map."""
+ self.rdigit.CleanUp()
+ # disconnect updating layers
+ self.GetMap().layerAdded.disconnect(self._updateRDigitLayers)
+ self.GetMap().layerRemoved.disconnect(self._updateRDigitLayers)
+ self.GetMap().layerChanged.disconnect(self._updateRDigitLayers)
+
+ self.RemoveToolbar('rdigit')
+ self.rdigit = None
Modified: grass/trunk/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/toolbars.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/mapdisp/toolbars.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -79,28 +79,29 @@
self._default = self.pointer
# optional tools
+ toolNum = 0
choices = [ _('2D view'), ]
- self.toolId = { '2d' : 0 }
+ self.toolId = { '2d' : toolNum }
+ toolNum += 1
if self.parent.GetLayerManager():
log = self.parent.GetLayerManager().GetLogWindow()
if haveNviz:
choices.append(_('3D view'))
- self.toolId['3d'] = 1
+ self.toolId['3d'] = toolNum
+ toolNum += 1
else:
from nviz.main import errorMsg
if self.parent.GetLayerManager():
- log.WriteCmdLog(_('3D view mode not available'))
- log.WriteWarning(_('Reason: %s') % str(errorMsg))
+ log.WriteCmdLog(_('3D view mode not available'))
+ log.WriteWarning(_('Reason: %s') % str(errorMsg))
self.toolId['3d'] = -1
if haveVDigit:
- choices.append(_('Digitize'))
- if self.toolId['3d'] > -1:
- self.toolId['vdigit'] = 2
- else:
- self.toolId['vdigit'] = 1
+ choices.append(_("Vector digitizer"))
+ self.toolId['vdigit'] = toolNum
+ toolNum += 1
else:
from vdigit.main import errorMsg
if self.parent.GetLayerManager():
@@ -112,7 +113,9 @@
'In the meantime you can use "v.digit" from the Develop Vector menu.'), wrap = 60)
self.toolId['vdigit'] = -1
-
+ choices.append(_("Raster digitizer"))
+ self.toolId['rdigit'] = toolNum
+
self.combo = wx.ComboBox(parent = self, id = wx.ID_ANY,
choices = choices,
style = wx.CB_READONLY, size = (110, -1))
@@ -218,11 +221,10 @@
"""Select / enable tool available in tools list
"""
tool = event.GetSelection()
-
+
if tool == self.toolId['2d']:
self.ExitToolbars()
- self.Enable2D(True)
- self.ChangeToolsDesc(mode2d = True)
+ self.Enable2D(True)
elif tool == self.toolId['3d'] and \
not (self.parent.MapWindow3D and self.parent.IsPaneShown('3d')):
@@ -235,6 +237,10 @@
self.parent.AddToolbar("vdigit")
self.parent.MapWindow.SetFocus()
+ elif tool == self.toolId['rdigit']:
+ self.ExitToolbars()
+ self.parent.AddRDigit()
+
def OnAnalyze(self, event):
"""Analysis tools menu
"""
@@ -261,7 +267,9 @@
if self.parent.GetLayerManager() and \
self.parent.GetLayerManager().IsPaneShown('toolbarNviz'):
self.parent.RemoveNviz()
-
+ if self.parent.GetToolbar('rdigit'):
+ self.parent.QuitRDigit()
+
def Enable2D(self, enabled):
"""Enable/Disable 2D display mode specific tools"""
for tool in (self.zoomRegion,
@@ -269,3 +277,6 @@
self.analyze,
self.printMap):
self.EnableTool(tool, enabled)
+ self.ChangeToolsDesc(enabled)
+ if enabled:
+ self.combo.SetValue(_("2D view"))
Modified: grass/trunk/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/buffered.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/mapwin/buffered.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -128,6 +128,8 @@
self.mouseLeftUpPointer = Signal('BufferedWindow.mouseLeftUpPointer')
# Emitted when left mouse button is released
self.mouseLeftUp = Signal('BufferedWindow.mouseLeftUp')
+ # Emitted when right mouse button is released
+ self.mouseRightUp = Signal('BufferedWindow.mouseRightUp')
# Emitted when left mouse button was pressed
self.mouseLeftDown = Signal('BufferedWindow.mouseLeftDown')
# Emitted after double-click
@@ -250,7 +252,8 @@
self.PopupMenu(menu)
menu.Destroy()
- def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0], pen = None):
+ def Draw(self, pdc, img=None, drawid=None, pdctype='image',
+ coords=[0, 0, 0, 0], pen=None, brush=None):
"""Draws map and overlay decorations
"""
if drawid is None:
@@ -307,7 +310,9 @@
elif pdctype == 'box': # draw a box on top of the map
if pen:
- pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+ if not brush:
+ brush = wx.Brush(wx.CYAN, wx.TRANSPARENT)
+ pdc.SetBrush(brush)
pdc.SetPen(pen)
x2 = max(coords[0],coords[2])
x1 = min(coords[0],coords[2])
@@ -367,7 +372,9 @@
elif pdctype == 'polygon':
if pen:
pdc.SetPen(pen)
- pdc.SetBrush(wx.TRANSPARENT_BRUSH)
+ if not brush:
+ brush = wx.TRANSPARENT_BRUSH
+ pdc.SetBrush(brush)
pdc.DrawPolygon(points=coords)
x = min(coords, key=lambda x: x[0])[0]
y = min(coords, key=lambda x: x[1])[1]
@@ -378,7 +385,9 @@
elif pdctype == 'circle': # draw circle
if pen:
pdc.SetPen(pen)
- pdc.SetBrush(wx.TRANSPARENT_BRUSH)
+ if not brush:
+ brush = wx.TRANSPARENT_BRUSH
+ pdc.SetBrush(brush)
radius = abs(coords[2] - coords[0]) / 2
pdc.DrawCircle(max(coords[0], coords[2]) - radius,
max(coords[1], coords[3]) - radius, radius=radius)
@@ -540,11 +549,15 @@
except NotImplementedError as e:
print >> sys.stderr, e
self.pdcDec.DrawToDC(dc)
-
# draw temporary object on the foreground
- ### self.pdcTmp.DrawToDCClipped(dc, rgn)
- self.pdcTmp.DrawToDC(dc)
+ try:
+ gcdc = wx.GCDC(dc)
+ self.pdcTmp.DrawToDC(gcdc)
+ except NotImplementedError as e:
+ print >> sys.stderr, e
+ self.pdcTmp.DrawToDC(dc)
+
if switchDraw:
self.redrawAll = False
@@ -1125,7 +1138,7 @@
return self.lineid
- def DrawRectangle(self, pdc, point1, point2, pen, drawid=None):
+ def DrawRectangle(self, pdc, point1, point2, pen, brush=None, drawid=None):
"""Draw rectangle (not filled) in PseudoDC
:param pdc: PseudoDC
@@ -1137,10 +1150,11 @@
Debug.msg(4, "BufferedWindow.DrawRectangle(): pdc=%s, point1=%s, point2=%s" % \
(pdc, point1, point2))
coords = [point1[0], point1[1], point2[0], point2[1]]
- self.lineid = self.Draw(pdc, drawid=drawid, pdctype='box', coords=coords, pen=pen)
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='box', coords=coords,
+ pen=pen, brush=brush)
return self.lineid
- def DrawCircle(self, pdc, coords, radius, pen, drawid=None):
+ def DrawCircle(self, pdc, coords, radius, pen, brush=None, drawid=None):
"""Draw circle (not filled) in PseudoDC
:param pdc: PseudoDC
@@ -1153,10 +1167,11 @@
(pdc, coords, radius))
newcoords = [coords[0] - radius, coords[1] - radius,
coords[0] + radius, coords[1] + radius]
- self.lineid = self.Draw(pdc, drawid=drawid, pdctype='circle', coords=newcoords, pen=pen)
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='circle', coords=newcoords,
+ pen=pen, brush=brush)
return self.lineid
- def DrawPolygon(self, pdc, coords, pen, drawid=None):
+ def DrawPolygon(self, pdc, coords, pen, brush=None, drawid=None):
"""Draws polygon from a list of points (do not append the first point)
:param pdc: PseudoDC
@@ -1164,8 +1179,11 @@
:param pen: pen
:param drawid: id of the drawn object (used by PseudoDC)
"""
+ # avid wx.GCDC assert
+ if len(coords) <= 1:
+ return None
self.lineid = self.Draw(pdc, drawid=drawid, pdctype='polygon',
- coords=coords, pen=pen)
+ coords=coords, pen=pen, brush=brush)
return self.lineid
def _computeZoomToPointAndRecenter(self, position, zoomtype):
@@ -1469,6 +1487,9 @@
self.redrawAll = True
self.Refresh()
+ coords = self.Pixel2Cell(event.GetPosition())
+ self.mouseRightUp.emit(x=coords[0], y=coords[1])
+
event.Skip()
def OnMiddleDown(self, event):
Modified: grass/trunk/gui/wxpython/mapwin/graphics.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/graphics.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/mapwin/graphics.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -37,6 +37,9 @@
"unused": wx.Pen(colour=wx.LIGHT_GREY, width=2, style=wx.SOLID),
"highest": wx.Pen(colour=wx.RED, width=2, style=wx.SOLID)
}
+ self.brushes = {
+ 'default': wx.TRANSPARENT_BRUSH
+ }
# list contains instances of GraphicsSetItem
self.itemsList = []
@@ -132,12 +135,16 @@
pen = self.pens[item.GetPropertyVal("penName")]
else:
pen = self.pens["default"]
+ if item.GetPropertyVal("brushName"):
+ brush = self.brushes[item.GetPropertyVal("brushName")]
+ else:
+ brush = self.brushes["default"]
if self.mapCoords:
coords = [self.parentMapWin.Cell2Pixel(coords) for coords in item.GetCoords()]
else:
coords = item.GetCoords()
- self.drawFunc(pdc=pdc, pen=pen, drawid=item.GetId(),
+ self.drawFunc(pdc=pdc, pen=pen, brush=brush, drawid=item.GetId(),
point1=coords[0],
point2=coords[1])
@@ -146,12 +153,16 @@
pen = self.pens[item.GetPropertyVal("penName")]
else:
pen = self.pens["default"]
+ if item.GetPropertyVal("brushName"):
+ brush = self.brushes[item.GetPropertyVal("brushName")]
+ else:
+ brush = self.brushes["default"]
if self.mapCoords:
coords = [self.parentMapWin.Cell2Pixel(coords) for coords in item.GetCoords()]
else:
coords = item.GetCoords()
- self.drawFunc(pdc=pdc, pen=pen,
+ self.drawFunc(pdc=pdc, pen=pen, brush=brush,
coords=coords, drawid=item.GetId())
itemOrderNum += 1
@@ -218,10 +229,7 @@
:return: instance of GraphicsSetItem which is drawn in drawNum order
:return: False if drawNum was out of range
"""
- if drawNum < len(self.itemsList) and drawNum >= 0:
- return self.itemsList[drawNum]
- else:
- return False
+ return self.itemsList[drawNum]
def SetPropertyVal(self, propName, propVal):
"""Set property value
@@ -288,6 +296,37 @@
return None
+ def AddBrush(self, brushName, brush):
+ """Add brush
+
+ :param brushName: name of added brush
+ :type brushName: str
+ :param brush: added brush
+ :type brush: wx.Brush
+
+ :return: True - if brush was added
+ :return: False - if brush already exists
+ """
+ if brushName in self.brushes:
+ return False
+
+ self.brushes[brushName] = brush
+ return True
+
+ def GetBrush(self, brushName):
+ """Get existing brush
+
+ :param brushName: name of brush
+ :type brushName: str
+
+ :return: wx.Brush reference if is found
+ :return: None if brushName was not found
+ """
+ if brushName in self.brushes:
+ return self.brushes[brushName]
+
+ return None
+
def SetItemDrawOrder(self, item, drawNum):
"""Set draw order for item
@@ -328,7 +367,7 @@
class GraphicsSetItem:
- def __init__(self, coords, penName=None, label=None, hide=False):
+ def __init__(self, coords, penName=None, brushName=None, label=None, hide=False):
"""Could be point or line according to graphicsType in
GraphicsSet class
@@ -338,6 +377,8 @@
rectangle: [[10, 12], [33, 45]]
:param penName: if it is not defined 'default' pen is used
:type penName: str
+ :param brushName: if it is not defined 'default' brush is used
+ :type brushName: str
:param label: label, which will be drawn with point. It is
relevant just for 'point' type
:type label: str
@@ -348,15 +389,26 @@
self.coords = coords
self.properties = {"penName": penName,
+ "brushName": brushName,
"hide": hide,
"label": label}
self.id = wx.NewId()
+ def AddProperty(self, propName):
+ """Adds new property, to set it, call SetPropertyVal afterwards.
+
+ :param propName - name of the newly defined property
+ :type propName: str
+ """
+ if not propName in self.properties:
+ self.properties[propName] = None
+
def SetPropertyVal(self, propName, propVal):
"""Set property value
:param propName: - property name: "penName", "hide" or "label"
- property "label" is relevant just for 'point' type
+ - or newly defined property name
:type propName: str
:param propVal: property value to be set
Added: grass/trunk/gui/wxpython/rdigit/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/rdigit/__init__.py (rev 0)
+++ grass/trunk/gui/wxpython/rdigit/__init__.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -0,0 +1,4 @@
+all = [
+ 'controller',
+ 'toolbars'
+ ]
Property changes on: grass/trunk/gui/wxpython/rdigit/__init__.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/trunk/gui/wxpython/rdigit/controller.py
===================================================================
--- grass/trunk/gui/wxpython/rdigit/controller.py (rev 0)
+++ grass/trunk/gui/wxpython/rdigit/controller.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -0,0 +1,510 @@
+# -*- coding: utf-8 -*-
+"""
+ at package rdigit.controller
+
+ at brief rdigit controller for drawing and rasterizing
+
+Classes:
+ - controller::RDigitController
+
+(C) 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.
+
+ at author Anna Petrasova <kratochanna gmail.com>
+"""
+import os
+import tempfile
+import wx
+import uuid
+from wx.lib.newevent import NewEvent
+
+from grass.script import core as gcore
+from grass.script import raster as grast
+from grass.exceptions import CalledModuleError, ScriptError
+from grass.pydispatch.signal import Signal
+
+from core.gcmd import GError, GMessage
+from core.settings import UserSettings
+from core.gthread import gThread
+from rdigit.dialogs import NewRasterDialog
+
+updateProgress, EVT_UPDATE_PROGRESS = NewEvent()
+
+
+class RDigitController(wx.EvtHandler):
+ """Controller object for raster digitizer.
+ Inherits from EvtHandler to be able to send wx events from thraed.
+ """
+ def __init__(self, giface, mapWindow):
+ """Constructs controller
+
+ :param giface: grass interface object
+ :param mapWindow: instance of BufferedMapWindow
+ """
+ wx.EvtHandler.__init__(self)
+ self._giface = giface
+ self._mapWindow = mapWindow
+
+ # thread for running rasterization process
+ self._thread = gThread()
+ # name of raster map which is edited (also new one)
+ self._editedRaster = None
+ # name of optional background raster
+ self._backgroundRaster = None
+ # name of temporary raster used to backup original state
+ self._backupRasterName = None
+ # GraphicsSet for drawing areas, lines, points
+ self._areas = None
+ self._lines = None
+ self._points = None
+ # list of all GraphicsItems in the order of drawing
+ self._all = []
+ # if in state of drawing lin or area
+ self._drawing = False
+ # if running digitizing process in thread (to block drawing)
+ self._running = False
+ # color used to draw (should be moved to settings)
+ self._drawColor = wx.GREEN
+ # transparency used to draw (should be moved to settings)
+ self._drawTransparency = 100
+ # current selected drawing method
+ self._graphicsType = 'area'
+ # last edited cell value
+ self._currentCellValue = None
+ # last edited buffer value
+ self._currentWidthValue = None
+
+ self._oldMouseUse = None
+ self._oldCursor = None
+
+ # signal to add new raster to toolbar items
+ self.newRasterCreated = Signal('RDigitController:newRasterCreated')
+ # signal to add just used cell value in toolbar combo
+ self.newFeatureCreated = Signal('RDigitController:newFeatureCreated')
+ # signal to upload unique categories of background map into toolbar combo
+ self.uploadMapCategories = Signal('RDigitController:uploadMapCategories')
+ self.quitDigitizer = Signal('RDigitController:quitDigitizer')
+ self.showNotification = Signal('RDigitController:showNotification')
+
+ def _connectAll(self):
+ self._mapWindow.mouseLeftDown.connect(self._start)
+ self._mapWindow.mouseLeftUp.connect(self._addPoint)
+ self._mapWindow.mouseRightUp.connect(self._finish)
+ self._mapWindow.Unbind(wx.EVT_CONTEXT_MENU)
+
+ def _disconnectAll(self):
+ self._mapWindow.mouseLeftDown.disconnect(self._start)
+ self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
+ self._mapWindow.mouseRightUp.connect(self._finish)
+ self._mapWindow.Bind(wx.EVT_CONTEXT_MENU, self._mapWindow.OnContextMenu)
+
+ def _start(self, x, y):
+ """Start digitizing a new object.
+ :param x: x coordinate in map units
+ :param y: y coordinate in map units
+ """
+ if self._running:
+ return
+
+ if not self._editedRaster:
+ GMessage(parent=self._mapWindow, message=_("Please select first the raster map"))
+ return
+ if not self._drawing:
+ if self._graphicsType == 'area':
+ item = self._areas.AddItem(coords=[])
+ item.SetPropertyVal('penName', 'pen1')
+ self._all.append(item)
+ elif self._graphicsType == 'line':
+ item = self._lines.AddItem(coords=[])
+ item.SetPropertyVal('penName', 'pen1')
+ self._all.append(item)
+ elif self._graphicsType == 'point':
+ item = self._points.AddItem(coords=[])
+ item.SetPropertyVal('penName', 'pen1')
+ self._all.append(item)
+ self._drawing = True
+
+ def _addPoint(self, x, y):
+ """Add point to an object.
+ :param x: x coordinate in map units
+ :param y: y coordinate in map units
+ """
+ if self._running:
+ return
+
+ if not self._drawing:
+ return
+
+ if self._graphicsType == 'area':
+ area = self._areas.GetItem(-1)
+ coords = area.GetCoords() + [[x, y]]
+ area.SetCoords(coords)
+ self.showNotification.emit(text=_("Right click to finish area"))
+ elif self._graphicsType == 'line':
+ line = self._lines.GetItem(-1)
+ coords = line.GetCoords() + [[x, y]]
+ line.SetCoords(coords)
+ self.showNotification.emit(text=_("Right click to finish line"))
+ elif self._graphicsType == 'point':
+ point = self._points.GetItem(-1)
+ point.SetCoords([x, y])
+ self._finish(x, y)
+ # draw
+ self._mapWindow.ClearLines()
+ self._lines.Draw(pdc=self._mapWindow.pdcTmp)
+ self._areas.Draw(pdc=self._mapWindow.pdcTmp)
+ self._points.Draw(pdc=self._mapWindow.pdcTmp)
+ self._mapWindow.Refresh()
+
+ def _finish(self, x, y):
+ """Finish digitizing a new object and redraws.
+ Saves current cell value and buffer width for that object.
+
+ :param x: x coordinate in map units
+ :param y: y coordinate in map units
+ """
+ if self._running:
+ return
+
+ if self._graphicsType == 'point':
+ item = self._points.GetItem(-1)
+ elif self._graphicsType == 'area':
+ item = self._areas.GetItem(-1)
+ elif self._graphicsType == 'line':
+ item = self._lines.GetItem(-1)
+ else:
+ return
+
+ self._drawing = False
+ item.SetPropertyVal('brushName', 'done')
+ item.AddProperty('cellValue')
+ item.AddProperty('widthValue')
+ item.SetPropertyVal('cellValue', self._currentCellValue)
+ item.SetPropertyVal('widthValue', self._currentWidthValue)
+ self.newFeatureCreated.emit()
+
+ self._mapWindow.ClearLines()
+ self._points.Draw(pdc=self._mapWindow.pdcTmp)
+ self._areas.Draw(pdc=self._mapWindow.pdcTmp)
+ self._lines.Draw(pdc=self._mapWindow.pdcTmp)
+
+ self._mapWindow.Refresh()
+
+ def SelectType(self, drawingType):
+ """Selects method (area/line/point) for drawing.
+ Connects and disconnects signal to allow other tools
+ in map toolbar to work.
+ """
+ if self._graphicsType and not drawingType:
+ self._mapWindow.ClearLines(pdc=self._mapWindow.pdcTmp)
+ self._mapWindow.mouse['end'] = self._mapWindow.mouse['begin']
+ # disconnect mouse events
+ self._disconnectAll()
+ self._mapWindow.SetNamedCursor(self._oldCursor)
+ self._mapWindow.mouse['use'] = self._oldMouseUse
+ elif self._graphicsType is None and drawingType:
+ self._connectAll()
+ # change mouse['box'] and pen to draw line during dragging
+ # TODO: better solution for drawing this line
+ self._mapWindow.mouse['use'] = None
+ self._mapWindow.mouse['box'] = "line"
+ self._mapWindow.pen = wx.Pen(colour='red', width=2, style=wx.SHORT_DASH)
+ # change the cursor
+ self._mapWindow.SetNamedCursor('pencil')
+
+ self._graphicsType = drawingType
+
+ def SetCellValue(self, value):
+ self._currentCellValue = value
+
+ def SetWidthValue(self, value):
+ self._currentWidthValue = value
+
+ def ChangeDrawColor(self, color):
+ self._drawColor = color[:3] + (self._drawTransparency,)
+ for each in (self._areas, self._lines, self._points):
+ each.GetPen('pen1').SetColour(self._drawColor)
+ each.GetBrush('done').SetColour(self._drawColor)
+ self._mapWindow.UpdateMap(render=False)
+
+ def Start(self):
+ """Registers graphics to map window,
+ connect required mouse signals.
+ """
+ self._oldMouseUse = self._mapWindow.mouse['use']
+ self._oldCursor = self._mapWindow.GetNamedCursor()
+
+ self._connectAll()
+
+ # change mouse['box'] and pen to draw line during dragging
+ # TODO: better solution for drawing this line
+ self._mapWindow.mouse['use'] = None
+ self._mapWindow.mouse['box'] = "line"
+ self._mapWindow.pen = wx.Pen(colour='red', width=2, style=wx.SHORT_DASH)
+
+ color = self._drawColor[:3] + (self._drawTransparency,)
+ self._areas = self._mapWindow.RegisterGraphicsToDraw(graphicsType='polygon',
+ mapCoords=True)
+ self._areas.AddPen('pen1', wx.Pen(colour=color, width=2, style=wx.SOLID))
+ self._areas.AddBrush('done', wx.Brush(colour=color, style=wx.SOLID))
+
+ self._lines = self._mapWindow.RegisterGraphicsToDraw(graphicsType='line',
+ mapCoords=True)
+ self._lines.AddPen('pen1', wx.Pen(colour=color, width=2, style=wx.SOLID))
+ self._lines.AddBrush('done', wx.Brush(colour=color, style=wx.SOLID))
+
+ self._points = self._mapWindow.RegisterGraphicsToDraw(graphicsType='point',
+ mapCoords=True)
+ self._points.AddPen('pen1', wx.Pen(colour=color, width=2, style=wx.SOLID))
+ self._points.AddBrush('done', wx.Brush(colour=color, style=wx.SOLID))
+
+ # change the cursor
+ self._mapWindow.SetNamedCursor('pencil')
+
+ def Stop(self):
+ """Before stopping digitizer, asks to save edits"""
+ dlg = wx.MessageDialog(self._mapWindow, _("Do you want to save changes?"),
+ _("Save raster map changes"), wx.YES_NO)
+ if dlg.ShowModal() == wx.ID_YES:
+ self._running = True
+ self._thread.Run(callable=self._exportRaster,
+ ondone=lambda event: self._updateAndQuit())
+ else:
+ self.quitDigitizer.emit()
+
+ def Save(self):
+ """Saves current edits to a raster map"""
+ self._thread.Run(callable=self._exportRaster,
+ ondone=lambda event: self._update())
+
+ def Undo(self):
+ """Undo a change, goes object back (finished or not finished)"""
+ if len(self._all):
+ removed = self._all.pop(-1)
+ # try to remove from each, it fails quietly when theitem is not there
+ self._areas.DeleteItem(removed)
+ self._lines.DeleteItem(removed)
+ self._points.DeleteItem(removed)
+ self._drawing = False
+ self._mapWindow.UpdateMap(render=False)
+
+ def CleanUp(self, restore=True):
+ """Cleans up drawing, temporary maps.
+ :param restore: if restore previous cursor, mouse['use']
+ """
+ try:
+ gcore.run_command('g.remove', type='rast', flags='f', name=self._backupRasterName, quiet=True)
+ except CalledModuleError:
+ pass
+
+ self._mapWindow.ClearLines(pdc=self._mapWindow.pdcTmp)
+ self._mapWindow.mouse['end'] = self._mapWindow.mouse['begin']
+ # disconnect mouse events
+ if self._graphicsType:
+ self._disconnectAll()
+ # unregister
+ self._mapWindow.UnregisterGraphicsToDraw(self._areas)
+ self._mapWindow.UnregisterGraphicsToDraw(self._lines)
+ self._mapWindow.UnregisterGraphicsToDraw(self._points)
+ #self._registeredGraphics = None
+ self._mapWindow.UpdateMap(render=False)
+
+ if restore:
+ # restore mouse['use'] and cursor to the state before measuring starts
+ self._mapWindow.SetNamedCursor(self._oldCursor)
+ self._mapWindow.mouse['use'] = self._oldMouseUse
+
+ def _updateAndQuit(self):
+ """Called when thread is done. Updates map and calls to quits digitizer."""
+ self._running = False
+ self._mapWindow.UpdateMap(render=True)
+ self.quitDigitizer.emit()
+
+ def _update(self):
+ """Called when thread is done. Updates map."""
+ self._running = False
+ self._mapWindow.UpdateMap(render=True)
+
+ def SelectOldMap(self, name):
+ """After selecting old raster, creates a backup copy for editing."""
+ try:
+ self._backupRaster(name)
+ except ScriptError:
+ GError(parent=self._mapWindow, message=_("Failed to create backup copy of edited raster map."))
+ return False
+ self._editedRaster = name
+ return True
+
+ def SelectNewMap(self):
+ """After selecting new raster, shows dialog to choose name,
+ background map and type of the new map."""
+ dlg = NewRasterDialog(parent=self._mapWindow)
+ if dlg.ShowModal() == wx.ID_OK:
+ try:
+ self._createNewMap(mapName=dlg.GetMapName(),
+ backgroundMap=dlg.GetBackgroundMapName(),
+ mapType=dlg.GetMapType())
+ except ScriptError:
+ GError(parent=self._mapWindow, message=_("Failed to create new raster map."))
+ return False
+ finally:
+ dlg.Destroy()
+ return True
+ else:
+ dlg.Destroy()
+ return False
+
+ def _createNewMap(self, mapName, backgroundMap, mapType):
+ """Creates a new raster map based on specified background and type."""
+ name = mapName.split('@')[0]
+ background = backgroundMap.split('@')[0]
+ types = {'CELL': 'int', 'FCELL': 'float', 'DCELL': 'double'}
+ if background:
+ back = background
+ else:
+ back = 'null()'
+ try:
+ grast.mapcalc(exp="{name} = {mtype}({back})".format(name=name, mtype=types[mapType],
+ back=back),
+ overwrite=True, quiet=True)
+ if background:
+ self._backgroundRaster = backgroundMap
+ gcore.run_command('r.colors', map=name, raster=self._backgroundRaster, quiet=True)
+ if mapType == 'CELL':
+ values = gcore.read_command('r.describe', flags='1n',
+ map=backgroundMap, quiet=True).strip()
+ if values:
+ self.uploadMapCategories.emit(values=values.split('\n'))
+ except CalledModuleError:
+ raise ScriptError
+ self._backupRaster(name)
+
+ name = name + '@' + gcore.gisenv()['MAPSET']
+ self._editedRaster = name
+ self.newRasterCreated.emit(name=name)
+
+ def _backupRaster(self, name):
+ """Creates a temporary backup raster necessary for undo behavior.
+
+ :param str name: name of raster map for which we create backup
+ """
+ name = name.split('@')[0]
+ backup = name + '_backupcopy_' + str(os.getpid())
+ try:
+ gcore.run_command('g.copy', rast=[name, backup], quiet=True)
+ except CalledModuleError:
+ raise ScriptError
+
+ self._backupRasterName = backup
+
+ def _exportRaster(self):
+ """Rasterizes digitized features.
+
+ Uses r.in.poly and r.grow for buffering features. Creates separate raster
+ maps depending on common cell values and buffering width necessary to
+ keep the order of editing. These rasters are then patched together.
+ Sets default color table for the newly digitized raster.
+ """
+ if not self._editedRaster:
+ return
+
+ if len(self._all) < 1:
+ return
+ tempRaster = 'tmp_rdigit_rast_' + str(os.getpid())
+ text = []
+ rastersToPatch = []
+ i = 0
+ lastCellValue = lastWidthValue = None
+ evt = updateProgress(range=len(self._all), value=0, text=_("Rasterizing..."))
+ wx.PostEvent(self, evt)
+ lastCellValue = self._all[0].GetPropertyVal('cellValue')
+ lastWidthValue = self._all[0].GetPropertyVal('widthValue')
+ for item in self._all:
+ if item.GetPropertyVal('widthValue') and \
+ (lastCellValue != item.GetPropertyVal('cellValue') or
+ lastWidthValue != item.GetPropertyVal('widthValue')):
+ if text:
+ out = self._rasterize(text, lastWidthValue, tempRaster)
+ rastersToPatch.append(out)
+ text = []
+ self._writeItem(item, text)
+ out = self._rasterize(text, item.GetPropertyVal('widthValue'),
+ tempRaster)
+ rastersToPatch.append(out)
+ text = []
+ else:
+ self._writeItem(item, text)
+ lastCellValue = item.GetPropertyVal('cellValue')
+ lastWidthValue = item.GetPropertyVal('widthValue')
+
+ i += 1
+ evt = updateProgress(range=len(self._all), value=i, text=_("Rasterizing..."))
+ wx.PostEvent(self, evt)
+ if text:
+ out = self._rasterize(text, item.GetPropertyVal('widthValue'),
+ tempRaster)
+ rastersToPatch.append(out)
+
+ gcore.run_command('r.patch', input=sorted(rastersToPatch, reverse=True) + [self._backupRasterName],
+ output=self._editedRaster, overwrite=True, quiet=True)
+ gcore.run_command('g.remove', type='rast', flags='f', name=rastersToPatch + [tempRaster],
+ quiet=True)
+ try:
+ if not self._backgroundRaster:
+ table = UserSettings.Get(group='rasterLayer', key='colorTable', subkey='selection')
+ gcore.run_command('r.colors', color=table, map=self._editedRaster, quiet=True)
+ else:
+ gcore.run_command('r.colors', map=self._editedRaster,
+ raster=self._backgroundRaster, quiet=True)
+ except CalledModuleError:
+ GError(parent=self._mapWindow,
+ message=_("Failed to set default color table for edited raster map"))
+
+ def _writeFeature(self, item, vtype, text):
+ """Writes digitized features in r.in.poly format."""
+ coords = item.GetCoords()
+ if vtype == 'P':
+ coords = [coords]
+ cellValue = item.GetPropertyVal('cellValue')
+ record = '{vtype}\n'.format(vtype=vtype)
+ for coord in coords:
+ record += ' '.join([str(c) for c in coord])
+ record += '\n'
+ record += '= {cellValue}\n'.format(cellValue=cellValue)
+
+ text.append(record)
+
+ def _writeItem(self, item, text):
+ if item in self._areas.GetAllItems():
+ self._writeFeature(item, vtype='A', text=text)
+ elif item in self._lines.GetAllItems():
+ self._writeFeature(item, vtype='L', text=text)
+ elif item in self._points.GetAllItems():
+ self._writeFeature(item, vtype='P', text=text)
+
+ def _rasterize(self, text, bufferDist, tempRaster):
+ """Performs the actual rasterization using r.in.poly
+ and buffering with r.grow if required.
+
+ :param str text: string in r.in.poly format
+ :param float bufferDist: buffer distance in map units
+ :param str tempRaster: name of temporary raster used in computation
+
+ :return: output raster map name as a result of digitization
+ """
+ output = 'x' + str(uuid.uuid4())[:8]
+ asciiFile = tempfile.NamedTemporaryFile(delete=False)
+ asciiFile.write('\n'.join(text))
+ asciiFile.close()
+ if bufferDist:
+ gcore.run_command('r.in.poly', input=asciiFile.name, output=tempRaster,
+ overwrite=True, quiet=True)
+ gcore.run_command('r.grow', input=tempRaster, output=output,
+ flags='m', radius=bufferDist, quiet=True)
+ else:
+ gcore.run_command('r.in.poly', input=asciiFile.name, output=output,
+ quiet=True)
+ os.unlink(asciiFile.name)
+ return output
Property changes on: grass/trunk/gui/wxpython/rdigit/controller.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/trunk/gui/wxpython/rdigit/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/rdigit/dialogs.py (rev 0)
+++ grass/trunk/gui/wxpython/rdigit/dialogs.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -0,0 +1,119 @@
+"""
+ at package rdigit.dialogs
+
+ at brief rdigit dialog for craeting new map.
+
+Classes:
+ - rdigit:NewRasterDialog
+
+(C) 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.
+
+ at author Anna Petrasova <kratochanna gmail.com>
+"""
+
+import wx
+
+from core.utils import _
+from gui_core.gselect import Select
+from core.gcmd import GWarning
+
+import grass.script.core as gcore
+import grass.script.raster as grast
+from grass.exceptions import CalledModuleError
+
+
+class NewRasterDialog(wx.Dialog):
+ """Dialog for new raster map name and type selection
+ and selection of optional background map."""
+ def __init__(self, parent):
+ wx.Dialog.__init__(self, parent)
+ self.SetTitle(_("Create new raster map"))
+ self._name = None
+ self._type = None
+
+ # create widgets
+ self._mapSelect = Select(parent=self, type='rast')
+ self._backgroundSelect = Select(parent=self, type='rast')
+ self._typeChoice = wx.Choice(self, choices=['CELL', 'FCELL', 'DCELL'])
+ self._typeChoice.SetSelection(0)
+ self._mapSelect.SetFocus()
+
+ btnCancel = wx.Button(parent=self, id=wx.ID_CANCEL)
+ btnOK = wx.Button(parent=self, id=wx.ID_OK)
+ btnOK.SetDefault()
+ btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
+
+ # do layout
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ sizer = wx.GridBagSizer(hgap=10, vgap=10)
+ sizer.Add(wx.StaticText(self, label=_("Name for new raster map:")),
+ pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+ sizer.Add(self._mapSelect, pos=(1, 0), span=(1, 2))
+ sizer.Add(wx.StaticText(self, label=_("Optionally select background raster map:")),
+ pos=(2, 0), span=(1, 2), flag=wx.ALIGN_CENTER_VERTICAL)
+ sizer.Add(self._backgroundSelect, pos=(3, 0), span=(1, 2))
+ sizer.Add(wx.StaticText(self, label=_("New raster map type:")),
+ pos=(4, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+ sizer.Add(self._typeChoice, pos=(4, 1), flag=wx.EXPAND)
+
+ mainSizer.Add(sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(btnCancel)
+ btnSizer.AddButton(btnOK)
+ btnSizer.Realize()
+
+ mainSizer.Add(btnSizer, flag=wx.EXPAND | wx.ALL, border=10)
+
+ self._backgroundSelect.Bind(wx.EVT_TEXT, self.OnBackgroundMap)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def OnBackgroundMap(self, event):
+ value = self._backgroundSelect.GetValue()
+ try:
+ ret = grast.raster_info(value)
+ self._typeChoice.SetStringSelection(ret['datatype'])
+ except CalledModuleError:
+ return
+
+ def OnOK(self, event):
+ mapName = self.GetMapName()
+ if not mapName:
+ GWarning(parent=self.GetParent(), message=_("Please specify name for a new raster map"))
+ else:
+ found = gcore.find_file(name=mapName, mapset=gcore.gisenv()['MAPSET'])
+ if found and found['mapset'] == gcore.gisenv()['MAPSET']:
+ dlgOverwrite = wx.MessageDialog(
+ self.GetParent(), message=_("Raster map <%s> already exists "
+ "in the current mapset. "
+ "Do you want to overwrite it?") % mapName,
+ caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if not dlgOverwrite.ShowModal() == wx.ID_YES:
+ dlgOverwrite.Destroy()
+ return
+ else:
+ dlgOverwrite.Destroy()
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_OK)
+
+ def GetMapName(self):
+ return self._mapSelect.GetValue()
+
+ def GetBackgroundMapName(self):
+ return self._backgroundSelect.GetValue()
+
+ def GetMapType(self):
+ return self._typeChoice.GetStringSelection()
+
+
+if __name__ == '__main__':
+ app = wx.App()
+ dlg = NewRasterDialog(None)
+ dlg.Show()
+ app.MainLoop()
Property changes on: grass/trunk/gui/wxpython/rdigit/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/trunk/gui/wxpython/rdigit/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/rdigit/toolbars.py (rev 0)
+++ grass/trunk/gui/wxpython/rdigit/toolbars.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -0,0 +1,173 @@
+"""
+ at package rdigit.toolbars
+
+ at brief rdigit toolbars and icons.
+
+Classes:
+ - toolbars::RDigitToolbar
+
+(C) 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.
+
+ at author Anna Petrasova <kratochanna gmail.com>
+"""
+
+import wx
+
+from core.utils import _
+from gui_core.toolbars import BaseToolbar
+from icons.icon import MetaIcon
+from gui_core.widgets import FloatValidator
+import wx.lib.colourselect as csel
+
+
+rdigitIcons = {'area': MetaIcon(img='polygon-create',
+ label=_('Digitize area')),
+ 'line': MetaIcon(img='line-create',
+ label=_('Digitize line')),
+ 'point': MetaIcon(img='point-create',
+ label=_('Digitize point')),
+ 'save': MetaIcon(img='save', label=_("Save raster map")),
+ 'undo': MetaIcon(img='undo', label=_("Undo")),
+ 'quit': MetaIcon(img='quit', label=_("Quit raster digitizer"))}
+
+
+class RDigitToolbar(BaseToolbar):
+ """RDigit toolbar
+ """
+ def __init__(self, parent, controller, toolSwitcher):
+ """RDigit toolbar constructor
+ """
+ BaseToolbar.__init__(self, parent, toolSwitcher)
+ self._controller = controller
+ self.InitToolbar(self._toolbarData())
+
+ self._mapSelectionComboId = wx.NewId()
+ self._mapSelectionCombo = wx.ComboBox(self, id=self._mapSelectionComboId,
+ value=_("Select raster map"),
+ choices=[], size=(120, -1))
+ self._mapSelectionCombo.Bind(wx.EVT_COMBOBOX, self.OnMapSelection)
+ self._mapSelectionCombo.SetEditable(False)
+ self.InsertControl(0, self._mapSelectionCombo)
+ self._previousMap = self._mapSelectionCombo.GetValue()
+
+ self._colorId = wx.NewId()
+ self._color = csel.ColourSelect(parent=self, colour=wx.GREEN,
+ size=(30, 30))
+ self._color.Bind(csel.EVT_COLOURSELECT, lambda evt: self._changeDrawColor())
+ self._color.SetToolTipString(_("Set drawing color (not raster cell color)"))
+ self.InsertControl(4, self._color)
+
+ self._cellValues = set(['1'])
+ self._valueComboId = wx.NewId()
+ # validator does not work with combobox, SetBackgroundColor is not working
+ self._valueCombo = wx.ComboBox(self, id=self._valueComboId,
+ choices=list(self._cellValues), size=(80, -1),
+ validator=FloatValidator())
+ self._valueCombo.Bind(wx.EVT_COMBOBOX, lambda evt: self._cellValueChanged())
+ self._valueCombo.Bind(wx.EVT_TEXT, lambda evt: self._cellValueChanged())
+ self._valueCombo.SetSelection(0)
+ self._cellValueChanged()
+ self.InsertControl(6, wx.StaticText(self, label=" %s" % _("Cell value:")))
+ self.InsertControl(7, self._valueCombo)
+
+ self._widthValueId = wx.NewId()
+ # validator does not work with combobox, SetBackgroundColor is not working
+ self._widthValue = wx.TextCtrl(self, id=self._widthValueId, value='0',
+ size=(80, -1), validator=FloatValidator())
+ self._widthValue.Bind(wx.EVT_TEXT, lambda evt: self._widthValueChanged())
+ self._widthValueChanged()
+ self._widthValue.SetToolTipString(_("Width of currently digitized line/point in map units."))
+ self.InsertControl(8, wx.StaticText(self, label=" %s" % _("Width:")))
+ self.InsertControl(9, self._widthValue)
+
+ for tool in (self.area, self.line, self.point):
+ self.toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self, tool=tool)
+ self.toolSwitcher.toggleToolChanged.connect(self.CheckSelectedTool)
+ self._default = self.area
+ # realize the toolbar
+ self.Realize()
+
+ def _toolbarData(self):
+ """Toolbar data"""
+ return self._getToolbarData((('area', rdigitIcons['area'],
+ lambda event: self._controller.SelectType('area'),
+ wx.ITEM_CHECK),
+ ('line', rdigitIcons['line'],
+ lambda event: self._controller.SelectType('line'),
+ wx.ITEM_CHECK),
+ ('point', rdigitIcons['point'],
+ lambda event: self._controller.SelectType('point'),
+ wx.ITEM_CHECK),
+ (None, ),
+ (None, ),
+ ('undo', rdigitIcons['undo'],
+ lambda event: self._controller.Undo()),
+ ('save', rdigitIcons['save'],
+ lambda event: self._controller.Save()),
+ ('quit', rdigitIcons['quit'],
+ lambda event: self._controller.Stop())))
+
+ def CheckSelectedTool(self, id):
+ print self.toolSwitcher.IsToolInGroup(tool=id, group='mouseUse')
+ if self.toolSwitcher.IsToolInGroup(tool=id, group='mouseUse') \
+ and id not in (self.area, self.line, self.point):
+ self._controller.SelectType(None)
+
+ def UpdateRasterLayers(self, rasters):
+ new = _("New raster map")
+ items = [raster.name for raster in rasters if raster.name is not None]
+ items.insert(0, new)
+ self._mapSelectionCombo.SetItems(items)
+
+ def OnMapSelection(self, event):
+ """!Either map to edit or create new map selected."""
+ idx = self._mapSelectionCombo.GetSelection()
+ if idx == 0:
+ ret = self._controller.SelectNewMap()
+ else:
+ ret = self._controller.SelectOldMap(self._mapSelectionCombo.GetString(idx))
+ if not ret:
+ # in wxpython 3 we can't set value which is not in the items
+ # when not editable
+ self._mapSelectionCombo.SetEditable(True)
+ self._mapSelectionCombo.SetValue(self._previousMap)
+ self._mapSelectionCombo.SetEditable(False)
+ # we need to get back to previous
+ self._previousMap = self._mapSelectionCombo.GetValue()
+
+ def NewRasterAdded(self, name):
+ idx = self._mapSelectionCombo.Append(name)
+ self._mapSelectionCombo.SetSelection(idx)
+
+ def UpdateCellValues(self, values=None):
+ if not values:
+ values = [self._valueCombo.GetValue()]
+ for value in values:
+ self._cellValues.add(str(value))
+
+ valList = sorted(list(self._cellValues), key=float)
+ self._valueCombo.SetItems(valList)
+
+ def _cellValueChanged(self):
+ value = self._valueCombo.GetValue()
+ try:
+ value = float(value)
+ self._controller.SetCellValue(value)
+ except ValueError:
+ return
+
+ def _widthValueChanged(self):
+ value = self._widthValue.GetValue()
+ try:
+ value = float(value)
+ self._controller.SetWidthValue(value)
+ except ValueError:
+ self._controller.SetWidthValue(0)
+ return
+
+ def _changeDrawColor(self):
+ color = self._color.GetColour()
+ self._controller.ChangeDrawColor(color=color)
Property changes on: grass/trunk/gui/wxpython/rdigit/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/trunk/gui/wxpython/vdigit/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/toolbars.py 2014-11-18 03:24:44 UTC (rev 62791)
+++ grass/trunk/gui/wxpython/vdigit/toolbars.py 2014-11-18 04:00:51 UTC (rev 62792)
@@ -913,7 +913,7 @@
if self.combo:
self.combo.SetValue(mapLayer.GetName())
if 'map' in self.parent.toolbars:
- self.parent.toolbars['map'].combo.SetValue (_('Digitize'))
+ self.parent.toolbars['map'].combo.SetValue (_('Vector digitizer'))
# here was dead code to enable vdigit button in toolbar
# with if to ignore iclass
More information about the grass-commit
mailing list