[GRASS-SVN] r57427 - in grass/trunk/gui/wxpython: . gcp gui_core iclass mapdisp mapswipe mapwin nviz vdigit

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Aug 6 09:10:51 PDT 2013


Author: wenzeslaus
Date: 2013-08-06 09:10:51 -0700 (Tue, 06 Aug 2013)
New Revision: 57427

Added:
   grass/trunk/gui/wxpython/mapwin/
   grass/trunk/gui/wxpython/mapwin/__init__.py
   grass/trunk/gui/wxpython/mapwin/analysis.py
   grass/trunk/gui/wxpython/mapwin/base.py
   grass/trunk/gui/wxpython/mapwin/buffered.py
   grass/trunk/gui/wxpython/mapwin/decorations.py
   grass/trunk/gui/wxpython/mapwin/graphics.py
Removed:
   grass/trunk/gui/wxpython/gui_core/mapwindow.py
   grass/trunk/gui/wxpython/mapdisp/analysis.py
   grass/trunk/gui/wxpython/mapdisp/mapwindow.py
   grass/trunk/gui/wxpython/mapdisp/overlays.py
Modified:
   grass/trunk/gui/wxpython/Makefile
   grass/trunk/gui/wxpython/gcp/mapdisplay.py
   grass/trunk/gui/wxpython/gui_core/dialogs.py
   grass/trunk/gui/wxpython/iclass/frame.py
   grass/trunk/gui/wxpython/mapdisp/frame.py
   grass/trunk/gui/wxpython/mapdisp/test_mapdisp.py
   grass/trunk/gui/wxpython/mapswipe/frame.py
   grass/trunk/gui/wxpython/mapswipe/mapwindow.py
   grass/trunk/gui/wxpython/nviz/mapwindow.py
   grass/trunk/gui/wxpython/vdigit/dialogs.py
   grass/trunk/gui/wxpython/vdigit/main.py
   grass/trunk/gui/wxpython/vdigit/mapwindow.py
   grass/trunk/gui/wxpython/vdigit/wxdigit.py
Log:
wxGUI/mapwin: new mapwin subdirectory with map window related code including buffered window

Modified: grass/trunk/gui/wxpython/Makefile
===================================================================
--- grass/trunk/gui/wxpython/Makefile	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/Makefile	2013-08-06 16:10:51 UTC (rev 57427)
@@ -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 mapdisp/*.py \
+	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* vdigit/* \
 	vnet/*.py web_services/*.py wxplot/*.py) \
 	gis_set.py gis_set_error.py wxgui.py README
@@ -20,7 +20,7 @@
 	$(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
 
 PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
-	gui_core iclass lmgr location_wizard mapdisp modules nviz psmap \
+	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
 	mapswipe vdigit wxplot web_services rlisetup vnet)
 
 DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)

Modified: grass/trunk/gui/wxpython/gcp/mapdisplay.py
===================================================================
--- grass/trunk/gui/wxpython/gcp/mapdisplay.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/gcp/mapdisplay.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -31,8 +31,8 @@
 from gui_core.dialogs  import GetImageHandlers, ImageSizeDialog
 from gui_core.mapdisp  import SingleMapFrame
 from core.settings     import UserSettings
-from mapdisp.mapwindow import BufferedWindow
-from gui_core.mapwindow import MapWindowProperties
+from mapwin.buffered import BufferedMapWindow
+from mapwin.base import MapWindowProperties
 
 import mapdisp.statusbar as sb
 import gcp.statusbar as sbgcp
@@ -114,14 +114,14 @@
         # Init map display (buffered DC & set default cursor)
         #
         self.grwiz.SwitchEnv('source')
-        self.SrcMapWindow = BufferedWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
-                                           properties=self.mapWindowProperties,
-                                           Map=self.SrcMap)
+        self.SrcMapWindow = BufferedMapWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
+                                              properties=self.mapWindowProperties,
+                                              Map=self.SrcMap)
 
         self.grwiz.SwitchEnv('target')
-        self.TgtMapWindow = BufferedWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
-                                           properties=self.mapWindowProperties,
-                                          Map=self.TgtMap)
+        self.TgtMapWindow = BufferedMapWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
+                                              properties=self.mapWindowProperties,
+                                              Map=self.TgtMap)
         self.MapWindow = self.SrcMapWindow
         self.Map = self.SrcMap
         self._setUpMapWindow(self.SrcMapWindow)

Modified: grass/trunk/gui/wxpython/gui_core/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/dialogs.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/gui_core/dialogs.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -9,8 +9,6 @@
  - dialogs::MapsetDialog
  - dialogs::NewVectorDialog
  - dialogs::SavedRegion
- - dialogs::DecorationDialog
- - dialogs::TextLayerDialog 
  - dialogs::GroupDialog
  - dialogs::MapLayersDialog
  - dialogs::ImportDialog
@@ -49,9 +47,8 @@
 from core             import globalvar
 from core.gcmd        import GError, RunCommand, GMessage
 from gui_core.gselect import LocationSelect, MapsetSelect, Select, OgrTypeSelect, GdalSelect, MapsetSelect
-from gui_core.forms   import GUI
 from gui_core.widgets import SingleSymbolPanel, GListCtrl, SimpleValidator
-from core.utils       import GetLayerNameFromCmd, GetValidLayerName, _
+from core.utils       import GetValidLayerName, _
 from core.settings    import UserSettings, GetDisplayVectSettings
 from core.debug       import Debug
 
@@ -510,366 +507,8 @@
     def GetName(self):
         """!Return region name"""
         return self.wind
-    
-DECOR_DIALOG_LEGEND = 0
-DECOR_DIALOG_BARSCALE = 1
 
-class DecorationDialog(wx.Dialog):
-    """!Controls setting options and displaying/hiding map overlay
-    decorations
-    """
-    def __init__(self, parent, title, giface, overlayController,
-                 ddstyle, **kwargs):
-        
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, **kwargs)
-        
-        self.parent  = parent  # MapFrame
-        self._overlay = overlayController
-        self._ddstyle = ddstyle
-        self._giface = giface
-        
-        self._oldMouseUse = None
-        self._oldCursor = None
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY)
-        self.chkbox.SetValue(True)
 
-        if self._ddstyle == DECOR_DIALOG_LEGEND:
-            self.chkbox.SetLabel("Show legend")
-        else:
-            self.chkbox.SetLabel("Show scale and North arrow")
-
-
-        box.Add(item = self.chkbox, proportion = 0,
-                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        optnbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set options"))
-        box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        if self._ddstyle == DECOR_DIALOG_LEGEND:
-            box = wx.BoxSizer(wx.HORIZONTAL)
-            self.resizeBtn = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
-            self.resizeBtn.SetToolTipString(_("Click and drag on the map display to set legend "
-                                              "size and position and then press OK"))
-            self.resizeBtn.Disable()
-            self.resizeBtn.Bind(wx.EVT_TOGGLEBUTTON, self.OnResize)
-            box.Add(item = self.resizeBtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-            sizer.Add(item = box, proportion = 0,
-                      flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        if self._ddstyle == DECOR_DIALOG_LEGEND:
-            labelText = _("Drag legend object with mouse in pointer mode to position.\n"
-                          "Double-click to change options.\n"
-                          "Define raster map name for legend in properties dialog.")
-        else:
-            labelText = _("Drag scale object with mouse in pointer mode to position.\n"
-                          "Double-click to change options.")
-
-        label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = labelText)
-
-        box.Add(item = label, proportion = 0,
-                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20,-1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        # buttons
-        btnsizer = wx.StdDialogButtonSizer()
-
-        self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
-        self.btnOK.SetDefault()
-        self.btnOK.Enable(self._ddstyle != DECOR_DIALOG_LEGEND)
-        btnsizer.AddButton(self.btnOK)
-
-        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btnCancel)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
-
-        #
-        # bindings
-        #
-        optnbtn.Bind(wx.EVT_BUTTON, self.OnOptions)
-        btnCancel.Bind(wx.EVT_BUTTON, lambda evt: self.CloseDialog())
-        self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-        mapName, found = GetLayerNameFromCmd(self._overlay.cmd)
-        if found:
-            # enable 'OK' and 'Resize' button
-            self.btnOK.Enable()
-
-            # set title
-            self.SetTitle(_('Legend of raster map <%s>') % \
-                              mapName)
-        
-    def OnOptions(self, event):
-        """!Sets option for decoration map overlays
-        """
-        if self._overlay.propwin is None:
-            # build properties dialog
-            GUI(parent = self.parent).ParseCommand(cmd = self._overlay.cmd,
-                                                   completed = (self.GetOptData, self._overlay.name, ''))
-            
-        else:
-            if self._overlay.propwin.IsShown():
-                self._overlay.propwin.SetFocus()
-            else:
-                self._overlay.propwin.Show()
-
-    def OnResize(self, event):
-        window = self._giface.GetMapWindow()
-        if event.GetInt(): 
-            self._oldMouseUse = window.mouse['use']
-            self._oldCursor = window.GetNamedCursor()
-            window.SetNamedCursor('cross')
-            window.mouse['use'] = None
-            window.mouse['box'] = 'box'
-            window.pen = wx.Pen(colour = 'Black', width = 2, style = wx.SHORT_DASH)
-            window.mouseLeftUp.connect(self._resizeLegend)
-        else:
-            self.Restore()
-            self.DisconnectResizing()
-
-    def Restore(self):
-        """!Restore conditions before resizing"""
-        window = self._giface.GetMapWindow()
-        if self._oldCursor:
-            window.SetNamedCursor(self._oldCursor)
-        if self._oldMouseUse:
-            window.mouse['use'] = self._oldMouseUse
-
-    def DisconnectResizing(self):
-        self._giface.GetMapWindow().mouseLeftUp.disconnect(self._resizeLegend)
-
-    def _resizeLegend(self, x, y):
-        """!Update legend after drawing new legend size (moved from BufferedWindow)"""
-        self.resizeBtn.SetValue(False)
-        window = self._giface.GetMapWindow()
-        self.DisconnectResizing()
-        self.Restore()
-        # resize legend
-        screenSize = window.GetClientSizeTuple()
-        self._overlay.ResizeLegend(window.mouse["begin"], window.mouse["end"], screenSize)
-        # redraw
-        self._giface.updateMap.emit()
-
-    def CloseDialog(self):
-        """!Hide dialog"""
-        if self._ddstyle == DECOR_DIALOG_LEGEND and self.resizeBtn.GetValue():
-            self.Restore()
-            self.resizeBtn.SetValue(False)
-            self.DisconnectResizing()
-
-        self.Hide()
-
-    def OnOK(self, event):
-        """!Button 'OK' pressed"""
-        # enable or disable overlay
-        self._overlay.Show(self.chkbox.IsChecked())
-
-        # update map
-        if self.parent.IsPaneShown('3d'):
-            self.parent.MapWindow.UpdateOverlays()
-
-        self._giface.updateMap.emit()
-
-        # hide dialog
-        self.CloseDialog()
-
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """!Process decoration layer data"""
-        if dcmd:
-            self._overlay.cmd = dcmd
-        self._overlay.propwin = propwin
-        if params:
-            self.btnOK.Enable()
-            if self._ddstyle == DECOR_DIALOG_LEGEND and not self.parent.IsPaneShown('3d'):
-                self.resizeBtn.Enable()
-
-    def Show(self, show=True):
-        if show:
-            self.resizeBtn.Enable(not self.parent.IsPaneShown('3d'))
-        wx.Dialog.Show(self, show)
-        
-class TextLayerDialog(wx.Dialog):
-    """
-    Controls setting options and displaying/hiding map overlay decorations
-    """
-
-    def __init__(self, parent, ovlId, title, name = 'text',
-                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE):
-
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
-        from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
-
-        self.ovlId = ovlId
-        self.parent = parent
-
-        if self.ovlId in self.parent.MapWindow.textdict.keys():
-            self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
-            self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
-            self.currClr  = self.parent.MapWindow.textdict[self.ovlId]['color']
-            self.currRot  = self.parent.MapWindow.textdict[self.ovlId]['rotation']
-            self.currCoords = self.parent.MapWindow.textdict[self.ovlId]['coords']
-            self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
-        else:
-            self.currClr = wx.BLACK
-            self.currText = ''
-            self.currFont = self.GetFont()
-            self.currRot = 0.0
-            self.currCoords = [10, 10]
-            self.currBB = wx.Rect()
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.GridBagSizer(vgap = 5, hgap = 5)
-
-        # show/hide
-        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                  label = _('Show text object'))
-        if self.parent.Map.GetOverlay(self.ovlId) is None:
-            self.chkbox.SetValue(True)
-        else:
-            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
-        box.Add(item = self.chkbox, span = (1,2),
-                flag = wx.ALIGN_LEFT|wx.ALL, border = 5,
-                pos = (0, 0))
-
-        # text entry
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Enter text:"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL,
-                pos = (1, 0))
-
-        self.textentry = ExpandoTextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (300,-1))
-        self.textentry.SetFont(self.currFont)
-        self.textentry.SetForegroundColour(self.currClr)
-        self.textentry.SetValue(self.currText)
-        # get rid of unneeded scrollbar when text box first opened
-        self.textentry.SetClientSize((300,-1))
-        
-        box.Add(item = self.textentry,
-                pos = (1, 1))
-
-        # rotation
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Rotation:"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL,
-                pos = (2, 0))
-        self.rotation = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                    size = (75,-1), style = wx.SP_ARROW_KEYS)
-        self.rotation.SetRange(-360, 360)
-        self.rotation.SetValue(int(self.currRot))
-        box.Add(item = self.rotation,
-                flag = wx.ALIGN_RIGHT,
-                pos = (2, 1))
-
-        # font
-        fontbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set font"))
-        box.Add(item = fontbtn,
-                flag = wx.ALIGN_RIGHT,
-                pos = (3, 1))
-
-        self.sizer.Add(item = box, proportion = 1,
-                  flag = wx.ALL, border = 10)
-
-        # note
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = _("Drag text with mouse in pointer mode "
-                                      "to position.\nDouble-click to change options"))
-        box.Add(item = label, proportion = 0,
-                flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
-        self.sizer.Add(item = box, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border = 5)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                             size = (20,-1), style = wx.LI_HORIZONTAL)
-        self.sizer.Add(item = line, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(parent = self, id = wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        self.sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        self.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-        # bindings
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
-        self.Bind(wx.EVT_BUTTON,     self.OnSelectFont, fontbtn)
-        self.Bind(wx.EVT_TEXT,       self.OnText,       self.textentry)
-        self.Bind(wx.EVT_SPINCTRL,   self.OnRotation,   self.rotation)
-
-    def OnRefit(self, event):
-        """!Resize text entry to match text"""
-        self.sizer.Fit(self)
-
-    def OnText(self, event):
-        """!Change text string"""
-        self.currText = event.GetString()
-
-    def OnRotation(self, event):
-        """!Change rotation"""
-        self.currRot = event.GetInt()
-
-        event.Skip()
-
-    def OnSelectFont(self, event):
-        """!Change font"""
-        data = wx.FontData()
-        data.EnableEffects(True)
-        data.SetColour(self.currClr)         # set colour
-        data.SetInitialFont(self.currFont)
-
-        dlg = wx.FontDialog(self, data)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            data = dlg.GetFontData()
-            self.currFont = data.GetChosenFont()
-            self.currClr = data.GetColour()
-
-            self.textentry.SetFont(self.currFont)
-            self.textentry.SetForegroundColour(self.currClr)
-
-            self.Layout()
-
-        dlg.Destroy()
-
-    def GetValues(self):
-        """!Get text properties"""
-        return { 'text' : self.currText,
-                 'font' : self.currFont,
-                 'color' : self.currClr,
-                 'rotation' : self.currRot,
-                 'coords' : self.currCoords,
-                 'active' : self.chkbox.IsChecked() }
-
 class GroupDialog(wx.Dialog):
     """!Dialog for creating/editing groups"""
     def __init__(self, parent = None, defaultGroup = None, 

Deleted: grass/trunk/gui/wxpython/gui_core/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/mapwindow.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/gui_core/mapwindow.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -1,356 +0,0 @@
-"""!
- at package gui_core.mapwindow
-
- at brief Map display canvas - base class for buffered window.
-
-Classes:
- - mapwindow::MapWindow
-
-(C) 2006-2012 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 Martin Landa <landa.martin gmail.com>
- at author Michael Barton
- at author Jachym Cepicky
- at author Vaclav Petras <wenzeslaus gmail.com> (handlers support)
- at author Stepan Turek <stepan.turek seznam.cz> (handlers support)
-"""
-
-import wx
-
-from core.settings import UserSettings
-from core.gcmd     import GError
-from core.utils import _
-
-from grass.script import core as grass
-from grass.pydispatch.signal import Signal
-
-
-class MapWindowProperties(object):
-    def __init__(self):
-        self._resolution = None
-        self.resolutionChanged = Signal('MapWindowProperties.resolutionChanged')
-        self._autoRender = None
-        self.autoRenderChanged = Signal('MapWindowProperties.autoRenderChanged')
-        self._showRegion = None
-        self.showRegionChanged = Signal('MapWindowProperties.showRegionChanged')
-        self._alignExtent = None
-        self.alignExtentChanged = Signal('MapWindowProperties.alignExtentChanged')
-
-    def setValuesFromUserSettings(self):
-        """Convenient function to get values from user settings into this object."""
-        self._resolution = UserSettings.Get(group='display',
-                                            key='compResolution',
-                                            subkey='enabled')
-        self._autoRender = UserSettings.Get(group='display',
-                                            key='autoRendering',
-                                            subkey='enabled')
-        self._showRegion = False  # in statusbar.py was not from settings
-        self._alignExtent = UserSettings.Get(group='display',
-                                             key='alignExtent',
-                                             subkey='enabled')
-    @property
-    def resolution(self):
-        return self._resolution
-
-    @resolution.setter
-    def resolution(self, value):
-        if value != self._resolution:
-            self._resolution = value
-            self.resolutionChanged.emit(value=value)
-
-    @property
-    def autoRender(self):
-        return self._autoRender
-
-    @autoRender.setter
-    def autoRender(self, value):
-        if value != self._autoRender:
-            self._autoRender = value
-            self.autoRenderChanged.emit(value=value)
-
-    @property
-    def showRegion(self):
-        return self._showRegion
-
-    @showRegion.setter
-    def showRegion(self, value):
-        if value != self._showRegion:
-            self._showRegion = value
-            self.showRegionChanged.emit(value=value)
-
-    @property
-    def alignExtent(self):
-        return self._alignExtent
-
-    @alignExtent.setter
-    def alignExtent(self, value):
-        if value != self._alignExtent:
-            self._alignExtent = value
-            self.alignExtentChanged.emit(value=value)
-
-
-class MapWindow(object):
-    """!Abstract map display window class
-    
-    Superclass for BufferedWindow class (2D display mode), and GLWindow
-    (3D display mode).
-    
-    Subclasses have to define
-     - _bindMouseEvents method which binds MouseEvent handlers
-     - Pixel2Cell
-     - Cell2Pixel (if it is possible)
-    """
-    def __init__(self, parent, giface, Map):
-        self.parent = parent
-        self.Map = Map
-        self._giface = giface
-
-        # Emitted when someone registers as mouse event handler
-        self.mouseHandlerRegistered = Signal('MapWindow.mouseHandlerRegistered')
-        # Emitted when mouse event handler is unregistered
-        self.mouseHandlerUnregistered = Signal('MapWindow.mouseHandlerUnregistered')
-        # emitted after double click in pointer mode on legend, text, scalebar
-        self.overlayActivated = Signal('MapWindow.overlayActivated')
-
-        # mouse attributes -- position on the screen, begin and end of
-        # dragging, and type of drawing
-        self.mouse = {
-            'begin': [0, 0], # screen coordinates
-            'end'  : [0, 0],
-            'use'  : "pointer",
-            'box'  : "point"
-            }
-        # last east, north coordinates, changes on mouse motion
-        self.lastEN = None 
-        
-        # stores overridden cursor
-        self._overriddenCursor = None
-
-        # dictionary where event types are stored as keys and lists of
-        # handlers for these types as values
-        self.handlersContainer = {
-            wx.EVT_LEFT_DOWN : [],
-            wx.EVT_LEFT_UP : [],
-            wx.EVT_LEFT_DCLICK : [],
-            wx.EVT_MIDDLE_DOWN : [],
-            wx.EVT_MIDDLE_UP : [],
-            wx.EVT_MIDDLE_DCLICK : [],
-            wx.EVT_RIGHT_DOWN : [],
-            wx.EVT_RIGHT_UP : [],
-            wx.EVT_RIGHT_DCLICK : [],
-            wx.EVT_MOTION : [],
-            wx.EVT_ENTER_WINDOW : [],
-            wx.EVT_LEAVE_WINDOW : [],
-            wx.EVT_MOUSEWHEEL : [],
-            wx.EVT_MOUSE_EVENTS : []
-            }
-
-        # available cursors
-        self._cursors = {
-            "default": wx.StockCursor(wx.CURSOR_ARROW),
-            "cross": wx.StockCursor(wx.CURSOR_CROSS),
-            "hand": wx.StockCursor(wx.CURSOR_HAND),
-            "pencil": wx.StockCursor(wx.CURSOR_PENCIL),
-            "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
-            }
-
-        # default cursor for window is arrow (at least we rely on it here)
-        # but we need to define attribute here
-        # cannot call SetNamedCursor since it expects the instance
-        # to be a wx window, so setting only the attribute
-        self._cursor = 'default'
-
-        wx.CallAfter(self.InitBinding)
-
-    def __del__(self):
-        self.UnregisterAllHandlers()
-
-    def InitBinding(self):
-        """!Binds helper functions, which calls all handlers
-           registered to events with the events
-        """
-        for ev, handlers in self.handlersContainer.iteritems():
-            self.Bind(ev, self.EventTypeHandler(handlers))
-    
-    def EventTypeHandler(self, evHandlers):
-        return lambda event:self.HandlersCaller(event, evHandlers)  
-    
-    def HandlersCaller(self, event, handlers):
-        """!Hepler function which calls all handlers registered for
-        event
-        """
-        for handler in handlers:
-            try:
-                handler(event)
-            except:
-                handlers.remove(handler)
-                GError(parent = self,
-                       message=_("Error occured during calling of handler: %s \n"
-                                 "Handler was unregistered.") % handler.__name__)
-        
-        event.Skip() 
-
-    def RegisterMouseEventHandler(self, event, handler, cursor = None):
-        """!Binds event handler
-
-        @depreciated This method is depreciated. Use Signals or drawing API instead.
-        Signals do not cover all events but new Signals can be added when needed
-        consider also adding generic signal. However, more interesing and useful
-        is higher level API to create objects, graphics etc.
-
-        Call event.Skip() in handler to allow default processing in MapWindow.
-
-        If any error occures inside of handler, the handler is removed.
-
-        Before handler is unregistered it is called with 
-        string value "unregistered" of event parameter.
-
-        @code
-        # your class methods
-        def OnButton(self, event):
-            # current map display's map window
-            # expects LayerManager to be the parent
-            self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
-            if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
-                                                wx.StockCursor(wx.CURSOR_CROSS)):
-                self.parent.GetLayerTree().GetMapDisplay().Raise()
-            else:
-                # handle that you cannot get coordinates
-        
-        def OnMouseAction(self, event):
-            # get real world coordinates of mouse click
-            coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
-            self.text.SetLabel('Coor: ' + str(coor))
-            self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction)
-            event.Skip()
-        @endcode
-
-        Emits mouseHandlerRegistered signal before handler is registered.        
-
-        @param event one of mouse events
-        @param handler function to handle event
-        @param cursor cursor which temporary overrides current cursor
-        
-        @return True if successful
-        @return False if event cannot be bind
-        """
-        self.mouseHandlerRegistered.emit()
-        # inserts handler into list
-        for containerEv, handlers in self.handlersContainer.iteritems():
-            if event == containerEv: 
-                handlers.append(handler)
-        
-        self.mouse['useBeforeGenericEvent'] = self.mouse['use']
-        self.mouse['use'] = 'genericEvent'
-        
-        if cursor:
-            self._overriddenCursor = self.GetNamedCursor()
-            self.SetNamedCursor(cursor)
-        
-        return True
-
-    def UnregisterAllHandlers(self):
-        """!Unregisters all registered handlers 
-
-        @depreciated This method is depreciated. Use Signals or drawing API instead.
-
-        Before each handler is unregistered it is called with string
-        value "unregistered" of event parameter.
-        """
-        for containerEv, handlers in self.handlersContainer.iteritems():
-            for handler in handlers:
-                try:
-                    handler("unregistered")
-                    handlers.remove(handler)
-                except:
-                    GError(parent = self,
-                           message = _("Error occured during unregistration of handler: %s \n \
-                                       Handler was unregistered.") % handler.__name__)
-                    handlers.remove(handler)
-        
-    def UnregisterMouseEventHandler(self, event, handler):
-        """!Unbinds event handler for event
-
-        @depreciated This method is depreciated. Use Signals or drawing API instead.
-
-        Before handler is unregistered it is called with string value
-        "unregistered" of event parameter.
-
-        Emits mouseHandlerUnregistered signal after handler is unregistered.
-
-        @param handler handler to unbind
-        @param event event from which handler will be unbinded
-        
-        @return True if successful
-        @return False if event cannot be unbind
-        """
-        # removes handler from list 
-        for containerEv, handlers in self.handlersContainer.iteritems():
-            if event != containerEv:
-                continue
-            try:
-                handler("unregistered")
-                if handler in handlers:
-                    handlers.remove(handler)
-                else:
-                    grass.warning(_("Handler: %s was not registered") \
-                                      % handler.__name__)
-            except:
-                GError(parent = self,
-                       message = _("Error occured during unregistration of handler: %s \n \
-                                       Handler was unregistered") % handler.__name__)
-                handlers.remove(handler) 
-        
-        # restore mouse use (previous state)
-        self.mouse['use'] = self.mouse['useBeforeGenericEvent']
-        
-        # restore overridden cursor
-        if self._overriddenCursor:
-            self.SetNamedCursor(self._overriddenCursor)
-
-        self.mouseHandlerUnregistered.emit()
-        return True
-    
-    def Pixel2Cell(self, xyCoords):
-        raise NotImplementedError()
-    
-    def Cell2Pixel(self, enCoords):
-        raise NotImplementedError()
-
-    def OnMotion(self, event):
-        """!Tracks mouse motion and update statusbar
-
-        @todo remove this method when lastEN is not used
-
-        @see GetLastEN
-        """
-        try:
-            self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
-        except (ValueError):
-            self.lastEN = None
-
-        event.Skip()
-
-    def GetLastEN(self):
-        """!Returns last coordinates of mouse cursor.
-
-        @depreciated This method is depreciated. Use Signal with coordinates as parameters.
-
-        @see OnMotion
-        """
-        return self.lastEN
-
-    def SetNamedCursor(self, cursorName):
-        """!Sets cursor defined by name."""
-        cursor = self._cursors[cursorName]
-        self.SetCursor(cursor)
-        self._cursor = cursorName
-
-    def GetNamedCursor(self):
-        """!Returns current cursor name."""
-        return self._cursor
-
-    cursor = property(fget=GetNamedCursor, fset=SetNamedCursor)

Modified: grass/trunk/gui/wxpython/iclass/frame.py
===================================================================
--- grass/trunk/gui/wxpython/iclass/frame.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/iclass/frame.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -45,13 +45,13 @@
 import grass.script as grass
 
 from mapdisp            import statusbar as sb
-from mapdisp.mapwindow  import BufferedWindow
+from mapwin.buffered import BufferedMapWindow
 from vdigit.toolbars    import VDigitToolbar
 from gui_core.mapdisp   import DoubleMapFrame
 from core.render        import Map, MapLayer
 from core.gcmd          import RunCommand, GMessage, GError, GWarning
 from gui_core.dialogs   import SetOpacityDialog
-from gui_core.mapwindow import MapWindowProperties
+from mapwin.base import MapWindowProperties
 from dbmgr.vinfo        import VectorDBInfo
 import grass.script as grass
 
@@ -96,9 +96,9 @@
         self.firstMapWindow = IClassVDigitWindow(parent = self, giface = self._giface,
                                                  properties=self.mapWindowProperties,
                                                  map = self.firstMap)
-        self.secondMapWindow = BufferedWindow(parent = self, giface = self._giface,
-                                              properties=self.mapWindowProperties,
-                                              Map = self.secondMap)
+        self.secondMapWindow = BufferedMapWindow(parent=self, giface=self._giface,
+                                                 properties=self.mapWindowProperties,
+                                                 Map=self.secondMap)
         self.MapWindow = self.firstMapWindow # current by default
         
         self._bindWindowsActivation()

Deleted: grass/trunk/gui/wxpython/mapdisp/analysis.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/analysis.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapdisp/analysis.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -1,284 +0,0 @@
-# -*- coding: utf-8 -*-
-"""!
- at package mapdisp.analysis
-
- at brief Map display controllers for analyses (profiling, measuring)
-
-Classes:
- - analysis::AnalysisControllerBase
- - analysis::ProfileController
- - analysis::MeasureDistanceController
-
-(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 math
-import wx
-
-from core.utils import _
-import core.units as units
-
-from grass.pydispatch.signal import Signal
-
-
-class AnalysisControllerBase:
-    """!Base class for analysis which require drawing line in map display."""
-    def __init__(self, giface, mapWindow):
-        """!
-
-        @param giface grass interface
-        @param mapWindow instance of BufferedWindow
-        """
-        self._giface = giface
-        self._mapWindow = mapWindow
-
-        self._registeredGraphics = None
-
-        self._oldMouseUse = None
-        self._oldCursor = None
-
-    def IsActive(self):
-        """!Returns True if analysis mode is activated."""
-        return bool(self._registeredGraphics)
-
-    def _start(self, x, y):
-        """!Handles the actual start of drawing line
-        and adding each new point.
-
-        @param x,y east north coordinates
-        """
-        if not self._registeredGraphics.GetAllItems():
-            item = self._registeredGraphics.AddItem(coords=[[x, y]])
-            item.SetPropertyVal('penName', 'analysisPen')
-        else:
-            # needed to switch mouse begin and end to draw intermediate line properly
-            coords = self._registeredGraphics.GetItem(0).GetCoords()[-1]
-            self._mapWindow.mouse['begin'] = self._mapWindow.Cell2Pixel(coords)
-
-    def _addPoint(self, x, y):
-        """!New point added.
-
-        @param x,y east north coordinates
-        """
-        # add new point and calculate distance
-        item = self._registeredGraphics.GetItem(0)
-        coords = item.GetCoords() + [[x, y]]
-        item.SetCoords(coords)
-        # draw
-        self._mapWindow.ClearLines()
-        self._registeredGraphics.Draw(pdc=self._mapWindow.pdcTmp)
-        wx.Yield()
-
-        self._doAnalysis(coords)
-
-    def _doAnalysis(self, coords):
-        """!Perform the required analysis
-        (compute distnace, update profile)
-
-        @param coords EN coordinates
-        """
-        raise NotImplementedError()
-
-    def _disconnectAll(self):
-        """!Disconnect all mouse signals
-        to stop drawing."""
-        raise NotImplementedError()
-
-    def _connectAll(self):
-        """!Connect all mouse signals to draw."""
-        raise NotImplementedError()
-
-    def _getPen(self):
-        """!Returns wx.Pen instance."""
-        raise NotImplementedError()
-
-    def Stop(self, restore=True):
-        """!Analysis mode is stopped.
-
-        @param restore if restore previous cursor, mouse['use']
-        """
-        self._mapWindow.ClearLines(pdc=self._mapWindow.pdcTmp)
-        self._mapWindow.mouse['end'] = self._mapWindow.mouse['begin']
-        # disconnect mouse events
-        self._disconnectAll()
-        # unregister
-        self._mapWindow.UnregisterGraphicsToDraw(self._registeredGraphics)
-        self._registeredGraphics = None
-        self._mapWindow.Refresh()
-
-        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 Start(self):
-        """!Init analysis: register graphics to map window,
-        connect required mouse signals.
-        """
-        self._oldMouseUse = self._mapWindow.mouse['use']
-        self._oldCursor = self._mapWindow.GetNamedCursor()
-
-        self._registeredGraphics = self._mapWindow.RegisterGraphicsToDraw(graphicsType='line')
-
-        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)
-
-        self._registeredGraphics.AddPen('analysisPen', self._getPen())
-
-        # change the cursor
-        self._mapWindow.SetNamedCursor('pencil')
-
-
-class ProfileController(AnalysisControllerBase):
-    """!Class controls profiling in map display.
-    It should be used inside ProfileFrame
-    """
-    def __init__(self, giface, mapWindow):
-        AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
-
-        self.transectChanged = Signal('ProfileController.transectChanged')
-
-    def _doAnalysis(self, coords):
-        """!Informs profile dialog that profile changed.
-
-        @param coords EN coordinates
-        """
-        self.transectChanged.emit(coords=coords)
-
-    def _disconnectAll(self):
-        self._mapWindow.mouseLeftDown.disconnect(self._start)
-        self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
-
-    def _connectAll(self):
-        self._mapWindow.mouseLeftDown.connect(self._start)
-        self._mapWindow.mouseLeftUp.connect(self._addPoint)
-
-    def _getPen(self):
-        return wx.Pen(colour=wx.Colour(0, 100, 0), width=2, style=wx.SHORT_DASH)
-
-    def Stop(self, restore=True):
-        AnalysisControllerBase.Stop(self, restore=restore)
-
-        self.transectChanged.emit(coords=[])
-
-
-class MeasureDistanceController(AnalysisControllerBase):
-    """!Class controls measuring distance in map display."""
-    def __init__(self, giface, mapWindow):
-        AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
-
-        self._projInfo = self._mapWindow.Map.projinfo
-        self._totaldist = 0.0  # total measured distance
-        self._useCtypes = False
-
-    def _doAnalysis(self, coords):
-        """!New point added.
-
-        @param x,y east north coordinates
-        """
-        self.MeasureDist(coords[-2], coords[-1])
-
-    def _disconnectAll(self):
-        self._mapWindow.mouseLeftDown.disconnect(self._start)
-        self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
-        self._mapWindow.mouseDClick.disconnect(self.Stop)
-
-    def _connectAll(self):
-        self._mapWindow.mouseLeftDown.connect(self._start)
-        self._mapWindow.mouseLeftUp.connect(self._addPoint)
-        self._mapWindow.mouseDClick.connect(self.Stop)
-
-    def _getPen(self):
-        return wx.Pen(colour='green', width=2, style=wx.SHORT_DASH)
-
-    def Stop(self, restore=True):
-        AnalysisControllerBase.Stop(self, restore=restore)
-
-        self._giface.WriteCmdLog(_('Measuring finished'))
-
-    def Start(self):
-        """!Init measurement routine that calculates map distance
-        along transect drawn on map display
-        """
-        AnalysisControllerBase.Start(self)
-        self._totaldist = 0.0  # total measured distance
-
-        # initiating output (and write a message)
-        # e.g., in Layer Manager switch to output console
-        # TODO: this should be something like: write important message or write tip
-        # TODO: mixed 'switching' and message? no, measuring handles 'swithing' on its own
-        self._giface.WriteWarning(_('Click and drag with left mouse button '
-                                    'to measure.%s'
-                                    'Double click with left button to clear.') % \
-                                    (os.linesep))
-        if self._projInfo['proj'] != 'xy':
-            mapunits = self._projInfo['units']
-            self._giface.WriteCmdLog(_('Measuring distance') + ' ('
-                                      + mapunits + '):')
-        else:
-            self._giface.WriteCmdLog(_('Measuring distance:'))
-
-        if self._projInfo['proj'] == 'll':
-            try:
-                import grass.lib.gis as gislib
-                gislib.G_begin_distance_calculations()
-                self._useCtypes = True
-            except ImportError, e:
-                self._giface.WriteWarning(_('Geodesic distance calculation '
-                                            'is not available.\n'
-                                            'Reason: %s' % e))
-
-    def MeasureDist(self, beginpt, endpt):
-        """!Calculate distance and print to output window.
-
-        @param beginpt,endpt EN coordinates
-        """
-        # move also Distance method?
-        dist, (north, east) = self._mapWindow.Distance(beginpt, endpt, screen=False)
-
-        dist = round(dist, 3)
-        mapunits = self._projInfo['units']
-        if mapunits == 'degrees' and self._useCtypes:
-            mapunits = 'meters'
-        d, dunits = units.formatDist(dist, mapunits)
-
-        self._totaldist += dist
-        td, tdunits = units.formatDist(self._totaldist,
-                                       mapunits)
-
-        strdist = str(d)
-        strtotdist = str(td)
-
-        if self._projInfo['proj'] == 'xy' or 'degree' not in self._projInfo['unit']:
-            angle = int(math.degrees(math.atan2(north, east)) + 0.5)
-            # uncomment below (or flip order of atan2(y,x) above) to use
-            #   the mathematical theta convention (CCW from +x axis)
-            #angle = 90 - angle
-            if angle < 0:
-                angle = 360 + angle
-
-            mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
-                % (_('segment'), strdist, dunits,
-                   _('total distance'), strtotdist, tdunits,
-                   _('bearing'), angle, _('degrees (clockwise from grid-north)'),
-                   '-' * 60)
-        else:
-            mstring = '%s = %s %s\n%s = %s %s\n%s' \
-                % (_('segment'), strdist, dunits,
-                   _('total distance'), strtotdist, tdunits,
-                   '-' * 60)
-
-        self._giface.WriteLog(mstring, priority=2)
-
-        return dist

Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -43,20 +43,21 @@
 from core.gcmd          import GError, GMessage
 from dbmgr.dialogs      import DisplayAttributesDialog
 from core.utils         import ListOfCatsToRange, GetLayerNameFromCmd, _
-from gui_core.dialogs   import GetImageHandlers, ImageSizeDialog, DecorationDialog, TextLayerDialog, \
-                               DECOR_DIALOG_LEGEND, DECOR_DIALOG_BARSCALE
+from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
 from core.debug         import Debug
 from core.settings      import UserSettings
 from gui_core.mapdisp   import SingleMapFrame
-from gui_core.mapwindow import MapWindowProperties
+from mapwin.base import MapWindowProperties
 from gui_core.query     import QueryDialog, PrepareQueryResults
-from mapdisp.mapwindow  import BufferedWindow
-from mapdisp.overlays   import LegendController, BarscaleController
+from mapwin.buffered import BufferedMapWindow
+from mapwin.decorations import DecorationDialog, TextLayerDialog, \
+    LegendController, BarscaleController, \
+    DECOR_DIALOG_LEGEND, DECOR_DIALOG_BARSCALE
 from modules.histogram  import HistogramFrame
 from wxplot.histogram   import HistogramPlotFrame
 from wxplot.profile     import ProfileFrame
 from wxplot.scatter     import ScatterFrame
-from mapdisp.analysis import ProfileController, MeasureDistanceController
+from mapwin.analysis import ProfileController, MeasureDistanceController
 
 from mapdisp import statusbar as sb
 
@@ -71,7 +72,7 @@
                  toolbars = ["map"], tree = None, notebook = None, lmgr = None,
                  page = None, Map = Map(), auimgr = None, name = 'MapWindow', **kwargs):
         """!Main map display window with toolbars, statusbar and
-        BufferedWindow (map canvas)
+        2D map window, 3D map window and digitizer.
         
         @param toolbars array of activated toolbars, e.g. ['map', 'digit']
         @param tree reference to layer tree
@@ -154,10 +155,10 @@
         #
         # Init map display (buffered DC & set default cursor)
         #
-        self.MapWindow2D = BufferedWindow(self, giface = self._giface,
-                                          Map=self.Map,
-                                          properties=self.mapWindowProperties,
-                                          overlays=self.decorations)
+        self.MapWindow2D = BufferedMapWindow(self, giface = self._giface,
+                                             Map=self.Map,
+                                             properties=self.mapWindowProperties,
+                                             overlays=self.decorations)
         self.MapWindow2D.mapQueried.connect(self.Query)
         self.MapWindow2D.overlayActivated.connect(self._activateOverlay)
         self._setUpMapWindow(self.MapWindow2D)

Deleted: grass/trunk/gui/wxpython/mapdisp/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/mapwindow.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapdisp/mapwindow.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -1,2086 +0,0 @@
-"""!
- at package mapdisp.mapwindow
-
- at brief Map display canvas - buffered window.
-
-Classes:
- - mapwindow::BufferedWindow
- - mapwindow::GraphicsSet
- - mapwindow::GraphicsSetItem
-
-(C) 2006-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 Martin Landa <landa.martin gmail.com>
- at author Michael Barton
- at author Jachym Cepicky
- at author Stepan Turek <stepan.turek seznam.cz> (handlers support, GraphicsSet)
- at author Anna Petrasova <kratochanna gmail.com> (refactoring)
- at author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
-"""
-
-import os
-import time
-import math
-import sys
-from copy import copy
-
-import wx
-
-from grass.pydispatch.signal import Signal
-
-import grass.script as grass
-
-from gui_core.dialogs   import SavedRegion
-from core.gcmd          import RunCommand, GException, GError, GMessage
-from core.debug         import Debug
-from core.settings      import UserSettings
-from gui_core.mapwindow import MapWindow
-from core.utils         import GetGEventAttribsForHandler, _
-import core.utils as utils
-
-try:
-    import grass.lib.gis as gislib
-    haveCtypes = True
-except ImportError:
-    haveCtypes = False
-
-class BufferedWindow(MapWindow, wx.Window):
-    """!A Buffered window class (2D view mode)
-
-    Superclass for VDigitWindow (vector digitizer).
-    
-    When the drawing needs to change, you app needs to call the
-    UpdateMap() method. Since the drawing is stored in a bitmap, you
-    can also save the drawing to file by calling the
-    SaveToFile() method.
-    """
-    def __init__(self, parent, giface, Map, properties,
-                 id=wx.ID_ANY, overlays=None,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        """!
-        @param parent parent window
-        @param giface grass interface instance
-        @param Map map instance
-        @param properties instance of MapWindowProperties
-        @param id wx window id
-        @param style wx window style
-        @param kwargs keyword arguments passed to MapWindow and wx.Window
-        """
-        MapWindow.__init__(self, parent=parent, giface=giface, Map=Map)
-        wx.Window.__init__(self, parent=parent, id=id, style=style, **kwargs)
-
-        self._properties = properties
-
-        # flags
-        self.resize = False # indicates whether or not a resize event has taken place
-        self.dragimg = None # initialize variable for map panning
-        self.alwaysRender = False # if it always sets render to True in self.UpdateMap()
-        
-        # variables for drawing on DC
-        self.pen = None      # pen for drawing zoom boxes, etc.
-        self.polypen = None  # pen for drawing polylines (measurements, profiles, etc)
-        # List of wx.Point tuples defining a polyline (geographical coordinates)
-        self.polycoords = []
-        # ID of rubber band line
-        self.lineid = None
-        # ID of poly line resulting from cumulative rubber band lines (e.g. measurement)
-        self.plineid = None
-
-        # Emitted when zoom of a window is changed
-        self.zoomChanged = Signal('BufferedWindow.zoomChanged')
-
-        # Emitted when map was queried, parameters x, y are mouse coordinates
-        # TODO: change pixel coordinates to map coordinates (using Pixel2Cell)
-        self.mapQueried = Signal('BufferedWindow.mapQueried')
-
-        # Emitted when the zoom history stack is emptied
-        self.zoomHistoryUnavailable = Signal('BufferedWindow.zoomHistoryUnavailable')
-        # Emitted when the zoom history stack is not empty
-        self.zoomHistoryAvailable = Signal('BufferedWindow.zoomHistoryAvailable')
-
-        # Emitted when map enters the window
-        self.mouseEntered = Signal('BufferedWindow.mouseEntered')
-        # Emitted when left mouse button is released and mouse use is 'pointer'
-        # Parameters are x and y of the mouse click in map (cell) units
-        # new and experimental, if the concept would be used widely,
-        # it could replace register and unregister mechanism
-        # and partially maybe also internal mouse use dictionary
-        self.mouseLeftUpPointer = Signal('BufferedWindow.mouseLeftUpPointer')
-        # Emitted when left mouse button is released
-        self.mouseLeftUp = Signal('BufferedWindow.mouseLeftUp')
-        # Emitted when left mouse button was pressed
-        self.mouseLeftDown = Signal('BufferedWindow.mouseLeftDown')
-        # Emitted after double-click
-        self.mouseDClick = Signal('BufferedWindow.mouseDClick')
-        # Emitted when mouse us moving (mouse motion event)
-        # Parametres are x and y of the mouse position in map (cell) units
-        self.mouseMoving = Signal('BufferedWindow.mouseMoving')
-
-        # event bindings
-        self.Bind(wx.EVT_PAINT,           self.OnPaint)
-        self.Bind(wx.EVT_SIZE,            self.OnSize)
-        self.Bind(wx.EVT_IDLE,            self.OnIdle)
-
-        self._bindMouseEvents()
-        
-        self.processMouse = True
-        
-        # render output objects
-        self.mapfile = None   # image file to be rendered
-        self.img     = None   # wx.Image object (self.mapfile)
-        # decoration overlays
-        self.overlays = overlays
-        # images and their PseudoDC ID's for painting and dragging
-        self.imagedict = {}   
-        self.select = {}      # selecting/unselecting decorations for dragging
-        self.textdict = {}    # text, font, and color indexed by id
-        
-        # zoom objects
-        self.zoomhistory  = [] # list of past zoom extents
-        self.currzoom     = 0  # current set of extents in zoom history being used
-        self.zoomtype     = 1  # 1 zoom in, 0 no zoom, -1 zoom out
-        self.hitradius    = 10 # distance for selecting map decorations
-        self.dialogOffset = 5  # offset for dialog (e.g. DisplayAttributesDialog)
-        
-        # OnSize called to make sure the buffer is initialized.
-        # This might result in OnSize getting called twice on some
-        # platforms at initialization, but little harm done.
-        ### self.OnSize(None)
-        
-        self._definePseudoDC()
-        # redraw all pdc's, pdcTmp layer is redrawn always (speed issue)
-        self.redrawAll = True
-        
-        # will store an off screen empty bitmap for saving to file
-        self._buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
-        
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
-        # rerender when Map reports change
-        self.Map.layerChanged.connect(lambda: self.UpdateMap())
-        
-        # vars for handling mouse clicks
-        self.dragid   = -1
-        self.lastpos  = (0, 0)
-        
-        # list for registration of graphics to draw
-        self.graphicsSetList = []
-        
-    def _definePseudoDC(self):
-        """!Define PseudoDC objects to use
-        """
-        # create PseudoDC used for background map, map decorations like scales and legends
-        self.pdc = wx.PseudoDC()
-        # used for digitization tool
-        self.pdcVector = None
-        # decorations (region box, etc.)
-        self.pdcDec = wx.PseudoDC()
-        # pseudoDC for temporal objects (select box, measurement tool, etc.)
-        self.pdcTmp = wx.PseudoDC()
-        
-    def _bindMouseEvents(self):
-        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
-        self.Bind(wx.EVT_MOTION,       self.OnMotion)
-        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
-
-    def OnContextMenu(self, event):
-        """!Show Map Display context menu"""
-        if hasattr(self, "digit"):
-            event.Skip()
-            return
-
-        if not hasattr(self, "popupCopyCoordinates"):
-            self.popupCopyCoordinates = wx.NewId()
-            self.Bind(wx.EVT_MENU, self.OnCopyCoordinates, id = self.popupCopyCoordinates)
-
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupCopyCoordinates, _("Copy coordinates to clipboard"))
-
-        self.PopupMenu(menu)
-        menu.Destroy()
-
-    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0], pen = None):
-        """!Draws map and overlay decorations
-        """
-        if drawid == None:
-            if pdctype == 'image' and img:
-                drawid = self.imagedict[img]
-            elif pdctype == 'clear':
-                drawid = None
-            else:
-                drawid = wx.NewId()
-        
-        # TODO: find better solution
-        if not pen:
-            if pdctype == 'polyline':
-                pen = self.polypen
-            else:
-                pen = self.pen
-
-        if img and pdctype == 'image':
-            # self.imagedict[img]['coords'] = coords
-            self.select[self.imagedict[img]['id']] = False # ?
-        
-        pdc.BeginDrawing()
-        
-        if drawid != 99:
-            bg = wx.TRANSPARENT_BRUSH
-        else:
-            bg = wx.Brush(self.GetBackgroundColour())
-        
-        pdc.SetBackground(bg)
-        
-        Debug.msg (5, "BufferedWindow.Draw(): id=%s, pdctype = %s, coord=%s" % \
-                       (drawid, pdctype, coords))
-        
-        # set PseudoDC id
-        if drawid is not None:
-            pdc.SetId(drawid)
-            
-        if pdctype == 'clear': # erase the display
-            bg = wx.WHITE_BRUSH
-            # bg = wx.Brush(self.GetBackgroundColour())
-            pdc.SetBackground(bg)
-            pdc.RemoveAll()
-            pdc.Clear()
-            pdc.EndDrawing()
-            
-            self.Refresh()
-            return
-        
-        if pdctype == 'image': # draw selected image
-            bitmap = wx.BitmapFromImage(img)
-            w,h = bitmap.GetSize()
-            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
-            pdc.SetIdBounds(drawid, wx.Rect(coords[0],coords[1], w, h))
-        
-        elif pdctype == 'box': # draw a box on top of the map
-            if pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(pen)
-                x2 = max(coords[0],coords[2])
-                x1 = min(coords[0],coords[2])
-                y2 = max(coords[1],coords[3])
-                y1 = min(coords[1],coords[3])
-                rwidth = x2-x1
-                rheight = y2-y1
-                rect = wx.Rect(x1, y1, rwidth, rheight)
-                pdc.DrawRectangleRect(rect)
-                pdc.SetIdBounds(drawid, rect)
-                
-        elif pdctype == 'line': # draw a line on top of the map
-            if pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(pen)
-                pdc.DrawLinePoint(wx.Point(coords[0], coords[1]),wx.Point(coords[2], coords[3]))
-                pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], coords[2], coords[3]))
-        
-        elif pdctype == 'polyline': # draw a polyline on top of the map
-            if pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(pen)
-                if (len(coords) < 2):
-                    return
-                i = 1
-                while i < len(coords):
-                    pdc.DrawLinePoint(wx.Point(coords[i-1][0], coords[i-1][1]),
-                                      wx.Point(coords[i][0], coords[i][1]))
-                    i += 1
-                
-                # get bounding rectangle for polyline
-                xlist = []
-                ylist = []
-                if len(coords) > 0:
-                    for point in coords:
-                        x,y = point
-                        xlist.append(x)
-                        ylist.append(y)
-                    x1 = min(xlist)
-                    x2 = max(xlist)
-                    y1 = min(ylist)
-                    y2 = max(ylist)
-                    pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
-                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
-        
-        elif pdctype == 'point': # draw point
-            if pen:
-                pdc.SetPen(pen)
-                pdc.DrawPoint(coords[0], coords[1])
-                coordsBound = (coords[0] - 5,
-                               coords[1] - 5,
-                               coords[0] + 5,
-                               coords[1] + 5)
-                pdc.SetIdBounds(drawid, wx.Rect(coordsBound))
-        
-        elif pdctype == 'text': # draw text on top of map
-            if not img['active']:
-                return # only draw active text
-            if 'rotation' in img:
-                rotation = float(img['rotation'])
-            else:
-                rotation = 0.0
-            w, h = self.GetFullTextExtent(img['text'])[0:2]
-            pdc.SetFont(img['font'])
-            pdc.SetTextForeground(img['color'])
-            coords, bbox = self.TextBounds(img)
-            if rotation == 0:
-                pdc.DrawText(img['text'], coords[0], coords[1])
-            else:
-                pdc.DrawRotatedText(img['text'], coords[0], coords[1], rotation)
-            pdc.SetIdBounds(drawid, bbox)
-        
-        pdc.EndDrawing()
-        
-        self.Refresh()
-        
-        return drawid
-    
-    def TextBounds(self, textinfo, relcoords = False):
-        """!Return text boundary data
-        
-        @param textinfo text metadata (text, font, color, rotation)
-        @param coords reference point
-        
-        @return coords of nonrotated text bbox (TL corner)
-        @return bbox of rotated text bbox (wx.Rect)
-        @return relCoords are text coord inside bbox
-        """
-        if 'rotation' in textinfo:
-            rotation = float(textinfo['rotation'])
-        else:
-            rotation = 0.0
-        
-        coords = textinfo['coords']
-        bbox = wx.Rect(coords[0], coords[1], 0, 0)
-        relCoords = (0, 0)
-        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
-                   (textinfo['text'], rotation))
-        
-        self.Update()
-        
-        self.SetFont(textinfo['font'])
-        
-        w, h = self.GetTextExtent(textinfo['text'])
-        
-        if rotation == 0:
-            bbox[2], bbox[3] = w, h
-            if relcoords:
-                return coords, bbox, relCoords
-            else:
-                return coords, bbox
-        
-        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
-        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
-        if rotation > 0 and rotation < 90:
-            bbox[1] -= boxh
-            relCoords = (0, boxh)
-        elif rotation >= 90 and rotation < 180:
-            bbox[0] -= boxw
-            bbox[1] -= boxh
-            relCoords = (boxw, boxh)
-        elif rotation >= 180 and rotation < 270:
-            bbox[0] -= boxw
-            relCoords = (boxw, 0)
-        bbox[2] = boxw
-        bbox[3] = boxh
-        bbox.Inflate(h,h)
-        if relcoords:
-            return coords, bbox, relCoords
-        else:
-            return coords, bbox
-
-    def OnPaint(self, event):
-        """!Draw PseudoDC's to buffered paint DC
-        
-        If self.redrawAll is False on self.pdcTmp content is re-drawn
-        """
-        Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
-        dc = wx.BufferedPaintDC(self, self._buffer)
-        dc.Clear()
-        
-        # use PrepareDC to set position correctly
-        # probably does nothing, removed from wxPython 2.9
-        # self.PrepareDC(dc)
-        
-        # create a clipping rect from our position and size
-        # and update region
-        rgn = self.GetUpdateRegion().GetBox()
-        dc.SetClippingRect(rgn)
-        
-        switchDraw = False
-        if self.redrawAll is None:
-            self.redrawAll = True
-            switchDraw = True
-        
-        if self.redrawAll: # redraw pdc and pdcVector
-            # draw to the dc using the calculated clipping rect
-            self.pdc.DrawToDCClipped(dc, rgn)
-            
-            # draw vector map layer
-            if hasattr(self, "digit"):
-                # decorate with GDDC (transparency)
-                try:
-                    gcdc = wx.GCDC(dc)
-                    self.pdcVector.DrawToDCClipped(gcdc, rgn)
-                except NotImplementedError, e:
-                    print >> sys.stderr, e
-                    self.pdcVector.DrawToDCClipped(dc, rgn)
-            
-            self.bufferLast = None
-        else: # do not redraw pdc and pdcVector
-            if self.bufferLast is None:
-                # draw to the dc
-                self.pdc.DrawToDC(dc)
-                
-                if hasattr(self, "digit"):
-                    # decorate with GDDC (transparency)
-                    try:
-                        gcdc = wx.GCDC(dc)
-                        self.pdcVector.DrawToDC(gcdc)
-                    except NotImplementedError, e:
-                        print >> sys.stderr, e
-                        self.pdcVector.DrawToDC(dc)
-                
-                # store buffered image
-                # self.bufferLast = wx.BitmapFromImage(self.buffer.ConvertToImage())
-                self.bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
-            
-            self.pdc.DrawBitmap(self.bufferLast, 0, 0, False)
-            self.pdc.DrawToDC(dc)
-        
-        # draw decorations (e.g. region box)
-        try:
-            gcdc = wx.GCDC(dc)
-            self.pdcDec.DrawToDC(gcdc)
-        except NotImplementedError, e:
-            print >> sys.stderr, e
-            self.pdcDec.DrawToDC(dc)
-        
-        # draw temporary object on the foreground
-        ### self.pdcTmp.DrawToDCClipped(dc, rgn)
-        self.pdcTmp.DrawToDC(dc)
-        
-        if switchDraw:
-            self.redrawAll = False
-        
-    def OnSize(self, event):
-        """!Scale map image so that it is the same size as the Window
-        """
-        # re-render image on idle
-        self.resize = time.clock()
-
-    def OnIdle(self, event):
-        """!Only re-render a composite map image from GRASS during
-        idle time instead of multiple times during resizing.
-        """
-        
-        # use OnInternalIdle() instead ?
-
-        if self.resize and self.resize + 0.2 < time.clock():
-            Debug.msg(3, "BufferedWindow.OnSize():")
-            
-            # set size of the input image
-            self.Map.ChangeMapSize(self.GetClientSize())
-
-            # Make new off screen bitmap: this bitmap will always have the
-            # current drawing in it, so it can be used to save the image to
-            # a file, or whatever.
-            self._buffer.Destroy()
-            self._buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
-            
-            # get the image to be rendered
-            self.img = self.GetImage()
-            
-            # update map display
-            updatemap = True
-            if self.img and self.Map.width + self.Map.height > 0: # scale image after resize
-                self.img = self.img.Scale(self.Map.width, self.Map.height)
-                if len(self.Map.GetListOfLayers()) > 0:
-                    self.UpdateMap()
-                    updatemap = False
-
-            if updatemap:
-                self.UpdateMap(render = True)
-            self.resize = False
-        elif self.resize:
-            event.RequestMore()
-        
-        event.Skip()
-
-    def SaveToFile(self, FileName, FileType, width, height):
-        """!This draws the pseudo DC to a buffer that can be saved to
-        a file.
-        
-        @param FileName file name
-        @param FileType type of bitmap
-        @param width image width
-        @param height image height
-        """
-        busy = wx.BusyInfo(message = _("Please wait, exporting image..."),
-                           parent = self)
-        wx.Yield()
-        
-        self.Map.ChangeMapSize((width, height))
-        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
-        self.Map.Render(force = True, windres = self._properties.resolution)
-        img = self.GetImage()
-        self.pdc.RemoveAll()
-        self.Draw(self.pdc, img, drawid = 99)
-        
-        # compute size ratio to move overlay accordingly
-        cSize = self.GetClientSizeTuple()
-        ratio = float(width) / cSize[0], float(height) / cSize[1]
-        
-        # redraw legend, scalebar
-        for img in self.GetOverlay():
-            # draw any active and defined overlays
-            if self.imagedict[img]['layer'].IsActive():
-                id = self.imagedict[img]['id']
-                coords = int(ratio[0] * self.overlays[id].coords[0]),\
-                         int(ratio[1] * self.overlays[id].coords[1])
-                self.Draw(self.pdc, img = img, drawid = id,
-                          pdctype = self.overlays[id].pdcType, coords = coords)
-                          
-        # redraw text labels
-        for id in self.textdict.keys():
-            textinfo = self.textdict[id]
-            oldCoords = textinfo['coords']
-            textinfo['coords'] = ratio[0] * textinfo['coords'][0],\
-                                 ratio[1] * textinfo['coords'][1]
-            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
-                      pdctype = 'text')
-            # set back old coordinates
-            textinfo['coords'] = oldCoords
-            
-        dc = wx.BufferedDC(None, ibuffer)
-        dc.Clear()
-        # probably does nothing, removed from wxPython 2.9
-        # self.PrepareDC(dc)
-        self.pdc.DrawToDC(dc)
-        if self.pdcVector:
-            self.pdcVector.DrawToDC(dc)
-        ibuffer.SaveFile(FileName, FileType)
-        
-        busy.Destroy()
-        
-        self.UpdateMap(render = True)
-        self.Refresh()
-        
-    def GetOverlay(self):
-        """!Converts rendered overlay files to wx.Image
-        
-        Updates self.imagedict
-        
-        @return list of images
-        """
-        imgs = []
-        for overlay in self.Map.GetListOfLayers(ltype = "overlay", active = True):
-            if overlay.mapfile is not None \
-               and os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
-                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
-
-                for key in self.imagedict.keys():
-                    if self.imagedict[key]['id'] == overlay.id:
-                        del self.imagedict[key]
-                
-                self.imagedict[img] = { 'id' : overlay.id,
-                                        'layer' : overlay }
-                imgs.append(img)
-
-        return imgs
-    
-    def GetImage(self):
-        """!Converts redered map files to wx.Image
-        
-        Updates self.imagedict (id=99)
-        
-        @return wx.Image instance (map composition)
-        """
-        imgId = 99
-        if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
-                os.path.getsize(self.Map.mapfile):
-            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
-        else:
-            img = None
-        
-        for key in self.imagedict.keys():
-            if self.imagedict[key]['id'] == imgId:
-                del self.imagedict[key]
-
-        self.imagedict[img] = { 'id': imgId }
-        
-        return img
-
-    def SetAlwaysRenderEnabled(self, alwaysRender = True):
-        self.alwaysRender = alwaysRender
-        
-    def IsAlwaysRenderEnabled(self):
-        return self.alwaysRender
-
-    def UpdateMap(self, render = True, renderVector = True):
-        """!Updates the canvas anytime there is a change to the
-        underlaying images or to the geometry of the canvas.
-        
-        This method should not be called directly.
-
-        @todo change direct calling of UpdateMap method to emittig grass
-        interface updateMap signal
-
-        @param render re-render map composition
-        @param renderVector re-render vector map layer enabled for editing (used for digitizer)
-        """
-        start = time.clock()
-        self.resize = False
-        
-        # was if self.Map.cmdfile and ...
-        if self.IsAlwaysRenderEnabled() and self.img is None:
-            render = True
-        
-        #
-        # render background image if needed
-        #
-
-        # here was the change of the layertree rerender variable
-        # but it is fully the problem of layertree
-        # and so it is handled there
-        # remove this comment when it is old enough
-
-        try:
-            if render:
-                # update display size
-                self.Map.ChangeMapSize(self.GetClientSize())
-                if self._properties.resolution:
-                    # use computation region resolution for rendering
-                    windres = True
-                else:
-                    windres = False
-                
-                self.mapfile = self.Map.Render(force = True,
-                                               windres = windres)
-            else:
-                self.mapfile = self.Map.Render(force = False)
-            
-        except GException, e:
-            GError(message = e.value)
-            self.mapfile = None
-        
-        self.img = self.GetImage() # id=99
-        
-        #
-        # clear pseudoDcs
-        #
-        for pdc in (self.pdc,
-                    self.pdcDec,
-                    self.pdcTmp):
-            pdc.Clear()
-            pdc.RemoveAll()
-        
-        #
-        # draw background map image to PseudoDC
-        #
-        if not self.img:
-            self.Draw(self.pdc, pdctype = 'clear')
-        else:
-            try:
-                id = self.imagedict[self.img]['id']
-            except:
-                return False
-            
-            self.Draw(self.pdc, self.img, drawid = id)
-        
-        #
-        # render vector map layer
-        #
-        if renderVector and hasattr(self, "digit"):
-            self._updateMap()
-        #
-        # render overlays
-        #
-        for img in self.GetOverlay():
-            # draw any active and defined overlays
-            if self.imagedict[img]['layer'].IsActive():
-                id = self.imagedict[img]['id']
-                self.Draw(self.pdc, img = img, drawid = id,
-                          pdctype = self.overlays[id].pdcType, coords = self.overlays[id].coords)
-        
-        for id in self.textdict.keys():
-            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
-                      pdctype = 'text', coords = [10, 10, 10, 10])
-        
-        # optionally draw computational extent box
-        self.DrawCompRegionExtent()
-        
-        #
-        # redraw pdcTmp if needed
-        #
-        
-        # draw registered graphics
-        if  len(self.graphicsSetList) > 0:
-            penOrig = self.pen
-            polypenOrig = self.polypen
-            
-            for item in self.graphicsSetList:
-                try:
-                    item.Draw(self.pdcTmp)
-                except:
-                    GError(parent = self,
-                           message = _('Unable to draw registered graphics. '
-                                       'The graphics was unregistered.'))
-                    self.UnregisterGraphicsToDraw(item) 
-            
-            self.pen = penOrig 
-            self.polypen = polypenOrig 
-        
-        if len(self.polycoords) > 0:
-            self.DrawLines(self.pdcTmp)
-            
-        stop = time.clock()
-        
-        Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
-                   (render, renderVector, (stop-start)))
-        
-        return True
-
-    def DrawCompRegionExtent(self):
-        """!Draw computational region extent in the display
-        
-        Display region is drawn as a blue box inside the computational region,
-        computational region inside a display region as a red box).
-        """
-        if self._properties.showRegion:
-            compReg = self.Map.GetRegion()
-            dispReg = self.Map.GetCurrentRegion()
-            reg = None
-            if utils.isInRegion(dispReg, compReg):
-                self.polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
-                reg = dispReg
-            else:
-                self.polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
-                                      width = 3, style = wx.SOLID)
-                reg = compReg
-
-            regionCoords = []
-            regionCoords.append((reg['w'], reg['n']))
-            regionCoords.append((reg['e'], reg['n']))
-            regionCoords.append((reg['e'], reg['s']))
-            regionCoords.append((reg['w'], reg['s']))
-            regionCoords.append((reg['w'], reg['n']))
-            # draw region extent
-            self.DrawLines(pdc=self.pdcDec, polycoords=regionCoords)
-
-    def EraseMap(self):
-        """!Erase map canvas
-        """
-        self.Draw(self.pdc, pdctype = 'clear')
-        
-        if hasattr(self, "digit"):
-            self.Draw(self.pdcVector, pdctype = 'clear')
-        
-        self.Draw(self.pdcDec, pdctype = 'clear')
-        self.Draw(self.pdcTmp, pdctype = 'clear')
-
-        self.Map.AbortAllThreads()
-
-    def DragMap(self, moveto):
-        """!Drag the entire map image for panning.
-        
-        @param moveto dx,dy
-        """
-        dc = wx.BufferedDC(wx.ClientDC(self))
-        dc.SetBackground(wx.Brush("White"))
-        dc.Clear()
-        
-        self.dragimg = wx.DragImage(self._buffer)
-        self.dragimg.BeginDrag((0, 0), self)
-        self.dragimg.GetImageRect(moveto)
-        self.dragimg.Move(moveto)
-        
-        self.dragimg.DoDrawImage(dc, moveto)
-        self.dragimg.EndDrag()
-        
-    def DragItem(self, id, coords):
-        """!Drag an overlay decoration item
-        """
-        if id == 99 or id == '' or id == None: return
-        Debug.msg (5, "BufferedWindow.DragItem(): id=%d" % id)
-        x, y = self.lastpos
-        dx = coords[0] - x
-        dy = coords[1] - y
-        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
-        r = self.pdc.GetIdBounds(id)
-        
-        if type(r) is list:
-            r = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100: # text dragging
-            rtop = (r[0],r[1]-r[3],r[2],r[3])
-            r = r.Union(rtop)
-            rleft = (r[0]-r[2],r[1],r[2],r[3])
-            r = r.Union(rleft)
-        self.pdc.TranslateId(id, dx, dy)
-        
-        r2 = self.pdc.GetIdBounds(id)
-        if type(r2) is list:
-            r2 = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100: # text
-            self.textdict[id]['bbox'] = r2
-            self.textdict[id]['coords'][0] += dx
-            self.textdict[id]['coords'][1] += dy
-        r = r.Union(r2)
-        r.Inflate(4,4)
-        self.RefreshRect(r, False)
-        self.lastpos = (coords[0], coords[1])
-                
-    def MouseDraw(self, pdc = None, begin = None, end = None):
-        """!Mouse box or line from 'begin' to 'end'
-        
-        If not given from self.mouse['begin'] to self.mouse['end'].
-        """
-        if not pdc:
-            return
-        
-        if begin is None:
-            begin = self.mouse['begin']
-        if end is None:
-            end   = self.mouse['end']
-        
-        Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
-                       (self.mouse['use'], self.mouse['box'],
-                        begin[0], begin[1], end[0], end[1]))
-        
-        if self.mouse['box'] == "box":
-            boxid = wx.ID_NEW
-            mousecoords = [begin[0], begin[1],
-                           end[0], end[1]]
-            r = pdc.GetIdBounds(boxid)
-            if type(r) is list:
-                r = wx.Rect(r[0], r[1], r[2], r[3])
-            r.Inflate(4, 4)
-            try:
-                pdc.ClearId(boxid)
-            except:
-                pass
-            self.RefreshRect(r, False)
-            pdc.SetId(boxid)
-            self.Draw(pdc, drawid = boxid, pdctype = 'box', coords = mousecoords)
-        
-        elif self.mouse['box'] == "line":
-            self.lineid = wx.ID_NEW
-            mousecoords = [begin[0], begin[1], \
-                           end[0], end[1]]
-            x1 = min(begin[0],end[0])
-            x2 = max(begin[0],end[0])
-            y1 = min(begin[1],end[1])
-            y2 = max(begin[1],end[1])
-            r = wx.Rect(x1,y1,x2-x1,y2-y1)
-            r.Inflate(4,4)
-            try:
-                pdc.ClearId(self.lineid)
-            except:
-                pass
-            self.RefreshRect(r, False)
-            pdc.SetId(self.lineid)
-            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = mousecoords)
-
-    def DrawLines(self, pdc = None, polycoords = None):
-        """!Draw polyline in PseudoDC
-        
-        Set self.pline to wx.NEW_ID + 1
-        
-        polycoords - list of polyline vertices, geographical coordinates
-        (if not given, self.polycoords is used)
-        """
-        if not pdc:
-            pdc = self.pdcTmp
-        
-        if not polycoords:
-            polycoords = self.polycoords
-        
-        if len(polycoords) > 0:
-            self.plineid = wx.ID_NEW + 1
-            # convert from EN to XY
-            coords = []
-            for p in polycoords:
-                coords.append(self.Cell2Pixel(p))
-
-            self.Draw(pdc, drawid = self.plineid, pdctype = 'polyline', coords = coords)
-            
-            Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \
-                           (coords, self.plineid))
-            
-            return self.plineid
-        
-        return -1
-
-    def DrawCross(self, pdc, coords, size, rotation = 0, pen = None,
-                  text = None, textAlign = 'lr', textOffset = (5, 5)):
-        """!Draw cross in PseudoDC
-
-        @todo implement rotation
-
-        @param pdc PseudoDC
-        @param coords center coordinates
-        @param rotation rotate symbol
-        @param text draw also text (text, font, color, rotation)
-        @param textAlign alignment (default 'lower-right')
-        @param textOffset offset for text (from center point)
-        """
-        Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
-                  (pdc, coords, size))
-        coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
-                       (coords[0], coords[1] - size, coords[0], coords[1] + size))
-
-        self.lineid = wx.NewId()
-        for lineCoords in coordsCross:
-            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = lineCoords, pen = pen)
-        
-        if not text:
-            return self.lineid
-        
-        if textAlign == 'ul':
-            coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
-        elif textAlign == 'ur':
-            coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
-        elif textAlign == 'lr':
-            coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
-        else:
-            coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
-        
-        self.Draw(pdc, img = text,
-                  pdctype = 'text', coords = coord, pen = pen)
-        
-        return self.lineid
-
-    def _computeZoomToPointAndRecenter(self, position, zoomtype):
-        """!Computes zoom parameters for recenter mode.
-
-        Computes begin and end parameters for Zoom() method.
-        Used for zooming by single click (not box)
-        and mouse wheel zooming (zoom and recenter mode).
-        """
-        if zoomtype > 0:
-            begin = (position[0] - self.Map.width / 4,
-                     position[1] - self.Map.height / 4)
-            end   = (position[0] + self.Map.width / 4,
-                     position[1] + self.Map.height / 4)
-        else:
-            begin = ((self.Map.width - position[0]) / 2,
-                     (self.Map.height - position[1]) / 2)
-            end = (begin[0] + self.Map.width / 2,
-                   begin[1] + self.Map.height / 2)
-        return begin, end
-
-    def MouseActions(self, event):
-        """!Mouse motion and button click notifier
-        """
-        if not self.processMouse:
-            return
-        
-        # zoom with mouse wheel
-        if event.GetWheelRotation() != 0:
-            self.OnMouseWheel(event)
-            
-        # left mouse button pressed
-        elif event.LeftDown():
-            self.OnLeftDown(event)
-        
-        # left mouse button released
-        elif event.LeftUp():
-            self.OnLeftUp(event)
-        
-        # dragging
-        elif event.Dragging():
-            self.OnDragging(event)
-        
-        # double click
-        elif event.ButtonDClick():
-            self.OnButtonDClick(event)
-        
-        # middle mouse button pressed
-        elif event.MiddleDown():
-            self.OnMiddleDown(event)
-        
-        # middle mouse button relesed
-        elif event.MiddleUp():
-            self.OnMiddleUp(event)
-        
-        # right mouse button pressed
-        elif event.RightDown():
-            self.OnRightDown(event)
-        
-        # right mouse button released
-        elif event.RightUp():
-            self.OnRightUp(event)
-        
-        elif event.Entering():
-            self.OnMouseEnter(event)
-        
-        elif event.Moving():
-            pixelCoordinates = event.GetPositionTuple()[:]
-            coordinates = self.Pixel2Cell(pixelCoordinates)
-            self.mouseMoving.emit(x=coordinates[0], y=coordinates[1])
-            self.OnMouseMoving(event)
-                
-    def OnMouseWheel(self, event):
-        """!Mouse wheel moved
-        """
-        zoomBehaviour = UserSettings.Get(group = 'display',
-                                         key = 'mouseWheelZoom',
-                                         subkey = 'selection')
-        if zoomBehaviour == 2:
-            event.Skip()
-            return
-            
-        self.processMouse = False
-        current  = event.GetPositionTuple()[:]
-        wheel = event.GetWheelRotation()
-        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
-        
-        if wheel > 0:
-            zoomtype = 1
-        else:
-            zoomtype = -1
-        if UserSettings.Get(group = 'display',
-                            key = 'scrollDirection',
-                            subkey = 'selection'):
-            zoomtype *= -1
-        # zoom 1/2 of the screen (TODO: settings)
-        if zoomBehaviour == 0:  # zoom and recenter
-            begin, end = self._computeZoomToPointAndRecenter(position = current, zoomtype = zoomtype)
-
-        elif zoomBehaviour == 1:  # zoom to current cursor position
-            begin = (current[0]/2, current[1]/2)
-            end = ((self.Map.width - current[0])/2 + current[0],
-                   (self.Map.height - current[1])/2 + current[1])
-        
-            
-        # zoom
-        self.Zoom(begin, end, zoomtype)
-        
-        # redraw map
-        self.UpdateMap()
-
-        self.Refresh()
-        self.processMouse = True
-        
-    def OnDragging(self, event):
-        """!Mouse dragging
-        """
-        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
-        current  = event.GetPositionTuple()[:]
-        previous = self.mouse['begin']
-        move = (current[0] - previous[0],
-                current[1] - previous[1])
-        
-        if hasattr(self, "digit"):
-            digitToolbar = self.toolbar
-        else:
-            digitToolbar = None
-        
-        # dragging or drawing box with left button
-        if self.mouse['use'] == 'pan' or \
-                event.MiddleIsDown():
-            self.DragMap(move)
-        
-        # dragging decoration overlay item
-        elif (self.mouse['use'] == 'pointer' and 
-                not digitToolbar and 
-                self.dragid != None):
-            coords = event.GetPositionTuple()
-            self.DragItem(self.dragid, coords)
-        
-        # dragging anything else - rubber band box or line
-        else:
-            if (self.mouse['use'] == 'pointer' and 
-                not digitToolbar):
-                return
-            
-            self.mouse['end'] = event.GetPositionTuple()[:]
-            if (event.LeftIsDown() and 
-                not (digitToolbar and 
-                    digitToolbar.GetAction() in ("moveLine",) and 
-                     self.digit.GetDisplay().GetSelected() > 0)):
-                self.MouseDraw(pdc = self.pdcTmp)
-        
-    def OnLeftDown(self, event):
-        """!Left mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
-                   self.mouse["use"])
-
-        self.mouse['begin'] = event.GetPositionTuple()[:]
-
-        # vector digizer
-        if self.mouse["use"] == "pointer" and \
-                hasattr(self, "digit"):
-            if event.ControlDown():
-                self.OnLeftDownUndo(event)
-            else:
-                self._onLeftDown(event)
-        
-        elif self.mouse['use'] == 'pointer':
-            # get decoration or text id
-            idlist = []
-            self.dragid = ''
-            self.lastpos = self.mouse['begin']
-            idlist = self.pdc.FindObjects(self.lastpos[0], self.lastpos[1],
-                                          self.hitradius)
-            if 99 in idlist:
-                idlist.remove(99)
-            if idlist != []:
-                self.dragid = idlist[0] #drag whatever is on top
-        else:
-            pass
-        coords = self.Pixel2Cell(self.mouse['begin'])
-        self.mouseLeftDown.emit(x=coords[0], y=coords[1])
-        
-        event.Skip()
-        
-    def OnLeftUp(self, event):
-        """!Left mouse button released
-
-        Emits mapQueried signal when mouse use is 'query'.
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
-                       self.mouse["use"])
-        
-        self.mouse['end'] = event.GetPositionTuple()[:]
-        coordinates = self.Pixel2Cell(self.mouse['end'])
-        
-        if self.mouse['use'] in ["zoom", "pan"]:
-            # set region in zoom or pan
-            begin = self.mouse['begin']
-            end = self.mouse['end']
-            
-            if self.mouse['use'] == 'zoom':
-                # set region for click (zero-width box)
-                if begin[0] - end[0] == 0 or \
-                        begin[1] - end[1] == 0:
-                    begin, end = self._computeZoomToPointAndRecenter(position = end, zoomtype = self.zoomtype)
-            self.Zoom(begin, end, self.zoomtype)
-
-            # redraw map
-            self.UpdateMap(render = True)
-
-        elif self.mouse["use"] == "query":
-            self.mapQueried.emit(x=self.mouse['end'][0], y=self.mouse['end'][1])
-
-        elif self.mouse["use"] == "pointer" and \
-                hasattr(self, "digit"):
-            self._onLeftUp(event)
-            
-        elif (self.mouse['use'] == 'pointer' and 
-                self.dragid >= 0):
-            # end drag of overlay decoration
-            
-            if self.dragid < 99 and self.dragid in self.overlays:
-                self.overlays[self.dragid].coords = self.pdc.GetIdBounds(self.dragid)
-            elif self.dragid > 100 and self.dragid in self.textdict:
-                self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
-            else:
-                pass
-            self.dragid = None
-
-            self.mouseLeftUpPointer.emit(x=coordinates[0], y=coordinates[1])
-
-       # TODO: decide which coordinates to send (e, n, mouse['begin'], mouse['end'])
-        self.mouseLeftUp.emit(x=coordinates[0], y=coordinates[1])
-
-    def OnButtonDClick(self, event):
-        """!Mouse button double click
-        """
-        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
-                   self.mouse["use"])
-        
-        screenCoords = event.GetPosition()
-
-        if self.mouse['use'] == 'pointer':
-            # select overlay decoration options dialog
-            idlist  = self.pdc.FindObjects(screenCoords[0], screenCoords[1], self.hitradius)
-            if idlist:
-                self.dragid = idlist[0]
-                self.overlayActivated.emit(overlayId=self.dragid)
-                
-        coords = self.Pixel2Cell(screenCoords)
-        self.mouseDClick.emit(x=coords[0], y=coords[1])
-
-    def OnRightDown(self, event):
-        """!Right mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
-                   self.mouse["use"])
-        
-        if hasattr(self, "digit"):
-            self._onRightDown(event)
-        
-        event.Skip()
-        
-    def OnRightUp(self, event):
-        """!Right mouse button released
-        """
-        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
-                   self.mouse["use"])
-        
-        if hasattr(self, "digit"):
-            self._onRightUp(event)
-        
-        self.redrawAll = True
-        self.Refresh()
-        
-        event.Skip()
-        
-    def OnMiddleDown(self, event):
-        """!Middle mouse button pressed
-        """
-        if not event:
-            return
-        
-        self.mouse['begin'] = event.GetPositionTuple()[:]
-        
-    def OnMiddleUp(self, event):
-        """!Middle mouse button released
-        """
-        self.mouse['end'] = event.GetPositionTuple()[:]
-        
-        # set region in zoom or pan
-        begin = self.mouse['begin']
-        end   = self.mouse['end']
-        
-        self.Zoom(begin, end, 0) # no zoom
-        
-        # redraw map
-        self.UpdateMap(render = True)
-
-    def OnMouseEnter(self, event):
-        """!Mouse entered window and no mouse buttons were pressed
-
-        Emits the mouseEntered signal.
-        """
-        self.mouseEntered.emit()
-        event.Skip()
-
-    def OnMouseMoving(self, event):
-        """!Motion event and no mouse buttons were pressed
-        """
-        if self.mouse["use"] == "pointer" and \
-                hasattr(self, "digit"):
-            self._onMouseMoving(event)
-        
-        event.Skip()
-
-    def OnCopyCoordinates(self, event):
-        """!Copy coordinates to cliboard"""
-        e, n = self.GetLastEN()
-        if wx.TheClipboard.Open():
-            do = wx.TextDataObject()
-            # TODO: put delimiter in settings and apply also for Go to in statusbar
-            delim = ';'
-            do.SetText(str(e) + delim + str(n))
-            wx.TheClipboard.SetData(do)
-            wx.TheClipboard.Close()
-        
-    def ClearLines(self, pdc = None):
-        """!Clears temporary drawn lines from PseudoDC
-        """
-        if not pdc:
-            pdc = self.pdcTmp
-        try:
-            pdc.ClearId(self.lineid)
-            pdc.RemoveId(self.lineid)
-        except:
-            pass
-        
-        try:
-            pdc.ClearId(self.plineid)
-            pdc.RemoveId(self.plineid)
-        except:
-            pass
-        
-        Debug.msg(4, "BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
-                  (self.lineid, self.plineid))
-        
-        return True
-
-    def Pixel2Cell(self, xyCoords):
-        """!Convert image coordinates to real word coordinates
-        
-        @param x, y image coordinates
-        
-        @return easting, northing
-        @return None on error
-        """
-        try:
-            x = int(xyCoords[0])
-            y = int(xyCoords[1])
-        except:
-            return None
-        
-        if self.Map.region["ewres"] > self.Map.region["nsres"]:
-            res = self.Map.region["ewres"]
-        else:
-            res = self.Map.region["nsres"]
-        
-        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
-        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
-        
-        east  = w + x * res
-        north = n - y * res
-        
-        return (east, north)
-    
-    def Cell2Pixel(self, enCoords):
-        """!Convert real word coordinates to image coordinates
-        """
-        try:
-            east  = float(enCoords[0])
-            north = float(enCoords[1])
-        except:
-            return None
-        
-        if self.Map.region["ewres"] > self.Map.region["nsres"]:
-            res = self.Map.region["ewres"]
-        else:
-            res = self.Map.region["nsres"]
-        
-        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
-        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
-        
-        x = (east  - w) / res
-        y = (n - north) / res
-        
-        return (x, y)
-
-    def Zoom(self, begin, end, zoomtype):
-        """!Calculates new region while (un)zoom/pan-ing
-        """
-        x1, y1 = begin
-        x2, y2 = end
-        newreg = {}
-        
-        # threshold - too small squares do not make sense
-        # can only zoom to windows of > 5x5 screen pixels
-        if abs(x2-x1) > 5 and abs(y2-y1) > 5 and zoomtype != 0:
-            if x1 > x2:
-                x1, x2 = x2, x1
-            if y1 > y2:
-                y1, y2 = y2, y1
-            
-            # zoom in
-            if zoomtype > 0:
-                newreg['w'], newreg['n'] = self.Pixel2Cell((x1, y1))
-                newreg['e'], newreg['s'] = self.Pixel2Cell((x2, y2))
-            
-            # zoom out
-            elif zoomtype < 0:
-                newreg['w'], newreg['n'] = self.Pixel2Cell((-x1 * 2, -y1 * 2))
-                newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + 2 * \
-                                                                (self.Map.width  - x2),
-                                                            self.Map.height + 2 * \
-                                                                (self.Map.height - y2)))
-        # pan
-        elif zoomtype == 0:
-            dx = x1 - x2
-            dy = y1 - y2
-            if dx == 0 and dy == 0:
-                dx = x1 - self.Map.width / 2
-                dy = y1 - self.Map.height / 2
-            newreg['w'], newreg['n'] = self.Pixel2Cell((dx, dy))
-            newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + dx,
-                                                        self.Map.height + dy))
-        
-        # if new region has been calculated, set the values
-        if newreg != {}:
-            # LL locations
-            if self.Map.projinfo['proj'] == 'll':
-                self.Map.region['n'] = min(self.Map.region['n'], 90.0)
-                self.Map.region['s'] = max(self.Map.region['s'], -90.0)
-            
-            ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
-            cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
-            
-            # calculate new center point and display resolution
-            self.Map.region['center_easting'] = ce
-            self.Map.region['center_northing'] = cn
-            self.Map.region['ewres'] = (newreg['e'] - newreg['w']) / self.Map.width
-            self.Map.region['nsres'] = (newreg['n'] - newreg['s']) / self.Map.height
-            if self._properties.alignExtent:
-                self.Map.AlignExtentFromDisplay()
-            else:
-                for k in ('n', 's', 'e', 'w'):
-                    self.Map.region[k] = newreg[k]
-            
-            if hasattr(self, "digit") and \
-                    hasattr(self, "moveInfo"):
-                self._zoom(None)
-            
-            self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                             self.Map.region['e'], self.Map.region['w'])
-        
-        if self.redrawAll is False:
-            self.redrawAll = True
-        
-    def ZoomBack(self):
-        """!Zoom to previous extents in zoomhistory list
-
-        Emits zoomChanged signal.
-        Emits zoomHistoryUnavailable signal when stack is empty.
-        """
-        Debug.msg(4, "BufferedWindow.ZoomBack(): hist)=%s" % self.zoomhistory)
-
-        zoom = list()
-        
-        if len(self.zoomhistory) > 1:
-            self.zoomhistory.pop()
-            zoom = self.zoomhistory[-1]
-
-        if len(self.zoomhistory) < 2:
-            self.zoomHistoryUnavailable.emit()
-
-        # zoom to selected region
-        self.Map.GetRegion(n = zoom[0], s = zoom[1],
-                           e = zoom[2], w = zoom[3],
-                           update = True)
-        # update map
-        self.UpdateMap()
-
-        self.zoomChanged.emit()
-
-    def ZoomHistory(self, n, s, e, w):
-        """!Manages a list of last 10 zoom extents
-
-        Emits zoomChanged signal.
-        Emits zoomHistoryAvailable signal when stack is not empty.
-        Emits zoomHistoryUnavailable signal when stack is empty.
-
-        All methods which are changing zoom should call this method
-        to make a record in the history. The signal zoomChanged will be
-        then emitted automatically.
-
-        @param n,s,e,w north, south, east, west
-
-        @return removed history item if exists (or None)
-        """
-        removed = None
-        self.zoomhistory.append((n,s,e,w))
-        
-        if len(self.zoomhistory) > 10:
-            removed = self.zoomhistory.pop(0)
-        
-        if removed:
-            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
-                      (self.zoomhistory, removed))
-        else:
-            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s" %
-                      (self.zoomhistory))
-        
-        # update toolbar
-        if len(self.zoomhistory) > 1:
-            self.zoomHistoryAvailable.emit()
-        else:
-            self.zoomHistoryUnavailable.emit()
-
-        self.zoomChanged.emit()
-        
-        return removed
-
-    def InitZoomHistory(self):
-        """Initializes zoom history.
-
-        @todo First item is handled in some special way. Improve the
-        documentation or fix the code.
-
-        It does not emits any signals.
-
-        This method can be possibly removed when the history will solve the
-        fist item in different way or when GCP manager (and possibly others)
-        will handle Map variable in the way that it will be prepared for
-        MapWindow/BufferedWindow and thus usable to initialize history.
-        """
-        self.zoomhistory.append((self.Map.region['n'],
-                                 self.Map.region['s'],
-                                 self.Map.region['e'],
-                                 self.Map.region['w']))
-        Debug.msg(4, "BufferedWindow.InitZoomHistory(): hist=%s" %
-                  (self.zoomhistory))
-
-    def ResetZoomHistory(self):
-        """!Reset zoom history"""
-        self.zoomhistory = list()
-                
-    def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
-        """!Set display extents to match selected raster
-        or vector map(s).
-
-        @param layers list of layers to be zoom to
-        @param ignoreNulls True to ignore null-values (valid only for rasters)
-        @param render True to re-render display
-        """
-        if not layers:
-            layers = self._giface.GetLayerList().GetSelectedLayers(checkedOnly=False)
-            layers = [layer.maplayer for layer in layers]
-
-        if not layers:
-            return
-        
-        rast = []
-        vect = []
-        updated = False
-        for l in layers:
-            # only raster/vector layers are currently supported
-            if l.type == 'raster':
-                rast.append(l.GetName())
-            elif l.type == 'vector':
-                if hasattr(self, "digit") and \
-                        self.toolbar.GetLayer() == l:
-                    w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
-                    self.Map.GetRegion(n = n, s = s, w = w, e = e,
-                                       update = True)
-                    updated = True
-                else:
-                    vect.append(l.name)
-            elif l.type == 'rgb':
-                for rname in l.GetName().splitlines():
-                    rast.append(rname)
-            
-        if not updated:
-            self.Map.GetRegion(rast = rast,
-                               vect = vect,
-                               zoom = ignoreNulls,
-                               update = True)
-        
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        if render:
-            self.UpdateMap()
-
-    def ZoomToWind(self):
-        """!Set display geometry to match computational region
-        settings (set with g.region)
-        """
-        self.Map.region = self.Map.GetRegion()
-        
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        self.UpdateMap()
-
-    def ZoomToDefault(self):
-        """!Set display geometry to match default region settings
-        """
-        self.Map.region = self.Map.GetRegion(default = True)
-        self.Map.AdjustRegion() # aling region extent to the display
-
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        self.UpdateMap()
-
-    def GoTo(self, e, n):
-        region = self.Map.GetCurrentRegion()
-
-        region['center_easting'], region['center_northing'] = e, n
-        
-        dn = (region['nsres'] * region['rows']) / 2.
-        region['n'] = region['center_northing'] + dn
-        region['s'] = region['center_northing'] - dn
-        de = (region['ewres'] * region['cols']) / 2.
-        region['e'] = region['center_easting'] + de
-        region['w'] = region['center_easting'] - de
-
-        self.Map.AdjustRegion()
-
-        # add to zoom history
-        self.ZoomHistory(region['n'], region['s'],
-                                   region['e'], region['w'])        
-        self.UpdateMap()
-    
-    def DisplayToWind(self):
-        """!Set computational region (WIND file) to match display
-        extents
-        """
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        # We ONLY want to set extents here. Don't mess with resolution. Leave that
-        # for user to set explicitly with g.region
-        new = self.Map.AlignResolution()
-        RunCommand('g.region',
-                   parent = self,
-                   overwrite = True,
-                   n = new['n'],
-                   s = new['s'],
-                   e = new['e'],
-                   w = new['w'],
-                   rows = int(new['rows']),
-                   cols = int(new['cols']))
-        
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-        
-    def ZoomToSaved(self):
-        """!Set display geometry to match extents in
-        saved region file
-        """
-        dlg = SavedRegion(parent = self,
-                          title = _("Zoom to saved region extents"),
-                          loadsave = 'load')
-        
-        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.GetName():
-            dlg.Destroy()
-            return
-        
-        if not grass.find_file(name = dlg.GetName(), element = 'windows')['name']:
-            wx.MessageBox(parent = self,
-                          message = _("Region <%s> not found. Operation canceled.") % dlg.GetName(),
-                          caption = _("Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
-            dlg.Destroy()
-            return
-        
-        self.Map.GetRegion(regionName = dlg.GetName(),
-                           update = True)
-        
-        dlg.Destroy()
-        
-        self.ZoomHistory(self.Map.region['n'],
-                         self.Map.region['s'],
-                         self.Map.region['e'],
-                         self.Map.region['w'])
-        
-        self.UpdateMap()
-                
-    def SaveRegion(self, display = True):
-        """!Save display extents/compulational region to named region
-        file.
-
-        @param display True for display extends otherwise computational region
-        """
-        if display:
-            title = _("Save display extents to region file")
-        else:
-            title = _("Save computational region to region file")
-        
-        dlg = SavedRegion(parent = self, title = title, loadsave = 'save')
-        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.GetName():
-            dlg.Destroy()
-            return
-        
-        # test to see if it already exists and ask permission to overwrite
-        if grass.find_file(name = dlg.GetName(), element = 'windows')['name']:
-            overwrite = wx.MessageBox(parent = self,
-                                      message = _("Region file <%s> already exists. "
-                                                  "Do you want to overwrite it?") % (dlg.GetName()),
-                                      caption = _("Warning"), style = wx.YES_NO | wx.CENTRE)
-            if overwrite != wx.YES:
-                dlg.Destroy()
-                return
-        
-        if display:
-            self._saveDisplayRegion(dlg.GetName())
-        else:
-            self._saveCompRegion(dlg.GetName())
-        
-        dlg.Destroy()
-
-    def _saveCompRegion(self, name):
-        """!Save region settings to region file
-        
-        @param name region name
-        """
-        RunCommand('g.region',
-                   overwrite = True,
-                   parent = self,
-                   flags = 'u',
-                   save = name)
-        
-    def _saveDisplayRegion(self, name):
-        """!Save display extents to region file
-        
-        @param name region name
-        """
-        new = self.Map.GetCurrentRegion()
-        
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        RunCommand('g.region',
-                   overwrite = True,
-                   parent = self,
-                   flags = 'u',
-                   n = new['n'],
-                   s = new['s'],
-                   e = new['e'],
-                   w = new['w'],
-                   rows = int(new['rows']),
-                   cols = int(new['cols']),
-                   save = name)
-        
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-        
-    def Distance(self, beginpt, endpt, screen = True):
-        """!Calculates distance
-        
-        Ctypes required for LL-locations
-        
-        @param beginpt first point
-        @param endpt second point
-        @param screen True for screen coordinates otherwise EN
-        """
-        if screen:
-            e1, n1 = self.Pixel2Cell(beginpt)
-            e2, n2 = self.Pixel2Cell(endpt)
-        else:
-            e1, n1 = beginpt
-            e2, n2 = endpt
-            
-        dEast  = (e2 - e1)
-        dNorth = (n2 - n1)
-        
-        if self.Map.projinfo['proj'] == 'll' and haveCtypes:
-            dist = gislib.G_distance(e1, n1, e2, n2)
-        else:
-            dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
-        
-        return (dist, (dEast, dNorth))
-
-    def GetMap(self):
-        """!Get render.Map() instance"""
-        return self.Map
-
-    def RegisterGraphicsToDraw(self, graphicsType, setStatusFunc = None, drawFunc = None):
-        """! This method registers graphics to draw.
-        
-        @param type (string) - graphics type: "point" or "line"
-        @param setStatusFunc (function reference) - function called before drawing each item
-                Status function should be in this form: setStatusFunc(item, itemOrderNum)
-                    item - passes instance of GraphicsSetItem which will be drawn
-                    itemOrderNum - number of item in drawing order (from O)
-                                   Hidden items are also counted in drawing order.
-        @param drawFunc (function reference) - defines own function for drawing
-                            If function is not defined DrawCross method is used for type "point"
-                            or DrawLines method for type "line".
-                            
-        @return reference to GraphicsSet, which was added.
-        """
-        item = GraphicsSet(parentMapWin = self, 
-                           graphicsType = graphicsType, 
-                           setStatusFunc = setStatusFunc, 
-                           drawFunc = drawFunc)
-        self.graphicsSetList.append(item)
-        
-        return item
-
-    def UnregisterGraphicsToDraw(self, item):
-        """!Unregisteres GraphicsSet instance
-        
-        @param item (GraphicsSetItem) - item to unregister
-        
-        @return True - if item was unregistered
-        @return False - if item was not found
-        """     
-        if item in self.graphicsSetList:
-            self.graphicsSetList.remove(item)
-            return True
-        
-        return False
-    
-class GraphicsSet:
-    def __init__(self, parentMapWin, graphicsType, setStatusFunc = None, drawFunc = None):
-        """!Class, which contains instances of GraphicsSetItem and
-            draws them For description of parameters look at method
-            RegisterGraphicsToDraw in BufferedWindow class.
-        """
-        self.pens =  {
-            "default"  :  wx.Pen(colour = wx.BLACK, width = 2, style = wx.SOLID),
-            "selected" :  wx.Pen(colour = wx.GREEN, width = 2, style = wx.SOLID),
-            "unused"   :  wx.Pen(colour = wx.LIGHT_GREY, width = 2, style = wx.SOLID),
-            "highest"  :  wx.Pen(colour = wx.RED, width = 2, style = wx.SOLID)
-            }
-        
-        # list contains instances of GraphicsSetItem
-        self.itemsList = []
-        
-        self.properties    = {}
-        self.graphicsType  = graphicsType
-        self.parentMapWin  = parentMapWin
-        self.setStatusFunc = setStatusFunc
-        
-        if drawFunc:
-            self.drawFunc = drawFunc
-        
-        elif self.graphicsType == "point":
-            self.properties["size"] = 5
-            
-            self.properties["text"] = {}
-            self.properties["text"]['font'] = wx.Font(pointSize = self.properties["size"],
-                                                      family = wx.FONTFAMILY_DEFAULT,
-                                                      style = wx.FONTSTYLE_NORMAL,
-                                                      weight = wx.FONTWEIGHT_NORMAL) 
-            self.properties["text"]['active'] = True
-            
-            self.drawFunc = self.parentMapWin.DrawCross
-        
-        elif self.graphicsType == "line":
-            self.drawFunc = self.parentMapWin.DrawLines
-        
-    def Draw(self, pdc):
-        """!Draws all containing items.
-        
-        @param pdc - device context, where items are drawn 
-        """
-        itemOrderNum = 0
-        for item in self.itemsList:
-            if self.setStatusFunc is not None:
-                self.setStatusFunc(item, itemOrderNum)
-            
-            if item.GetPropertyVal("hide") == True:
-                itemOrderNum += 1
-                continue
-            
-            if self.graphicsType  == "point":
-                if item.GetPropertyVal("penName"):
-                    self.parentMapWin.pen = self.pens[item.GetPropertyVal("penName")]
-                else:
-                    self.parentMapWin.pen = self.pens["default"]
-                
-                coords = self.parentMapWin.Cell2Pixel(item.GetCoords())
-                size = self.properties["size"]
-                
-                self.properties["text"]['coords'] = [coords[0] + size, coords[1] + size, size, size]
-                self.properties["text"]['color'] = self.parentMapWin.pen.GetColour() 
-                self.properties["text"]['text'] = item.GetPropertyVal("label")
-                
-                self.drawFunc(pdc = pdc,
-                              coords = coords, 
-                              text = self.properties["text"], 
-                              size = self.properties["size"])
-            
-            elif self.graphicsType == "line":
-                if item.GetPropertyVal("penName"):
-                    self.parentMapWin.polypen = self.pens[item.GetPropertyVal("penName")]
-                else:
-                    self.parentMapWin.polypen = self.pens["default"]
-                coords = item.GetCoords()
-                
-                self.drawFunc(pdc = pdc, 
-                              polycoords = coords)
-            itemOrderNum += 1
-        
-    def AddItem(self, coords, penName = None, label = None, hide = False):
-        """!Append item to the list.
-        
-        Added item is put to the last place in drawing order. 
-        Could be 'point' or 'line' according to graphicsType.
-        
-        @param coords - list of east, north coordinates (double) of item
-                        Example: point: [1023, 122] 
-                                 line: [[10, 12],[20,40],[23, 2334]] 
-        @param penName (string) - the 'default' pen is used if is not defined
-        @param label (string) - label, which will be drawn with point. It is relavant just for 'point' type.
-        @param hide (bool) -  If it is True, the item is not drawn, when self.Draw is called. 
-                              Hidden items are also counted in drawing order.
-                              
-        @return (GraphicsSetItem) - added item reference
-        """
-        item = GraphicsSetItem(coords = coords, penName = penName, label = label, hide = hide)
-        self.itemsList.append(item)
-        
-        return item
-    
-    def DeleteItem(self, item):
-        """!Deletes item
-
-        @param item (GraphicsSetItem) - item to remove
-        
-        @return True if item was removed
-        @return False if item was not found 
-        """
-        try:
-            self.itemsList.remove(item)
-        except ValueError:
-            return False
-        
-        return True
-
-    def GetAllItems(self):
-        """!Returns list of all containing instances of GraphicsSetItem, in order 
-        as they are drawn. If you want to change order of drawing use: SetItemDrawOrder method.
-        """
-        # user can edit objects but not order in list, that is reason,
-        # why is returned shallow copy of data list it should be used
-        # SetItemDrawOrder for changing order
-        return copy(self.itemsList)
-
-    def GetItem(self, drawNum):
-        """!Get given item from the list.
-        
-        @param drawNum (int) - drawing order (index) number of item 
-        
-        @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
-
-    def SetPropertyVal(self, propName, propVal):
-        """!Set property value
-        
-        @param propName (string) - property name: "size", "text"
-                                 - both properties are relevant for "point" type
-        @param propVal - property value to be set  
-        
-        @return True - if value was set
-        @return False - if propName is not "size" or "text" or type is "line"   
-        """
-        if self.properties.has_key(propName):
-            self.properties[propName] = propVal
-            return True
-        
-        return False       
-
-    def GetPropertyVal(self, propName):
-        """!Get property value
-        
-        Raises KeyError if propName is not "size" or "text" or type is
-        "line"
-
-        @param propName (string) - property name: "size", "text"
-                                 - both properties are relevant for "point" type
-                                
-        @return value of property
-        """       
-        if self.properties.has_key(propName):
-            return self.properties[propName]
-        
-        raise KeyError(_("Property does not exist: %s") % (propName))          
-        
-    def AddPen(self, penName, pen):
-        """!Add pen
-        
-        @param penName (string) - name of added pen
-        @param pen (wx.Pen) - added pen
-        
-        @return True - if pen was added
-        @return False - if pen already exists   
-        """       
-        if self.pens.has_key(penName):
-            return False
-        
-        self.pens[penName] = pen
-        return True
-
-    def GetPen(self, penName):
-        """!Get existing pen
-        
-        @param penName (string) - name of pen
-        
-        @return wx.Pen reference if is found
-        @return None if penName was not found
-        """       
-        if self.pens.has_key(penName):
-            return self.pens[penName]
-        
-        return None
-
-    def SetItemDrawOrder(self, item, drawNum): 
-        """!Set draw order for item
-        
-        @param item (GraphicsSetItem)
-        @param drawNum (int) - drawing order of item to be set
-        
-        @return True - if order was changed
-        @return False - if drawNum is out of range or item was not found
-        """ 
-        if drawNum < len(self.itemsList) and drawNum >= 0 and \
-            item in self.itemsList:
-            self.itemsList.insert(drawNum, self.itemsList.pop(self.itemsList.index(item)))
-            return True
-        
-        return False
-
-    def GetItemDrawOrder(self, item):       
-        """!Get draw order for given item
-        
-        @param item (GraphicsSetItem) 
-        
-        @return (int) - drawing order of item
-        @return None - if item was not found
-        """ 
-        try:
-            return self.itemsList.index(item)
-        except ValueError:
-            return None
-
-class GraphicsSetItem:
-    def __init__(self, coords, penName = None, label = None, hide = False):
-        """!Could be point or line according to graphicsType in
-        GraphicsSet class
-
-        @param coords - list of coordinates (double) of item 
-                        Example: point: [1023, 122] 
-                                 line: [[10, 12],[20,40],[23, 2334]] 
-        @param penName (string) - if it is not defined 'default' pen is used
-        @param label (string) - label, which will be drawn with point. It is relevant just for 'point' type
-        @param hide (bool) - if it is True, item is not drawn
-                             Hidden items are also counted in drawing order in GraphicsSet class.
-        """
-        self.coords = coords
-        
-        self.properties = { "penName" : penName,
-                            "hide"    : hide,
-                            "label"   : label }
-        
-    def SetPropertyVal(self, propName, propVal):
-        """!Set property value
-        
-        @param propName (string) - property name: "penName", "hide" or "label"
-                                 - property "label" is relevant just for 'point' type
-        @param propVal - property value to be set  
-        
-        @return True - if value was set
-        @return False - if propName is not "penName", "hide" or "label"  
-        """
-        if self.properties.has_key(propName):
-            self.properties[propName] = propVal
-            return True
-        
-        return False
-
-    def GetPropertyVal(self, propName):
-        """!Get property value
-
-        Raises KeyError if propName is not "penName", "hide" or
-        "label".
-        
-        @param propName (string) - property name: "penName", "hide" or "label"
-                                 - property "label" is relevant just for 'point' type
-                                 
-        @return value of property
-        """       
-        if self.properties.has_key(propName):
-            return self.properties[propName]
-        
-        raise KeyError(_("Property does not exist: %s") % (propName))          
-
-    def SetCoords(self, coords):
-        """!Set coordinates of item
-        
-        @param coords - list of east, north coordinates (double) of item
-                        Example: point: [1023, 122] 
-                                 line: [[10, 12],[20,40],[23, 2334]]  
-        """   
-        self.coords = coords
-        
-    def GetCoords(self):
-        """!Get item coordinates
-        
-        @returns coordinates
-        """ 
-        return self.coords

Deleted: grass/trunk/gui/wxpython/mapdisp/overlays.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/overlays.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapdisp/overlays.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -1,156 +0,0 @@
-"""!
- at package mapdisp.overlays
-
- at brief Map display overlays - barscale and legend
-
-Classes:
- - overlays::OverlayController
- - overlays::BarscaleController
- - overlays::LegendController
-
-(C) 2006-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>
-"""
-
-class OverlayController(object):
-    """!Base class for decorations (barscale, legend) controller."""
-    def __init__(self, renderer):
-        self._renderer = renderer
-        self._overlay = None
-        self._coords = [0, 0]
-        self._pdcType = 'image'
-        self._propwin = None
-        self._defaultAt = ''
-        self._cmd = None   # to be set by user
-        self._name = None  # to be defined by subclass
-        self._id = None    # to be defined by subclass
-
-    def SetCmd(self, cmd):
-        hasAt = False
-        for i in cmd:
-            if i.startswith("at="):
-                hasAt = True
-                break
-        if not hasAt:
-            cmd.append(self._defaultAt)
-        self._cmd = cmd
-
-    def GetCmd(self):
-        return self._cmd
-
-    cmd = property(fset = SetCmd, fget = GetCmd)
-
-    def SetCoords(self, coords):
-        self._coords = list(coords)
-
-    def GetCoords(self):
-        return self._coords
-
-    coords = property(fset = SetCoords, fget = GetCoords)
-
-    def GetPdcType(self):
-        return self._pdcType
-
-    pdcType = property(fget = GetPdcType)
-
-    def GetName(self):
-        return self._name
-
-    name = property(fget = GetName)
-
-    def GetId(self):
-        return self._id
-
-    id = property(fget = GetId)
-
-    def GetPropwin(self):
-        return self._propwin
-
-    def SetPropwin(self, win):
-        self._propwin = win
-
-    propwin = property(fget = GetPropwin, fset = SetPropwin)
-
-    def GetLayer(self):
-        return self._overlay
-
-    layer = property(fget = GetLayer)
-
-    def IsShown(self):
-        if self._overlay and self._overlay.IsActive():
-            return True
-        return False
-
-    def Show(self, show = True):
-        """!Activate or deactivate overlay."""
-        if show:
-            if not self._overlay:
-                self._add()
-            self._overlay.SetActive(True)
-            self._update()
-        else:
-            self.Hide()
-
-    def Hide(self):
-        if self._overlay:
-            self._overlay.SetActive(False)
-
-    def _add(self):
-        self._overlay = self._renderer.AddOverlay(id = self._id, ltype = self._name,
-                                                  command = self.cmd, active = False,
-                                                  render = False, hidden = True)
-        # check if successful
-
-    def _update(self):
-        self._renderer.ChangeOverlay(id = self._id, command = self._cmd,
-                                     render = False)
-
-
-class BarscaleController(OverlayController):
-    def __init__(self, renderer):
-        OverlayController.__init__(self, renderer)
-        self._id = 0
-        self._name = 'barscale'
-        self._defaultAt = 'at=0,95'
-        self._cmd = ['d.barscale', self._defaultAt]
-
-
-class LegendController(OverlayController):
-    def __init__(self, renderer):
-        OverlayController.__init__(self, renderer)
-        self._id = 1
-        self._name = 'legend'
-        # TODO: synchronize with d.legend?
-        self._defaultAt = 'at=5,50,2,5'
-        self._cmd = ['d.legend', self._defaultAt]
-
-    def ResizeLegend(self, begin, end, screenSize):
-        """!Resize legend according to given bbox coordinates."""
-        w = abs(begin[0] - end[0])
-        h = abs(begin[1] - end[1])
-        if begin[0] < end[0]:
-            x = begin[0]
-        else:
-            x = end[0]
-        if begin[1] < end[1]:
-            y = begin[1]
-        else:
-            y = end[1]
-        
-        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
-              (screenSize[1] - y) / float(screenSize[1]) * 100,
-              x / float(screenSize[0]) * 100,
-              (x + w) / float(screenSize[0]) * 100]
-        atStr = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
-
-        for i, subcmd in enumerate(self._cmd):
-            if subcmd.startswith('at='):
-                self._cmd[i] = atStr
-                break
-
-        self._coords = [0, 0]
-        self.Show()

Modified: grass/trunk/gui/wxpython/mapdisp/test_mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/test_mapdisp.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapdisp/test_mapdisp.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -66,9 +66,8 @@
 from core.settings import UserSettings
 from core.globalvar import CheckWxVersion
 from core.giface import StandaloneGrassInterface
-from gui_core.mapwindow import MapWindowProperties
-from mapdisp.mapwindow import BufferedWindow
-from mapdisp.frame import MapFrame
+from mapwin.base import MapWindowProperties
+from mapwin.buffered import BufferedMapWindow
 from core.render import Map
 
 
@@ -174,14 +173,16 @@
         mapWindowProperties.setValuesFromUserSettings()
         width, height = self.frame.GetClientSize()
         copyOfInitMap(map_, width, height)
-        window = BufferedWindow(parent=panel, giface=giface, Map=map_,
-                                properties=mapWindowProperties)
+        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
+                                   properties=mapWindowProperties)
         sizer.Add(item=window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
         panel.SetSizer(sizer)
         panel.Layout()
         self.frame.Show()
 
     def testMapDisplay(self, giface, map_):
+        from mapdisp.frame import MapFrame
+
         # known issues (should be similar with d.mon):
         # * opening map in digitizer ends with: vdigit/toolbars.py:723: 'selection' referenced before assignment
         # * nviz start fails (closes window? segfaults?) after mapdisp/frame.py:306: 'NoneType' object has no attribute 'GetLayerNotebook'
@@ -204,8 +205,8 @@
 
         width, height = self.frame.GetClientSize()
         copyOfInitMap(map_, width, height)
-        window = BufferedWindow(parent=panel, giface=giface, Map=map_,
-                                properties=mapWindowProperties)
+        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
+                                   properties=mapWindowProperties)
 
         giface.mapWindow = window
 
@@ -234,8 +235,8 @@
 
         width, height = self.frame.GetClientSize()
         copyOfInitMap(map_, width, height)
-        window = BufferedWindow(parent=panel, giface=giface, Map=map_,
-                                properties=mapWindowProperties)
+        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
+                                   properties=mapWindowProperties)
 
         giface.mapWindow = window
 
@@ -249,7 +250,7 @@
 
         self.frame.Show()
 
-        from mapdisp.analysis import MeasureDistanceController
+        from mapwin.analysis import MeasureDistanceController
         self.controller = MeasureDistanceController(giface, window)
         self.controller.Start()
 
@@ -265,8 +266,8 @@
 
         width, height = self.frame.GetClientSize()
         copyOfInitMap(map_, width, height)
-        window = BufferedWindow(parent=panel, giface=giface, Map=map_,
-                                properties=mapWindowProperties)
+        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
+                                   properties=mapWindowProperties)
 
         giface.mapWindow = window
 
@@ -280,7 +281,7 @@
 
         self.frame.Show()
 
-        from mapdisp.analysis import ProfileController
+        from mapwin.analysis import ProfileController
         self.controller = ProfileController(giface, window)
         self.controller.Start()
 

Modified: grass/trunk/gui/wxpython/mapswipe/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapswipe/frame.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapswipe/frame.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -23,7 +23,7 @@
 
 from gui_core.mapdisp   import DoubleMapFrame
 from gui_core.dialogs   import GetImageHandlers
-from gui_core.mapwindow import MapWindowProperties
+from mapwin.base import MapWindowProperties
 from core.render        import Map
 from mapdisp            import statusbar as sb
 from core.debug         import Debug

Modified: grass/trunk/gui/wxpython/mapswipe/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/mapswipe/mapwindow.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/mapswipe/mapwindow.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -21,7 +21,7 @@
 
 from core.debug import Debug
 from core.utils import _
-from mapdisp.mapwindow import BufferedWindow
+from mapwin.buffered import BufferedMapWindow
 
 
 EVT_MY_MOUSE_EVENTS = wx.NewEventType()
@@ -30,15 +30,15 @@
 EVT_MOTION = wx.PyEventBinder(EVT_MY_MOTION)
 
 
-class SwipeBufferedWindow(BufferedWindow):
+class SwipeBufferedWindow(BufferedMapWindow):
     """!A subclass of BufferedWindow class. 
 
     Enables to draw the image translated.
     Special mouse events with changed coordinates are used.
     """
     def __init__(self, parent, giface, Map, properties, **kwargs):
-        BufferedWindow.__init__(self, parent=parent, giface=giface, Map=Map, 
-                                properties=properties, **kwargs)
+        BufferedMapWindow.__init__(self, parent=parent, giface=giface, Map=Map,
+                                   properties=properties, **kwargs)
         Debug.msg(2, "SwipeBufferedWindow.__init__()")
 
         self.specialSize = super(SwipeBufferedWindow, self).GetClientSize()

Added: grass/trunk/gui/wxpython/mapwin/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/__init__.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/__init__.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,7 @@
+all = [
+    'graphics',
+    'buffered',
+    'analysis',
+    'decorations',
+    'base',
+    ]


Property changes on: grass/trunk/gui/wxpython/mapwin/__init__.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapwin/analysis.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/analysis.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/analysis.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+"""!
+ at package mapwin.analysis
+
+ at brief Map display controllers for analyses (profiling, measuring)
+
+Classes:
+ - analysis::AnalysisControllerBase
+ - analysis::ProfileController
+ - analysis::MeasureDistanceController
+
+(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 math
+import wx
+
+from core.utils import _
+import core.units as units
+
+from grass.pydispatch.signal import Signal
+
+
+class AnalysisControllerBase:
+    """!Base class for analysis which require drawing line in map display."""
+    def __init__(self, giface, mapWindow):
+        """!
+
+        @param giface grass interface
+        @param mapWindow instance of BufferedMapWindow
+        """
+        self._giface = giface
+        self._mapWindow = mapWindow
+
+        self._registeredGraphics = None
+
+        self._oldMouseUse = None
+        self._oldCursor = None
+
+    def IsActive(self):
+        """!Returns True if analysis mode is activated."""
+        return bool(self._registeredGraphics)
+
+    def _start(self, x, y):
+        """!Handles the actual start of drawing line
+        and adding each new point.
+
+        @param x,y east north coordinates
+        """
+        if not self._registeredGraphics.GetAllItems():
+            item = self._registeredGraphics.AddItem(coords=[[x, y]])
+            item.SetPropertyVal('penName', 'analysisPen')
+        else:
+            # needed to switch mouse begin and end to draw intermediate line properly
+            coords = self._registeredGraphics.GetItem(0).GetCoords()[-1]
+            self._mapWindow.mouse['begin'] = self._mapWindow.Cell2Pixel(coords)
+
+    def _addPoint(self, x, y):
+        """!New point added.
+
+        @param x,y east north coordinates
+        """
+        # add new point and calculate distance
+        item = self._registeredGraphics.GetItem(0)
+        coords = item.GetCoords() + [[x, y]]
+        item.SetCoords(coords)
+        # draw
+        self._mapWindow.ClearLines()
+        self._registeredGraphics.Draw(pdc=self._mapWindow.pdcTmp)
+        wx.Yield()
+
+        self._doAnalysis(coords)
+
+    def _doAnalysis(self, coords):
+        """!Perform the required analysis
+        (compute distnace, update profile)
+
+        @param coords EN coordinates
+        """
+        raise NotImplementedError()
+
+    def _disconnectAll(self):
+        """!Disconnect all mouse signals
+        to stop drawing."""
+        raise NotImplementedError()
+
+    def _connectAll(self):
+        """!Connect all mouse signals to draw."""
+        raise NotImplementedError()
+
+    def _getPen(self):
+        """!Returns wx.Pen instance."""
+        raise NotImplementedError()
+
+    def Stop(self, restore=True):
+        """!Analysis mode is stopped.
+
+        @param restore if restore previous cursor, mouse['use']
+        """
+        self._mapWindow.ClearLines(pdc=self._mapWindow.pdcTmp)
+        self._mapWindow.mouse['end'] = self._mapWindow.mouse['begin']
+        # disconnect mouse events
+        self._disconnectAll()
+        # unregister
+        self._mapWindow.UnregisterGraphicsToDraw(self._registeredGraphics)
+        self._registeredGraphics = None
+        self._mapWindow.Refresh()
+
+        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 Start(self):
+        """!Init analysis: register graphics to map window,
+        connect required mouse signals.
+        """
+        self._oldMouseUse = self._mapWindow.mouse['use']
+        self._oldCursor = self._mapWindow.GetNamedCursor()
+
+        self._registeredGraphics = self._mapWindow.RegisterGraphicsToDraw(graphicsType='line')
+
+        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)
+
+        self._registeredGraphics.AddPen('analysisPen', self._getPen())
+
+        # change the cursor
+        self._mapWindow.SetNamedCursor('pencil')
+
+
+class ProfileController(AnalysisControllerBase):
+    """!Class controls profiling in map display.
+    It should be used inside ProfileFrame
+    """
+    def __init__(self, giface, mapWindow):
+        AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
+
+        self.transectChanged = Signal('ProfileController.transectChanged')
+
+    def _doAnalysis(self, coords):
+        """!Informs profile dialog that profile changed.
+
+        @param coords EN coordinates
+        """
+        self.transectChanged.emit(coords=coords)
+
+    def _disconnectAll(self):
+        self._mapWindow.mouseLeftDown.disconnect(self._start)
+        self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
+
+    def _connectAll(self):
+        self._mapWindow.mouseLeftDown.connect(self._start)
+        self._mapWindow.mouseLeftUp.connect(self._addPoint)
+
+    def _getPen(self):
+        return wx.Pen(colour=wx.Colour(0, 100, 0), width=2, style=wx.SHORT_DASH)
+
+    def Stop(self, restore=True):
+        AnalysisControllerBase.Stop(self, restore=restore)
+
+        self.transectChanged.emit(coords=[])
+
+
+class MeasureDistanceController(AnalysisControllerBase):
+    """!Class controls measuring distance in map display."""
+    def __init__(self, giface, mapWindow):
+        AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
+
+        self._projInfo = self._mapWindow.Map.projinfo
+        self._totaldist = 0.0  # total measured distance
+        self._useCtypes = False
+
+    def _doAnalysis(self, coords):
+        """!New point added.
+
+        @param x,y east north coordinates
+        """
+        self.MeasureDist(coords[-2], coords[-1])
+
+    def _disconnectAll(self):
+        self._mapWindow.mouseLeftDown.disconnect(self._start)
+        self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
+        self._mapWindow.mouseDClick.disconnect(self.Stop)
+
+    def _connectAll(self):
+        self._mapWindow.mouseLeftDown.connect(self._start)
+        self._mapWindow.mouseLeftUp.connect(self._addPoint)
+        self._mapWindow.mouseDClick.connect(self.Stop)
+
+    def _getPen(self):
+        return wx.Pen(colour='green', width=2, style=wx.SHORT_DASH)
+
+    def Stop(self, restore=True):
+        AnalysisControllerBase.Stop(self, restore=restore)
+
+        self._giface.WriteCmdLog(_('Measuring finished'))
+
+    def Start(self):
+        """!Init measurement routine that calculates map distance
+        along transect drawn on map display
+        """
+        AnalysisControllerBase.Start(self)
+        self._totaldist = 0.0  # total measured distance
+
+        # initiating output (and write a message)
+        # e.g., in Layer Manager switch to output console
+        # TODO: this should be something like: write important message or write tip
+        # TODO: mixed 'switching' and message? no, measuring handles 'swithing' on its own
+        self._giface.WriteWarning(_('Click and drag with left mouse button '
+                                    'to measure.%s'
+                                    'Double click with left button to clear.') % \
+                                    (os.linesep))
+        if self._projInfo['proj'] != 'xy':
+            mapunits = self._projInfo['units']
+            self._giface.WriteCmdLog(_('Measuring distance') + ' ('
+                                      + mapunits + '):')
+        else:
+            self._giface.WriteCmdLog(_('Measuring distance:'))
+
+        if self._projInfo['proj'] == 'll':
+            try:
+                import grass.lib.gis as gislib
+                gislib.G_begin_distance_calculations()
+                self._useCtypes = True
+            except ImportError, e:
+                self._giface.WriteWarning(_('Geodesic distance calculation '
+                                            'is not available.\n'
+                                            'Reason: %s' % e))
+
+    def MeasureDist(self, beginpt, endpt):
+        """!Calculate distance and print to output window.
+
+        @param beginpt,endpt EN coordinates
+        """
+        # move also Distance method?
+        dist, (north, east) = self._mapWindow.Distance(beginpt, endpt, screen=False)
+
+        dist = round(dist, 3)
+        mapunits = self._projInfo['units']
+        if mapunits == 'degrees' and self._useCtypes:
+            mapunits = 'meters'
+        d, dunits = units.formatDist(dist, mapunits)
+
+        self._totaldist += dist
+        td, tdunits = units.formatDist(self._totaldist,
+                                       mapunits)
+
+        strdist = str(d)
+        strtotdist = str(td)
+
+        if self._projInfo['proj'] == 'xy' or 'degree' not in self._projInfo['unit']:
+            angle = int(math.degrees(math.atan2(north, east)) + 0.5)
+            # uncomment below (or flip order of atan2(y,x) above) to use
+            #   the mathematical theta convention (CCW from +x axis)
+            #angle = 90 - angle
+            if angle < 0:
+                angle = 360 + angle
+
+            mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
+                % (_('segment'), strdist, dunits,
+                   _('total distance'), strtotdist, tdunits,
+                   _('bearing'), angle, _('degrees (clockwise from grid-north)'),
+                   '-' * 60)
+        else:
+            mstring = '%s = %s %s\n%s = %s %s\n%s' \
+                % (_('segment'), strdist, dunits,
+                   _('total distance'), strtotdist, tdunits,
+                   '-' * 60)
+
+        self._giface.WriteLog(mstring, priority=2)
+
+        return dist


Property changes on: grass/trunk/gui/wxpython/mapwin/analysis.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapwin/base.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/base.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/base.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,357 @@
+"""!
+ at package mapwin.mapwindow
+
+ at brief Map display canvas basic functionality - base class and properties.
+
+Classes:
+ - mapwindow::MapWindowProperties
+ - mapwindow::MapWindowBase
+
+(C) 2006-2012 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 Martin Landa <landa.martin gmail.com>
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Vaclav Petras <wenzeslaus gmail.com> (handlers support)
+ at author Stepan Turek <stepan.turek seznam.cz> (handlers support)
+"""
+
+import wx
+
+from core.settings import UserSettings
+from core.gcmd     import GError
+from core.utils import _
+
+from grass.script import core as grass
+from grass.pydispatch.signal import Signal
+
+
+class MapWindowProperties(object):
+    def __init__(self):
+        self._resolution = None
+        self.resolutionChanged = Signal('MapWindowProperties.resolutionChanged')
+        self._autoRender = None
+        self.autoRenderChanged = Signal('MapWindowProperties.autoRenderChanged')
+        self._showRegion = None
+        self.showRegionChanged = Signal('MapWindowProperties.showRegionChanged')
+        self._alignExtent = None
+        self.alignExtentChanged = Signal('MapWindowProperties.alignExtentChanged')
+
+    def setValuesFromUserSettings(self):
+        """Convenient function to get values from user settings into this object."""
+        self._resolution = UserSettings.Get(group='display',
+                                            key='compResolution',
+                                            subkey='enabled')
+        self._autoRender = UserSettings.Get(group='display',
+                                            key='autoRendering',
+                                            subkey='enabled')
+        self._showRegion = False  # in statusbar.py was not from settings
+        self._alignExtent = UserSettings.Get(group='display',
+                                             key='alignExtent',
+                                             subkey='enabled')
+    @property
+    def resolution(self):
+        return self._resolution
+
+    @resolution.setter
+    def resolution(self, value):
+        if value != self._resolution:
+            self._resolution = value
+            self.resolutionChanged.emit(value=value)
+
+    @property
+    def autoRender(self):
+        return self._autoRender
+
+    @autoRender.setter
+    def autoRender(self, value):
+        if value != self._autoRender:
+            self._autoRender = value
+            self.autoRenderChanged.emit(value=value)
+
+    @property
+    def showRegion(self):
+        return self._showRegion
+
+    @showRegion.setter
+    def showRegion(self, value):
+        if value != self._showRegion:
+            self._showRegion = value
+            self.showRegionChanged.emit(value=value)
+
+    @property
+    def alignExtent(self):
+        return self._alignExtent
+
+    @alignExtent.setter
+    def alignExtent(self, value):
+        if value != self._alignExtent:
+            self._alignExtent = value
+            self.alignExtentChanged.emit(value=value)
+
+
+class MapWindowBase(object):
+    """!Abstract map display window class
+    
+    Superclass for BufferedWindow class (2D display mode), and GLWindow
+    (3D display mode).
+    
+    Subclasses have to define
+     - _bindMouseEvents method which binds MouseEvent handlers
+     - Pixel2Cell
+     - Cell2Pixel (if it is possible)
+    """
+    def __init__(self, parent, giface, Map):
+        self.parent = parent
+        self.Map = Map
+        self._giface = giface
+
+        # Emitted when someone registers as mouse event handler
+        self.mouseHandlerRegistered = Signal('MapWindow.mouseHandlerRegistered')
+        # Emitted when mouse event handler is unregistered
+        self.mouseHandlerUnregistered = Signal('MapWindow.mouseHandlerUnregistered')
+        # emitted after double click in pointer mode on legend, text, scalebar
+        self.overlayActivated = Signal('MapWindow.overlayActivated')
+
+        # mouse attributes -- position on the screen, begin and end of
+        # dragging, and type of drawing
+        self.mouse = {
+            'begin': [0, 0], # screen coordinates
+            'end'  : [0, 0],
+            'use'  : "pointer",
+            'box'  : "point"
+            }
+        # last east, north coordinates, changes on mouse motion
+        self.lastEN = None 
+        
+        # stores overridden cursor
+        self._overriddenCursor = None
+
+        # dictionary where event types are stored as keys and lists of
+        # handlers for these types as values
+        self.handlersContainer = {
+            wx.EVT_LEFT_DOWN : [],
+            wx.EVT_LEFT_UP : [],
+            wx.EVT_LEFT_DCLICK : [],
+            wx.EVT_MIDDLE_DOWN : [],
+            wx.EVT_MIDDLE_UP : [],
+            wx.EVT_MIDDLE_DCLICK : [],
+            wx.EVT_RIGHT_DOWN : [],
+            wx.EVT_RIGHT_UP : [],
+            wx.EVT_RIGHT_DCLICK : [],
+            wx.EVT_MOTION : [],
+            wx.EVT_ENTER_WINDOW : [],
+            wx.EVT_LEAVE_WINDOW : [],
+            wx.EVT_MOUSEWHEEL : [],
+            wx.EVT_MOUSE_EVENTS : []
+            }
+
+        # available cursors
+        self._cursors = {
+            "default": wx.StockCursor(wx.CURSOR_ARROW),
+            "cross": wx.StockCursor(wx.CURSOR_CROSS),
+            "hand": wx.StockCursor(wx.CURSOR_HAND),
+            "pencil": wx.StockCursor(wx.CURSOR_PENCIL),
+            "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
+            }
+
+        # default cursor for window is arrow (at least we rely on it here)
+        # but we need to define attribute here
+        # cannot call SetNamedCursor since it expects the instance
+        # to be a wx window, so setting only the attribute
+        self._cursor = 'default'
+
+        wx.CallAfter(self.InitBinding)
+
+    def __del__(self):
+        self.UnregisterAllHandlers()
+
+    def InitBinding(self):
+        """!Binds helper functions, which calls all handlers
+           registered to events with the events
+        """
+        for ev, handlers in self.handlersContainer.iteritems():
+            self.Bind(ev, self.EventTypeHandler(handlers))
+    
+    def EventTypeHandler(self, evHandlers):
+        return lambda event:self.HandlersCaller(event, evHandlers)  
+    
+    def HandlersCaller(self, event, handlers):
+        """!Hepler function which calls all handlers registered for
+        event
+        """
+        for handler in handlers:
+            try:
+                handler(event)
+            except:
+                handlers.remove(handler)
+                GError(parent = self,
+                       message=_("Error occured during calling of handler: %s \n"
+                                 "Handler was unregistered.") % handler.__name__)
+        
+        event.Skip() 
+
+    def RegisterMouseEventHandler(self, event, handler, cursor = None):
+        """!Binds event handler
+
+        @depreciated This method is depreciated. Use Signals or drawing API instead.
+        Signals do not cover all events but new Signals can be added when needed
+        consider also adding generic signal. However, more interesing and useful
+        is higher level API to create objects, graphics etc.
+
+        Call event.Skip() in handler to allow default processing in MapWindow.
+
+        If any error occures inside of handler, the handler is removed.
+
+        Before handler is unregistered it is called with 
+        string value "unregistered" of event parameter.
+
+        @code
+        # your class methods
+        def OnButton(self, event):
+            # current map display's map window
+            # expects LayerManager to be the parent
+            self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
+            if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
+                                                wx.StockCursor(wx.CURSOR_CROSS)):
+                self.parent.GetLayerTree().GetMapDisplay().Raise()
+            else:
+                # handle that you cannot get coordinates
+        
+        def OnMouseAction(self, event):
+            # get real world coordinates of mouse click
+            coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
+            self.text.SetLabel('Coor: ' + str(coor))
+            self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction)
+            event.Skip()
+        @endcode
+
+        Emits mouseHandlerRegistered signal before handler is registered.        
+
+        @param event one of mouse events
+        @param handler function to handle event
+        @param cursor cursor which temporary overrides current cursor
+        
+        @return True if successful
+        @return False if event cannot be bind
+        """
+        self.mouseHandlerRegistered.emit()
+        # inserts handler into list
+        for containerEv, handlers in self.handlersContainer.iteritems():
+            if event == containerEv: 
+                handlers.append(handler)
+        
+        self.mouse['useBeforeGenericEvent'] = self.mouse['use']
+        self.mouse['use'] = 'genericEvent'
+        
+        if cursor:
+            self._overriddenCursor = self.GetNamedCursor()
+            self.SetNamedCursor(cursor)
+        
+        return True
+
+    def UnregisterAllHandlers(self):
+        """!Unregisters all registered handlers 
+
+        @depreciated This method is depreciated. Use Signals or drawing API instead.
+
+        Before each handler is unregistered it is called with string
+        value "unregistered" of event parameter.
+        """
+        for containerEv, handlers in self.handlersContainer.iteritems():
+            for handler in handlers:
+                try:
+                    handler("unregistered")
+                    handlers.remove(handler)
+                except:
+                    GError(parent = self,
+                           message = _("Error occured during unregistration of handler: %s \n \
+                                       Handler was unregistered.") % handler.__name__)
+                    handlers.remove(handler)
+        
+    def UnregisterMouseEventHandler(self, event, handler):
+        """!Unbinds event handler for event
+
+        @depreciated This method is depreciated. Use Signals or drawing API instead.
+
+        Before handler is unregistered it is called with string value
+        "unregistered" of event parameter.
+
+        Emits mouseHandlerUnregistered signal after handler is unregistered.
+
+        @param handler handler to unbind
+        @param event event from which handler will be unbinded
+        
+        @return True if successful
+        @return False if event cannot be unbind
+        """
+        # removes handler from list 
+        for containerEv, handlers in self.handlersContainer.iteritems():
+            if event != containerEv:
+                continue
+            try:
+                handler("unregistered")
+                if handler in handlers:
+                    handlers.remove(handler)
+                else:
+                    grass.warning(_("Handler: %s was not registered") \
+                                      % handler.__name__)
+            except:
+                GError(parent = self,
+                       message = _("Error occured during unregistration of handler: %s \n \
+                                       Handler was unregistered") % handler.__name__)
+                handlers.remove(handler) 
+        
+        # restore mouse use (previous state)
+        self.mouse['use'] = self.mouse['useBeforeGenericEvent']
+        
+        # restore overridden cursor
+        if self._overriddenCursor:
+            self.SetNamedCursor(self._overriddenCursor)
+
+        self.mouseHandlerUnregistered.emit()
+        return True
+    
+    def Pixel2Cell(self, xyCoords):
+        raise NotImplementedError()
+    
+    def Cell2Pixel(self, enCoords):
+        raise NotImplementedError()
+
+    def OnMotion(self, event):
+        """!Tracks mouse motion and update statusbar
+
+        @todo remove this method when lastEN is not used
+
+        @see GetLastEN
+        """
+        try:
+            self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
+        except (ValueError):
+            self.lastEN = None
+
+        event.Skip()
+
+    def GetLastEN(self):
+        """!Returns last coordinates of mouse cursor.
+
+        @depreciated This method is depreciated. Use Signal with coordinates as parameters.
+
+        @see OnMotion
+        """
+        return self.lastEN
+
+    def SetNamedCursor(self, cursorName):
+        """!Sets cursor defined by name."""
+        cursor = self._cursors[cursorName]
+        self.SetCursor(cursor)
+        self._cursor = cursorName
+
+    def GetNamedCursor(self):
+        """!Returns current cursor name."""
+        return self._cursor
+
+    cursor = property(fget=GetNamedCursor, fset=SetNamedCursor)


Property changes on: grass/trunk/gui/wxpython/mapwin/base.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/buffered.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/buffered.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,1791 @@
+"""!
+ at package mapwin.mapwindow
+
+ at brief Map display canvas - buffered window.
+
+Classes:
+ - mapwindow::BufferedWindow
+ - mapwindow::GraphicsSet
+ - mapwindow::GraphicsSetItem
+
+(C) 2006-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 Martin Landa <landa.martin gmail.com>
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Stepan Turek <stepan.turek seznam.cz> (handlers support, GraphicsSet)
+ at author Anna Petrasova <kratochanna gmail.com> (refactoring)
+ at author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
+"""
+
+import os
+import time
+import math
+import sys
+from copy import copy
+
+import wx
+
+from grass.pydispatch.signal import Signal
+
+import grass.script as grass
+
+from gui_core.dialogs   import SavedRegion
+from core.gcmd          import RunCommand, GException, GError, GMessage
+from core.debug         import Debug
+from core.settings      import UserSettings
+from mapwin.base import MapWindowBase
+from core.utils         import GetGEventAttribsForHandler, _
+import core.utils as utils
+from mapwin.graphics import GraphicsSet
+
+try:
+    import grass.lib.gis as gislib
+    haveCtypes = True
+except ImportError:
+    haveCtypes = False
+
+class BufferedMapWindow(MapWindowBase, wx.Window):
+    """!A Buffered window class (2D view mode)
+
+    Superclass for VDigitWindow (vector digitizer).
+    
+    When the drawing needs to change, you app needs to call the
+    UpdateMap() method. Since the drawing is stored in a bitmap, you
+    can also save the drawing to file by calling the
+    SaveToFile() method.
+    """
+    def __init__(self, parent, giface, Map, properties,
+                 id=wx.ID_ANY, overlays=None,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+        """!
+        @param parent parent window
+        @param giface grass interface instance
+        @param Map map instance
+        @param properties instance of MapWindowProperties
+        @param id wx window id
+        @param style wx window style
+        @param kwargs keyword arguments passed to MapWindow and wx.Window
+        """
+        MapWindowBase.__init__(self, parent=parent, giface=giface, Map=Map)
+        wx.Window.__init__(self, parent=parent, id=id, style=style, **kwargs)
+
+        self._properties = properties
+
+        # flags
+        self.resize = False # indicates whether or not a resize event has taken place
+        self.dragimg = None # initialize variable for map panning
+        self.alwaysRender = False # if it always sets render to True in self.UpdateMap()
+        
+        # variables for drawing on DC
+        self.pen = None      # pen for drawing zoom boxes, etc.
+        self.polypen = None  # pen for drawing polylines (measurements, profiles, etc)
+        # List of wx.Point tuples defining a polyline (geographical coordinates)
+        self.polycoords = []
+        # ID of rubber band line
+        self.lineid = None
+        # ID of poly line resulting from cumulative rubber band lines (e.g. measurement)
+        self.plineid = None
+
+        # Emitted when zoom of a window is changed
+        self.zoomChanged = Signal('BufferedWindow.zoomChanged')
+
+        # Emitted when map was queried, parameters x, y are mouse coordinates
+        # TODO: change pixel coordinates to map coordinates (using Pixel2Cell)
+        self.mapQueried = Signal('BufferedWindow.mapQueried')
+
+        # Emitted when the zoom history stack is emptied
+        self.zoomHistoryUnavailable = Signal('BufferedWindow.zoomHistoryUnavailable')
+        # Emitted when the zoom history stack is not empty
+        self.zoomHistoryAvailable = Signal('BufferedWindow.zoomHistoryAvailable')
+
+        # Emitted when map enters the window
+        self.mouseEntered = Signal('BufferedWindow.mouseEntered')
+        # Emitted when left mouse button is released and mouse use is 'pointer'
+        # Parameters are x and y of the mouse click in map (cell) units
+        # new and experimental, if the concept would be used widely,
+        # it could replace register and unregister mechanism
+        # and partially maybe also internal mouse use dictionary
+        self.mouseLeftUpPointer = Signal('BufferedWindow.mouseLeftUpPointer')
+        # Emitted when left mouse button is released
+        self.mouseLeftUp = Signal('BufferedWindow.mouseLeftUp')
+        # Emitted when left mouse button was pressed
+        self.mouseLeftDown = Signal('BufferedWindow.mouseLeftDown')
+        # Emitted after double-click
+        self.mouseDClick = Signal('BufferedWindow.mouseDClick')
+        # Emitted when mouse us moving (mouse motion event)
+        # Parametres are x and y of the mouse position in map (cell) units
+        self.mouseMoving = Signal('BufferedWindow.mouseMoving')
+
+        # event bindings
+        self.Bind(wx.EVT_PAINT,           self.OnPaint)
+        self.Bind(wx.EVT_SIZE,            self.OnSize)
+        self.Bind(wx.EVT_IDLE,            self.OnIdle)
+
+        self._bindMouseEvents()
+        
+        self.processMouse = True
+        
+        # render output objects
+        self.mapfile = None   # image file to be rendered
+        self.img     = None   # wx.Image object (self.mapfile)
+        # decoration overlays
+        self.overlays = overlays
+        # images and their PseudoDC ID's for painting and dragging
+        self.imagedict = {}   
+        self.select = {}      # selecting/unselecting decorations for dragging
+        self.textdict = {}    # text, font, and color indexed by id
+        
+        # zoom objects
+        self.zoomhistory  = [] # list of past zoom extents
+        self.currzoom     = 0  # current set of extents in zoom history being used
+        self.zoomtype     = 1  # 1 zoom in, 0 no zoom, -1 zoom out
+        self.hitradius    = 10 # distance for selecting map decorations
+        self.dialogOffset = 5  # offset for dialog (e.g. DisplayAttributesDialog)
+        
+        # OnSize called to make sure the buffer is initialized.
+        # This might result in OnSize getting called twice on some
+        # platforms at initialization, but little harm done.
+        ### self.OnSize(None)
+        
+        self._definePseudoDC()
+        # redraw all pdc's, pdcTmp layer is redrawn always (speed issue)
+        self.redrawAll = True
+        
+        # will store an off screen empty bitmap for saving to file
+        self._buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
+        # rerender when Map reports change
+        self.Map.layerChanged.connect(lambda: self.UpdateMap())
+        
+        # vars for handling mouse clicks
+        self.dragid   = -1
+        self.lastpos  = (0, 0)
+        
+        # list for registration of graphics to draw
+        self.graphicsSetList = []
+        
+    def _definePseudoDC(self):
+        """!Define PseudoDC objects to use
+        """
+        # create PseudoDC used for background map, map decorations like scales and legends
+        self.pdc = wx.PseudoDC()
+        # used for digitization tool
+        self.pdcVector = None
+        # decorations (region box, etc.)
+        self.pdcDec = wx.PseudoDC()
+        # pseudoDC for temporal objects (select box, measurement tool, etc.)
+        self.pdcTmp = wx.PseudoDC()
+        
+    def _bindMouseEvents(self):
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
+        self.Bind(wx.EVT_MOTION,       self.OnMotion)
+        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
+
+    def OnContextMenu(self, event):
+        """!Show Map Display context menu"""
+        if hasattr(self, "digit"):
+            event.Skip()
+            return
+
+        if not hasattr(self, "popupCopyCoordinates"):
+            self.popupCopyCoordinates = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnCopyCoordinates, id = self.popupCopyCoordinates)
+
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupCopyCoordinates, _("Copy coordinates to clipboard"))
+
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0], pen = None):
+        """!Draws map and overlay decorations
+        """
+        if drawid == None:
+            if pdctype == 'image' and img:
+                drawid = self.imagedict[img]
+            elif pdctype == 'clear':
+                drawid = None
+            else:
+                drawid = wx.NewId()
+        
+        # TODO: find better solution
+        if not pen:
+            if pdctype == 'polyline':
+                pen = self.polypen
+            else:
+                pen = self.pen
+
+        if img and pdctype == 'image':
+            # self.imagedict[img]['coords'] = coords
+            self.select[self.imagedict[img]['id']] = False # ?
+        
+        pdc.BeginDrawing()
+        
+        if drawid != 99:
+            bg = wx.TRANSPARENT_BRUSH
+        else:
+            bg = wx.Brush(self.GetBackgroundColour())
+        
+        pdc.SetBackground(bg)
+        
+        Debug.msg (5, "BufferedWindow.Draw(): id=%s, pdctype = %s, coord=%s" % \
+                       (drawid, pdctype, coords))
+        
+        # set PseudoDC id
+        if drawid is not None:
+            pdc.SetId(drawid)
+            
+        if pdctype == 'clear': # erase the display
+            bg = wx.WHITE_BRUSH
+            # bg = wx.Brush(self.GetBackgroundColour())
+            pdc.SetBackground(bg)
+            pdc.RemoveAll()
+            pdc.Clear()
+            pdc.EndDrawing()
+            
+            self.Refresh()
+            return
+        
+        if pdctype == 'image': # draw selected image
+            bitmap = wx.BitmapFromImage(img)
+            w,h = bitmap.GetSize()
+            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
+            pdc.SetIdBounds(drawid, wx.Rect(coords[0],coords[1], w, h))
+        
+        elif pdctype == 'box': # draw a box on top of the map
+            if pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(pen)
+                x2 = max(coords[0],coords[2])
+                x1 = min(coords[0],coords[2])
+                y2 = max(coords[1],coords[3])
+                y1 = min(coords[1],coords[3])
+                rwidth = x2-x1
+                rheight = y2-y1
+                rect = wx.Rect(x1, y1, rwidth, rheight)
+                pdc.DrawRectangleRect(rect)
+                pdc.SetIdBounds(drawid, rect)
+                
+        elif pdctype == 'line': # draw a line on top of the map
+            if pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(pen)
+                pdc.DrawLinePoint(wx.Point(coords[0], coords[1]),wx.Point(coords[2], coords[3]))
+                pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], coords[2], coords[3]))
+        
+        elif pdctype == 'polyline': # draw a polyline on top of the map
+            if pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(pen)
+                if (len(coords) < 2):
+                    return
+                i = 1
+                while i < len(coords):
+                    pdc.DrawLinePoint(wx.Point(coords[i-1][0], coords[i-1][1]),
+                                      wx.Point(coords[i][0], coords[i][1]))
+                    i += 1
+                
+                # get bounding rectangle for polyline
+                xlist = []
+                ylist = []
+                if len(coords) > 0:
+                    for point in coords:
+                        x,y = point
+                        xlist.append(x)
+                        ylist.append(y)
+                    x1 = min(xlist)
+                    x2 = max(xlist)
+                    y1 = min(ylist)
+                    y2 = max(ylist)
+                    pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
+                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
+        
+        elif pdctype == 'point': # draw point
+            if pen:
+                pdc.SetPen(pen)
+                pdc.DrawPoint(coords[0], coords[1])
+                coordsBound = (coords[0] - 5,
+                               coords[1] - 5,
+                               coords[0] + 5,
+                               coords[1] + 5)
+                pdc.SetIdBounds(drawid, wx.Rect(coordsBound))
+        
+        elif pdctype == 'text': # draw text on top of map
+            if not img['active']:
+                return # only draw active text
+            if 'rotation' in img:
+                rotation = float(img['rotation'])
+            else:
+                rotation = 0.0
+            w, h = self.GetFullTextExtent(img['text'])[0:2]
+            pdc.SetFont(img['font'])
+            pdc.SetTextForeground(img['color'])
+            coords, bbox = self.TextBounds(img)
+            if rotation == 0:
+                pdc.DrawText(img['text'], coords[0], coords[1])
+            else:
+                pdc.DrawRotatedText(img['text'], coords[0], coords[1], rotation)
+            pdc.SetIdBounds(drawid, bbox)
+        
+        pdc.EndDrawing()
+        
+        self.Refresh()
+        
+        return drawid
+    
+    def TextBounds(self, textinfo, relcoords = False):
+        """!Return text boundary data
+        
+        @param textinfo text metadata (text, font, color, rotation)
+        @param coords reference point
+        
+        @return coords of nonrotated text bbox (TL corner)
+        @return bbox of rotated text bbox (wx.Rect)
+        @return relCoords are text coord inside bbox
+        """
+        if 'rotation' in textinfo:
+            rotation = float(textinfo['rotation'])
+        else:
+            rotation = 0.0
+        
+        coords = textinfo['coords']
+        bbox = wx.Rect(coords[0], coords[1], 0, 0)
+        relCoords = (0, 0)
+        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
+                   (textinfo['text'], rotation))
+        
+        self.Update()
+        
+        self.SetFont(textinfo['font'])
+        
+        w, h = self.GetTextExtent(textinfo['text'])
+        
+        if rotation == 0:
+            bbox[2], bbox[3] = w, h
+            if relcoords:
+                return coords, bbox, relCoords
+            else:
+                return coords, bbox
+        
+        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
+        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
+        if rotation > 0 and rotation < 90:
+            bbox[1] -= boxh
+            relCoords = (0, boxh)
+        elif rotation >= 90 and rotation < 180:
+            bbox[0] -= boxw
+            bbox[1] -= boxh
+            relCoords = (boxw, boxh)
+        elif rotation >= 180 and rotation < 270:
+            bbox[0] -= boxw
+            relCoords = (boxw, 0)
+        bbox[2] = boxw
+        bbox[3] = boxh
+        bbox.Inflate(h,h)
+        if relcoords:
+            return coords, bbox, relCoords
+        else:
+            return coords, bbox
+
+    def OnPaint(self, event):
+        """!Draw PseudoDC's to buffered paint DC
+        
+        If self.redrawAll is False on self.pdcTmp content is re-drawn
+        """
+        Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
+        dc = wx.BufferedPaintDC(self, self._buffer)
+        dc.Clear()
+        
+        # use PrepareDC to set position correctly
+        # probably does nothing, removed from wxPython 2.9
+        # self.PrepareDC(dc)
+        
+        # create a clipping rect from our position and size
+        # and update region
+        rgn = self.GetUpdateRegion().GetBox()
+        dc.SetClippingRect(rgn)
+        
+        switchDraw = False
+        if self.redrawAll is None:
+            self.redrawAll = True
+            switchDraw = True
+        
+        if self.redrawAll: # redraw pdc and pdcVector
+            # draw to the dc using the calculated clipping rect
+            self.pdc.DrawToDCClipped(dc, rgn)
+            
+            # draw vector map layer
+            if hasattr(self, "digit"):
+                # decorate with GDDC (transparency)
+                try:
+                    gcdc = wx.GCDC(dc)
+                    self.pdcVector.DrawToDCClipped(gcdc, rgn)
+                except NotImplementedError, e:
+                    print >> sys.stderr, e
+                    self.pdcVector.DrawToDCClipped(dc, rgn)
+            
+            self.bufferLast = None
+        else: # do not redraw pdc and pdcVector
+            if self.bufferLast is None:
+                # draw to the dc
+                self.pdc.DrawToDC(dc)
+                
+                if hasattr(self, "digit"):
+                    # decorate with GDDC (transparency)
+                    try:
+                        gcdc = wx.GCDC(dc)
+                        self.pdcVector.DrawToDC(gcdc)
+                    except NotImplementedError, e:
+                        print >> sys.stderr, e
+                        self.pdcVector.DrawToDC(dc)
+                
+                # store buffered image
+                # self.bufferLast = wx.BitmapFromImage(self.buffer.ConvertToImage())
+                self.bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
+            
+            self.pdc.DrawBitmap(self.bufferLast, 0, 0, False)
+            self.pdc.DrawToDC(dc)
+        
+        # draw decorations (e.g. region box)
+        try:
+            gcdc = wx.GCDC(dc)
+            self.pdcDec.DrawToDC(gcdc)
+        except NotImplementedError, e:
+            print >> sys.stderr, e
+            self.pdcDec.DrawToDC(dc)
+        
+        # draw temporary object on the foreground
+        ### self.pdcTmp.DrawToDCClipped(dc, rgn)
+        self.pdcTmp.DrawToDC(dc)
+        
+        if switchDraw:
+            self.redrawAll = False
+        
+    def OnSize(self, event):
+        """!Scale map image so that it is the same size as the Window
+        """
+        # re-render image on idle
+        self.resize = time.clock()
+
+    def OnIdle(self, event):
+        """!Only re-render a composite map image from GRASS during
+        idle time instead of multiple times during resizing.
+        """
+        
+        # use OnInternalIdle() instead ?
+
+        if self.resize and self.resize + 0.2 < time.clock():
+            Debug.msg(3, "BufferedWindow.OnSize():")
+            
+            # set size of the input image
+            self.Map.ChangeMapSize(self.GetClientSize())
+
+            # Make new off screen bitmap: this bitmap will always have the
+            # current drawing in it, so it can be used to save the image to
+            # a file, or whatever.
+            self._buffer.Destroy()
+            self._buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
+            
+            # get the image to be rendered
+            self.img = self.GetImage()
+            
+            # update map display
+            updatemap = True
+            if self.img and self.Map.width + self.Map.height > 0: # scale image after resize
+                self.img = self.img.Scale(self.Map.width, self.Map.height)
+                if len(self.Map.GetListOfLayers()) > 0:
+                    self.UpdateMap()
+                    updatemap = False
+
+            if updatemap:
+                self.UpdateMap(render = True)
+            self.resize = False
+        elif self.resize:
+            event.RequestMore()
+        
+        event.Skip()
+
+    def SaveToFile(self, FileName, FileType, width, height):
+        """!This draws the pseudo DC to a buffer that can be saved to
+        a file.
+        
+        @param FileName file name
+        @param FileType type of bitmap
+        @param width image width
+        @param height image height
+        """
+        busy = wx.BusyInfo(message = _("Please wait, exporting image..."),
+                           parent = self)
+        wx.Yield()
+        
+        self.Map.ChangeMapSize((width, height))
+        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
+        self.Map.Render(force = True, windres = self._properties.resolution)
+        img = self.GetImage()
+        self.pdc.RemoveAll()
+        self.Draw(self.pdc, img, drawid = 99)
+        
+        # compute size ratio to move overlay accordingly
+        cSize = self.GetClientSizeTuple()
+        ratio = float(width) / cSize[0], float(height) / cSize[1]
+        
+        # redraw legend, scalebar
+        for img in self.GetOverlay():
+            # draw any active and defined overlays
+            if self.imagedict[img]['layer'].IsActive():
+                id = self.imagedict[img]['id']
+                coords = int(ratio[0] * self.overlays[id].coords[0]),\
+                         int(ratio[1] * self.overlays[id].coords[1])
+                self.Draw(self.pdc, img = img, drawid = id,
+                          pdctype = self.overlays[id].pdcType, coords = coords)
+                          
+        # redraw text labels
+        for id in self.textdict.keys():
+            textinfo = self.textdict[id]
+            oldCoords = textinfo['coords']
+            textinfo['coords'] = ratio[0] * textinfo['coords'][0],\
+                                 ratio[1] * textinfo['coords'][1]
+            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
+                      pdctype = 'text')
+            # set back old coordinates
+            textinfo['coords'] = oldCoords
+            
+        dc = wx.BufferedDC(None, ibuffer)
+        dc.Clear()
+        # probably does nothing, removed from wxPython 2.9
+        # self.PrepareDC(dc)
+        self.pdc.DrawToDC(dc)
+        if self.pdcVector:
+            self.pdcVector.DrawToDC(dc)
+        ibuffer.SaveFile(FileName, FileType)
+        
+        busy.Destroy()
+        
+        self.UpdateMap(render = True)
+        self.Refresh()
+        
+    def GetOverlay(self):
+        """!Converts rendered overlay files to wx.Image
+        
+        Updates self.imagedict
+        
+        @return list of images
+        """
+        imgs = []
+        for overlay in self.Map.GetListOfLayers(ltype = "overlay", active = True):
+            if overlay.mapfile is not None \
+               and os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
+                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
+
+                for key in self.imagedict.keys():
+                    if self.imagedict[key]['id'] == overlay.id:
+                        del self.imagedict[key]
+                
+                self.imagedict[img] = { 'id' : overlay.id,
+                                        'layer' : overlay }
+                imgs.append(img)
+
+        return imgs
+    
+    def GetImage(self):
+        """!Converts redered map files to wx.Image
+        
+        Updates self.imagedict (id=99)
+        
+        @return wx.Image instance (map composition)
+        """
+        imgId = 99
+        if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
+                os.path.getsize(self.Map.mapfile):
+            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
+        else:
+            img = None
+        
+        for key in self.imagedict.keys():
+            if self.imagedict[key]['id'] == imgId:
+                del self.imagedict[key]
+
+        self.imagedict[img] = { 'id': imgId }
+        
+        return img
+
+    def SetAlwaysRenderEnabled(self, alwaysRender = True):
+        self.alwaysRender = alwaysRender
+        
+    def IsAlwaysRenderEnabled(self):
+        return self.alwaysRender
+
+    def UpdateMap(self, render = True, renderVector = True):
+        """!Updates the canvas anytime there is a change to the
+        underlaying images or to the geometry of the canvas.
+        
+        This method should not be called directly.
+
+        @todo change direct calling of UpdateMap method to emittig grass
+        interface updateMap signal
+
+        @param render re-render map composition
+        @param renderVector re-render vector map layer enabled for editing (used for digitizer)
+        """
+        start = time.clock()
+        self.resize = False
+        
+        # was if self.Map.cmdfile and ...
+        if self.IsAlwaysRenderEnabled() and self.img is None:
+            render = True
+        
+        #
+        # render background image if needed
+        #
+
+        # here was the change of the layertree rerender variable
+        # but it is fully the problem of layertree
+        # and so it is handled there
+        # remove this comment when it is old enough
+
+        try:
+            if render:
+                # update display size
+                self.Map.ChangeMapSize(self.GetClientSize())
+                if self._properties.resolution:
+                    # use computation region resolution for rendering
+                    windres = True
+                else:
+                    windres = False
+                
+                self.mapfile = self.Map.Render(force = True,
+                                               windres = windres)
+            else:
+                self.mapfile = self.Map.Render(force = False)
+            
+        except GException, e:
+            GError(message = e.value)
+            self.mapfile = None
+        
+        self.img = self.GetImage() # id=99
+        
+        #
+        # clear pseudoDcs
+        #
+        for pdc in (self.pdc,
+                    self.pdcDec,
+                    self.pdcTmp):
+            pdc.Clear()
+            pdc.RemoveAll()
+        
+        #
+        # draw background map image to PseudoDC
+        #
+        if not self.img:
+            self.Draw(self.pdc, pdctype = 'clear')
+        else:
+            try:
+                id = self.imagedict[self.img]['id']
+            except:
+                return False
+            
+            self.Draw(self.pdc, self.img, drawid = id)
+        
+        #
+        # render vector map layer
+        #
+        if renderVector and hasattr(self, "digit"):
+            self._updateMap()
+        #
+        # render overlays
+        #
+        for img in self.GetOverlay():
+            # draw any active and defined overlays
+            if self.imagedict[img]['layer'].IsActive():
+                id = self.imagedict[img]['id']
+                self.Draw(self.pdc, img = img, drawid = id,
+                          pdctype = self.overlays[id].pdcType, coords = self.overlays[id].coords)
+        
+        for id in self.textdict.keys():
+            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
+                      pdctype = 'text', coords = [10, 10, 10, 10])
+        
+        # optionally draw computational extent box
+        self.DrawCompRegionExtent()
+        
+        #
+        # redraw pdcTmp if needed
+        #
+        
+        # draw registered graphics
+        if  len(self.graphicsSetList) > 0:
+            penOrig = self.pen
+            polypenOrig = self.polypen
+            
+            for item in self.graphicsSetList:
+                try:
+                    item.Draw(self.pdcTmp)
+                except:
+                    GError(parent = self,
+                           message = _('Unable to draw registered graphics. '
+                                       'The graphics was unregistered.'))
+                    self.UnregisterGraphicsToDraw(item) 
+            
+            self.pen = penOrig 
+            self.polypen = polypenOrig 
+        
+        if len(self.polycoords) > 0:
+            self.DrawLines(self.pdcTmp)
+            
+        stop = time.clock()
+        
+        Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
+                   (render, renderVector, (stop-start)))
+        
+        return True
+
+    def DrawCompRegionExtent(self):
+        """!Draw computational region extent in the display
+        
+        Display region is drawn as a blue box inside the computational region,
+        computational region inside a display region as a red box).
+        """
+        if self._properties.showRegion:
+            compReg = self.Map.GetRegion()
+            dispReg = self.Map.GetCurrentRegion()
+            reg = None
+            if utils.isInRegion(dispReg, compReg):
+                self.polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
+                reg = dispReg
+            else:
+                self.polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
+                                      width = 3, style = wx.SOLID)
+                reg = compReg
+
+            regionCoords = []
+            regionCoords.append((reg['w'], reg['n']))
+            regionCoords.append((reg['e'], reg['n']))
+            regionCoords.append((reg['e'], reg['s']))
+            regionCoords.append((reg['w'], reg['s']))
+            regionCoords.append((reg['w'], reg['n']))
+            # draw region extent
+            self.DrawLines(pdc=self.pdcDec, polycoords=regionCoords)
+
+    def EraseMap(self):
+        """!Erase map canvas
+        """
+        self.Draw(self.pdc, pdctype = 'clear')
+        
+        if hasattr(self, "digit"):
+            self.Draw(self.pdcVector, pdctype = 'clear')
+        
+        self.Draw(self.pdcDec, pdctype = 'clear')
+        self.Draw(self.pdcTmp, pdctype = 'clear')
+
+        self.Map.AbortAllThreads()
+
+    def DragMap(self, moveto):
+        """!Drag the entire map image for panning.
+        
+        @param moveto dx,dy
+        """
+        dc = wx.BufferedDC(wx.ClientDC(self))
+        dc.SetBackground(wx.Brush("White"))
+        dc.Clear()
+        
+        self.dragimg = wx.DragImage(self._buffer)
+        self.dragimg.BeginDrag((0, 0), self)
+        self.dragimg.GetImageRect(moveto)
+        self.dragimg.Move(moveto)
+        
+        self.dragimg.DoDrawImage(dc, moveto)
+        self.dragimg.EndDrag()
+        
+    def DragItem(self, id, coords):
+        """!Drag an overlay decoration item
+        """
+        if id == 99 or id == '' or id == None: return
+        Debug.msg (5, "BufferedWindow.DragItem(): id=%d" % id)
+        x, y = self.lastpos
+        dx = coords[0] - x
+        dy = coords[1] - y
+        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+        r = self.pdc.GetIdBounds(id)
+        
+        if type(r) is list:
+            r = wx.Rect(r[0], r[1], r[2], r[3])
+        if id > 100: # text dragging
+            rtop = (r[0],r[1]-r[3],r[2],r[3])
+            r = r.Union(rtop)
+            rleft = (r[0]-r[2],r[1],r[2],r[3])
+            r = r.Union(rleft)
+        self.pdc.TranslateId(id, dx, dy)
+        
+        r2 = self.pdc.GetIdBounds(id)
+        if type(r2) is list:
+            r2 = wx.Rect(r[0], r[1], r[2], r[3])
+        if id > 100: # text
+            self.textdict[id]['bbox'] = r2
+            self.textdict[id]['coords'][0] += dx
+            self.textdict[id]['coords'][1] += dy
+        r = r.Union(r2)
+        r.Inflate(4,4)
+        self.RefreshRect(r, False)
+        self.lastpos = (coords[0], coords[1])
+                
+    def MouseDraw(self, pdc = None, begin = None, end = None):
+        """!Mouse box or line from 'begin' to 'end'
+        
+        If not given from self.mouse['begin'] to self.mouse['end'].
+        """
+        if not pdc:
+            return
+        
+        if begin is None:
+            begin = self.mouse['begin']
+        if end is None:
+            end   = self.mouse['end']
+        
+        Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
+                       (self.mouse['use'], self.mouse['box'],
+                        begin[0], begin[1], end[0], end[1]))
+        
+        if self.mouse['box'] == "box":
+            boxid = wx.ID_NEW
+            mousecoords = [begin[0], begin[1],
+                           end[0], end[1]]
+            r = pdc.GetIdBounds(boxid)
+            if type(r) is list:
+                r = wx.Rect(r[0], r[1], r[2], r[3])
+            r.Inflate(4, 4)
+            try:
+                pdc.ClearId(boxid)
+            except:
+                pass
+            self.RefreshRect(r, False)
+            pdc.SetId(boxid)
+            self.Draw(pdc, drawid = boxid, pdctype = 'box', coords = mousecoords)
+        
+        elif self.mouse['box'] == "line":
+            self.lineid = wx.ID_NEW
+            mousecoords = [begin[0], begin[1], \
+                           end[0], end[1]]
+            x1 = min(begin[0],end[0])
+            x2 = max(begin[0],end[0])
+            y1 = min(begin[1],end[1])
+            y2 = max(begin[1],end[1])
+            r = wx.Rect(x1,y1,x2-x1,y2-y1)
+            r.Inflate(4,4)
+            try:
+                pdc.ClearId(self.lineid)
+            except:
+                pass
+            self.RefreshRect(r, False)
+            pdc.SetId(self.lineid)
+            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = mousecoords)
+
+    def DrawLines(self, pdc = None, polycoords = None):
+        """!Draw polyline in PseudoDC
+        
+        Set self.pline to wx.NEW_ID + 1
+        
+        polycoords - list of polyline vertices, geographical coordinates
+        (if not given, self.polycoords is used)
+        """
+        if not pdc:
+            pdc = self.pdcTmp
+        
+        if not polycoords:
+            polycoords = self.polycoords
+        
+        if len(polycoords) > 0:
+            self.plineid = wx.ID_NEW + 1
+            # convert from EN to XY
+            coords = []
+            for p in polycoords:
+                coords.append(self.Cell2Pixel(p))
+
+            self.Draw(pdc, drawid = self.plineid, pdctype = 'polyline', coords = coords)
+            
+            Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \
+                           (coords, self.plineid))
+            
+            return self.plineid
+        
+        return -1
+
+    def DrawCross(self, pdc, coords, size, rotation = 0, pen = None,
+                  text = None, textAlign = 'lr', textOffset = (5, 5)):
+        """!Draw cross in PseudoDC
+
+        @todo implement rotation
+
+        @param pdc PseudoDC
+        @param coords center coordinates
+        @param rotation rotate symbol
+        @param text draw also text (text, font, color, rotation)
+        @param textAlign alignment (default 'lower-right')
+        @param textOffset offset for text (from center point)
+        """
+        Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
+                  (pdc, coords, size))
+        coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
+                       (coords[0], coords[1] - size, coords[0], coords[1] + size))
+
+        self.lineid = wx.NewId()
+        for lineCoords in coordsCross:
+            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = lineCoords, pen = pen)
+        
+        if not text:
+            return self.lineid
+        
+        if textAlign == 'ul':
+            coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
+        elif textAlign == 'ur':
+            coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
+        elif textAlign == 'lr':
+            coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
+        else:
+            coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
+        
+        self.Draw(pdc, img = text,
+                  pdctype = 'text', coords = coord, pen = pen)
+        
+        return self.lineid
+
+    def _computeZoomToPointAndRecenter(self, position, zoomtype):
+        """!Computes zoom parameters for recenter mode.
+
+        Computes begin and end parameters for Zoom() method.
+        Used for zooming by single click (not box)
+        and mouse wheel zooming (zoom and recenter mode).
+        """
+        if zoomtype > 0:
+            begin = (position[0] - self.Map.width / 4,
+                     position[1] - self.Map.height / 4)
+            end   = (position[0] + self.Map.width / 4,
+                     position[1] + self.Map.height / 4)
+        else:
+            begin = ((self.Map.width - position[0]) / 2,
+                     (self.Map.height - position[1]) / 2)
+            end = (begin[0] + self.Map.width / 2,
+                   begin[1] + self.Map.height / 2)
+        return begin, end
+
+    def MouseActions(self, event):
+        """!Mouse motion and button click notifier
+        """
+        if not self.processMouse:
+            return
+        
+        # zoom with mouse wheel
+        if event.GetWheelRotation() != 0:
+            self.OnMouseWheel(event)
+            
+        # left mouse button pressed
+        elif event.LeftDown():
+            self.OnLeftDown(event)
+        
+        # left mouse button released
+        elif event.LeftUp():
+            self.OnLeftUp(event)
+        
+        # dragging
+        elif event.Dragging():
+            self.OnDragging(event)
+        
+        # double click
+        elif event.ButtonDClick():
+            self.OnButtonDClick(event)
+        
+        # middle mouse button pressed
+        elif event.MiddleDown():
+            self.OnMiddleDown(event)
+        
+        # middle mouse button relesed
+        elif event.MiddleUp():
+            self.OnMiddleUp(event)
+        
+        # right mouse button pressed
+        elif event.RightDown():
+            self.OnRightDown(event)
+        
+        # right mouse button released
+        elif event.RightUp():
+            self.OnRightUp(event)
+        
+        elif event.Entering():
+            self.OnMouseEnter(event)
+        
+        elif event.Moving():
+            pixelCoordinates = event.GetPositionTuple()[:]
+            coordinates = self.Pixel2Cell(pixelCoordinates)
+            self.mouseMoving.emit(x=coordinates[0], y=coordinates[1])
+            self.OnMouseMoving(event)
+                
+    def OnMouseWheel(self, event):
+        """!Mouse wheel moved
+        """
+        zoomBehaviour = UserSettings.Get(group = 'display',
+                                         key = 'mouseWheelZoom',
+                                         subkey = 'selection')
+        if zoomBehaviour == 2:
+            event.Skip()
+            return
+            
+        self.processMouse = False
+        current  = event.GetPositionTuple()[:]
+        wheel = event.GetWheelRotation()
+        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
+        
+        if wheel > 0:
+            zoomtype = 1
+        else:
+            zoomtype = -1
+        if UserSettings.Get(group = 'display',
+                            key = 'scrollDirection',
+                            subkey = 'selection'):
+            zoomtype *= -1
+        # zoom 1/2 of the screen (TODO: settings)
+        if zoomBehaviour == 0:  # zoom and recenter
+            begin, end = self._computeZoomToPointAndRecenter(position = current, zoomtype = zoomtype)
+
+        elif zoomBehaviour == 1:  # zoom to current cursor position
+            begin = (current[0]/2, current[1]/2)
+            end = ((self.Map.width - current[0])/2 + current[0],
+                   (self.Map.height - current[1])/2 + current[1])
+        
+            
+        # zoom
+        self.Zoom(begin, end, zoomtype)
+        
+        # redraw map
+        self.UpdateMap()
+
+        self.Refresh()
+        self.processMouse = True
+        
+    def OnDragging(self, event):
+        """!Mouse dragging
+        """
+        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
+        current  = event.GetPositionTuple()[:]
+        previous = self.mouse['begin']
+        move = (current[0] - previous[0],
+                current[1] - previous[1])
+        
+        if hasattr(self, "digit"):
+            digitToolbar = self.toolbar
+        else:
+            digitToolbar = None
+        
+        # dragging or drawing box with left button
+        if self.mouse['use'] == 'pan' or \
+                event.MiddleIsDown():
+            self.DragMap(move)
+        
+        # dragging decoration overlay item
+        elif (self.mouse['use'] == 'pointer' and 
+                not digitToolbar and 
+                self.dragid != None):
+            coords = event.GetPositionTuple()
+            self.DragItem(self.dragid, coords)
+        
+        # dragging anything else - rubber band box or line
+        else:
+            if (self.mouse['use'] == 'pointer' and 
+                not digitToolbar):
+                return
+            
+            self.mouse['end'] = event.GetPositionTuple()[:]
+            if (event.LeftIsDown() and 
+                not (digitToolbar and 
+                    digitToolbar.GetAction() in ("moveLine",) and 
+                     self.digit.GetDisplay().GetSelected() > 0)):
+                self.MouseDraw(pdc = self.pdcTmp)
+        
+    def OnLeftDown(self, event):
+        """!Left mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
+                   self.mouse["use"])
+
+        self.mouse['begin'] = event.GetPositionTuple()[:]
+
+        # vector digizer
+        if self.mouse["use"] == "pointer" and \
+                hasattr(self, "digit"):
+            if event.ControlDown():
+                self.OnLeftDownUndo(event)
+            else:
+                self._onLeftDown(event)
+        
+        elif self.mouse['use'] == 'pointer':
+            # get decoration or text id
+            idlist = []
+            self.dragid = ''
+            self.lastpos = self.mouse['begin']
+            idlist = self.pdc.FindObjects(self.lastpos[0], self.lastpos[1],
+                                          self.hitradius)
+            if 99 in idlist:
+                idlist.remove(99)
+            if idlist != []:
+                self.dragid = idlist[0] #drag whatever is on top
+        else:
+            pass
+        coords = self.Pixel2Cell(self.mouse['begin'])
+        self.mouseLeftDown.emit(x=coords[0], y=coords[1])
+        
+        event.Skip()
+        
+    def OnLeftUp(self, event):
+        """!Left mouse button released
+
+        Emits mapQueried signal when mouse use is 'query'.
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
+                       self.mouse["use"])
+        
+        self.mouse['end'] = event.GetPositionTuple()[:]
+        coordinates = self.Pixel2Cell(self.mouse['end'])
+        
+        if self.mouse['use'] in ["zoom", "pan"]:
+            # set region in zoom or pan
+            begin = self.mouse['begin']
+            end = self.mouse['end']
+            
+            if self.mouse['use'] == 'zoom':
+                # set region for click (zero-width box)
+                if begin[0] - end[0] == 0 or \
+                        begin[1] - end[1] == 0:
+                    begin, end = self._computeZoomToPointAndRecenter(position = end, zoomtype = self.zoomtype)
+            self.Zoom(begin, end, self.zoomtype)
+
+            # redraw map
+            self.UpdateMap(render = True)
+
+        elif self.mouse["use"] == "query":
+            self.mapQueried.emit(x=self.mouse['end'][0], y=self.mouse['end'][1])
+
+        elif self.mouse["use"] == "pointer" and \
+                hasattr(self, "digit"):
+            self._onLeftUp(event)
+            
+        elif (self.mouse['use'] == 'pointer' and 
+                self.dragid >= 0):
+            # end drag of overlay decoration
+            
+            if self.dragid < 99 and self.dragid in self.overlays:
+                self.overlays[self.dragid].coords = self.pdc.GetIdBounds(self.dragid)
+            elif self.dragid > 100 and self.dragid in self.textdict:
+                self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
+            else:
+                pass
+            self.dragid = None
+
+            self.mouseLeftUpPointer.emit(x=coordinates[0], y=coordinates[1])
+
+       # TODO: decide which coordinates to send (e, n, mouse['begin'], mouse['end'])
+        self.mouseLeftUp.emit(x=coordinates[0], y=coordinates[1])
+
+    def OnButtonDClick(self, event):
+        """!Mouse button double click
+        """
+        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
+                   self.mouse["use"])
+        
+        screenCoords = event.GetPosition()
+
+        if self.mouse['use'] == 'pointer':
+            # select overlay decoration options dialog
+            idlist  = self.pdc.FindObjects(screenCoords[0], screenCoords[1], self.hitradius)
+            if idlist:
+                self.dragid = idlist[0]
+                self.overlayActivated.emit(overlayId=self.dragid)
+                
+        coords = self.Pixel2Cell(screenCoords)
+        self.mouseDClick.emit(x=coords[0], y=coords[1])
+
+    def OnRightDown(self, event):
+        """!Right mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
+                   self.mouse["use"])
+        
+        if hasattr(self, "digit"):
+            self._onRightDown(event)
+        
+        event.Skip()
+        
+    def OnRightUp(self, event):
+        """!Right mouse button released
+        """
+        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
+                   self.mouse["use"])
+        
+        if hasattr(self, "digit"):
+            self._onRightUp(event)
+        
+        self.redrawAll = True
+        self.Refresh()
+        
+        event.Skip()
+        
+    def OnMiddleDown(self, event):
+        """!Middle mouse button pressed
+        """
+        if not event:
+            return
+        
+        self.mouse['begin'] = event.GetPositionTuple()[:]
+        
+    def OnMiddleUp(self, event):
+        """!Middle mouse button released
+        """
+        self.mouse['end'] = event.GetPositionTuple()[:]
+        
+        # set region in zoom or pan
+        begin = self.mouse['begin']
+        end   = self.mouse['end']
+        
+        self.Zoom(begin, end, 0) # no zoom
+        
+        # redraw map
+        self.UpdateMap(render = True)
+
+    def OnMouseEnter(self, event):
+        """!Mouse entered window and no mouse buttons were pressed
+
+        Emits the mouseEntered signal.
+        """
+        self.mouseEntered.emit()
+        event.Skip()
+
+    def OnMouseMoving(self, event):
+        """!Motion event and no mouse buttons were pressed
+        """
+        if self.mouse["use"] == "pointer" and \
+                hasattr(self, "digit"):
+            self._onMouseMoving(event)
+        
+        event.Skip()
+
+    def OnCopyCoordinates(self, event):
+        """!Copy coordinates to cliboard"""
+        e, n = self.GetLastEN()
+        if wx.TheClipboard.Open():
+            do = wx.TextDataObject()
+            # TODO: put delimiter in settings and apply also for Go to in statusbar
+            delim = ';'
+            do.SetText(str(e) + delim + str(n))
+            wx.TheClipboard.SetData(do)
+            wx.TheClipboard.Close()
+        
+    def ClearLines(self, pdc = None):
+        """!Clears temporary drawn lines from PseudoDC
+        """
+        if not pdc:
+            pdc = self.pdcTmp
+        try:
+            pdc.ClearId(self.lineid)
+            pdc.RemoveId(self.lineid)
+        except:
+            pass
+        
+        try:
+            pdc.ClearId(self.plineid)
+            pdc.RemoveId(self.plineid)
+        except:
+            pass
+        
+        Debug.msg(4, "BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
+                  (self.lineid, self.plineid))
+        
+        return True
+
+    def Pixel2Cell(self, xyCoords):
+        """!Convert image coordinates to real word coordinates
+        
+        @param x, y image coordinates
+        
+        @return easting, northing
+        @return None on error
+        """
+        try:
+            x = int(xyCoords[0])
+            y = int(xyCoords[1])
+        except:
+            return None
+        
+        if self.Map.region["ewres"] > self.Map.region["nsres"]:
+            res = self.Map.region["ewres"]
+        else:
+            res = self.Map.region["nsres"]
+        
+        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
+        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
+        
+        east  = w + x * res
+        north = n - y * res
+        
+        return (east, north)
+    
+    def Cell2Pixel(self, enCoords):
+        """!Convert real word coordinates to image coordinates
+        """
+        try:
+            east  = float(enCoords[0])
+            north = float(enCoords[1])
+        except:
+            return None
+        
+        if self.Map.region["ewres"] > self.Map.region["nsres"]:
+            res = self.Map.region["ewres"]
+        else:
+            res = self.Map.region["nsres"]
+        
+        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
+        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
+        
+        x = (east  - w) / res
+        y = (n - north) / res
+        
+        return (x, y)
+
+    def Zoom(self, begin, end, zoomtype):
+        """!Calculates new region while (un)zoom/pan-ing
+        """
+        x1, y1 = begin
+        x2, y2 = end
+        newreg = {}
+        
+        # threshold - too small squares do not make sense
+        # can only zoom to windows of > 5x5 screen pixels
+        if abs(x2-x1) > 5 and abs(y2-y1) > 5 and zoomtype != 0:
+            if x1 > x2:
+                x1, x2 = x2, x1
+            if y1 > y2:
+                y1, y2 = y2, y1
+            
+            # zoom in
+            if zoomtype > 0:
+                newreg['w'], newreg['n'] = self.Pixel2Cell((x1, y1))
+                newreg['e'], newreg['s'] = self.Pixel2Cell((x2, y2))
+            
+            # zoom out
+            elif zoomtype < 0:
+                newreg['w'], newreg['n'] = self.Pixel2Cell((-x1 * 2, -y1 * 2))
+                newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + 2 * \
+                                                                (self.Map.width  - x2),
+                                                            self.Map.height + 2 * \
+                                                                (self.Map.height - y2)))
+        # pan
+        elif zoomtype == 0:
+            dx = x1 - x2
+            dy = y1 - y2
+            if dx == 0 and dy == 0:
+                dx = x1 - self.Map.width / 2
+                dy = y1 - self.Map.height / 2
+            newreg['w'], newreg['n'] = self.Pixel2Cell((dx, dy))
+            newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + dx,
+                                                        self.Map.height + dy))
+        
+        # if new region has been calculated, set the values
+        if newreg != {}:
+            # LL locations
+            if self.Map.projinfo['proj'] == 'll':
+                self.Map.region['n'] = min(self.Map.region['n'], 90.0)
+                self.Map.region['s'] = max(self.Map.region['s'], -90.0)
+            
+            ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
+            cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
+            
+            # calculate new center point and display resolution
+            self.Map.region['center_easting'] = ce
+            self.Map.region['center_northing'] = cn
+            self.Map.region['ewres'] = (newreg['e'] - newreg['w']) / self.Map.width
+            self.Map.region['nsres'] = (newreg['n'] - newreg['s']) / self.Map.height
+            if self._properties.alignExtent:
+                self.Map.AlignExtentFromDisplay()
+            else:
+                for k in ('n', 's', 'e', 'w'):
+                    self.Map.region[k] = newreg[k]
+            
+            if hasattr(self, "digit") and \
+                    hasattr(self, "moveInfo"):
+                self._zoom(None)
+            
+            self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                             self.Map.region['e'], self.Map.region['w'])
+        
+        if self.redrawAll is False:
+            self.redrawAll = True
+        
+    def ZoomBack(self):
+        """!Zoom to previous extents in zoomhistory list
+
+        Emits zoomChanged signal.
+        Emits zoomHistoryUnavailable signal when stack is empty.
+        """
+        Debug.msg(4, "BufferedWindow.ZoomBack(): hist)=%s" % self.zoomhistory)
+
+        zoom = list()
+        
+        if len(self.zoomhistory) > 1:
+            self.zoomhistory.pop()
+            zoom = self.zoomhistory[-1]
+
+        if len(self.zoomhistory) < 2:
+            self.zoomHistoryUnavailable.emit()
+
+        # zoom to selected region
+        self.Map.GetRegion(n = zoom[0], s = zoom[1],
+                           e = zoom[2], w = zoom[3],
+                           update = True)
+        # update map
+        self.UpdateMap()
+
+        self.zoomChanged.emit()
+
+    def ZoomHistory(self, n, s, e, w):
+        """!Manages a list of last 10 zoom extents
+
+        Emits zoomChanged signal.
+        Emits zoomHistoryAvailable signal when stack is not empty.
+        Emits zoomHistoryUnavailable signal when stack is empty.
+
+        All methods which are changing zoom should call this method
+        to make a record in the history. The signal zoomChanged will be
+        then emitted automatically.
+
+        @param n,s,e,w north, south, east, west
+
+        @return removed history item if exists (or None)
+        """
+        removed = None
+        self.zoomhistory.append((n,s,e,w))
+        
+        if len(self.zoomhistory) > 10:
+            removed = self.zoomhistory.pop(0)
+        
+        if removed:
+            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
+                      (self.zoomhistory, removed))
+        else:
+            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s" %
+                      (self.zoomhistory))
+        
+        # update toolbar
+        if len(self.zoomhistory) > 1:
+            self.zoomHistoryAvailable.emit()
+        else:
+            self.zoomHistoryUnavailable.emit()
+
+        self.zoomChanged.emit()
+        
+        return removed
+
+    def InitZoomHistory(self):
+        """Initializes zoom history.
+
+        @todo First item is handled in some special way. Improve the
+        documentation or fix the code.
+
+        It does not emits any signals.
+
+        This method can be possibly removed when the history will solve the
+        fist item in different way or when GCP manager (and possibly others)
+        will handle Map variable in the way that it will be prepared for
+        MapWindow/BufferedWindow and thus usable to initialize history.
+        """
+        self.zoomhistory.append((self.Map.region['n'],
+                                 self.Map.region['s'],
+                                 self.Map.region['e'],
+                                 self.Map.region['w']))
+        Debug.msg(4, "BufferedWindow.InitZoomHistory(): hist=%s" %
+                  (self.zoomhistory))
+
+    def ResetZoomHistory(self):
+        """!Reset zoom history"""
+        self.zoomhistory = list()
+                
+    def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
+        """!Set display extents to match selected raster
+        or vector map(s).
+
+        @param layers list of layers to be zoom to
+        @param ignoreNulls True to ignore null-values (valid only for rasters)
+        @param render True to re-render display
+        """
+        if not layers:
+            layers = self._giface.GetLayerList().GetSelectedLayers(checkedOnly=False)
+            layers = [layer.maplayer for layer in layers]
+
+        if not layers:
+            return
+        
+        rast = []
+        vect = []
+        updated = False
+        for l in layers:
+            # only raster/vector layers are currently supported
+            if l.type == 'raster':
+                rast.append(l.GetName())
+            elif l.type == 'vector':
+                if hasattr(self, "digit") and \
+                        self.toolbar.GetLayer() == l:
+                    w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
+                    self.Map.GetRegion(n = n, s = s, w = w, e = e,
+                                       update = True)
+                    updated = True
+                else:
+                    vect.append(l.name)
+            elif l.type == 'rgb':
+                for rname in l.GetName().splitlines():
+                    rast.append(rname)
+            
+        if not updated:
+            self.Map.GetRegion(rast = rast,
+                               vect = vect,
+                               zoom = ignoreNulls,
+                               update = True)
+        
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        if render:
+            self.UpdateMap()
+
+    def ZoomToWind(self):
+        """!Set display geometry to match computational region
+        settings (set with g.region)
+        """
+        self.Map.region = self.Map.GetRegion()
+        
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        self.UpdateMap()
+
+    def ZoomToDefault(self):
+        """!Set display geometry to match default region settings
+        """
+        self.Map.region = self.Map.GetRegion(default = True)
+        self.Map.AdjustRegion() # aling region extent to the display
+
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        self.UpdateMap()
+
+    def GoTo(self, e, n):
+        region = self.Map.GetCurrentRegion()
+
+        region['center_easting'], region['center_northing'] = e, n
+        
+        dn = (region['nsres'] * region['rows']) / 2.
+        region['n'] = region['center_northing'] + dn
+        region['s'] = region['center_northing'] - dn
+        de = (region['ewres'] * region['cols']) / 2.
+        region['e'] = region['center_easting'] + de
+        region['w'] = region['center_easting'] - de
+
+        self.Map.AdjustRegion()
+
+        # add to zoom history
+        self.ZoomHistory(region['n'], region['s'],
+                                   region['e'], region['w'])        
+        self.UpdateMap()
+    
+    def DisplayToWind(self):
+        """!Set computational region (WIND file) to match display
+        extents
+        """
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        # We ONLY want to set extents here. Don't mess with resolution. Leave that
+        # for user to set explicitly with g.region
+        new = self.Map.AlignResolution()
+        RunCommand('g.region',
+                   parent = self,
+                   overwrite = True,
+                   n = new['n'],
+                   s = new['s'],
+                   e = new['e'],
+                   w = new['w'],
+                   rows = int(new['rows']),
+                   cols = int(new['cols']))
+        
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+        
+    def ZoomToSaved(self):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        dlg = SavedRegion(parent = self,
+                          title = _("Zoom to saved region extents"),
+                          loadsave = 'load')
+        
+        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.GetName():
+            dlg.Destroy()
+            return
+        
+        if not grass.find_file(name = dlg.GetName(), element = 'windows')['name']:
+            wx.MessageBox(parent = self,
+                          message = _("Region <%s> not found. Operation canceled.") % dlg.GetName(),
+                          caption = _("Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
+            dlg.Destroy()
+            return
+        
+        self.Map.GetRegion(regionName = dlg.GetName(),
+                           update = True)
+        
+        dlg.Destroy()
+        
+        self.ZoomHistory(self.Map.region['n'],
+                         self.Map.region['s'],
+                         self.Map.region['e'],
+                         self.Map.region['w'])
+        
+        self.UpdateMap()
+                
+    def SaveRegion(self, display = True):
+        """!Save display extents/compulational region to named region
+        file.
+
+        @param display True for display extends otherwise computational region
+        """
+        if display:
+            title = _("Save display extents to region file")
+        else:
+            title = _("Save computational region to region file")
+        
+        dlg = SavedRegion(parent = self, title = title, loadsave = 'save')
+        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.GetName():
+            dlg.Destroy()
+            return
+        
+        # test to see if it already exists and ask permission to overwrite
+        if grass.find_file(name = dlg.GetName(), element = 'windows')['name']:
+            overwrite = wx.MessageBox(parent = self,
+                                      message = _("Region file <%s> already exists. "
+                                                  "Do you want to overwrite it?") % (dlg.GetName()),
+                                      caption = _("Warning"), style = wx.YES_NO | wx.CENTRE)
+            if overwrite != wx.YES:
+                dlg.Destroy()
+                return
+        
+        if display:
+            self._saveDisplayRegion(dlg.GetName())
+        else:
+            self._saveCompRegion(dlg.GetName())
+        
+        dlg.Destroy()
+
+    def _saveCompRegion(self, name):
+        """!Save region settings to region file
+        
+        @param name region name
+        """
+        RunCommand('g.region',
+                   overwrite = True,
+                   parent = self,
+                   flags = 'u',
+                   save = name)
+        
+    def _saveDisplayRegion(self, name):
+        """!Save display extents to region file
+        
+        @param name region name
+        """
+        new = self.Map.GetCurrentRegion()
+        
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        RunCommand('g.region',
+                   overwrite = True,
+                   parent = self,
+                   flags = 'u',
+                   n = new['n'],
+                   s = new['s'],
+                   e = new['e'],
+                   w = new['w'],
+                   rows = int(new['rows']),
+                   cols = int(new['cols']),
+                   save = name)
+        
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+        
+    def Distance(self, beginpt, endpt, screen = True):
+        """!Calculates distance
+        
+        Ctypes required for LL-locations
+        
+        @param beginpt first point
+        @param endpt second point
+        @param screen True for screen coordinates otherwise EN
+        """
+        if screen:
+            e1, n1 = self.Pixel2Cell(beginpt)
+            e2, n2 = self.Pixel2Cell(endpt)
+        else:
+            e1, n1 = beginpt
+            e2, n2 = endpt
+            
+        dEast  = (e2 - e1)
+        dNorth = (n2 - n1)
+        
+        if self.Map.projinfo['proj'] == 'll' and haveCtypes:
+            dist = gislib.G_distance(e1, n1, e2, n2)
+        else:
+            dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
+        
+        return (dist, (dEast, dNorth))
+
+    def GetMap(self):
+        """!Get render.Map() instance"""
+        return self.Map
+
+    def RegisterGraphicsToDraw(self, graphicsType, setStatusFunc = None, drawFunc = None):
+        """! This method registers graphics to draw.
+        
+        @param type (string) - graphics type: "point" or "line"
+        @param setStatusFunc (function reference) - function called before drawing each item
+                Status function should be in this form: setStatusFunc(item, itemOrderNum)
+                    item - passes instance of GraphicsSetItem which will be drawn
+                    itemOrderNum - number of item in drawing order (from O)
+                                   Hidden items are also counted in drawing order.
+        @param drawFunc (function reference) - defines own function for drawing
+                            If function is not defined DrawCross method is used for type "point"
+                            or DrawLines method for type "line".
+                            
+        @return reference to GraphicsSet, which was added.
+        """
+        item = GraphicsSet(parentMapWin = self, 
+                           graphicsType = graphicsType, 
+                           setStatusFunc = setStatusFunc, 
+                           drawFunc = drawFunc)
+        self.graphicsSetList.append(item)
+        
+        return item
+
+    def UnregisterGraphicsToDraw(self, item):
+        """!Unregisteres GraphicsSet instance
+        
+        @param item (GraphicsSetItem) - item to unregister
+        
+        @return True - if item was unregistered
+        @return False - if item was not found
+        """     
+        if item in self.graphicsSetList:
+            self.graphicsSetList.remove(item)
+            return True
+        
+        return False


Property changes on: grass/trunk/gui/wxpython/mapwin/buffered.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapwin/decorations.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/decorations.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/decorations.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,536 @@
+"""!
+ at package mapwin.decorations
+
+ at brief Map display decorations (overlays) - text, barscale and legend
+
+Classes:
+ - decorations::OverlayController
+ - decorations::BarscaleController
+ - decorations::LegendController
+ - decorations::DecorationDialog
+ - decorations::TextLayerDialog
+
+(C) 2006-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>
+"""
+
+import wx
+from core.utils import GetLayerNameFromCmd, _
+from gui_core.forms import GUI
+
+
+class OverlayController(object):
+
+    """!Base class for decorations (barscale, legend) controller."""
+
+    def __init__(self, renderer):
+        self._renderer = renderer
+        self._overlay = None
+        self._coords = [0, 0]
+        self._pdcType = 'image'
+        self._propwin = None
+        self._defaultAt = ''
+        self._cmd = None   # to be set by user
+        self._name = None  # to be defined by subclass
+        self._id = None    # to be defined by subclass
+
+    def SetCmd(self, cmd):
+        hasAt = False
+        for i in cmd:
+            if i.startswith("at="):
+                hasAt = True
+                break
+        if not hasAt:
+            cmd.append(self._defaultAt)
+        self._cmd = cmd
+
+    def GetCmd(self):
+        return self._cmd
+
+    cmd = property(fset=SetCmd, fget=GetCmd)
+
+    def SetCoords(self, coords):
+        self._coords = list(coords)
+
+    def GetCoords(self):
+        return self._coords
+
+    coords = property(fset=SetCoords, fget=GetCoords)
+
+    def GetPdcType(self):
+        return self._pdcType
+
+    pdcType = property(fget=GetPdcType)
+
+    def GetName(self):
+        return self._name
+
+    name = property(fget=GetName)
+
+    def GetId(self):
+        return self._id
+
+    id = property(fget=GetId)
+
+    def GetPropwin(self):
+        return self._propwin
+
+    def SetPropwin(self, win):
+        self._propwin = win
+
+    propwin = property(fget=GetPropwin, fset=SetPropwin)
+
+    def GetLayer(self):
+        return self._overlay
+
+    layer = property(fget=GetLayer)
+
+    def IsShown(self):
+        if self._overlay and self._overlay.IsActive():
+            return True
+        return False
+
+    def Show(self, show=True):
+        """!Activate or deactivate overlay."""
+        if show:
+            if not self._overlay:
+                self._add()
+            self._overlay.SetActive(True)
+            self._update()
+        else:
+            self.Hide()
+
+    def Hide(self):
+        if self._overlay:
+            self._overlay.SetActive(False)
+
+    def _add(self):
+        self._overlay = self._renderer.AddOverlay(id=self._id, ltype=self._name,
+                                                  command=self.cmd, active=False,
+                                                  render=False, hidden=True)
+        # check if successful
+
+    def _update(self):
+        self._renderer.ChangeOverlay(id=self._id, command=self._cmd,
+                                     render=False)
+
+
+class BarscaleController(OverlayController):
+
+    def __init__(self, renderer):
+        OverlayController.__init__(self, renderer)
+        self._id = 0
+        self._name = 'barscale'
+        self._defaultAt = 'at=0,95'
+        self._cmd = ['d.barscale', self._defaultAt]
+
+
+class LegendController(OverlayController):
+
+    def __init__(self, renderer):
+        OverlayController.__init__(self, renderer)
+        self._id = 1
+        self._name = 'legend'
+        # TODO: synchronize with d.legend?
+        self._defaultAt = 'at=5,50,2,5'
+        self._cmd = ['d.legend', self._defaultAt]
+
+    def ResizeLegend(self, begin, end, screenSize):
+        """!Resize legend according to given bbox coordinates."""
+        w = abs(begin[0] - end[0])
+        h = abs(begin[1] - end[1])
+        if begin[0] < end[0]:
+            x = begin[0]
+        else:
+            x = end[0]
+        if begin[1] < end[1]:
+            y = begin[1]
+        else:
+            y = end[1]
+
+        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
+              (screenSize[1] - y) / float(screenSize[1]) * 100,
+              x / float(screenSize[0]) * 100,
+              (x + w) / float(screenSize[0]) * 100]
+        atStr = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
+
+        for i, subcmd in enumerate(self._cmd):
+            if subcmd.startswith('at='):
+                self._cmd[i] = atStr
+                break
+
+        self._coords = [0, 0]
+        self.Show()
+
+
+DECOR_DIALOG_LEGEND = 0
+DECOR_DIALOG_BARSCALE = 1
+
+
+class DecorationDialog(wx.Dialog):
+
+    """!Controls setting options and displaying/hiding map overlay
+    decorations
+    """
+
+    def __init__(self, parent, title, giface, overlayController,
+                 ddstyle, **kwargs):
+
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, **kwargs)
+
+        self.parent = parent  # MapFrame
+        self._overlay = overlayController
+        self._ddstyle = ddstyle
+        self._giface = giface
+
+        self._oldMouseUse = None
+        self._oldCursor = None
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        self.chkbox = wx.CheckBox(parent=self, id=wx.ID_ANY)
+        self.chkbox.SetValue(True)
+
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
+            self.chkbox.SetLabel("Show legend")
+        else:
+            self.chkbox.SetLabel("Show scale and North arrow")
+
+        box.Add(item=self.chkbox, proportion=0,
+                flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+        sizer.Add(item=box, proportion=0,
+                  flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        optnbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set options"))
+        box.Add(item=optnbtn, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+        sizer.Add(item=box, proportion=0,
+                  flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
+            box = wx.BoxSizer(wx.HORIZONTAL)
+            self.resizeBtn = wx.ToggleButton(
+                parent=self, id=wx.ID_ANY, label=_("Set size and position"))
+            self.resizeBtn.SetToolTipString(_("Click and drag on the map display to set legend "
+                                              "size and position and then press OK"))
+            self.resizeBtn.Disable()
+            self.resizeBtn.Bind(wx.EVT_TOGGLEBUTTON, self.OnResize)
+            box.Add(item=self.resizeBtn, proportion=0,
+                    flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+            sizer.Add(item=box, proportion=0,
+                      flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        if self._ddstyle == DECOR_DIALOG_LEGEND:
+            labelText = _("Drag legend object with mouse in pointer mode to position.\n"
+                          "Double-click to change options.\n"
+                          "Define raster map name for legend in properties dialog.")
+        else:
+            labelText = _("Drag scale object with mouse in pointer mode to position.\n"
+                          "Double-click to change options.")
+
+        label = wx.StaticText(parent=self, id=wx.ID_ANY,
+                              label=labelText)
+
+        box.Add(item=label, proportion=0,
+                flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+        sizer.Add(item=box, proportion=0,
+                  flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+
+        line = wx.StaticLine(
+            parent=self, id=wx.ID_ANY, size=(20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item=line, proportion=0,
+                  flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+
+        # buttons
+        btnsizer = wx.StdDialogButtonSizer()
+
+        self.btnOK = wx.Button(parent=self, id=wx.ID_OK)
+        self.btnOK.SetDefault()
+        self.btnOK.Enable(self._ddstyle != DECOR_DIALOG_LEGEND)
+        btnsizer.AddButton(self.btnOK)
+
+        btnCancel = wx.Button(parent=self, id=wx.ID_CANCEL)
+        btnsizer.AddButton(btnCancel)
+        btnsizer.Realize()
+
+        sizer.Add(item=btnsizer, proportion=0,
+                  flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+
+        #
+        # bindings
+        #
+        optnbtn.Bind(wx.EVT_BUTTON, self.OnOptions)
+        btnCancel.Bind(wx.EVT_BUTTON, lambda evt: self.CloseDialog())
+        self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+        mapName, found = GetLayerNameFromCmd(self._overlay.cmd)
+        if found:
+            # enable 'OK' and 'Resize' button
+            self.btnOK.Enable()
+
+            # set title
+            self.SetTitle(_('Legend of raster map <%s>') %
+                          mapName)
+
+    def OnOptions(self, event):
+        """!Sets option for decoration map overlays
+        """
+        if self._overlay.propwin is None:
+            # build properties dialog
+            GUI(parent=self.parent).ParseCommand(cmd=self._overlay.cmd,
+                                                 completed=(self.GetOptData, self._overlay.name, ''))
+
+        else:
+            if self._overlay.propwin.IsShown():
+                self._overlay.propwin.SetFocus()
+            else:
+                self._overlay.propwin.Show()
+
+    def OnResize(self, event):
+        window = self._giface.GetMapWindow()
+        if event.GetInt():
+            self._oldMouseUse = window.mouse['use']
+            self._oldCursor = window.GetNamedCursor()
+            window.SetNamedCursor('cross')
+            window.mouse['use'] = None
+            window.mouse['box'] = 'box'
+            window.pen = wx.Pen(colour='Black', width=2, style=wx.SHORT_DASH)
+            window.mouseLeftUp.connect(self._resizeLegend)
+        else:
+            self.Restore()
+            self.DisconnectResizing()
+
+    def Restore(self):
+        """!Restore conditions before resizing"""
+        window = self._giface.GetMapWindow()
+        if self._oldCursor:
+            window.SetNamedCursor(self._oldCursor)
+        if self._oldMouseUse:
+            window.mouse['use'] = self._oldMouseUse
+
+    def DisconnectResizing(self):
+        self._giface.GetMapWindow().mouseLeftUp.disconnect(self._resizeLegend)
+
+    def _resizeLegend(self, x, y):
+        """!Update legend after drawing new legend size (moved from BufferedWindow)"""
+        self.resizeBtn.SetValue(False)
+        window = self._giface.GetMapWindow()
+        self.DisconnectResizing()
+        self.Restore()
+        # resize legend
+        screenSize = window.GetClientSizeTuple()
+        self._overlay.ResizeLegend(window.mouse["begin"], window.mouse["end"], screenSize)
+        # redraw
+        self._giface.updateMap.emit()
+
+    def CloseDialog(self):
+        """!Hide dialog"""
+        if self._ddstyle == DECOR_DIALOG_LEGEND and self.resizeBtn.GetValue():
+            self.Restore()
+            self.resizeBtn.SetValue(False)
+            self.DisconnectResizing()
+
+        self.Hide()
+
+    def OnOK(self, event):
+        """!Button 'OK' pressed"""
+        # enable or disable overlay
+        self._overlay.Show(self.chkbox.IsChecked())
+
+        # update map
+        if self.parent.IsPaneShown('3d'):
+            self.parent.MapWindow.UpdateOverlays()
+
+        self._giface.updateMap.emit()
+
+        # hide dialog
+        self.CloseDialog()
+
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """!Process decoration layer data"""
+        if dcmd:
+            self._overlay.cmd = dcmd
+        self._overlay.propwin = propwin
+        if params:
+            self.btnOK.Enable()
+            if self._ddstyle == DECOR_DIALOG_LEGEND and not self.parent.IsPaneShown('3d'):
+                self.resizeBtn.Enable()
+
+    def Show(self, show=True):
+        if show:
+            self.resizeBtn.Enable(not self.parent.IsPaneShown('3d'))
+        wx.Dialog.Show(self, show)
+
+
+class TextLayerDialog(wx.Dialog):
+
+    """
+    Controls setting options and displaying/hiding map overlay decorations
+    """
+
+    def __init__(self, parent, ovlId, title, name='text',
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.DEFAULT_DIALOG_STYLE):
+
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
+        from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
+
+        self.ovlId = ovlId
+        self.parent = parent
+
+        if self.ovlId in self.parent.MapWindow.textdict.keys():
+            self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
+            self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
+            self.currClr = self.parent.MapWindow.textdict[self.ovlId]['color']
+            self.currRot = self.parent.MapWindow.textdict[self.ovlId]['rotation']
+            self.currCoords = self.parent.MapWindow.textdict[self.ovlId]['coords']
+            self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
+        else:
+            self.currClr = wx.BLACK
+            self.currText = ''
+            self.currFont = self.GetFont()
+            self.currRot = 0.0
+            self.currCoords = [10, 10]
+            self.currBB = wx.Rect()
+
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        box = wx.GridBagSizer(vgap=5, hgap=5)
+
+        # show/hide
+        self.chkbox = wx.CheckBox(parent=self, id=wx.ID_ANY,
+                                  label=_('Show text object'))
+        if self.parent.Map.GetOverlay(self.ovlId) is None:
+            self.chkbox.SetValue(True)
+        else:
+            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
+        box.Add(item=self.chkbox, span=(1, 2),
+                flag=wx.ALIGN_LEFT | wx.ALL, border=5,
+                pos=(0, 0))
+
+        # text entry
+        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Enter text:"))
+        box.Add(item=label,
+                flag=wx.ALIGN_CENTER_VERTICAL,
+                pos=(1, 0))
+
+        self.textentry = ExpandoTextCtrl(
+            parent=self, id=wx.ID_ANY, value="", size=(300, -1))
+        self.textentry.SetFont(self.currFont)
+        self.textentry.SetForegroundColour(self.currClr)
+        self.textentry.SetValue(self.currText)
+        # get rid of unneeded scrollbar when text box first opened
+        self.textentry.SetClientSize((300, -1))
+
+        box.Add(item=self.textentry,
+                pos=(1, 1))
+
+        # rotation
+        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Rotation:"))
+        box.Add(item=label,
+                flag=wx.ALIGN_CENTER_VERTICAL,
+                pos=(2, 0))
+        self.rotation = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
+                                    size = (75, -1), style = wx.SP_ARROW_KEYS)
+        self.rotation.SetRange(-360, 360)
+        self.rotation.SetValue(int(self.currRot))
+        box.Add(item=self.rotation,
+                flag=wx.ALIGN_RIGHT,
+                pos=(2, 1))
+
+        # font
+        fontbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set font"))
+        box.Add(item=fontbtn,
+                flag=wx.ALIGN_RIGHT,
+                pos=(3, 1))
+
+        self.sizer.Add(item=box, proportion=1,
+                       flag=wx.ALL, border=10)
+
+        # note
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(parent=self, id=wx.ID_ANY,
+                              label=_("Drag text with mouse in pointer mode "
+                                      "to position.\nDouble-click to change options"))
+        box.Add(item=label, proportion=0,
+                flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+        self.sizer.Add(item=box, proportion=0,
+                       flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border=5)
+
+        line = wx.StaticLine(parent=self, id=wx.ID_ANY,
+                             size=(20, -1), style = wx.LI_HORIZONTAL)
+        self.sizer.Add(item=line, proportion=0,
+                       flag=wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border=5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(parent=self, id=wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(parent=self, id=wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        self.sizer.Add(item=btnsizer, proportion=0,
+                       flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+        self.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+        # bindings
+        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
+        self.Bind(wx.EVT_BUTTON,     self.OnSelectFont, fontbtn)
+        self.Bind(wx.EVT_TEXT,       self.OnText,       self.textentry)
+        self.Bind(wx.EVT_SPINCTRL,   self.OnRotation,   self.rotation)
+
+    def OnRefit(self, event):
+        """!Resize text entry to match text"""
+        self.sizer.Fit(self)
+
+    def OnText(self, event):
+        """!Change text string"""
+        self.currText = event.GetString()
+
+    def OnRotation(self, event):
+        """!Change rotation"""
+        self.currRot = event.GetInt()
+
+        event.Skip()
+
+    def OnSelectFont(self, event):
+        """!Change font"""
+        data = wx.FontData()
+        data.EnableEffects(True)
+        data.SetColour(self.currClr)         # set colour
+        data.SetInitialFont(self.currFont)
+
+        dlg = wx.FontDialog(self, data)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetFontData()
+            self.currFont = data.GetChosenFont()
+            self.currClr = data.GetColour()
+
+            self.textentry.SetFont(self.currFont)
+            self.textentry.SetForegroundColour(self.currClr)
+
+            self.Layout()
+
+        dlg.Destroy()
+
+    def GetValues(self):
+        """!Get text properties"""
+        return {'text': self.currText,
+                'font': self.currFont,
+                'color': self.currClr,
+                'rotation': self.currRot,
+                'coords': self.currCoords,
+                'active': self.chkbox.IsChecked()}


Property changes on: grass/trunk/gui/wxpython/mapwin/decorations.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapwin/graphics.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/graphics.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapwin/graphics.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -0,0 +1,328 @@
+"""!
+ at package mapwin.graphics
+
+ at brief Map display canvas - buffered window.
+
+Classes:
+ - graphics::GraphicsSet
+ - graphics::GraphicsSetItem
+
+(C) 2006-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 Stepan Turek <stepan.turek seznam.cz> (handlers support, GraphicsSet)
+"""
+
+
+from copy import copy
+
+import wx
+
+from core.utils import _
+
+
+class GraphicsSet:
+
+    def __init__(self, parentMapWin, graphicsType,
+                 setStatusFunc=None, drawFunc=None):
+        """!Class, which contains instances of GraphicsSetItem and
+            draws them For description of parameters look at method
+            RegisterGraphicsToDraw in BufferedWindow class.
+        """
+        self.pens = {
+            "default":  wx.Pen(colour=wx.BLACK, width=2, style=wx.SOLID),
+            "selected":  wx.Pen(colour=wx.GREEN, width=2, style=wx.SOLID),
+            "unused":  wx.Pen(colour=wx.LIGHT_GREY, width=2, style=wx.SOLID),
+            "highest":  wx.Pen(colour=wx.RED, width=2, style=wx.SOLID)
+        }
+
+        # list contains instances of GraphicsSetItem
+        self.itemsList = []
+
+        self.properties = {}
+        self.graphicsType = graphicsType
+        self.parentMapWin = parentMapWin
+        self.setStatusFunc = setStatusFunc
+
+        if drawFunc:
+            self.drawFunc = drawFunc
+
+        elif self.graphicsType == "point":
+            self.properties["size"] = 5
+
+            self.properties["text"] = {}
+            self.properties["text"]['font'] = wx.Font(pointSize=self.properties["size"],
+                                                      family=wx.FONTFAMILY_DEFAULT,
+                                                      style=wx.FONTSTYLE_NORMAL,
+                                                      weight=wx.FONTWEIGHT_NORMAL)
+            self.properties["text"]['active'] = True
+
+            self.drawFunc = self.parentMapWin.DrawCross
+
+        elif self.graphicsType == "line":
+            self.drawFunc = self.parentMapWin.DrawLines
+
+    def Draw(self, pdc):
+        """!Draws all containing items.
+
+        @param pdc - device context, where items are drawn
+        """
+        itemOrderNum = 0
+        for item in self.itemsList:
+            if self.setStatusFunc is not None:
+                self.setStatusFunc(item, itemOrderNum)
+
+            if item.GetPropertyVal("hide") is True:
+                itemOrderNum += 1
+                continue
+
+            if self.graphicsType == "point":
+                if item.GetPropertyVal("penName"):
+                    self.parentMapWin.pen = self.pens[item.GetPropertyVal("penName")]
+                else:
+                    self.parentMapWin.pen = self.pens["default"]
+
+                coords = self.parentMapWin.Cell2Pixel(item.GetCoords())
+                size = self.properties["size"]
+
+                self.properties["text"]['coords'] = [coords[0] + size, coords[1] + size, size, size]
+                self.properties["text"]['color'] = self.parentMapWin.pen.GetColour()
+                self.properties["text"]['text'] = item.GetPropertyVal("label")
+
+                self.drawFunc(pdc=pdc,
+                              coords=coords,
+                              text=self.properties["text"],
+                              size=self.properties["size"])
+
+            elif self.graphicsType == "line":
+                if item.GetPropertyVal("penName"):
+                    self.parentMapWin.polypen = self.pens[item.GetPropertyVal("penName")]
+                else:
+                    self.parentMapWin.polypen = self.pens["default"]
+                coords = item.GetCoords()
+
+                self.drawFunc(pdc=pdc,
+                              polycoords=coords)
+            itemOrderNum += 1
+
+    def AddItem(self, coords, penName=None, label=None, hide=False):
+        """!Append item to the list.
+
+        Added item is put to the last place in drawing order.
+        Could be 'point' or 'line' according to graphicsType.
+
+        @param coords - list of east, north coordinates (double) of item
+                        Example: point: [1023, 122]
+                                 line: [[10, 12],[20,40],[23, 2334]]
+        @param penName (string) the 'default' pen is used if is not defined
+        @param label (string) label, which will be drawn with point. It is
+        relavant just for 'point' type.
+        @param hide (bool) If it is True, the item is not drawn
+        when self.Draw is called. Hidden items are also counted in drawing
+        order.
+
+        @return (GraphicsSetItem) - added item reference
+        """
+        item = GraphicsSetItem(coords=coords, penName=penName, label=label, hide=hide)
+        self.itemsList.append(item)
+
+        return item
+
+    def DeleteItem(self, item):
+        """!Deletes item
+
+        @param item (GraphicsSetItem) - item to remove
+
+        @return True if item was removed
+        @return False if item was not found
+        """
+        try:
+            self.itemsList.remove(item)
+        except ValueError:
+            return False
+
+        return True
+
+    def GetAllItems(self):
+        """!Returns list of all containing instances of GraphicsSetItem, in order
+        as they are drawn. If you want to change order of drawing use: SetItemDrawOrder method.
+        """
+        # user can edit objects but not order in list, that is reason,
+        # why is returned shallow copy of data list it should be used
+        # SetItemDrawOrder for changing order
+        return copy(self.itemsList)
+
+    def GetItem(self, drawNum):
+        """!Get given item from the list.
+
+        @param drawNum (int) - drawing order (index) number of item
+
+        @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
+
+    def SetPropertyVal(self, propName, propVal):
+        """!Set property value
+
+        @param propName (string) - property name: "size", "text"
+                                 - both properties are relevant for "point" type
+        @param propVal - property value to be set
+
+        @return True - if value was set
+        @return False - if propName is not "size" or "text" or type is "line"
+        """
+        if propName in self.properties:
+            self.properties[propName] = propVal
+            return True
+
+        return False
+
+    def GetPropertyVal(self, propName):
+        """!Get property value
+
+        Raises KeyError if propName is not "size" or "text" or type is
+        "line"
+
+        @param propName (string) property name: "size", "text"
+                                 both properties are relevant for "point" type
+
+        @return value of property
+        """
+        if propName in self.properties:
+            return self.properties[propName]
+
+        raise KeyError(_("Property does not exist: %s") % (propName))
+
+    def AddPen(self, penName, pen):
+        """!Add pen
+
+        @param penName (string) - name of added pen
+        @param pen (wx.Pen) - added pen
+
+        @return True - if pen was added
+        @return False - if pen already exists
+        """
+        if penName in self.pens:
+            return False
+
+        self.pens[penName] = pen
+        return True
+
+    def GetPen(self, penName):
+        """!Get existing pen
+
+        @param penName (string) - name of pen
+
+        @return wx.Pen reference if is found
+        @return None if penName was not found
+        """
+        if penName in self.pens:
+            return self.pens[penName]
+
+        return None
+
+    def SetItemDrawOrder(self, item, drawNum):
+        """!Set draw order for item
+
+        @param item (GraphicsSetItem)
+        @param drawNum (int) - drawing order of item to be set
+
+        @return True - if order was changed
+        @return False - if drawNum is out of range or item was not found
+        """
+        if drawNum < len(self.itemsList) and drawNum >= 0 and \
+                item in self.itemsList:
+            self.itemsList.insert(drawNum, self.itemsList.pop(self.itemsList.index(item)))
+            return True
+
+        return False
+
+    def GetItemDrawOrder(self, item):
+        """!Get draw order for given item
+
+        @param item (GraphicsSetItem)
+
+        @return (int) - drawing order of item
+        @return None - if item was not found
+        """
+        try:
+            return self.itemsList.index(item)
+        except ValueError:
+            return None
+
+
+class GraphicsSetItem:
+
+    def __init__(self, coords, penName=None, label=None, hide=False):
+        """!Could be point or line according to graphicsType in
+        GraphicsSet class
+
+        @param coords - list of coordinates (double) of item
+                        Example: point: [1023, 122]
+                                 line: [[10, 12],[20,40],[23, 2334]]
+        @param penName (string) if it is not defined 'default' pen is used
+        @param label (string) label, which will be drawn with point. It is
+        relevant just for 'point' type
+        @param hide (bool) if it is True, item is not drawn
+                           Hidden items are also counted in drawing order in
+                           GraphicsSet class.
+        """
+        self.coords = coords
+
+        self.properties = {"penName": penName,
+                           "hide": hide,
+                           "label": label}
+
+    def SetPropertyVal(self, propName, propVal):
+        """!Set property value
+
+        @param propName (string) - property name: "penName", "hide" or "label"
+                                 - property "label" is relevant just for 'point' type
+        @param propVal - property value to be set
+
+        @return True - if value was set
+        @return False - if propName is not "penName", "hide" or "label"
+        """
+        if propName in self.properties:
+            self.properties[propName] = propVal
+            return True
+
+        return False
+
+    def GetPropertyVal(self, propName):
+        """!Get property value
+
+        Raises KeyError if propName is not "penName", "hide" or
+        "label".
+
+        @param propName (string) - property name: "penName", "hide" or "label"
+                                 - property "label" is relevant just for 'point' type
+
+        @return value of property
+        """
+        if propName in self.properties:
+            return self.properties[propName]
+
+        raise KeyError(_("Property does not exist: %s") % (propName))
+
+    def SetCoords(self, coords):
+        """!Set coordinates of item
+
+        @param coords - list of east, north coordinates (double) of item
+                        Example: point: [1023, 122]
+                                 line: [[10, 12],[20,40],[23, 2334]]
+        """
+        self.coords = coords
+
+    def GetCoords(self):
+        """!Get item coordinates
+
+        @returns coordinates
+        """
+        return self.coords


Property changes on: grass/trunk/gui/wxpython/mapwin/graphics.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Modified: grass/trunk/gui/wxpython/nviz/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/nviz/mapwindow.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/nviz/mapwindow.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -37,7 +37,7 @@
 
 from core.gcmd          import GMessage, GException, GError
 from core.debug         import Debug
-from gui_core.mapwindow import MapWindow
+from mapwin.base import MapWindowBase
 from core.settings      import UserSettings
 from nviz.workspace     import NvizSettings
 from nviz.animation     import Animation
@@ -69,7 +69,7 @@
         """!Get display instance"""
         return self._display
 
-class GLWindow(MapWindow, glcanvas.GLCanvas):
+class GLWindow(MapWindowBase, glcanvas.GLCanvas):
     """!OpenGL canvas for Map Display Window"""
     def __init__(self, parent, giface, frame, Map, tree, lmgr, id=wx.ID_ANY):
         """All parameters except for id are mandatory. The todo is to remove
@@ -90,10 +90,10 @@
         else:
             glcanvas.GLCanvas.__init__(self, parent, id)
 
-        MapWindow.__init__(self, parent=parent, giface=giface, Map=Map)
+        MapWindowBase.__init__(self, parent=parent, giface=giface, Map=Map)
         self.Hide()
 
-        # TODO: same signals as in BufferedWindow
+        # TODO: same signals as in BufferedMapWindow
         # same interface is good, but how to ensure same names
         # or avoid duplication, define in map window base class?
 

Modified: grass/trunk/gui/wxpython/vdigit/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/dialogs.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/vdigit/dialogs.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -42,7 +42,7 @@
         @param cats  directory of lines (layer/categories) - used by vdigit
         @param style dialog style
         """
-        self.parent = parent       # mapdisplay.BufferedWindow class instance
+        self.parent = parent  # map window class instance
         self.digit = parent.digit
         
         # map name
@@ -584,7 +584,7 @@
         """
         wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
 
-        self.parent = parent # mapdisplay.BufferedWindow class instance
+        self.parent = parent  # map window class instance
 
         # panel  = wx.Panel(parent=self, id=wx.ID_ANY)
 
@@ -648,7 +648,7 @@
         wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
                            pos = pos)
         
-        self.parent = parent # BufferedWindow
+        self.parent = parent  # map window instance
         self.data = data
         self.winList = []
 

Modified: grass/trunk/gui/wxpython/vdigit/main.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/main.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/vdigit/main.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -29,7 +29,7 @@
 class VDigit(IVDigit):
     def __init__(self, mapwindow):
         """!Base class of vector digitizer
-        
-        @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance
+
+        @param mapwindow reference to a map window instance
         """
         IVDigit.__init__(self, mapwindow)

Modified: grass/trunk/gui/wxpython/vdigit/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/mapwindow.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/vdigit/mapwindow.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -22,22 +22,22 @@
 from dbmgr.dialogs  import DisplayAttributesDialog
 from core.gcmd      import RunCommand, GMessage, GError
 from core.debug     import Debug
-from mapdisp.mapwindow import BufferedWindow
+from mapwin.buffered import BufferedMapWindow
 from core.settings  import UserSettings
 from core.utils     import ListOfCatsToRange, _
 from core.globalvar import QUERYLAYER
 from vdigit.dialogs import VDigitCategoryDialog, VDigitZBulkDialog, VDigitDuplicatesDialog
 from gui_core       import gselect
 
-class VDigitWindow(BufferedWindow):
+class VDigitWindow(BufferedMapWindow):
     """!A Buffered window extended for vector digitizer.
     """
     def __init__(self, parent, giface, Map, properties, tree=None,
                  id=wx.ID_ANY, lmgr=None,
                  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        BufferedWindow.__init__(self, parent=parent, giface=giface, Map=Map,
-                                properties=properties,
-                                style=style, **kwargs)
+        BufferedMapWindow.__init__(self, parent=parent, giface=giface, Map=Map,
+                                   properties=properties,
+                                   style=style, **kwargs)
         self.lmgr = lmgr
         self.tree = tree
         self.pdcVector = wx.PseudoDC()
@@ -49,13 +49,13 @@
         # Parameter text is a string with information
         # currently used only for coordinates of mouse cursor + segmnt and
         # total feature length
-        self.digitizingInfo = Signal('BufferedWindow.digitizingInfo')
+        self.digitizingInfo = Signal('VDigitWindow.digitizingInfo')
         # Emitted when some info about digitizing is or will be availbale
-        self.digitizingInfoAvailable = Signal('BufferedWindow.digitizingInfo')
+        self.digitizingInfoAvailable = Signal('VDigitWindow.digitizingInfo')
         # Emitted when some info about digitizing is or will be availbale
         # digitizingInfo signal is emmited only between digitizingInfoAvailable
         # and digitizingInfoUnavailable signals
-        self.digitizingInfoUnavailable = Signal('BufferedWindow.digitizingInfo')
+        self.digitizingInfoUnavailable = Signal('VDigitWindow.digitizingInfo')
 
         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
         self.mouseMoving.connect(self._mouseMovingToDigitizingInfo)
@@ -469,8 +469,8 @@
             # add line or boundary -> remove last point from the line
             try:
                 removed = self.polycoords.pop()
-                Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
-                              [removed,])
+                Debug.msg(4, "VDigitWindow.OnMiddleDown(): polycoords_poped=%s" %
+                          [removed, ])
                 # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
             except:
                 pass
@@ -1050,10 +1050,10 @@
         
     def _onMouseMoving(self, event):
         self.mouse['end'] = event.GetPositionTuple()[:]
-        
-        Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
-                       (self.mouse['end'][0], self.mouse['end'][1]))
 
+        Debug.msg(5, "VDigitWindow.OnMouseMoving(): coords=%f,%f" %
+                  (self.mouse['end'][0], self.mouse['end'][1]))
+
         action = self.toolbar.GetAction()
         if action == "addLine" and \
                 self.toolbar.GetAction('type') in ["line", "boundary", "area"]:

Modified: grass/trunk/gui/wxpython/vdigit/wxdigit.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/wxdigit.py	2013-08-06 11:20:43 UTC (rev 57426)
+++ grass/trunk/gui/wxpython/vdigit/wxdigit.py	2013-08-06 16:10:51 UTC (rev 57427)
@@ -129,7 +129,7 @@
     def __init__(self, mapwindow, driver = DisplayDriver):
         """!Base class for vector digitizer (ctypes interface)
         
-        @param mapwindow reference for map window (BufferedWindow)
+        @param mapwindow reference to a map window
         """
         self.poMapInfo   = None      # pointer to Map_info
         self.mapWindow = mapwindow



More information about the grass-commit mailing list