[GRASS-SVN] r40807 - grass-addons/gui/wxpython/data_catalog

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Feb 3 23:58:02 EST 2010


Author: rashadkm
Date: 2010-02-03 23:58:00 -0500 (Wed, 03 Feb 2010)
New Revision: 40807

Added:
   grass-addons/gui/wxpython/data_catalog/mapframe.py
Removed:
   grass-addons/gui/wxpython/data_catalog/mapdisp_1.py
Log:
fixed error on updateMap

Deleted: grass-addons/gui/wxpython/data_catalog/mapdisp_1.py
===================================================================
--- grass-addons/gui/wxpython/data_catalog/mapdisp_1.py	2010-02-04 04:23:35 UTC (rev 40806)
+++ grass-addons/gui/wxpython/data_catalog/mapdisp_1.py	2010-02-04 04:58:00 UTC (rev 40807)
@@ -1,4227 +0,0 @@
-"""
- at package mapdisp.py
-
- at brief GIS map display canvas, with toolbar for various display
-management functions, and second toolbar for vector
-digitizing. 
-
-Can be used either from GIS Manager or as p.mon backend.
-
-Classes:
- - Command
- - MapWindow
- - BufferedWindow
- - MapFrame
- - MapApp
-
-Usage:
- python mapdisp.py monitor-identifier /path/to/command/file
-
-(C) 2006-2008 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 Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import time
-import glob
-import math
-import tempfile
-import copy
-
-import globalvar
-if not os.getenv("GRASS_WXBUNDLED"):
-    globalvar.CheckForWx()
-import wx
-import wx.aui
-
-from threading import Thread
-try:
-    import subprocess
-except:
-    CompatPath = os.path.join(globalvar.ETCWXDIR)
-    sys.path.append(CompatPath)
-    from compat import subprocess
-
-gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
-sys.path.append(gmpath)
-
-import render
-import toolbars
-import track
-import menuform
-import gselect
-import disp_print
-import gcmd
-import dbm
-import histogram
-import profile
-import globalvar
-import utils
-import gdialogs
-from grass.script import core as grass
-from vdigit import VDigitCategoryDialog as VDigitCategoryDialog
-from vdigit import VDigitZBulkDialog    as VDigitZBulkDialog
-from vdigit import VDigitDuplicatesDialog as VDigitDuplicatesDialog
-from vdigit import GV_LINES            as VDigit_Lines_Type
-from debug import Debug               as Debug
-from icon  import Icons               as Icons
-from preferences import globalSettings as UserSettings
-
-import images
-imagepath = images.__path__[0]
-sys.path.append(imagepath)
-
-###
-### global variables
-###
-# for standalone app
-cmdfilename = None
-
-class Command(Thread):
-    """
-    Creates thread which will observe the command file and see, if
-    there is new command to be executed
-    """
-    def __init__ (self, parent, Map):
-        Thread.__init__(self)
-
-        global cmdfilename
-
-        self.parent = parent
-        self.map = Map
-        self.cmdfile = open(cmdfilename, "r")
-
-    def run(self):
-        """
-        Run this in thread
-        """
-        dispcmd = []
-        while 1:
-            self.parent.redraw = False
-            line = self.cmdfile.readline().strip()
-            if line == "quit":
-                break
-
-            if line:
-                try:
-                    Debug.msg (3, "Command.run(): cmd=%s" % (line))
-
-                    self.map.AddLayer(item=None, type="raster",
-                                      name='',
-                                      command=line,
-                                      l_opacity=1)
-
-                    self.parent.redraw =True
-
-                except Exception, e:
-                    print "Command Thread: ",e
-
-            time.sleep(0.1)
-
-        sys.exit()
-
-class MapWindow(object):
-    """
-    Abstract map window class
-
-    Parent for BufferedWindow class (2D display mode) and
-    GLWindow (3D display mode)
-    """
-    def __init__(self, parent, id=wx.ID_ANY,
-                 pos=wx.DefaultPosition,
-                 size=wx.DefaultSize,
-                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
-                 Map=None, tree=None, gismgr=None):
-        self.parent = parent # MapFrame
-
-        #
-        # mouse attributes like currently pressed buttons, position on
-        # the screen, begin and end of dragging, and type of drawing
-        #
-        self.mouse = {
-            'l'    : False,
-            'r'    : False,
-            'm'    : False,
-            'begin': [0, 0], # screen coordinates
-            'end'  : [0, 0],
-            'use'  : "pointer",
-            'box'  : "point"
-            }
-        
-    def EraseMap(self):
-        """
-        Erase the canvas (virtual method)
-        """
-        pass
-
-    def UpdateMap(self):
-        """
-        Updates the canvas anytime there is a change to the
-        underlaying images or to the geometry of the canvas.
-        """
-        pass
-
-    def OnLeftDown(self, event):
-        pass
-
-    def OnLeftUp(self, event):
-        pass
-
-    def OnMouseMotion(self, event):
-        pass
-
-    def OnZoomToMap(self, event):
-        pass
-
-    def OnZoomToRaster(self, event):
-        pass
-
-    def GetSelectedLayer(self, type = 'layer', multi = False):
-        """
-        Get selected layer from layer tree
-
-        @param type 'item' / 'layer' / 'nviz'
-        @param multi return first selected layer or all
-        
-        @return layer / map layer properties / nviz properties
-        @return None / [] on failure
-        """
-        ret = []
-        if not self.tree or \
-                not self.tree.GetSelection():
-            if multi:
-                return []
-            else:
-                return None
-        
-        if multi and \
-                type == 'item':
-            return self.tree.GetSelections()
-        
-        for item in self.tree.GetSelections():
-            if not item.IsChecked():
-                if multi:
-                    continue
-                else:
-                    return None
-
-            if type == 'item': # -> multi = False
-                return item
-        
-            try:
-                if type == 'nviz':
-                    layer = self.tree.GetPyData(item)[0]['nviz']
-                else:
-                    layer = self.tree.GetPyData(item)[0]['maplayer']
-            except:
-                layer = None
-
-            if multi:
-                ret.append(layer)
-            else:
-                return layer
-            
-        return ret
-
-class BufferedWindow(MapWindow, wx.Window):
-    """
-    A Buffered window class.
-
-    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(self,file_name,file_type) method.
-    """
-
-    def __init__(self, parent, id,
-                 pos = wx.DefaultPosition,
-                 size = wx.DefaultSize,
-                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
-                 Map=None, tree=None, gismgr=None):
-
-        MapWindow.__init__(self, parent, id, pos, size, style,
-                           Map, tree, gismgr)
-        wx.Window.__init__(self, parent, id, pos, size, style)
-
-        self.Map = Map
-        self.tree = tree
-        self.gismanager = gismgr
-
-        #
-        # Flags
-        #
-        self.resize = False # indicates whether or not a resize event has taken place
-        self.dragimg = None # initialize variable for map panning
-
-        #
-        # Variable 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
-        
-        #
-        # Event bindings
-        #
-        self.Bind(wx.EVT_PAINT,        self.OnPaint)
-        self.Bind(wx.EVT_SIZE,         self.OnSize)
-        self.Bind(wx.EVT_IDLE,         self.OnIdle)
-        self.Bind(wx.EVT_MOTION,       self.MouseActions)
-        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
-        self.processMouse = True
-        
-        #
-        # Render output objects
-        #
-        self.mapfile = None   # image file to be rendered
-        self.img = ""         # wx.Image object (self.mapfile)
-        # used in digitization tool (do not redraw vector map)
-        self.imgVectorMap = None
-        # decoration overlays
-        self.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
-        self.currtxtid = None # PseudoDC id for currently selected text
-
-        #
-        # 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)
-
-        # 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()
-        # 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 = ''
-
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
-
-        # vars for handling mouse clicks
-        self.dragid   = -1
-        self.lastpos  = (0, 0)
-
-    def Draw(self, pdc, img=None, drawid=None, pdctype='image', coords=[0, 0, 0, 0]):
-        """
-        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()
-        
-        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)
-        ### pdc.Clear()
-
-        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, (coords[0],coords[1], w, h))
-
-        elif pdctype == 'box': # draw a box on top of the map
-            if self.pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.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)
-                # self.ovlcoords[drawid] = coords
-
-        elif pdctype == 'line': # draw a line on top of the map
-            if self.pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.pen)
-                pdc.DrawLine(coords[0], coords[1], coords[2], coords[3])
-                pdc.SetIdBounds(drawid,(coords[0], coords[1], coords[2], coords[3]))
-                # self.ovlcoords[drawid] = coords
-
-        elif pdctype == 'polyline': # draw a polyline on top of the map
-            if self.polypen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.polypen)
-                pdc.DrawLines(coords)
-
-                # 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,(x1,y1,x2,y2))
-                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
-
-        elif pdctype == 'point': # draw point
-            if self.pen:
-                pdc.SetPen(self.pen)
-                pdc.DrawPoint(coords[0], coords[1])
-                coordsBound = (coords[0] - 5,
-                               coords[1] - 5,
-                               coords[0] + 5,
-                               coords[1] + 5)
-                pdc.SetIdBounds(drawid, coordsBound)
-                # self.ovlcoords[drawid] = coords
-
-        elif pdctype == 'text': # draw text on top of map
-            if not img['active']:
-                return #only draw active text
-            if img.has_key('rotation'):
-                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, w, h = 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, (coords[0], coords[1], w, h))
-            
-        pdc.EndDrawing()
-        
-        self.Refresh()
-        
-        return drawid
-
-    def TextBounds(self, textinfo):
-        """
-        Return text boundary data
-
-        @param textinfo text metadata (text, font, color, rotation)
-        @param coords reference point
-        """
-        if textinfo.has_key('rotation'):
-            rotation = float(textinfo['rotation'])
-        else:
-            rotation = 0.0
-        
-        coords = textinfo['coords']
-        
-        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
-                   (textinfo['text'], rotation))
-
-        self.Update()
-        ### self.Refresh()
-
-        self.SetFont(textinfo['font'])
-
-        w, h = self.GetTextExtent(textinfo['text'])
-
-        if rotation == 0:
-            coords[2], coords[3] = coords[0] + w, coords[1] + h
-            return coords, w, h
-
-        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
-        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
-        coords[2] = coords[0] + boxw
-        coords[3] = coords[1] + boxh
-        
-        return coords, boxw, boxh
-
-    def OnPaint(self, event):
-        """
-        Draw PseudoDC's to buffered paint DC
-
-        self.pdc for background and decorations
-        self.pdcVector for vector map which is edited
-        self.pdcTmp for temporaly drawn objects (self.polycoords)
-
-        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.SetBackground(wx.Brush("White"))
-        dc.Clear()
-
-        # use PrepareDC to set position correctly
-        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 self.pdcVector:
-                # 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 self.pdcVector:
-                    # 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))
-
-            pdcLast = wx.PseudoDC()
-            pdcLast.DrawBitmap(bmp=self.bufferLast, x=0, y=0)
-            pdcLast.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
-        """
-        Debug.msg(3, "BufferedWindow.OnSize():")
-
-        # set size of the input image
-        self.Map.ChangeMapSize(self.GetClientSize())
-        # align extent based on center point and display resolution
-        # this causes that image is not resized when display windows is resized
-        # self.Map.AlignExtentFromDisplay()
-
-        # 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 = 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
-        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
-            self.img = self.img.Scale(self.Map.width, self.Map.height)
-            if len(self.Map.GetListOfLayers()) > 0:
-                self.UpdateMap()
-
-        # re-render image on idle
-        self.resize = True
-
-        # reposition checkbox in statusbar
-        self.parent.StatusbarReposition()
-
-        # update statusbar
-        self.parent.StatusbarUpdate()
-
-    def OnIdle(self, event):
-        """
-        Only re-render a composite map image from GRASS during
-        idle time instead of multiple times during resizing.
-        """
-        if self.resize:
-            self.UpdateMap(render=True)
-
-        event.Skip()
-
-    def SaveToFile(self, FileName, FileType):
-        """
-        This draws the psuedo DC to a buffer that
-        can be saved to a file.
-        """
-        dc = wx.BufferedPaintDC(self, self.buffer)
-        self.pdc.DrawToDC(dc)
-        if self.pdcVector:
-            self.pdcVector.DrawToDC(dc)
-        self.buffer.SaveFile(FileName, FileType)
-
-    def GetOverlay(self):
-        """
-        Converts rendered overlay files to wx.Image
-
-        Updates self.imagedict
-
-        @return list of images
-        """
-        imgs = []
-        for overlay in self.Map.GetListOfLayers(l_type="overlay", l_active=True):
-            if os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
-                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
-                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.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
-
-        self.imagedict[img] = { 'id': imgId }
-
-        return img
-
-    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.
-
-        @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
-
-        # if len(self.Map.GetListOfLayers()) == 0:
-        #    return False
-        
-        if self.img is None:
-            render = True
-
-        #
-        # initialize process bar (only on 'render')
-        #
-        if render is True or renderVector is True:
-            self.parent.onRenderGauge.Show()
-            if self.parent.onRenderGauge.GetRange() > 0:
-                self.parent.onRenderGauge.SetValue(1)
-        
-        #
-        # render background image if needed
-        #
-        
-        # update layer dictionary if there has been a change in layers
-        if self.tree and self.tree.reorder == True:
-            self.tree.ReorderLayers()
-            
-        # reset flag for auto-rendering
-        if self.tree:
-            self.tree.rerender = False
-        
-        if render:
-            # update display size
-            self.Map.ChangeMapSize(self.GetClientSize())
-            if self.parent.compResolution.IsChecked():
-                # use computation region resolution for rendering
-                windres = True
-            else:
-                windres = False
-            self.mapfile = self.Map.Render(force=True, mapWindow=self.parent,
-                                           windres=windres)
-        else:
-            self.mapfile = self.Map.Render(force=False, mapWindow=self.parent)
-        
-        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
-        #
-        digitToolbar = self.parent.toolbars['vdigit']
-        if renderVector and digitToolbar and \
-                digitToolbar.GetLayer():
-            # set region
-            self.parent.digit.driver.UpdateRegion()
-            # re-calculate threshold for digitization tool
-            self.parent.digit.driver.GetThreshold()
-            # draw map
-            self.pdcVector.Clear()
-            self.pdcVector.RemoveAll()
-            try:
-                item = self.tree.FindItemByData('maplayer', digitToolbar.GetLayer())
-            except TypeError:
-                item = None
-            
-            if item and self.tree.IsItemChecked(item):
-                self.parent.digit.driver.DrawMap()
-
-            # translate tmp objects (pointer position)
-            if digitToolbar.GetAction() == 'moveLine':
-                if  hasattr(self, "vdigitMove") and \
-                        self.vdigitMove.has_key('beginDiff'):
-                    # move line
-                    for id in self.vdigitMove['id']:
-                        # print self.pdcTmp.GetIdBounds(id)
-                        self.pdcTmp.TranslateId(id,
-                                                self.vdigitMove['beginDiff'][0],
-                                                self.vdigitMove['beginDiff'][1])
-                    del self.vdigitMove['beginDiff']
-        
-        #
-        # 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
-        #
-        if len(self.polycoords) > 0:
-            self.DrawLines(self.pdcTmp)
-        
-        if self.gismanager.georectifying:
-            # -> georectifier (redraw GCPs)
-            if self.parent.toolbars['georect']:
-                coordtype = 'gcpcoord'
-            else:
-                coordtype = 'mapcoord'
-            self.parent.gismanager.georectifying.DrawGCP(coordtype)
-            
-        # 
-        # clear measurement
-        #
-        
-        if self.mouse["use"] == "measure":
-            self.ClearLines(pdc=self.pdcTmp)
-            self.polycoords = []
-            self.mouse['use'] = 'pointer'
-            self.mouse['box'] = 'point'
-            self.mouse['end'] = [0, 0]
-            self.SetCursor(self.parent.cursors["default"])
-            
-        stop = time.clock()
-
-        #
-        # hide process bar
-        #
-        self.parent.onRenderGauge.Hide()
-
-        #
-        # update statusbar
-        #
-        ### self.Map.SetRegion()
-        self.parent.StatusbarUpdate()
-        if grass.find_file(name = 'MASK', element = 'cell')['name']:
-            # mask found
-            self.parent.maskInfo.SetLabel(_('MASK'))
-        else:
-            self.parent.maskInfo.SetLabel('')
-        
-        Debug.msg (2, "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 hasattr(self, "regionCoords"):
-            compReg = self.Map.GetRegion()
-            dispReg = self.Map.GetCurrentRegion()
-            reg = None
-            if self.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
-            
-            self.regionCoords = []
-            self.regionCoords.append((reg['w'], reg['n']))
-            self.regionCoords.append((reg['e'], reg['n']))
-            self.regionCoords.append((reg['e'], reg['s']))
-            self.regionCoords.append((reg['w'], reg['s']))
-            self.regionCoords.append((reg['w'], reg['n']))
-            # draw region extent
-            self.DrawLines(pdc=self.pdcDec, polycoords=self.regionCoords)
-
-    def IsInRegion(self, region, refRegion):
-        """
-        Test if 'region' is inside of 'refRegion'
-
-        @param region input region
-        @param refRegion reference region (e.g. computational region)
-
-        @return True if region is inside of refRegion
-        @return False 
-        """
-        if region['s'] >= refRegion['s'] and \
-                region['n'] <= refRegion['n'] and \
-                region['w'] >= refRegion['w'] and \
-                region['e'] <= refRegion['e']:
-            return True
-
-        return False
-
-    def EraseMap(self):
-        """
-        Erase the canvas
-        """
-        self.Draw(self.pdc, pdctype='clear')
-                  
-        if self.pdcVector:
-            self.Draw(self.pdcVector, pdctype='clear')
-        
-        self.Draw(self.pdcDec, pdctype='clear')
-        self.Draw(self.pdcTmp, pdctype='clear')
-        
-    def DragMap(self, moveto):
-        """
-        Drag the entire map image for panning.
-        """
-
-        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()
-
-        return True
-
-    def DragItem(self, id, event):
-        """
-        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 = event.GetX() - x
-        dy = event.GetY() - y
-        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
-        r = self.pdc.GetIdBounds(id)
-        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 id > 100: # text
-            self.textdict[id]['coords'] = r2
-        r = r.Union(r2)
-        r.Inflate(4,4)
-        self.RefreshRect(r, False)
-        self.lastpos = (event.GetX(), event.GetY())
-                
-    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'].
-
-        """
-        self.redrawAll = False
-        
-        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)
-            r.Inflate(4,4)
-            pdc.ClearId(boxid)
-            self.RefreshRect(r, False)
-            pdc.SetId(boxid)
-            self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords)
-        elif self.mouse['box'] == "line" or self.mouse['box'] == 'point':
-            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,
-                  text=None, textAlign='lr', textOffset=(5, 5)):
-        """Draw cross in PseudoDC
-
-        @todo implement rotation
-
-        @param pdc PseudoDC
-        @param coord center coordinates
-        @param rotation rotate symbol
-        @param text draw also text (text, font, color, rotation)
-        @param textAlign alignment (default 'lower-right')
-        @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)
-
-        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)
-
-        return self.lineid
-
-    def MouseActions(self, event):
-        """
-        Mouse motion and button click notifier
-        """
-        if not self.processMouse:
-            return
-        
-        ### if self.redrawAll is False:
-        ###    self.redrawAll = True
-        
-        # 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)
-
-        # right mouse button pressed
-        elif event.RightDown():
-            self.OnRightDown(event)
-
-        # right mouse button released
-        elif event.RightUp():
-            self.OnRightUp(event)
-
-        elif event.Moving():
-            self.OnMouseMoving(event)
-
-#        event.Skip()
-        
-    def OnMouseWheel(self, event):
-        """
-        Mouse wheel moved
-        """
-        self.processMouse = False
-        current  = event.GetPositionTuple()[:]
-        wheel = event.GetWheelRotation()
-        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
-        # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
-        begin = (current[0] - self.Map.width / 4,
-                 current[1] - self.Map.height / 4)
-        end   = (current[0] + self.Map.width / 4,
-                 current[1] + self.Map.height / 4)
-
-        if wheel > 0:
-            zoomtype = 1
-        else:
-            zoomtype = -1
-
-        # zoom
-        self.Zoom(begin, end, zoomtype)
-
-        # redraw map
-        self.UpdateMap()
-
-        ### self.OnPaint(None)
-
-        # update statusbar
-        self.parent.StatusbarUpdate()
-
-        self.Refresh()
-        self.processMouse = True
-#        event.Skip()
-
-    def OnDragging(self, event):
-        """
-        Mouse dragging with left button down
-        """
-        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
-        current  = event.GetPositionTuple()[:]
-        previous = self.mouse['begin']
-        move = (current[0] - previous[0],
-                current[1] - previous[1])
-
-        digitToolbar = self.parent.toolbars['vdigit']
-
-        # dragging or drawing box with left button
-        if self.mouse['use'] == 'pan':
-            self.DragMap(move)
-
-        # dragging decoration overlay item
-        elif (self.mouse['use'] == 'pointer' and 
-                not digitToolbar and 
-                self.dragid != None):
-            self.DragItem(self.dragid, event)
-
-        # dragging anything else - rubber band box or line
-        else:
-            if (self.mouse['use'] == 'pointer' and 
-                not digitToolbar): return
-            self.mouse['end'] = event.GetPositionTuple()[:]
-            digitClass = self.parent.digit
-            if (event.LeftIsDown() and 
-                not (digitToolbar and 
-                    digitToolbar.GetAction() in ("moveLine",) and 
-                    digitClass.driver.GetSelected() > 0)):
-                # draw box only when left mouse button is pressed
-                self.MouseDraw(pdc=self.pdcTmp)
-      
-#        event.Skip()
-
-    def OnLeftDown(self, event):
-        """
-        Left mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
-                   self.mouse["use"])
-
-        self.mouse['begin'] = event.GetPositionTuple()[:]
-
-        if self.mouse["use"] in ["measure", "profile"]:
-            # measure or profile
-            if len(self.polycoords) == 0:
-                self.mouse['end'] = self.mouse['begin']
-                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
-                self.ClearLines(pdc=self.pdcTmp)
-            else:
-                self.mouse['begin'] = self.mouse['end']
-        elif self.mouse['use'] == 'zoom':
-            pass
-        elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
-            # digitization
-            digitToolbar = self.parent.toolbars['vdigit']
-            digitClass   = self.parent.digit
-            east, north = self.Pixel2Cell(self.mouse['begin'])
-
-            try:
-                map = digitToolbar.GetLayer().GetName()
-            except:
-                map = None
-                wx.MessageBox(parent=self,
-                              message=_("No vector map selected for editing."),
-                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                event.Skip()
-                return
-
-            # calculate position of 'update record' dialog
-            position = self.mouse['begin']
-            posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
-                                             position[1] + self.dialogOffset))
-
-            if digitToolbar.GetAction() not in ("moveVertex", "addVertex",
-                                                "removeVertex", "editLine"):
-                # set pen
-                self.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-                self.polypen = wx.Pen(colour='dark green', width=2, style=wx.SOLID)
-
-            if digitToolbar.GetAction() in ("addVertex", "removeVertex"):
-                # unselect
-                digitClass.driver.SetSelected([])
-
-            if digitToolbar.GetAction() == "addLine":
-                if digitToolbar.GetAction('type') in ["point", "centroid"]:
-                    # add new point
-                    if digitToolbar.GetAction('type') == 'point':
-                        point = True
-                    else:
-                        point = False
-
-                    fid = digitClass.AddPoint(map, point, east, north)
-                    if fid < 0:
-                        return
-
-                    self.UpdateMap(render=False) # redraw map
-
-                    # add new record into atribute table
-                    if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled')  is True:
-                        # select attributes based on layer and category
-                        cats = { fid : {
-                                UserSettings.Get(group='vdigit', key="layer", subkey='value') :
-                                    (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
-                                }}
-                        addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
-                                                                   cats=cats,
-                                                                   pos=posWindow,
-                                                                   action="add")
-                        if addRecordDlg.mapDBInfo and \
-                               addRecordDlg.ShowModal() == wx.ID_OK:
-                            sqlfile = tempfile.NamedTemporaryFile(mode="w")
-                            for sql in addRecordDlg.GetSQLString():
-                                sqlfile.file.write(sql + ";\n")
-                            sqlfile.file.flush()
-                            executeCommand = gcmd.Command(cmd=["db.execute",
-                                                               "--q",
-                                                               "input=%s" % sqlfile.name])
-
-                elif digitToolbar.GetAction('type') in ["line", "boundary"]:
-                    # add new point to the line
-                    self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
-                    self.DrawLines(pdc=self.pdcTmp)
-            
-            elif digitToolbar.GetAction() == "editLine" and hasattr(self, "vdigitMove"):
-                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
-                self.vdigitMove['id'].append(wx.NewId())
-                self.DrawLines(pdc=self.pdcTmp)
-
-            elif digitToolbar.GetAction() == "deleteLine":
-                pass
-
-            elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
-                    not hasattr(self, "vdigitMove"):
-                self.vdigitMove = {}
-                # geographic coordinates of initial position (left-down)
-                self.vdigitMove['begin'] = None
-                # list of ids to modify    
-                self.vdigitMove['id'] = []
-                # ids geographic coordinates
-                self.vdigitMove['coord'] = {}
-                
-                if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
-                    # set pen
-                    pcolor = UserSettings.Get(group='vdigit', key="symbol",
-                                              subkey=["highlight", "color"])
-                    self.pen = self.polypen = wx.Pen(colour=pcolor,
-                                                     width=2, style=wx.SHORT_DASH)
-                    self.pdcTmp.SetPen(self.polypen)
-
-            elif digitToolbar.GetAction() == "splitLine":
-                # unselect
-                digitClass.driver.SetSelected([])
-
-            elif digitToolbar.GetAction() in ["displayAttrs", "displayCats"]:
-                qdist = digitClass.driver.GetThreshold(type='selectThresh')
-                coords = (east, north)
-                if digitClass.type == 'vdigit':
-                    # unselect
-                    digitClass.driver.SetSelected([])
-
-                    # select feature by point
-                    cats = {}
-                    if digitClass.driver.SelectLineByPoint(coords,
-                                                        digitClass.GetSelectType()) is not None:
-                        if UserSettings.Get(group='vdigit', key='checkForDupl',
-                                            subkey='enabled'):
-                            lines = digitClass.driver.GetSelected()
-                        else:
-                            lines = (digitClass.driver.GetSelected()[0],) # only first found
-                        
-                        for line in lines:
-                            cats[line] = digitClass.GetLineCats(line)
-                    
-                if digitToolbar.GetAction() == "displayAttrs":
-                    # select attributes based on coordinates (all layers)
-                    if self.parent.dialogs['attributes'] is None:
-                        if digitClass.type == 'vedit':
-                            self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
-                                                                                            query=(coords, qdist),
-                                                                                            pos=posWindow,
-                                                                                            action="update")
-                        else:
-                            self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
-                                                                                            cats=cats,
-                                                                                            action="update")
-                    else:
-                        # update currently open dialog
-                        if digitClass.type == 'vedit':
-                            self.parent.dialogs['attributes'].UpdateDialog(query=(coords, qdist))
-                        else:
-                            # upgrade dialog
-                            self.parent.dialogs['attributes'].UpdateDialog(cats=cats)
-
-                    if self.parent.dialogs['attributes']:
-                        if len(cats.keys()) > 0:
-                            # highlight feature & re-draw map
-                            if not self.parent.dialogs['attributes'].IsShown():
-                                self.parent.dialogs['attributes'].Show()
-                        else:
-                            if self.parent.dialogs['attributes'] and \
-                                   self.parent.dialogs['attributes'].IsShown():
-                                self.parent.dialogs['attributes'].Hide()
-
-                else: # displayCats
-                    if self.parent.dialogs['category'] is None:
-                        # open new dialog
-                        if digitClass.type == 'vedit':
-                            dlg = VDigitCategoryDialog(parent=self,
-                                                        map=map,
-                                                        query=(coords, qdist),
-                                                        pos=posWindow,
-                                                        title=_("Update categories"))
-                            self.parent.dialogs['category'] = dlg
-                        else:
-                            dlg = VDigitCategoryDialog(parent=self,
-                                                       map=map,
-                                                       cats=cats,
-                                                       pos=posWindow,
-                                                       title=_("Update categories"))
-                            self.parent.dialogs['category'] = dlg
-                    else:
-                        # update currently open dialog
-                        if digitClass.type == 'vedit':
-                            self.parent.dialogs['category'].UpdateDialog(query=(coords, qdist))
-                        else:
-                            # upgrade dialog
-                            self.parent.dialogs['category'].UpdateDialog(cats=cats)
-                            
-                    if self.parent.dialogs['category']:
-                        if len(cats.keys()) > 0:
-                            # highlight feature & re-draw map
-                            ### digitClass.driver.SetSelected(line)
-                            if not self.parent.dialogs['category'].IsShown():
-                                self.parent.dialogs['category'].Show()
-                        else:
-                            if self.parent.dialogs['category'].IsShown():
-                                self.parent.dialogs['category'].Hide()
-                
-                self.UpdateMap(render=False)
-
-            elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
-                if not hasattr(self, "copyCatsList"):
-                    self.copyCatsList = []
-                else:
-                    self.copyCatsIds = []
-                    self.mouse['box'] = 'box'
-
-            elif digitToolbar.GetAction() == "copyLine":
-                self.copyIds = []
-                self.layerTmp = None
-
-            elif digitToolbar.GetAction() == "zbulkLine":
-                if len(self.polycoords) > 1: # start new line
-                    self.polycoords = []
-                    self.ClearLines(pdc=self.pdcTmp)
-                self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
-                if len(self.polycoords) == 1:
-                    begin = self.Pixel2Cell(self.polycoords[-1])
-                    end   = self.Pixel2Cell(self.mouse['end'])
-                else:
-                    end   = self.Pixel2Cell(self.polycoords[-1])
-                    begin = self.Pixel2Cell(self.mouse['begin'])
-
-                    self.DrawLines(self.pdcTmp, polycoords = [begin, end])
-        elif self.mouse['use'] == 'pointer':
-            # get decoration or text id
-            self.idlist = []
-            self.dragid = ''
-            self.lastpos = self.mouse['begin']
-            idlist = self.pdc.FindObjects(x=self.lastpos[0], y=self.lastpos[1],
-                                          radius=self.hitradius)
-                                          
-            if 99 in idlist: idlist.remove(99)                             
-            if idlist != [] :
-                self.dragid = idlist[0] #drag whatever is on top
-        else:
-            pass
-
-        event.Skip()
-
-    def OnLeftUp(self, event):
-        """
-        Left mouse button released
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
-                   self.mouse["use"])
-
-        self.mouse['end'] = event.GetPositionTuple()[:]
-
-        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:
-                    # zoom 1/2 of the screen (TODO: settings)
-                    begin = (end[0] - self.Map.width / 4,
-                             end[1] - self.Map.height / 4)
-                    end   = (end[0] + self.Map.width / 4,
-                             end[1] + self.Map.height / 4)
-
-            self.Zoom(begin, end, self.zoomtype)
-
-            # redraw map
-            self.UpdateMap(render=True)
-
-            # update statusbar
-            self.parent.StatusbarUpdate()
-
-        elif self.mouse["use"] == "query":
-            # querying
-            self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
-
-        elif self.mouse["use"] == "queryVector":
-            # editable mode for vector map layers
-            self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
-
-            # clear temp canvas
-            self.UpdateMap(render=False, renderVector=False)
-            
-        elif self.mouse["use"] in ["measure", "profile"]:
-            # measure or profile
-            if self.mouse["use"] == "measure":
-                self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
-
-            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
-            self.ClearLines(pdc=self.pdcTmp)
-            self.DrawLines(pdc=self.pdcTmp)
-        
-        elif self.mouse["use"] == "pointer" and self.parent.gismanager.georectifying:
-            # -> georectifying
-            coord = self.Pixel2Cell(self.mouse['end'])
-            if self.parent.toolbars['georect']:
-                coordtype = 'gcpcoord'
-            else:
-                coordtype = 'mapcoord'
-
-            self.parent.gismanager.georectifying.SetGCPData(coordtype, coord, self)
-            self.UpdateMap(render=False, renderVector=False)
-
-        elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
-            # digitization tool active
-            digitToolbar = self.parent.toolbars['vdigit']
-            digitClass   = self.parent.digit
-
-            pos1 = self.Pixel2Cell(self.mouse['begin'])
-            pos2 = self.Pixel2Cell(self.mouse['end'])
-
-            if hasattr(self, "vdigitMove"):
-                if len(digitClass.driver.GetSelected()) == 0:
-                    self.vdigitMove['begin'] = pos1 # left down
-                ### else:
-                ###    dx = pos2[0] - pos1[0] ### ???
-                ###    dy = pos2[1] - pos1[1]
-                ###    self.vdigitMove = (self.vdigitMove['begin'][0] + dx,
-                ###                       self.vdigitMove['begin'][1] + dy)
-                
-                # eliminate initial mouse moving efect
-                self.mouse['begin'] = self.mouse['end'] 
-
-            if digitToolbar.GetAction() in ["deleteLine", "moveLine", "moveVertex",
-                                            "copyCats", "copyAttrs", "editLine", "flipLine",
-                                            "mergeLine", "snapLine",
-                                            "queryLine", "breakLine", "typeConv", "connectLine"]:
-                nselected = 0
-                # -> delete line || move line || move vertex
-                if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
-                    if len(digitClass.driver.GetSelected()) == 0:
-                        nselected = digitClass.driver.SelectLineByPoint(pos1, type=VDigit_Lines_Type)
-                        if digitToolbar.GetAction() == "editLine":
-                            try:
-                                selVertex = digitClass.driver.GetSelectedVertex(pos1)[0]
-                            except IndexError:
-                                selVertex = None
-
-                            if selVertex:
-                                # self.UpdateMap(render=False)
-                                ids = digitClass.driver.GetSelected(grassId=False)
-                                # move this line to tmp layer
-                                self.polycoords = []
-                                for id in ids:
-                                    if id % 2: # register only vertices
-                                        e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
-                                        self.polycoords.append((e, n))
-                                    # self.pdcVector.RemoveId(id)
-                                digitClass.driver.DrawSelected(False) 
-                                
-                                if selVertex < ids[-1] / 2:
-                                    # choose first or last node of line
-                                    self.vdigitMove['id'].reverse()
-                                    self.polycoords.reverse()
-                            else:
-                                # unselect
-                                digitClass.driver.SetSelected([])
-                                del self.vdigitMove
-                                
-                            self.UpdateMap(render=False)
-
-                        
-                elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
-                    if not hasattr(self, "copyCatsIds"):
-                        # 'from' -> select by point
-                        nselected = digitClass.driver.SelectLineByPoint(pos1, digitClass.GetSelectType())
-                        if nselected:
-                            self.copyCatsList = digitClass.driver.GetSelected()
-                    else:
-                        # -> 'to' -> select by bbox
-                        digitClass.driver.SetSelected([])
-                        # return number of selected features (by box/point)
-                        nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
-                                                                       digitClass.GetSelectType())
-                        if nselected == 0:
-                            if digitClass.driver.SelectLineByPoint(pos1,
-                                                                   digitClass.GetSelectType()) is not None:
-                                nselected = 1
-
-                        if nselected > 0:
-                            self.copyCatsIds = digitClass.driver.GetSelected()
-
-                elif digitToolbar.GetAction() == "queryLine":
-                    selected = digitClass.SelectLinesByQuery(pos1, pos2)
-                    nselected = len(selected)
-                    if nselected > 0:
-                        digitClass.driver.SetSelected(selected)
-
-                else:
-                    # -> moveLine || deleteLine, etc. (select by point/box)
-                    if digitToolbar.GetAction() == 'moveLine' and \
-                           len(digitClass.driver.GetSelected()) > 0:
-                        nselected = 0
-                    else:
-                        if digitToolbar.GetAction() == 'moveLine':
-                            drawSeg = True
-                        else:
-                            drawSeg = False
-                        nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
-                                                                       digitClass.GetSelectType(),
-                                                                       drawSeg)
-                        
-                        if nselected == 0:
-                            if digitClass.driver.SelectLineByPoint(pos1,
-                                                                   digitClass.GetSelectType()) is not None:
-                                nselected = 1
-                
-                if nselected > 0:
-                    if digitToolbar.GetAction() in ["moveLine", "moveVertex"]:
-                        # get pseudoDC id of objects which should be redrawn
-                        if digitToolbar.GetAction() == "moveLine":
-                            # -> move line
-                            self.vdigitMove['id'] = digitClass.driver.GetSelected(grassId=False)
-                            self.vdigitMove['coord'] = digitClass.driver.GetSelectedCoord()
-                        elif digitToolbar.GetAction() == "moveVertex":
-                            # -> move vertex
-                            self.vdigitMove['id'] = digitClass.driver.GetSelectedVertex(pos1)
-                            if len(self.vdigitMove['id']) == 0: # no vertex found
-                                digitClass.driver.SetSelected([])
-
-                                   
-                    #
-                    # check for duplicates
-                    #
-                    if UserSettings.Get(group='vdigit', key='checkForDupl', subkey='enabled') is True:
-                        dupl = digitClass.driver.GetDuplicates()
-                        self.UpdateMap(render=False)
-
-                        if dupl:
-                            posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
-                                                             self.mouse['end'][1] + self.dialogOffset))
-                            
-                            dlg = VDigitDuplicatesDialog(parent=self, data=dupl, pos=posWindow)
-
-                            if dlg.ShowModal() == wx.ID_OK:
-                                digitClass.driver.UnSelect(dlg.GetUnSelected())
-                                # update selected
-                                self.UpdateMap(render=False)
-
-                    if digitToolbar.GetAction() != "editLine":
-                        # -> move line || move vertex
-                        self.UpdateMap(render=False)
-
-                else: # no vector object found
-                    if not (digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
-                                len(self.vdigitMove['id']) > 0):
-                        # avoid left-click when features are already selected
-                        self.UpdateMap(render=False, renderVector=False)
-
-            elif digitToolbar.GetAction() in ["splitLine", "addVertex", "removeVertex"]:
-                pointOnLine = digitClass.driver.SelectLineByPoint(pos1,
-                                                                  type=VDigit_Lines_Type)
-                if pointOnLine:
-                    if digitToolbar.GetAction() in ["splitLine", "addVertex"]:
-                        self.UpdateMap(render=False) # highlight object
-                        self.DrawCross(pdc=self.pdcTmp, coords=self.Cell2Pixel(pointOnLine),
-                                       size=5)
-                    elif digitToolbar.GetAction() == "removeVertex":
-                        # get only id of vertex
-                        try:
-                            id = digitClass.driver.GetSelectedVertex(pos1)[0]
-                        except IndexError:
-                            id = None
-
-                        if id:
-                            x, y = self.pdcVector.GetIdBounds(id)[0:2]
-                            self.pdcVector.RemoveId(id)
-                            self.UpdateMap(render=False) # highlight object
-                            self.DrawCross(pdc=self.pdcTmp, coords=(x, y),
-                                           size=5)
-                        else:
-                            # unselect
-                            digitClass.driver.SetSelected([])
-                            self.UpdateMap(render=False)
-                            
-            elif digitToolbar.GetAction() == "copyLine":
-                if UserSettings.Get(group='vdigit', key='bgmap',
-                                    subkey='value', internal=True) == '':
-                    # no background map -> copy from current vector map layer
-                    nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
-                                                                   digitClass.GetSelectType())
-
-                    if nselected > 0:
-                        # highlight selected features
-                        self.UpdateMap(render=False)
-                    else:
-                        self.UpdateMap(render=False, renderVector=False)
-                else:
-                    # copy features from background map
-                    self.copyIds = digitClass.SelectLinesFromBackgroundMap(pos1, pos2)
-                    if len(self.copyIds) > 0:
-                        color = UserSettings.Get(group='vdigit', key='symbol',
-                                                 subkey=['highlight', 'color'])
-                        colorStr = str(color[0]) + ":" + \
-                            str(color[1]) + ":" + \
-                            str(color[2])
-                        dVectTmp = ['d.vect',
-                                    'map=%s' % UserSettings.Get(group='vdigit', key='bgmap',
-                                                                subkey='value', internal=True),
-                                    'cats=%s' % utils.ListOfCatsToRange(self.copyIds),
-                                    '-i',
-                                    'color=%s' % colorStr,
-                                    'fcolor=%s' % colorStr,
-                                    'type=point,line,boundary,centroid',
-                                    'width=2']
-                        
-                        self.layerTmp = self.Map.AddLayer(type='vector',
-                                                          name=globalvar.QUERYLAYER,
-                                                          command=dVectTmp)
-                        self.UpdateMap(render=True, renderVector=False)
-                    else:
-                        self.UpdateMap(render=False, renderVector=False)
-                    self.redrawAll = None
-
-            elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
-                # select lines to be labeled
-                pos1 = self.polycoords[0]
-                pos2 = self.polycoords[1]
-                nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
-                                                               digitClass.GetSelectType())
-
-                if nselected > 0:
-                    # highlight selected features
-                    self.UpdateMap(render=False)
-                    self.DrawLines(pdc=self.pdcTmp) # redraw temp line
-                else:
-                    self.UpdateMap(render=False, renderVector=False)
-
-            elif digitToolbar.GetAction() == "connectLine":
-                if len(digitClass.driver.GetSelected()) > 0:
-                    self.UpdateMap(render=False)
-                    
-            if len(digitClass.driver.GetSelected()) > 0:
-                self.redrawAll = None
-                ### self.OnPaint(None)
-                
-        elif (self.mouse['use'] == 'pointer' and 
-                self.dragid >= 0):
-            # end drag of overlay decoration
-            
-            if self.dragid < 99 and self.overlays.has_key(self.dragid):
-                self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
-            elif self.dragid > 100 and self.textdict.has_key(self.dragid):
-                self.textdict[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
-            else:
-                pass
-            self.dragid = None
-            self.currtxtid = None
-#            self.UpdateMap(render=True)
-            
-        else:
-            pass
-                                              
-#        event.Skip()
-
-    def OnButtonDClick(self, event):
-        """
-        Mouse button double click
-        """
-        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
-                   self.mouse["use"])
-
-        if self.mouse["use"] == "measure":
-            # measure
-            self.ClearLines(pdc=self.pdcTmp)
-            self.polycoords = []
-            self.mouse['use'] = 'pointer'
-            self.mouse['box'] = 'point'
-            self.mouse['end'] = [0, 0]
-            self.Refresh()
-            self.SetCursor(self.parent.cursors["default"])
-        elif self.mouse["use"] == "profile":
-            # profile
-            pass
-        #                self.pdc.ClearId(self.lineid)
-        #                self.pdc.ClearId(self.plineid)
-        #                print 'coordinates: ',self.polycoords
-        #                self.polycoords = []
-        #                self.mouse['begin'] = self.mouse['end'] = [0, 0]
-        #                self.Refresh()
-        elif self.mouse['use'] == 'pointer' and self.parent.toolbars['vdigit']:
-            # digitization tool
-            pass
-        else:
-            # select overlay decoration options dialog
-            clickposition = event.GetPositionTuple()[:]
-            idlist  = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
-            if idlist == []:
-                return
-            self.dragid = idlist[0]
-
-            # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
-            if self.dragid > 100:
-                self.currtxtid = self.dragid
-                self.parent.OnAddText(None)
-            elif self.dragid == 0:
-                self.parent.OnAddBarscale(None)
-            elif self.dragid == 1:
-                self.parent.OnAddLegend(None)
-                
-#        event.Skip()
-
-    def OnRightDown(self, event):
-        """
-        Right mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
-                   self.mouse["use"])
-                   
-        digitToolbar = self.parent.toolbars['vdigit']
-        if digitToolbar:
-            digitClass = self.parent.digit
-            # digitization tool (confirm action)
-            if digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
-                    hasattr(self, "vdigitMove"):
-
-                pFrom = self.vdigitMove['begin']
-                pTo = self.Pixel2Cell(event.GetPositionTuple())
-                
-                move = (pTo[0] - pFrom[0],
-                        pTo[1] - pFrom[1])
-                
-                if digitToolbar.GetAction() == "moveLine":
-                    # move line
-                    if digitClass.MoveSelectedLines(move) < 0:
-                        return
-                elif digitToolbar.GetAction() == "moveVertex":
-                    # move vertex
-                    if digitClass.MoveSelectedVertex(pFrom, move) < 0:
-                        return
-                
-                del self.vdigitMove
-                
-        event.Skip()
-
-    def OnRightUp(self, event):
-        """
-        Right mouse button released
-        """
-        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
-                   self.mouse["use"])
-
-        digitToolbar = self.parent.toolbars['vdigit']
-        if digitToolbar:
-            digitClass = self.parent.digit
-            # digitization tool (confirm action)
-            if digitToolbar.GetAction() == "addLine" and \
-                    digitToolbar.GetAction('type') in ["line", "boundary"]:
-                # -> add new line / boundary
-                try:
-                    map = digitToolbar.GetLayer().GetName()
-                except:
-                    map = None
-                    wx.MessageBox(parent=self,
-                                  message=_("No vector map selected for editing."),
-                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                    
-                if map:
-                    # mapcoords = []
-                    # xy -> EN
-                    # for coord in self.polycoords:
-                    #    mapcoords.append(self.Pixel2Cell(coord))
-                    if digitToolbar.GetAction('type') == 'line':
-                        line = True
-                    else:
-                        line = False
-
-                    if len(self.polycoords) < 2: # ignore 'one-point' lines
-                        return
-                    
-                    fid = digitClass.AddLine(map, line, self.polycoords)
-                    if fid < 0:
-                        return
-                    
-                    position = self.Cell2Pixel(self.polycoords[-1])
-                    self.polycoords = []
-                    self.UpdateMap(render=False)
-                    self.redrawAll = True
-                    self.Refresh()
-                    
-                    # add new record into atribute table
-                    if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled') is True:
-                        posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
-                                                         position[1] + self.dialogOffset))
-
-                        # select attributes based on layer and category
-                        cats = { fid : {
-                                UserSettings.Get(group='vdigit', key="layer", subkey='value') :
-                                    (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
-                                }}
-
-                        addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
-                                                                   cats=cats,
-                                                                   pos=posWindow,
-                                                                   action="add")
-                        if addRecordDlg.mapDBInfo and \
-                               addRecordDlg.ShowModal() == wx.ID_OK:
-                            sqlfile = tempfile.NamedTemporaryFile(mode="w")
-                            for sql in addRecordDlg.GetSQLString():
-                                sqlfile.file.write(sql + ";\n")
-                            sqlfile.file.flush()
-                            executeCommand = gcmd.Command(cmd=["db.execute",
-                                                              "--q",
-                                                              "input=%s" % sqlfile.name])
-            elif digitToolbar.GetAction() == "deleteLine":
-                # -> delete selected vector features
-                if digitClass.DeleteSelectedLines() < 0:
-                    return
-            elif digitToolbar.GetAction() == "splitLine":
-                # split line
-                if digitClass.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
-                    return
-            elif digitToolbar.GetAction() == "addVertex":
-                # add vertex
-                if digitClass.AddVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
-                    return
-            elif digitToolbar.GetAction() == "removeVertex":
-                # remove vertex
-                if digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
-                    return
-            elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
-                try:
-                    if digitToolbar.GetAction() == 'copyCats':
-                        if digitClass.CopyCats(self.copyCatsList,
-                                               self.copyCatsIds, copyAttrb=False) < 0:
-                            return
-                    else:
-                        if digitClass.CopyCats(self.copyCatsList,
-                                               self.copyCatsIds, copyAttrb=True) < 0:
-                            return
-                    
-                    del self.copyCatsList
-                    del self.copyCatsIds
-                except AttributeError:
-                    pass
-            elif digitToolbar.GetAction() == "editLine" and \
-                    hasattr(self, "vdigitMove"):
-                line = digitClass.driver.GetSelected()
-                if digitClass.EditLine(line, self.polycoords) < 0:
-                    return
-                
-                del self.vdigitMove
-                
-            elif digitToolbar.GetAction() == "flipLine":
-                if digitClass.FlipLine() < 0:
-                    return
-            elif digitToolbar.GetAction() == "mergeLine":
-                if digitClass.MergeLine() < 0:
-                    return
-            elif digitToolbar.GetAction() == "breakLine":
-                if digitClass.BreakLine() < 0:
-                    return
-            elif digitToolbar.GetAction() == "snapLine":
-                if digitClass.SnapLine() < 0:
-                    return
-            elif digitToolbar.GetAction() == "connectLine":
-                if len(digitClass.driver.GetSelected()) > 1:
-                    if digitClass.ConnectLine() < 0:
-                        return
-            elif digitToolbar.GetAction() == "copyLine":
-                if digitClass.CopyLine(self.copyIds) < 0:
-                    return
-                del self.copyIds
-                if self.layerTmp:
-                    self.Map.DeleteLayer(self.layerTmp)
-                    self.UpdateMap(render=True, renderVector=False)
-                del self.layerTmp
-
-            elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
-                pos1 = self.polycoords[0]
-                pos2 = self.polycoords[1]
-
-                selected = digitClass.driver.GetSelected()
-                dlg = VDigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"),
-                                        nselected=len(selected))
-                if dlg.ShowModal() == wx.ID_OK:
-                    if digitClass.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
-                                            dlg.step.GetValue()) < 0:
-                        return
-                self.UpdateMap(render=False, renderVector=True)
-            elif digitToolbar.GetAction() == "typeConv":
-                # -> feature type conversion
-                # - point <-> centroid
-                # - line <-> boundary
-                if digitClass.TypeConvForSelectedLines() < 0:
-                    return
-
-            if digitToolbar.GetAction() != "addLine":
-                # unselect and re-render
-                digitClass.driver.SetSelected([])
-                self.polycoords = []
-                self.UpdateMap(render=False)
-
-            self.redrawAll = True
-            self.Refresh()
-        
-        event.Skip()
-
-    def OnMiddleDown(self, event):
-        """
-        Middle mouse button pressed
-        """
-        digitToolbar = self.parent.toolbars['vdigit']
-        # digitization tool
-        if self.mouse["use"] == "pointer" and digitToolbar:
-            digitClass = self.parent.digit
-            if (digitToolbar.GetAction() == "addLine" and \
-                    digitToolbar.GetAction('type') in ["line", "boundary"]) or \
-                    digitToolbar.GetAction() == "editLine":
-                # add line or boundary -> remove last point from the line
-                try:
-                    removed = self.polycoords.pop()
-                    Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
-                                  [removed,])
-
-                    self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
-                except:
-                    pass
-
-                if digitToolbar.GetAction() == "editLine":
-                    # remove last vertex & line
-                    if len(self.vdigitMove['id']) > 1:
-                        self.vdigitMove['id'].pop()
-
-                self.UpdateMap(render=False, renderVector=False)
-
-            elif digitToolbar.GetAction() in ["deleteLine", "moveLine", "splitLine",
-                                              "addVertex", "removeVertex", "moveVertex",
-                                              "copyCats", "flipLine", "mergeLine",
-                                              "snapLine", "connectLine", "copyLine",
-                                              "queryLine", "breakLine", "typeConv"]:
-                # varios tools -> unselected selected features
-                digitClass.driver.SetSelected([])
-                if digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
-                        hasattr(self, "vdigitMove"):
-
-                    del self.vdigitMove
-                    
-                elif digitToolbar.GetAction() == "copyCats":
-                    try:
-                        del self.copyCatsList
-                        del self.copyCatsIds
-                    except AttributeError:
-                        pass
-                
-                elif digitToolbar.GetAction() == "copyLine":
-                    del self.copyIds
-                    if self.layerTmp:
-                        self.Map.DeleteLayer(self.layerTmp)
-                        self.UpdateMap(render=True, renderVector=False)
-                    del self.layerTmp
-
-                self.polycoords = []
-                self.UpdateMap(render=False) # render vector
-
-            elif digitToolbar.GetAction() == "zbulkLine":
-                # reset polyline
-                self.polycoords = []
-                digitClass.driver.SetSelected([])
-                self.UpdateMap(render=False)
-            
-            self.redrawAll = True
-            
-    def OnMouseMoving(self, event):
-        """
-        Motion event and no mouse buttons were pressed
-        """
-        digitToolbar = self.parent.toolbars['vdigit']
-        if self.mouse["use"] == "pointer" and digitToolbar:
-            digitClass = self.parent.digit
-            self.mouse['end'] = event.GetPositionTuple()[:]
-            Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
-                           (self.mouse['end'][0], self.mouse['end'][1]))
-            if digitToolbar.GetAction() == "addLine" and digitToolbar.GetAction('type') in ["line", "boundary"]:
-                if len(self.polycoords) > 0:
-                    self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1]))
-            elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] \
-                    and hasattr(self, "vdigitMove"):
-                dx = self.mouse['end'][0] - self.mouse['begin'][0]
-                dy = self.mouse['end'][1] - self.mouse['begin'][1]
-                
-                if len(self.vdigitMove['id']) > 0:
-                    # draw lines on new position
-                    if digitToolbar.GetAction() == "moveLine":
-                        # move line
-                        for id in self.vdigitMove['id']:
-                            self.pdcTmp.TranslateId(id, dx, dy)
-                    elif digitToolbar.GetAction() in ["moveVertex", "editLine"]:
-                        # move vertex ->
-                        # (vertex, left vertex, left line,
-                        # right vertex, right line)
-
-                        # do not draw static lines
-                        if digitToolbar.GetAction() == "moveVertex":
-                            self.polycoords = []
-                            ### self.pdcTmp.TranslateId(self.vdigitMove['id'][0], dx, dy)
-                            self.pdcTmp.RemoveId(self.vdigitMove['id'][0])
-                            if self.vdigitMove['id'][1] > 0: # previous vertex
-                                x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][1])[0:2])
-                                self.pdcTmp.RemoveId(self.vdigitMove['id'][1]+1)
-                                self.polycoords.append((x, y))
-                            ### x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][0])[0:2])
-                            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
-                            if self.vdigitMove['id'][2] > 0: # next vertex
-                                x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][2])[0:2])
-                                self.pdcTmp.RemoveId(self.vdigitMove['id'][2]-1)
-                                self.polycoords.append((x, y))
-                            
-                            self.ClearLines(pdc=self.pdcTmp)
-                            self.DrawLines(pdc=self.pdcTmp)
-
-                        else: # edit line
-                            try:
-                                if self.vdigitMove['id'][-1] > 0: # previous vertex
-                                    self.MouseDraw(pdc=self.pdcTmp,
-                                                   begin=self.Cell2Pixel(self.polycoords[-1]))
-                            except: # no line
-                                self.vdigitMove['id'] = []
-                                self.polycoords = []
-
-                self.Refresh() # TODO: use RefreshRect()
-                self.mouse['begin'] = self.mouse['end']
-
-            elif digitToolbar.GetAction() == "zbulkLine":
-                if len(self.polycoords) == 1:
-                    # draw mouse moving
-                    self.MouseDraw(self.pdcTmp)
-
-        event.Skip()
-
-    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))
-
-        ### self.Refresh()
-
-        return True
-
-    def Pixel2Cell(self, (x, y)):
-        """
-        Convert image coordinates to real word coordinates
-
-        Input : int x, int y
-        Output: float x, float y
-        """
-
-        try:
-            x = int(x)
-            y = int(y)
-        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
-
-        # extent does not correspond with whole map canvas area...
-        # east  = self.Map.region['w'] + x * self.Map.region["ewres"]
-        # north = self.Map.region['n'] - y * self.Map.region["nsres"]
-
-        return (east, north)
-
-    def Cell2Pixel(self, (east, north)):
-        """
-        Convert real word coordinates to image coordinates
-        """
-
-        try:
-            east  = float(east)
-            north = float(north)
-        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 = int((east  - w) / res)
-        # y = int((n - north) / 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
-            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.parent.Map.projinfo['proj'] == 'll':
-                if newreg['n'] > 90.0:
-                    newreg['n'] = 90.0
-                if newreg['s'] < -90.0:
-                    newreg['s'] = -90.0
-            
-            ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
-            cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
-            
-            if hasattr(self, "vdigitMove"):
-                # xo = self.Cell2Pixel((self.Map.region['center_easting'], self.Map.region['center_northing']))
-                # xn = self.Cell2Pixel(ce, cn))
-                tmp = self.Pixel2Cell(self.mouse['end'])
-            
-            # 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
-            self.Map.AlignExtentFromDisplay()
-
-            if hasattr(self, "vdigitMove"):
-                tmp1 = self.mouse['end']
-                tmp2 = self.Cell2Pixel(self.vdigitMove['begin'])
-                dx = tmp1[0] - tmp2[0]
-                dy = tmp1[1] - tmp2[1]
-                self.vdigitMove['beginDiff'] = (dx, dy)
-                for id in self.vdigitMove['id']:
-                    self.pdcTmp.RemoveId(id)
-            
-            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
-        """
-
-        zoom = []
-        if len(self.zoomhistory) > 1:
-            self.zoomhistory.pop()
-            zoom = self.zoomhistory[len(self.zoomhistory)-1]
-            # (n, s, e, w)
-        if zoom:
-            # zoom to selected region
-            self.Map.region['center_easting'] = zoom[3] + \
-                (zoom[2] - zoom[3]) / 2
-            self.Map.region['center_northing'] = zoom[1] + \
-                (zoom[0] - zoom[1]) / 2
-            self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width
-            self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height
-            self.Map.AlignExtentFromDisplay()
-
-            # update map
-            self.UpdateMap()
-
-            # update statusbar
-            self.parent.StatusbarUpdate()
-
-    def ZoomHistory(self, n, s, e, w):
-        """
-        Manages a list of last 10 zoom extents
-
-        Return removed history item if exists
-        """
-        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))
-
-        return removed
-
-    def OnZoomToMap(self, event):
-        """
-        Set display extents to match selected raster (including NULLs)
-        or vector map.
-        """
-        self.ZoomToMap()
-
-    def OnZoomToRaster(self, event):
-        """
-        Set display extents to match selected raster map (ignore NULLs)
-        """
-        self.ZoomToMap(zoom=True)
-        
-    def ZoomToMap(self, layer = None, zoom = False):
-        """
-        Set display extents to match selected raster
-        or vector map.
-        """
-        zoomreg = {}
-
-        if not layer:
-            layer = self.GetSelectedLayer(multi = True)
-        
-        if not layer:
-            return
-
-        rast = []
-        vect = []
-        updated = False
-        for l in layer:
-            # only raster/vector layers are currently supported
-            if l.type == 'raster':
-                rast.append(l.name)
-            elif l.type == 'vector':
-                if self.parent.digit and l.name == self.parent.digit.map and \
-                        self.parent.digit.type == 'vdigit':
-                    w, s, b, e, n, t = self.parent.digit.driver.GetMapBoundingBox()
-                    self.Map.GetRegion(n=n, s=s, w=w, e=e,
-                                       update=True)
-                    updated = True
-                else:
-                    vect.append(l.name)
-
-        if not updated:
-            self.Map.GetRegion(rast = rast,
-                               vect = vect,
-                               update = True)
-        
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-
-        self.UpdateMap()
-
-        self.parent.StatusbarUpdate()
-
-    def ZoomToWind(self, event):
-        """
-        Set display geometry to match computational
-        region settings (set with g.region)
-        """
-        self.Map.region = self.Map.GetRegion()
-        ### self.Map.SetRegion(windres=True)
-
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-
-        self.UpdateMap()
-
-        self.parent.StatusbarUpdate()
-
-    def ZoomToDefault(self, event):
-        """
-        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()
-
-        self.parent.StatusbarUpdate()
-        
-    def DisplayToWind(self, event):
-        """
-        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()
-        
-        cmdRegion = ["g.region", "--o",
-                     "n=%f"    % new['n'],
-                     "s=%f"    % new['s'],
-                     "e=%f"    % new['e'],
-                     "w=%f"    % new['w'],
-                     "rows=%d" % int(new['rows']),
-                     "cols=%d" % int(new['cols'])]
-        
-        p = gcmd.Command(cmdRegion)
-
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-
-    def ZoomToSaved(self, event):
-        """!Set display geometry to match extents in
-        saved region file
-        """
-        dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
-                                   title = _("Zoom to saved region extents"),
-                                   pos=wx.DefaultPosition, size=wx.DefaultSize,
-                                   style=wx.DEFAULT_DIALOG_STYLE,
-                                   loadsave='load')
-        
-        if dlg.ShowModal() == wx.ID_CANCEL:
-            dlg.Destroy()
-            return
-        
-        wind = dlg.wind
-        
-        self.Map.GetRegion(regionName = wind,
-                           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 SaveDisplayRegion(self, event):
-        """
-        Save display extents to named region file.
-        """
-
-        dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
-                                   title = _("Save display extents to region file"),
-                                   pos=wx.DefaultPosition, size=wx.DefaultSize,
-                                   style=wx.DEFAULT_DIALOG_STYLE,
-                                   loadsave='save')
-        if dlg.ShowModal() == wx.ID_CANCEL:
-            dlg.Destroy()
-            return
-        
-        wind = dlg.wind
-        
-        # test to see if it already exists and ask permission to overwrite
-        windpath = os.path.join(self.Map.env["GISDBASE"], self.Map.env["LOCATION_NAME"],
-                                self.Map.env["MAPSET"], "windows", wind)
-        
-        if windpath and not os.path.exists(windpath):
-            self.SaveRegion(wind)
-        elif windpath and os.path.exists(windpath):
-            overwrite = wx.MessageBox(_("Region file <%s> already exists. "
-                                        "Do you want to overwrite it?") % (wind),
-                                      _("Warning"), wx.YES_NO | wx.CENTRE)
-            if (overwrite == wx.YES):
-                self.SaveRegion(wind)
-        else:
-            pass
-
-        dlg.Destroy()
-
-    def SaveRegion(self, wind):
-        """
-        Save region settings
-        """
-        ### new = self.Map.AlignResolution()
-        new = self.Map.GetCurrentRegion()
-        
-        cmdRegion = ["g.region",
-                     "-u",
-                     "n=%f" % new['n'],
-                     "s=%f" % new['s'],
-                     "e=%f" % new['e'],
-                     "w=%f" % new['w'],
-                     "rows=%d" % new['rows'],
-                     "cols=%d" % new['cols'],
-                     "save=%s" % wind,
-                     "--o"]
-
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        p = gcmd.Command(cmdRegion)
-
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-
-    def Distance(self, beginpt, endpt, screen=True):
-        """Calculete distance
-
-        LL-locations not supported
-
-        @todo Use m.distance
-
-        @param beginpt first point
-        @param endpt second point
-        @param screen True for screen coordinates otherwise EN
-        """
-        x1, y1 = beginpt
-        x2, y2 = endpt
-        if screen:
-            dEast  = (x2 - x1) * self.Map.region["ewres"]
-            dNorth = (y2 - y1) * self.Map.region["nsres"]
-        else:
-            dEast  = (x2 - x1)
-            dNorth = (y2 - y1)
-            
-
-        return (math.sqrt(math.pow((dEast),2) + math.pow((dNorth),2)), (dEast, dNorth))
-
-class MapFrame(wx.Frame):
-    """
-    Main frame for map display window. Drawing takes place in child double buffered
-    drawing window.
-    """
-
-    def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS - Map display"),
-                 pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=wx.DEFAULT_FRAME_STYLE, toolbars=["map"],
-                 tree=None, notebook=None, gismgr=None, page=None,
-                 Map=None, auimgr=None):
-        """
-        Main map display window with toolbars, statusbar and
-        DrawWindow
-
-        @param toolbars array of activated toolbars, e.g. ['map', 'digit']
-        @param tree reference to layer tree
-        @param notebook control book ID in Layer Manager
-        @param gismgr Layer Manager panel
-        @param page notebook page with layer tree
-        @param Map instance of render.Map
-        """
-        self.gismanager = gismgr    # GIS Manager object
-        self.Map        = Map       # instance of render.Map
-        self.tree       = tree      # GIS Manager layer tree object
-        self.page       = page      # Notebook page holding the layer tree
-        self.layerbook  = notebook  # GIS Manager layer tree notebook
-        self.parent     = parent
-
-        #
-        # available cursors
-        #
-        self.cursors = {
-            # default: cross
-            # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
-            "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)
-            }
-
-        wx.Frame.__init__(self, parent, id, title, pos, size, style)
-        self.SetName("MapWindow")
-
-        #
-        # set the size & system icon
-        #
-        self.SetClientSize(size)
-        self.iconsize = (16, 16)
-
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
-
-        #
-        # Fancy gui
-        #
-        # self._mgr = auimgr
-        self._mgr = wx.aui.AuiManager(self)
-
-        #
-        # Add toolbars
-        #
-        self.toolbars = { 'map' : None,
-                          'vdigit' : None,
-                          'georect' : None, 
-                          'nviz' : None }
-        for toolb in toolbars:
-            self.AddToolbar(toolb)
-
-        #
-        # Add statusbar
-        #
-        self.statusbar = self.CreateStatusBar(number=4, style=0)
-        self.statusbar.SetStatusWidths([-5, -2, -1, -1])
-        self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY,
-                                      choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
-        self.toggleStatus.SetSelection(UserSettings.Get(group='display', key='statusbarMode', subkey='selection'))
-        self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.toggleStatus)
-        # auto-rendering checkbox
-        self.autoRender = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
-                                      label=_("Render"))
-        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.autoRender)
-        self.autoRender.SetValue(UserSettings.Get(group='display', key='autoRendering', subkey='enabled'))
-        self.autoRender.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
-        # show region
-        self.showRegion = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
-                                      label=_("Show computational extent"))
-        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.showRegion)
-        
-        self.showRegion.SetValue(False)
-        self.showRegion.Hide()
-        self.showRegion.SetToolTip(wx.ToolTip (_("Show/hide computational "
-                                                 "region extent (set with g.region). "
-                                                 "Display region drawn as a blue box inside the "
-                                                 "computational region, "
-                                                 "computational region inside a display region "
-                                                 "as a red box).")))
-        # set resolution
-        self.compResolution = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
-                                         label=_("Constrain display resolution to computational settings"))
-        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.compResolution)
-        self.compResolution.SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
-        self.compResolution.Hide()
-        self.compResolution.SetToolTip(wx.ToolTip (_("Constrain display resolution "
-                                                     "to computational region settings. "
-                                                     "Default value for new map displays can "
-                                                     "be set up in 'User GUI settings' dialog.")))
-        # map scale
-        self.mapScale = wx.TextCtrl(parent=self.statusbar, id=wx.ID_ANY,
-                                    value="", style=wx.TE_PROCESS_ENTER,
-                                    size=(150, -1))
-        self.mapScale.Hide()
-        self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.mapScale)
-
-        # mask
-        self.maskInfo = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
-                                                  label = '')
-        self.maskInfo.SetForegroundColour(wx.Colour(255, 0, 0))
-        
-
-        # on-render gauge
-        self.onRenderGauge = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
-                                      range=0, style=wx.GA_HORIZONTAL)
-        self.onRenderGauge.Hide()
-        
-        self.StatusbarReposition() # reposition statusbar
-
-        #
-        # Init map display (buffered DC & set default cursor)
-        #
-        self.MapWindow2D = BufferedWindow(self, id=wx.ID_ANY,
-                                          Map=self.Map, tree=self.tree, gismgr=self.gismanager)
-        # default is 2D display mode
-        self.MapWindow = self.MapWindow2D
-        self.MapWindow.Bind(wx.EVT_MOTION, self.OnMotion)
-        self.MapWindow.SetCursor(self.cursors["default"])
-        # used by Nviz (3D display mode)
-        self.MapWindow3D = None 
-
-        #
-        # initialize region values
-        #
-        self.__InitDisplay() 
-
-        #
-        # Bind various events
-        #
-        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
-        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
-        self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
-        
-        #
-        # Update fancy gui style
-        #
-        self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
-                   Dockable(False).BestSize((-1,-1)).
-                   CloseButton(False).DestroyOnClose(True).
-                   Layer(0))
-        self._mgr.Update()
-
-        #
-        # Init print module and classes
-        #
-        self.printopt = disp_print.PrintOptions(self, self.MapWindow)
-        
-        #
-        # Initialization of digitization tool
-        #
-        self.digit = None
-
-        #
-        # Init zoom history
-        #
-        self.MapWindow.ZoomHistory(self.Map.region['n'],
-                                   self.Map.region['s'],
-                                   self.Map.region['e'],
-                                   self.Map.region['w'])
-
-        #
-        # Re-use dialogs
-        #
-        self.dialogs = {}
-        self.dialogs['attributes'] = None
-        self.dialogs['category'] = None
-        self.dialogs['barscale'] = None
-        self.dialogs['legend'] = None
-
-        self.decorationDialog = None # decoration/overlays
-
-    def AddToolbar(self, name):
-        """
-        Add defined toolbar to the window
-
-        Currently known toolbars are:
-         - map basic map toolbar
-         - digit vector digitizer
-         - georect georectifier
-        """
-        # default toolbar
-        if name == "map":
-            self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
-
-            self._mgr.AddPane(self.toolbars['map'].toolbar,
-                              wx.aui.AuiPaneInfo().
-                              Name("maptoolbar").Caption(_("Map Toolbar")).
-                              ToolbarPane().Top().
-                              LeftDockable(False).RightDockable(False).
-                              BottomDockable(False).TopDockable(True).
-                              CloseButton(False).Layer(2).
-                              BestSize((self.toolbars['map'].GetToolbar().GetSize())))
-	
-        # vector digitizer
-        elif name == "vdigit":
-            from vdigit import haveVDigit
-            if not haveVDigit:
-                from vdigit import errorMsg
-                msg = _("Unable to start vector digitizer.\nThe VDigit python extension "
-                        "was not found or loaded properly.\n"
-                        "Switching back to 2D display mode.\n\nDetails: %s" % errorMsg)
-                
-                self.toolbars['map'].combo.SetValue (_("2D view"))
-                wx.MessageBox(parent=self,
-                              message=msg,
-                              caption=_("Error"),
-                              style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                return
-            
-            self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent=self, map=self.Map,
-                                                             layerTree=self.tree,
-                                                             log=self.gismanager.goutput)
-
-            for toolRow in range(0, self.toolbars['vdigit'].numOfRows):
-                self._mgr.AddPane(self.toolbars['vdigit'].toolbar[toolRow],
-                                  wx.aui.AuiPaneInfo().
-                                  Name("vdigittoolbar" + str(toolRow)).Caption(_("Vector digitizer toolbar")).
-                                  ToolbarPane().Top().Row(toolRow + 1).
-                                  LeftDockable(False).RightDockable(False).
-                                  BottomDockable(False).TopDockable(True).
-                                  CloseButton(False).Layer(2).
-                                  BestSize((self.toolbars['vdigit'].GetToolbar().GetSize())))
-	
-            # change mouse to draw digitized line
-            self.MapWindow.mouse['box'] = "point"
-            self.MapWindow.zoomtype = 0
-            self.MapWindow.pen     = wx.Pen(colour='red',   width=2, style=wx.SOLID)
-            self.MapWindow.polypen = wx.Pen(colour='green', width=2, style=wx.SOLID)
-        # georectifier
-        elif name == "georect":
-            self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
-
-            self._mgr.AddPane(self.toolbars['georect'].toolbar,
-                              wx.aui.AuiPaneInfo().
-                              Name("georecttoolbar").Caption(_("Georectification toolbar")).
-                              ToolbarPane().Top().
-                              LeftDockable(False).RightDockable(False).
-                              BottomDockable(False).TopDockable(True).
-                              CloseButton(False).Layer(2))
-        # nviz
-        elif name == "nviz":
-            import nviz
-
-            # check for GLCanvas and OpenGL
-            msg = None
-            if not nviz.haveGLCanvas:
-                msg = _("Unable to switch to 3D display mode.\nThe GLCanvas class has not been "
-                        "included with this build "
-                        "of wxPython!\nSwitching back to "
-                        "2D display mode.\n\nDetails: %s" % nviz.errorMsg)
-            if not nviz.haveNviz:
-                msg = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
-                        "was not found or loaded properly.\n"
-                        "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg)
-
-            if msg:
-                self.toolbars['map'].combo.SetValue (_("2D view"))
-                wx.MessageBox(parent=self,
-                              message=msg,
-                              caption=_("Error"),
-                              style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                return
-
-            #
-            # add Nviz toolbar and disable 2D display mode tools
-            #
-            self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
-            self.toolbars['map'].Enable2D(False)
-
-            #
-            # update layer tree (-> enable 3d-rasters)
-            #
-            self.tree.EnableItemType(type='3d-raster', enable=True)
-            
-            #
-            # update status bar
-            #
-            self.toggleStatus.Enable(False)
-
-            #
-            # erase map window
-            #
-            self.MapWindow.EraseMap()
-
-            busy = wx.BusyInfo(message=_("Please wait, loading data..."),
-                               parent=self)
-            wx.Yield()
-        
-            #
-            # create GL window & NVIZ toolbar
-            #
-            if not self.MapWindow3D:
-                self.MapWindow3D = nviz.GLWindow(self, id=wx.ID_ANY,
-                                                 Map=self.Map, tree=self.tree, gismgr=self.gismanager)
-                self.nvizToolWin = nviz.NvizToolWindow(self, id=wx.ID_ANY,
-                                                       mapWindow=self.MapWindow3D)
-                self.MapWindow3D.OnPaint(None) # -> LoadData
-                self.MapWindow3D.Show()
-                self.MapWindow3D.UpdateView(None)
-
-            busy.Destroy()
-
-            self.nvizToolWin.Show()
-
-            #
-            # switch from MapWindow to MapWindowGL
-            # add nviz toolbar
-            #
-            self._mgr.DetachPane(self.MapWindow2D)
-            self.MapWindow2D.Hide()
-            self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
-                              Dockable(False).BestSize((-1,-1)).
-                              CloseButton(False).DestroyOnClose(True).
-                              Layer(0))
-            self._mgr.AddPane(self.toolbars['nviz'].toolbar,
-                              wx.aui.AuiPaneInfo().
-                              Name("nviztoolbar").Caption(_("Nviz toolbar")).
-                              ToolbarPane().Top().Row(1).
-                              LeftDockable(False).RightDockable(False).
-                              BottomDockable(False).TopDockable(True).
-                              CloseButton(False).Layer(2))
-            
-            self.MapWindow = self.MapWindow3D
-            self.SetStatusText("", 0)
-            
-        self._mgr.Update()
-
-    def RemoveToolbar (self, name):
-        """
-        Removes toolbar from the window
-
-        TODO: Only hide, activate by calling AddToolbar()
-        """
-
-        # cannot hide main toolbar
-        if name == "map":
-            return
-        elif name == "vdigit":
-            # TODO: not destroy only hide
-            for toolRow in range(0, self.toolbars['vdigit'].numOfRows):
-                self._mgr.DetachPane (self.toolbars['vdigit'].toolbar[toolRow])
-                self.toolbars['vdigit'].toolbar[toolRow].Destroy()
-        else:
-            self._mgr.DetachPane (self.toolbars[name].toolbar)
-            self.toolbars[name].toolbar.Destroy()
-
-        self.toolbars[name] = None
-
-        if name == 'nviz':
-            # hide nviz tools
-            self.nvizToolWin.Hide()
-            # unload data
-#            self.MapWindow3D.Reset()
-            # switch from MapWindowGL to MapWindow
-            self._mgr.DetachPane(self.MapWindow3D)
-            self.MapWindow3D.Hide()
-            self.MapWindow2D.Show()
-            self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
-                              Dockable(False).BestSize((-1,-1)).
-                              CloseButton(False).DestroyOnClose(True).
-                              Layer(0))
-            self.MapWindow = self.MapWindow2D
-  
-            #
-            # update layer tree (-> disable 3d-rasters)
-            #
-            self.tree.EnableItemType(type='3d-raster', enable=False)
-            self.MapWindow.UpdateMap()
-            
-        self.toolbars['map'].combo.SetValue (_("2D view"))
-        self.toolbars['map'].Enable2D(True)
-        self.toggleStatus.Enable(True)
-
-        self._mgr.Update()
-
-    def __InitDisplay(self):
-        """
-        Initialize map display, set dimensions and map region
-        """
-        self.width, self.height = self.GetClientSize()
-
-        Debug.msg(2, "MapFrame.__InitDisplay():")
-        self.Map.ChangeMapSize(self.GetClientSize())
-        self.Map.region = self.Map.GetRegion() # g.region -upgc
-        # self.Map.SetRegion() # adjust region to match display window
-
-    def OnUpdateProgress(self, event):
-        """
-        Update progress bar info
-        """
-        self.onRenderGauge.SetValue(event.value)
-        
-        event.Skip()
-        
-    def OnFocus(self, event):
-        """
-        Change choicebook page to match display.
-        Or set display for georectifying
-        """
-        if self.gismanager.georectifying:
-            # in georectifying session; display used to get get geographic
-            # coordinates for GCPs
-            self.OnPointer(event)
-        else:
-            # change bookcontrol page to page associated with display
-            if self.page:
-                pgnum = self.layerbook.GetPageIndex(self.page)
-                if pgnum > -1:
-                    self.layerbook.SetSelection(pgnum)
-        
-        event.Skip()
-
-    def OnMotion(self, event):
-        """
-        Mouse moved
-        Track mouse motion and update status bar
-        """
-        # update statusbar if required
-        if self.toggleStatus.GetSelection() == 0: # Coordinates
-            e, n = self.MapWindow.Pixel2Cell(event.GetPositionTuple())
-            if self.toolbars['vdigit'] and \
-                    self.toolbars['vdigit'].GetAction() == 'addLine' and \
-                    self.toolbars['vdigit'].GetAction('type') in ('line', 'boundary') and \
-                    len(self.MapWindow.polycoords) > 0:
-                # for linear feature show segment and total length
-                distance_seg = self.MapWindow.Distance(self.MapWindow.polycoords[-1],
-                                                       (e, n), screen=False)[0]
-                distance_tot = distance_seg
-                for idx in range(1, len(self.MapWindow.polycoords)):
-                    distance_tot += self.MapWindow.Distance(self.MapWindow.polycoords[idx-1],
-                                                            self.MapWindow.polycoords[idx],
-                                                            screen=False )[0]
-                self.statusbar.SetStatusText("%.2f, %.2f (seg: %.2f; tot: %.2f)" % \
-                                                 (e, n, distance_seg, distance_tot), 0)
-            else:
-                if self.Map.projinfo['proj'] == 'll':
-                    self.statusbar.SetStatusText("%s" % utils.Deg2DMS(e, n), 0)
-                else:
-                    self.statusbar.SetStatusText("%.2f, %.2f" % (e, n), 0)
-        
-        event.Skip()
-
-    def OnDraw(self, event):
-        """
-        Re-display current map composition
-        """
-        self.MapWindow.UpdateMap(render=False)
-        
-    def OnRender(self, event):
-        """
-        Re-render map composition (each map layer)
-        """
-        # delete tmp map layers (queries)
-        qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
-        for layer in qlayer:
-            self.Map.DeleteLayer(layer)
-
-        # delete tmp lines
-        if self.MapWindow.mouse["use"] in ["measure", "profile"]:
-            self.MapWindow.polycoords = []
-            self.MapWindow.ClearLines()
-        
-        # deselect features in vdigit
-        if self.toolbars['vdigit'] and self.digit:
-            self.digit.driver.SetSelected([])
-            self.MapWindow.UpdateMap(render=True, renderVector=True)
-        else:
-            self.MapWindow.UpdateMap(render=True)
-        
-        # update statusbar
-        self.StatusbarUpdate()
-
-    def OnPointer(self, event):
-        """
-        Pointer button clicked
-        """
-        if self.toolbars['map']:
-            if event:
-                self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "pointer"
-        self.MapWindow.mouse['box'] = "point"
-
-        # change the cursor
-        if self.toolbars['vdigit']:
-            # digitization tool activated
-            self.MapWindow.SetCursor(self.cursors["cross"])
-
-            # reset mouse['box'] if needed
-            if self.toolbars['vdigit'].GetAction() in ['addLine']:
-                if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
-                    self.MapWindow.mouse['box'] = 'point'
-                else: # line, boundary
-                    self.MapWindow.mouse['box'] = 'line'
-            elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
-                                                         'editLine', 'displayCats', 'displayAttrs',
-                                                         'copyCats']:
-                self.MapWindow.mouse['box'] = 'point'
-            else: # moveLine, deleteLine
-                self.MapWindow.mouse['box'] = 'box'
-        
-        elif self.gismanager.georectifying:
-            self.MapWindow.SetCursor(self.cursors["cross"])
-        
-        else:
-            self.MapWindow.SetCursor(self.cursors["default"])
-
-    def OnZoomIn(self, event):
-        """
-        Zoom in the map.
-        Set mouse cursor, zoombox attributes, and zoom direction
-        """
-        if self.toolbars['map']:
-            self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "zoom"
-        self.MapWindow.mouse['box'] = "box"
-        self.MapWindow.zoomtype = 1
-        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["cross"])
-
-    def OnZoomOut(self, event):
-        """
-        Zoom out the map.
-        Set mouse cursor, zoombox attributes, and zoom direction
-        """
-        if self.toolbars['map']:
-            self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "zoom"
-        self.MapWindow.mouse['box'] = "box"
-        self.MapWindow.zoomtype = -1
-        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["cross"])
-
-    def OnZoomBack(self, event):
-        """
-        Zoom last (previously stored position)
-        """
-        self.MapWindow.ZoomBack()
-
-    def OnPan(self, event):
-        """
-        Panning, set mouse to drag
-        """
-        if self.toolbars['map']:
-            self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "pan"
-        self.MapWindow.mouse['box'] = "pan"
-        self.MapWindow.zoomtype = 0
-                
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["hand"])
-
-    def OnErase(self, event):
-        """
-        Erase the canvas
-        """
-        self.MapWindow.EraseMap()
-
-    def OnZoomRegion(self, event):
-        """
-        Zoom to region
-        """
-        self.Map.getRegion()
-        self.Map.getResolution()
-        self.UpdateMap()
-        # event.Skip()
-
-    def OnAlignRegion(self, event):
-        """
-        Align region
-        """
-        if not self.Map.alignRegion:
-            self.Map.alignRegion = True
-        else:
-            self.Map.alignRegion = False
-        # event.Skip()
-
-    def OnToggleRender(self, event):
-        """
-        Enable/disable auto-rendering
-        """
-        if self.autoRender.GetValue():
-            self.OnRender(None)
-
-    def OnToggleShowRegion(self, event):
-        """
-        Show/Hide extent in map canvas
-        """
-        if self.showRegion.GetValue():
-            # show extent
-            self.MapWindow.regionCoords = []
-        else:
-            del self.MapWindow.regionCoords
-
-        # redraw map if auto-rendering is enabled
-        if self.autoRender.GetValue():
-            self.OnRender(None)
-
-    def OnToggleResolution(self, event):
-        """
-        Use resolution of computation region settings
-        for redering image instead of display resolution
-        """
-        # redraw map if auto-rendering is enabled
-        if self.autoRender.GetValue():
-            self.OnRender(None)
-        
-    def OnToggleStatus(self, event):
-        """
-        Toggle status text
-        """
-        self.StatusbarUpdate()
-
-    def OnChangeMapScale(self, event):
-        """
-        Map scale changed by user
-        """
-        scale = event.GetString()
-
-        try:
-            if scale[:2] != '1:':
-                raise ValueError
-            value = int(scale[2:])
-        except ValueError:
-            self.mapScale.SetValue('1:%ld' % int(self.mapScaleValue))
-            return
-
-        dEW = value * (self.Map.region['cols'] / self.ppm[0])
-        dNS = value * (self.Map.region['rows'] / self.ppm[1])
-        self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
-        self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
-        self.Map.region['w'] = self.Map.region['center_easting']  - dEW / 2.
-        self.Map.region['e'] = self.Map.region['center_easting']  + dEW / 2.
-        
-        # add to zoom history
-        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                                   self.Map.region['e'], self.Map.region['w'])
-        
-        # redraw a map
-        self.MapWindow.UpdateMap()
-        self.mapScale.SetFocus()
-        
-    def StatusbarUpdate(self):
-        """Update statusbar content"""
-
-        self.showRegion.Hide()
-        self.compResolution.Hide()
-        self.mapScale.Hide()
-        self.mapScaleValue = self.ppm = None
-
-        if self.toggleStatus.GetSelection() == 0: # Coordinates
-            self.statusbar.SetStatusText("", 0)
-            # enable long help
-            self.StatusbarEnableLongHelp()
-
-        elif self.toggleStatus.GetSelection() == 1: # Extent
-            self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f" %
-                                         (self.Map.region["w"], self.Map.region["e"],
-                                          self.Map.region["s"], self.Map.region["n"]), 0)
-            # enable long help
-            self.StatusbarEnableLongHelp()
-
-        elif self.toggleStatus.GetSelection() == 2: # Comp. region
-            compregion = self.Map.GetRegion()
-            self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f (%.2f, %.2f)" %
-                                         (compregion["w"], compregion["e"],
-                                          compregion["s"], compregion["n"],
-                                          compregion["ewres"], compregion["nsres"]), 0)
-            # enable long help
-            self.StatusbarEnableLongHelp()
-
-        elif self.toggleStatus.GetSelection() == 3: # Show comp. extent
-            self.statusbar.SetStatusText("", 0)
-            self.showRegion.Show()
-            # disable long help
-            self.StatusbarEnableLongHelp(False)
-
-        elif self.toggleStatus.GetSelection() == 4: # Display mode
-            self.statusbar.SetStatusText("", 0)
-            self.compResolution.Show()
-            # disable long help
-            self.StatusbarEnableLongHelp(False)
-
-        elif self.toggleStatus.GetSelection() == 5: # Display geometry
-            self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
-                                         (self.Map.region["rows"], self.Map.region["cols"],
-                                          self.Map.region["nsres"], self.Map.region["ewres"]), 0)
-            # enable long help
-            self.StatusbarEnableLongHelp()
-
-        elif self.toggleStatus.GetSelection() == 6: # Map scale
-            # TODO: need to be fixed...
-            ### screen X region problem
-            ### user should specify ppm
-            dc = wx.ScreenDC()
-            dpSizePx = wx.DisplaySize()   # display size in pixels
-            dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
-            dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
-            sysPpi  = dc.GetPPI()
-            comPpi = (dpSizePx[0] / dpSizeIn[0],
-                      dpSizePx[1] / dpSizeIn[1])
-
-            ppi = comPpi                  # pixel per inch
-            self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
-                        (ppi[1] / 2.54) * 100)
-
-            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
-                      "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
-                          (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
-                           dpSizeIn[0], dpSizeIn[1],
-                           sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
-                           self.ppm[0], self.ppm[1]))
-
-            region = self.Map.region
-
-            heightCm = region['rows'] / self.ppm[1] * 100
-            widthCm  = region['cols'] / self.ppm[0] * 100
-
-            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
-                      (widthCm, heightCm))
-
-            xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
-            yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
-            scale = (xscale + yscale) / 2.
-            
-            Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
-                          (xscale, yscale, scale))
-
-            self.statusbar.SetStatusText("")
-            try:
-                self.mapScale.SetValue("1:%ld" % (scale + 0.5))
-            except TypeError:
-                pass
-            self.mapScaleValue = scale
-            self.mapScale.Show()
-
-            # disable long help
-            self.StatusbarEnableLongHelp(False)
-
-        else:
-            self.statusbar.SetStatusText("", 1)
-
-    def StatusbarEnableLongHelp(self, enable=True):
-        """Enable/disable toolbars long help"""
-        for toolbar in self.toolbars.itervalues():
-            if toolbar:
-                toolbar.EnableLongHelp(enable)
-                
-    def StatusbarReposition(self):
-        """Reposition checkbox in statusbar"""
-        # reposition checkbox
-        widgets = [(0, self.showRegion),
-                   (0, self.compResolution),
-                   (0, self.mapScale),
-                   (0, self.onRenderGauge),
-                   (1, self.toggleStatus),
-                   (2, self.maskInfo),
-                   (3, self.autoRender)]
-        for idx, win in widgets:
-            rect = self.statusbar.GetFieldRect(idx)
-            if idx == 0: # show region / mapscale / process bar
-                # -> size
-                wWin, hWin = win.GetBestSize()
-                if win == self.onRenderGauge:
-                    wWin = rect.width - 6
-                # -> position
-                # if win == self.showRegion:
-                    # x, y = rect.x + rect.width - wWin, rect.y - 1
-                    # align left
-                # else:
-                x, y = rect.x + 3, rect.y - 1
-                w, h = wWin, rect.height + 2
-            else: # choice || auto-rendering
-                x, y = rect.x, rect.y - 1
-                w, h = rect.width, rect.height + 2
-                if idx == 2: # mask
-                    x += 5
-                    y += 4
-                elif idx == 3: # render
-                    x += 5
-            
-            win.SetPosition((x, y))
-            win.SetSize((w, h))
-
-    def SaveToFile(self, event):
-        """
-        Save image to file
-        """
-        filetype =  "PNG file (*.png)|*.png|"\
-                    "TIF file (*.tif)|*.tif|"\
-                    "GIF file (*.gif)|*.gif"
-
-        dlg = wx.FileDialog(self, "Choose a file name to save the image as a PNG to",
-            defaultDir = "",
-            defaultFile = "",
-            wildcard = filetype,
-            style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
-        if dlg.ShowModal() == wx.ID_OK:
-            base = os.path.splitext(dlg.GetPath())[0]
-            ext = os.path.splitext(dlg.GetPath())[1]
-            if dlg.GetFilterIndex() == 0:
-                type = wx.BITMAP_TYPE_PNG
-                path = dlg.GetPath()
-                if ext != '.png': path = base+'.png'
-            elif dlg.GetFilterIndex() == 1:
-                type = wx.BITMAP_TYPE_TIF
-                if ext != '.tif': path = base+'.tif'
-            elif dlg.GetFilterIndex() == 2:
-                type = wx.BITMAP_TYPE_TIF
-                if ext != '.gif': path = base+'.gif'
-            self.MapWindow.SaveToFile(path, type)
-
-        dlg.Destroy()
-
-    def PrintMenu(self, event):
-        """
-        Print options and output menu for map display
-        """
-        point = wx.GetMousePosition()
-        printmenu = wx.Menu()
-        # Add items to the menu
-        setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
-        printmenu.AppendItem(setup)
-        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
-
-        preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
-        printmenu.AppendItem(preview)
-        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
-
-        doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
-        printmenu.AppendItem(doprint)
-        self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(printmenu)
-        printmenu.Destroy()
-
-    def OnCloseWindow(self, event):
-        """
-        Window closed.
-        Also close associated layer tree page
-        """
-        pgnum = None
-        self.Map.Clean()
-        
-        # close edited map and 3D tools properly
-        if self.toolbars['vdigit']:
-            maplayer = self.toolbars['vdigit'].GetLayer()
-            if maplayer:
-                self.toolbars['vdigit'].OnExit()
-                self.imgVectorMap = None
-
-        if self.toolbars['nviz']:
-            self.toolbars['nviz'].OnExit()
-        
-        if self.page:
-            pgnum = self.layerbook.GetPageIndex(self.page)
-            if pgnum > -1:
-                self.layerbook.DeletePage(pgnum)
-        
-        ### self.Destroy()
-        # if event:
-        #    event.Skip() <- causes application crash
-        
-    def GetRender(self):
-        """
-        Returns the current instance of render.Map()
-        """
-        return self.Map
-
-    def OnQueryDisplay(self, event):
-        """
-        Query currrent raster/vector map layers (display mode)
-        """
-        if self.toolbars['map'].GetAction() == 'displayAttrb': # select previous action
-            self.toolbars['map'].SelectDefault(event)
-            return
-
-        self.toolbars['map'].action['desc'] = 'displayAttrb'
-        
-        # switch GIS Manager to output console to show query results
-        self.gismanager.notebook.SetSelection(1)
-
-        self.MapWindow.mouse['use'] = "query"
-        self.MapWindow.mouse['box'] = "point"
-        self.MapWindow.zoomtype = 0
-
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["cross"])
-
-    def OnQueryModify(self, event):
-        """
-        Query vector map layer (edit mode)
-        """
-        if self.toolbars['map'].GetAction() == 'modifyAttrb': # select previous action
-            self.toolbars['map'].SelectDefault(event)
-            return
-        
-        self.toolbars['map'].action['desc'] = 'modifyAttrb'
-        
-        self.MapWindow.mouse['use'] = "queryVector"
-        self.MapWindow.mouse['box'] = "point"
-        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-        self.MapWindow.zoomtype = 0
-
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["cross"])
-        
-    def QueryMap(self, x, y):
-        """!Query map layer features
-
-        Currently only raster and vector map layers are supported.
-        
-        @param x,y coordinates
-        """
-        #set query snap distance for v.what at mapunit equivalent of 10 pixels
-        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
-        east, north = self.MapWindow.Pixel2Cell((x, y))
-
-        num = 0
-        for layer in self.tree.GetSelections():
-            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
-            if type in ('raster', 'rgb', 'his',
-                        'vector', 'thememap', 'themechart'):
-                num += 1
-        
-        if num < 1:
-            dlg = wx.MessageDialog(parent=self,
-                                   message=_('No raster or vector map layer selected for querying.'),
-                                   caption=_('No map layer selected'),
-                                   style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-            dlg.ShowModal()
-            dlg.Destroy()
-            return
-        
-        mapname = None
-        raststr = ''
-        vectstr = ''
-        rcmd = []
-        vcmd = []
-        for layer in self.tree.GetSelections():
-            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
-            dcmd = self.tree.GetPyData(layer)[0]['cmd']
-            name = utils.GetLayerNameFromCmd(dcmd)
-            if name == '':
-                continue
-            if type in ('raster', 'rgb', 'his'):
-                raststr += "%s," % name
-            elif type in ('vector', 'thememap', 'themechart'):
-                vectstr += "%s," % name
-
-        # use display region settings instead of computation region settings
-        self.tmpreg = os.getenv("GRASS_REGION")
-        os.environ["GRASS_REGION"] = self.Map.SetRegion(windres=False)
-        
-        # build query commands for any selected rasters and vectors
-        if raststr != '':
-            rcmd = ['r.what', '--q',
-                    '-f',
-                    'input=%s' % raststr.rstrip(','),
-                    'east_north=%f,%f' % (float(east), float(north))]
-
-        if vectstr != '':
-            # check for vector maps open to be edited
-            digitToolbar = self.toolbars['vdigit']
-            if digitToolbar:
-                map = digitToolbar.GetLayer().GetName()
-                vect = []
-                for vector in vectstr.split(','):
-                    if map == vector:
-                        self.gismanager.goutput.WriteWarning("Vector map <%s> "
-                                                             "opened for editing - skipped." % map)
-                        continue
-                    vect.append(vector)
-                vectstr = ','.join(vect)
-                
-            if len(vectstr) <= 1:
-                self.gismanager.goutput.WriteCmdLog("Nothing to query.")
-                return
-            
-            vcmd = ['v.what', '--q',
-                    '-a',
-                    'map=%s' % vectstr.rstrip(','),
-                    'east_north=%f,%f' % (float(east), float(north)),
-                    'distance=%f' % qdist]
-
-        # parse query command(s)
-        if self.gismanager:
-            if rcmd:
-                self.gismanager.goutput.RunCmd(rcmd, compReg=False,
-                                               onDone = self._QueryMapDone)
-            if vcmd:
-                self.gismanager.goutput.RunCmd(vcmd,
-                                               onDone = self._QueryMapDone)
-        else:
-            if rcmd:
-                gcmd.Command(rcmd)
-            if vcmd:
-                gcmd.Command(vcmd)
-
-    def _QueryMapDone(self, returncode):
-        """!Restore settings after querying (restore GRASS_REGION)
-
-        @param returncode command return code
-        """
-        if hasattr(self, "tmpreg"):
-            if self.tmpreg:
-                os.environ["GRASS_REGION"] = self.tmpreg
-            elif os.environ.has_key('GRASS_REGION'):
-                del os.environ["GRASS_REGION"]
-        elif os.environ.has_key('GRASS_REGION'):
-            del os.environ["GRASS_REGION"]
-        
-        if hasattr(self, "tmpreg"):
-            del self.tmpreg
-        
-    def QueryVector(self, x, y):
-        """
-        Query vector map layer features
-
-        Attribute data of selected vector object are displayed in GUI dialog.
-        Data can be modified (On Submit)
-        """
-        if not self.tree.layer_selected or \
-                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
-            wx.MessageBox(parent=self,
-                          message=_("No vector map selected for querying."),
-                          caption=_("Vector querying"),
-                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-            return
-        
-        if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
-                grass.gisenv()['MAPSET']:
-            wx.MessageBox(parent=self,
-                          message=_("Only vector map from the current mapset can be modified."),
-                          caption=_("Vector querying"),
-                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-            return
-        
-        posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
-                                         y + self.MapWindow.dialogOffset))
-
-        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / \
-                            self.Map.width)
-        east, north = self.MapWindow.Pixel2Cell((x, y))
-
-        mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
-        
-        if self.dialogs['attributes'] is None:
-            self.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self.MapWindow,
-                                                                     map=mapName,
-                                                                     query=((east, north), qdist),
-                                                                     pos=posWindow,
-                                                                     action="update")
-        else:
-            # selection changed?
-            if not self.dialogs['attributes'].mapDBInfo or \
-                   self.dialogs['attributes'].mapDBInfo.map != mapName:
-                self.dialogs['attributes'].UpdateDialog(map=mapName, query=((east, north), qdist))
-            else:
-                self.dialogs['attributes'].UpdateDialog(query=((east, north), qdist))
-
-        cats = self.dialogs['attributes'].GetCats()
-        try:
-            qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)[0]
-        except IndexError:
-            qlayer = None
-        
-        if self.dialogs['attributes'].mapDBInfo and cats:
-            # highlight feature & re-draw map
-            if qlayer:
-                qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
-                                                        useId=False,
-                                                        addLayer=False))
-            else:
-                qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId=False)
-
-            # set opacity based on queried layer
-            opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float=True)
-            qlayer.SetOpacity(opacity)
-            
-            self.MapWindow.UpdateMap(render=False, renderVector=False)
-            if not self.dialogs['attributes'].IsShown():
-                self.dialogs['attributes'].Show()
-        else:
-            if qlayer:
-                self.Map.DeleteLayer(qlayer)
-                self.MapWindow.UpdateMap(render=False, renderVector=False)
-            if self.dialogs['attributes'].IsShown():
-                self.dialogs['attributes'].Hide()
-
-    def OnQuery(self, event):
-        """Query tools menu"""
-        if self.toolbars['map']:
-            self.toolbars['map'].OnTool(event)
-            action = self.toolbars['map'].GetAction()
-        
-        point = wx.GetMousePosition()
-        toolsmenu = wx.Menu()
-        # Add items to the menu
-        display = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
-                              text=_("Query raster/vector map(s) (display mode)"),
-                              kind=wx.ITEM_CHECK)
-        toolsmenu.AppendItem(display)
-        self.Bind(wx.EVT_MENU, self.OnQueryDisplay, display)
-        numLayers = 0
-        for layer in self.tree.GetSelections():
-            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
-            if type in ('raster', 'rgb', 'his',
-                        'vector', 'thememap', 'themechart'):
-                numLayers += 1
-        if numLayers < 1:
-            display.Enable(False)
-        
-        if action == "displayAttrb":
-            display.Check(True)
-        
-        modify = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
-                             text=_("Query vector map (edit mode)"),
-                             kind=wx.ITEM_CHECK)
-        toolsmenu.AppendItem(modify)
-        self.Bind(wx.EVT_MENU, self.OnQueryModify, modify)
-        digitToolbar = self.toolbars['vdigit']
-        if self.tree.layer_selected:
-            layer_selected = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer']
-            if layer_selected.GetType() != 'vector' or \
-                    (digitToolbar and \
-                         digitToolbar.GetLayer() == layer_selected):
-                modify.Enable(False)
-            else:
-                if action == "modifyAttrb":
-                    modify.Check(True)
-        
-        self.PopupMenu(toolsmenu)
-        toolsmenu.Destroy()
-
-    def AddTmpVectorMapLayer(self, name, cats, useId=False, addLayer=True):
-        """
-        Add temporal vector map layer to map composition
-
-        @param name name of map layer
-        @param useId use feature id instead of category 
-        """
-        # color settings from ATM
-        color = UserSettings.Get(group='atm', key='highlight', subkey='color')
-        colorStr = str(color[0]) + ":" + \
-        str(color[1]) + ":" + \
-        str(color[2])
-
-        pattern = ["d.vect",
-                   "map=%s" % name,
-                   "color=%s" % colorStr,
-                   "fcolor=%s" % colorStr,
-                   "width=%d"  % UserSettings.Get(group='atm', key='highlight', subkey='width')]
-        
-        if useId:
-            cmd = pattern
-            cmd.append('-i')
-            cmd.append('cats=%s' % str(cats))
-        else:
-            cmd = []
-            for layer in cats.keys():
-                cmd.append(copy.copy(pattern))
-                lcats = cats[layer]
-                cmd[-1].append("layer=%d" % layer)
-                cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
-        
-        #     if self.icon:
-        #         cmd.append("icon=%s" % (self.icon))
-        #     if self.pointsize:
-        #         cmd.append("size=%s" % (self.pointsize))
-
-        if addLayer:
-            if useId:
-                return self.Map.AddLayer(type='vector', name=globalvar.QUERYLAYER, command=cmd,
-                                         l_active=True, l_hidden=True, l_opacity=1.0)
-            else:
-                return self.Map.AddLayer(type='command', name=globalvar.QUERYLAYER, command=cmd,
-                                         l_active=True, l_hidden=True, l_opacity=1.0)
-        else:
-            return cmd
-
-    def OnAnalyze(self, event):
-        """
-        Analysis tools menu
-        """
-        point = wx.GetMousePosition()
-        toolsmenu = wx.Menu()
-        # Add items to the menu
-        measure = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["measure"].GetLabel())
-        measure.SetBitmap(Icons["measure"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(measure)
-        self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
-
-        profile = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["profile"].GetLabel())
-        profile.SetBitmap(Icons["profile"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(profile)
-        self.Bind(wx.EVT_MENU, self.Profile, profile)
-
-        histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["histogram"].GetLabel())
-        histogram.SetBitmap(Icons["histogram"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(histogram)
-        self.Bind(wx.EVT_MENU, self.Histogram, histogram)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(toolsmenu)
-        toolsmenu.Destroy()
-
-    def OnMeasure(self, event):
-        """
-        Init measurement routine that calculates
-        map distance along transect drawn on
-        map display
-        """
-
-        self.totaldist = 0.0 # total measured distance
-
-        # switch GIS Manager to output console to show measure results
-        self.gismanager.notebook.SetSelection(1)
-
-        # change mouse to draw line for measurement
-        self.MapWindow.mouse['use'] = "measure"
-        self.MapWindow.mouse['box'] = "line"
-        self.MapWindow.zoomtype = 0
-        self.MapWindow.pen     = wx.Pen(colour='red', width=2, style=wx.SHORT_DASH)
-        self.MapWindow.polypen = wx.Pen(colour='green', width=2, style=wx.SHORT_DASH)
-
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["pencil"])
-
-        # initiating output
-        style = self.gismanager.goutput.cmd_output.StyleWarning
-        self.gismanager.goutput.WriteLog(_('Click and drag with left mouse button '
-                                           'to measure.%s'
-                                           'Double click with left button to clear.') % \
-                                             (os.linesep), style)
-        if self.Map.projinfo['proj'] != 'xy':
-            units = self.Map.projinfo['units']
-            style = self.gismanager.goutput.cmd_output.StyleCommand
-            self.gismanager.goutput.WriteLog(_('Measuring distance') + ' ('
-                                             + units + '):',
-                                             style)
-        else:
-            self.gismanager.goutput.WriteLog(_('Measuring distance:'),
-                                             style)
-
-    def MeasureDist(self, beginpt, endpt):
-        """
-        Calculate map distance from screen distance
-        and print to output window
-        """
-
-        if self.gismanager.notebook.GetSelection() != 1:
-            self.gismanager.notebook.SetSelection(1)
-
-        dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
-
-        dist = round(dist, 3)
-        d, dunits = self.FormatDist(dist)
-
-        self.totaldist += dist
-        td, tdunits = self.FormatDist(self.totaldist)
-
-        strdist = str(d)
-        strtotdist = str(td)
-
-        if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
-            angle = int(math.degrees(math.atan2(north,east)) + 0.5)
-            angle = 180 - angle
-            if angle < 0:
-                angle = 360+angle
-
-            mstring = 'segment = %s %s\ttotal distance = %s %s\tbearing = %d deg' \
-                % (strdist,dunits,strtotdist,tdunits,angle)
-        else:
-            mstring = 'segment = %s %s\ttotal distance = %s %s' \
-                % (strdist,dunits,strtotdist,tdunits)
-
-        self.gismanager.goutput.WriteLog(mstring)
-
-        return dist
-
-    def Profile(self, event):
-        """
-        Init profile canvas and tools
-        """
-        raster = []
-        if self.tree.layer_selected and \
-               self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
-            raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-
-        self.profile = profile.ProfileFrame(self,
-                                            id=wx.ID_ANY, pos=wx.DefaultPosition, size=(700,300),
-                                            style=wx.DEFAULT_FRAME_STYLE, rasterList=raster)
-        self.profile.Show()
-        # Open raster select dialog to make sure that a raster (and the desired raster)
-        # is selected to be profiled
-        self.profile.OnSelectRaster(None)
-
-    def FormatDist(self, dist):
-        """Format length numbers and units in a nice way,
-        as a function of length. From code by Hamish Bowman
-        Grass Development Team 2006"""
-
-        mapunits = self.Map.projinfo['units']
-        if mapunits == 'metres': mapunits = 'meters'
-        outunits = mapunits
-        dist = float(dist)
-        divisor = 1.0
-
-        # figure out which units to use
-        if mapunits == 'meters':
-            if dist > 2500.0:
-                outunits = 'km'
-                divisor = 1000.0
-            else: outunits = 'm'
-        elif mapunits == 'feet':
-            # nano-bug: we match any "feet", but US Survey feet is really
-            #  5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
-            #  miles the tick markers are rounded to the nearest 10th of a
-            #  mile (528'), the difference in foot flavours is ignored.
-            if dist > 5280.0:
-                outunits = 'miles'
-                divisor = 5280.0
-            else:
-                outunits = 'ft'
-        elif 'degree' in mapunits:
-            if dist < 1:
-                outunits = 'min'
-                divisor = (1/60.0)
-            else:
-                outunits = 'deg'
-
-        # format numbers in a nice way
-        if (dist/divisor) >= 2500.0:
-            outdist = round(dist/divisor)
-        elif (dist/divisor) >= 1000.0:
-            outdist = round(dist/divisor,1)
-        elif (dist/divisor) > 0.0:
-            outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
-        else:
-            outdist = float(dist/divisor)
-
-        return (outdist, outunits)
-
-
-    def Histogram(self, event):
-        """
-        Init histogram display canvas and tools
-        """
-        self.histogram = histogram.HistFrame(self,
-                                             id=wx.ID_ANY, size=globalvar.HIST_WINDOW_SIZE,
-                                             style=wx.DEFAULT_FRAME_STYLE)
-
-        #show new display
-        self.histogram.Show()
-        self.histogram.Refresh()
-        self.histogram.Update()
-
-
-    def OnDecoration(self, event):
-        """
-        Decorations overlay menu
-        """
-        point = wx.GetMousePosition()
-        decmenu = wx.Menu()
-        # Add items to the menu
-        AddScale = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addbarscale"].GetLabel())
-        AddScale.SetBitmap(Icons["addbarscale"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddScale)
-        self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
-
-        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addlegend"].GetLabel())
-        AddLegend.SetBitmap(Icons["addlegend"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddLegend)
-        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
-
-        AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addtext"].GetLabel())
-        AddText.SetBitmap(Icons["addtext"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddText)
-        self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(decmenu)
-        decmenu.Destroy()
-
-    def OnAddBarscale(self, event):
-        """
-        Handler for scale/arrow map decoration menu selection.
-        """
-        if self.dialogs['barscale']:
-            return
-
-        id = 0 # unique index for overlay layer
-
-        # If location is latlon, only display north arrow (scale won't work)
-        #        proj = self.Map.projinfo['proj']
-        #        if proj == 'll':
-        #            barcmd = 'd.barscale -n'
-        #        else:
-        #            barcmd = 'd.barscale'
-
-        # decoration overlay control dialog
-        self.dialogs['barscale'] = \
-            gdialogs.DecorationDialog(parent=self, title=_('Scale and North arrow'),
-                                      size=(350, 200),
-                                      style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                                      cmd=['d.barscale', 'at=0,5'],
-                                      ovlId=id,
-                                      name='barscale',
-                                      checktxt = _("Show/hide scale and North arrow"),
-                                      ctrltxt = _("scale object"))
-
-        self.dialogs['barscale'].CentreOnParent()
-        ### dialog cannot be show as modal - in the result d.barscale is not selectable
-        ### self.dialogs['barscale'].ShowModal()
-        self.dialogs['barscale'].Show()
-        self.MapWindow.mouse['use'] = 'pointer'        
-
-    def OnAddLegend(self, event):
-        """
-        Handler for legend map decoration menu selection.
-        """
-        if self.dialogs['legend']:
-            return
-        
-        id = 1 # index for overlay layer in render
-
-        cmd = ['d.legend', 'at=5,50,2,5']
-        if self.tree.layer_selected and \
-               self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
-            cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-
-        # Decoration overlay control dialog
-        self.dialogs['legend'] = \
-            gdialogs.DecorationDialog(parent=self, title=('Legend'),
-                                      size=(350, 200),
-                                      style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                                      cmd=cmd,
-                                      ovlId=id,
-                                      name='legend',
-                                      checktxt = _("Show/hide legend"),
-                                      ctrltxt = _("legend object")) 
-
-        self.dialogs['legend'].CentreOnParent() 
-        ### dialog cannot be show as modal - in the result d.legend is not selectable
-        ### self.dialogs['legend'].ShowModal()
-        self.dialogs['legend'].Show()
-        self.MapWindow.mouse['use'] = 'pointer'
-
-    def OnAddText(self, event):
-        """
-        Handler for text decoration menu selection.
-        """
-        if self.MapWindow.dragid > -1:
-            id = self.MapWindow.dragid
-        else:
-            # index for overlay layer in render
-            if len(self.MapWindow.textdict.keys()) > 0:
-                id = self.MapWindow.textdict.keys()[-1] + 1
-            else:
-                id = 101
-
-        self.dialogs['text'] = gdialogs.TextLayerDialog(parent=self, ovlId=id, 
-                                                    title=_('Add text layer'),
-                                                    size=(400, 200))
-        self.dialogs['text'].CenterOnParent()
-
-        # If OK button pressed in decoration control dialog
-        if self.dialogs['text'].ShowModal() == wx.ID_OK:
-            text = self.dialogs['text'].GetValues()['text']
-            active = self.dialogs['text'].GetValues()['active']
-            coords, w, h = self.MapWindow.TextBounds(self.dialogs['text'].GetValues())
-        
-            # delete object if it has no text or is not active
-            if text == '' or active == False:
-                try:
-                    self.MapWindow.pdc.ClearId(id)
-                    self.MapWindow.pdc.RemoveId(id)
-                    del self.MapWindow.textdict[id]
-                except:
-                    pass
-                return
-
-            self.MapWindow.pdc.ClearId(id)
-            self.MapWindow.pdc.SetId(id)
-            self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
-            
-            self.MapWindow.Draw(self.MapWindow.pdcDec, img=self.MapWindow.textdict[id],
-                                drawid=id, pdctype='text', coords=coords)
-            
-            self.MapWindow.UpdateMap(render=False, renderVector=False)
-            
-        self.MapWindow.mouse['use'] = 'pointer'
-
-    def GetOptData(self, dcmd, type, params, propwin):
-        """
-        Callback method for decoration overlay command generated by
-        dialog created in menuform.py
-        """
-        # Reset comand and rendering options in render.Map. Always render decoration.
-        # Showing/hiding handled by PseudoDC
-        self.Map.ChangeOverlay(ovltype=type, type='overlay', name='', command=dcmd,
-                               l_active=True, l_render=False)
-        self.params[type] = params
-        self.propwin[type] = propwin
-
-    def OnZoomMenu(self, event):
-        """
-        Zoom menu
-        """
-        point = wx.GetMousePosition()
-        zoommenu = wx.Menu()
-        # Add items to the menu
-        zoommap = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to selected map(s)'))
-        zoommenu.AppendItem(zoommap)
-        self.Bind(wx.EVT_MENU, self.MapWindow.OnZoomToMap, zoommap)
-
-        zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
-        zoommenu.AppendItem(zoomwind)
-        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToWind, zoomwind)
-
-        zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
-        zoommenu.AppendItem(zoomdefault)
-        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToDefault, zoomdefault)
-
-        zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
-        zoommenu.AppendItem(zoomsaved)
-        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToSaved, zoomsaved)
-
-        savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
-        zoommenu.AppendItem(savewind)
-        self.Bind(wx.EVT_MENU, self.MapWindow.DisplayToWind, savewind)
-
-        savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
-        zoommenu.AppendItem(savezoom)
-        self.Bind(wx.EVT_MENU, self.MapWindow.SaveDisplayRegion, savezoom)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(zoommenu)
-        zoommenu.Destroy()
-
-    def SetProperties(self, render=False, mode=0, showCompExtent=False,
-                      constrainRes=False):
-        """Set properies of map display window"""
-        self.autoRender.SetValue(render)
-        self.toggleStatus.SetSelection(mode)
-        self.StatusbarUpdate()
-        self.showRegion.SetValue(showCompExtent)
-        self.compResolution.SetValue(constrainRes)
-        if showCompExtent:
-            self.MapWindow.regionCoords = []
-        
-    def IsStandalone(self):
-        """!Check if Map display is standalone"""
-        if self.gismanager:
-            return False
-        
-        return True
-    
-    def GetLayerManager(self):
-        """!Get reference to Layer Manager
-
-        @return window reference
-        @return None (if standalone)
-        """
-        return self.gismanager
-
-# end of class MapFrame
-
-class MapApp(wx.App):
-    """
-    MapApp class
-    """
-
-    def OnInit(self):
-        wx.InitAllImageHandlers()
-        if __name__ == "__main__":
-            Map = render.Map() # instance of Map class to render GRASS display output to PPM file
-        else:
-            Map = None
-
-        self.mapFrm = MapFrame(parent=None, id=wx.ID_ANY, Map=Map, size=(640,480))
-        #self.SetTopWindow(Map)
-        self.mapFrm.Show()
-
-        if __name__ == "__main__":
-            # redraw map, if new command appears
-            self.redraw = False
-            status = Command(self, Map)
-            status.start()
-            self.timer = wx.PyTimer(self.watcher)
-            # check each 0.1s
-            self.timer.Start(100)
-
-        return 1
-
-    def OnExit(self):
-        if __name__ == "__main__":
-            # stop the timer
-            self.timer.Stop()
-            # terminate thread (a bit ugly)
-            os.system("""echo "quit" >> %s""" % (cmdfilename))
-
-    def watcher(self):
-        """Redraw, if new layer appears"""
-        if self.redraw:
-            self.mapFrm.OnDraw(None)
-        self.redraw = False
-        return
-# end of class MapApp
-
-if __name__ == "__main__":
-
-    ###### SET command variable
-    if len(sys.argv) != 3:
-        print __doc__
-        sys.exit()
-
-    title = sys.argv[1]
-    cmdfilename = sys.argv[2]
-
-    import gettext
-    gettext.install("gm_map") # replace with the appropriate catalog name
-
-    print "Starting monitor <%s>" % (title)
-
-    gm_map = MapApp(0)
-    # set title
-    gm_map.mapFrm.SetTitle ("GRASS GIS - Map Display: " + title + " - Location: " + \
-                                grass.gisenv()['LOCATION_NAME'])
-    gm_map.MainLoop()
-
-    if grass.gisenv().has_key("MONITOR"):
-        os.system("d.mon sel=%s" % grass.gisenv()["MONITOR"])
-
-    os.remove(cmdfilename)
-    os.system("""g.gisenv set="GRASS_PYCMDFILE" """)
-
-    print "Stoping monitor <%s>" % (title)
-
-    sys.exit()

Added: grass-addons/gui/wxpython/data_catalog/mapframe.py
===================================================================
--- grass-addons/gui/wxpython/data_catalog/mapframe.py	                        (rev 0)
+++ grass-addons/gui/wxpython/data_catalog/mapframe.py	2010-02-04 04:58:00 UTC (rev 40807)
@@ -0,0 +1,4235 @@
+"""
+ at package mapdisp.py
+
+ at brief GIS map display canvas, with toolbar for various display
+management functions, and second toolbar for vector
+digitizing. 
+
+Can be used either from GIS Manager or as p.mon backend.
+
+Classes:
+ - Command
+ - MapWindow
+ - BufferedWindow
+ - MapFrame
+ - MapApp
+
+Usage:
+ python mapdisp.py monitor-identifier /path/to/command/file
+
+(C) 2006-2008 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 Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import time
+import glob
+import math
+import tempfile
+import copy
+
+import globalvar
+if not os.getenv("GRASS_WXBUNDLED"):
+    globalvar.CheckForWx()
+import wx
+import wx.aui
+
+from threading import Thread
+try:
+    import subprocess
+except:
+    CompatPath = os.path.join(globalvar.ETCWXDIR)
+    sys.path.append(CompatPath)
+    from compat import subprocess
+
+gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
+sys.path.append(gmpath)
+
+import render
+import toolbars
+import track
+import menuform
+import gselect
+import disp_print
+import gcmd
+import dbm
+import histogram
+import profile
+import globalvar
+import utils
+import gdialogs
+from grass.script import core as grass
+from vdigit import VDigitCategoryDialog as VDigitCategoryDialog
+from vdigit import VDigitZBulkDialog    as VDigitZBulkDialog
+from vdigit import VDigitDuplicatesDialog as VDigitDuplicatesDialog
+from vdigit import GV_LINES            as VDigit_Lines_Type
+from debug import Debug               as Debug
+from icon  import Icons               as Icons
+from preferences import globalSettings as UserSettings
+
+import images
+imagepath = images.__path__[0]
+sys.path.append(imagepath)
+
+###
+### global variables
+###
+# for standalone app
+cmdfilename = None
+
+class Command(Thread):
+    """
+    Creates thread which will observe the command file and see, if
+    there is new command to be executed
+    """
+    def __init__ (self, parent, Map):
+        Thread.__init__(self)
+
+        global cmdfilename
+
+        self.parent = parent
+        self.map = Map
+        self.cmdfile = open(cmdfilename, "r")
+
+    def run(self):
+        """
+        Run this in thread
+        """
+        dispcmd = []
+        while 1:
+            self.parent.redraw = False
+            line = self.cmdfile.readline().strip()
+            if line == "quit":
+                break
+
+            if line:
+                try:
+                    Debug.msg (3, "Command.run(): cmd=%s" % (line))
+
+                    self.map.AddLayer(item=None, type="raster",
+                                      name='',
+                                      command=line,
+                                      l_opacity=1)
+
+                    self.parent.redraw =True
+
+                except Exception, e:
+                    print "Command Thread: ",e
+
+            time.sleep(0.1)
+
+        sys.exit()
+
+class MapWindow(object):
+    """
+    Abstract map window class
+
+    Parent for BufferedWindow class (2D display mode) and
+    GLWindow (3D display mode)
+    """
+    def __init__(self, parent, id=wx.ID_ANY,
+                 pos=wx.DefaultPosition,
+                 size=wx.DefaultSize,
+                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
+                 Map=None, tree=None, gismgr=None):
+        self.parent = parent # MapFrame
+
+        #
+        # mouse attributes like currently pressed buttons, position on
+        # the screen, begin and end of dragging, and type of drawing
+        #
+        self.mouse = {
+            'l'    : False,
+            'r'    : False,
+            'm'    : False,
+            'begin': [0, 0], # screen coordinates
+            'end'  : [0, 0],
+            'use'  : "pointer",
+            'box'  : "point"
+            }
+        
+    def EraseMap(self):
+        """
+        Erase the canvas (virtual method)
+        """
+        pass
+
+    def UpdateMap(self):
+        """
+        Updates the canvas anytime there is a change to the
+        underlaying images or to the geometry of the canvas.
+        """
+        pass
+
+    def OnLeftDown(self, event):
+        pass
+
+    def OnLeftUp(self, event):
+        pass
+
+    def OnMouseMotion(self, event):
+        pass
+
+    def OnZoomToMap(self, event):
+        pass
+
+    def OnZoomToRaster(self, event):
+        pass
+
+    def GetSelectedLayer(self, type = 'layer', multi = False):
+        """
+        Get selected layer from layer tree
+
+        @param type 'item' / 'layer' / 'nviz'
+        @param multi return first selected layer or all
+        
+        @return layer / map layer properties / nviz properties
+        @return None / [] on failure
+        """
+        ret = []
+        if not self.tree or \
+                not self.tree.GetSelection():
+            if multi:
+                return []
+            else:
+                return None
+        
+        if multi and \
+                type == 'item':
+            return self.tree.GetSelections()
+        
+        for item in self.tree.GetSelections():
+            if not item.IsChecked():
+                if multi:
+                    continue
+                else:
+                    return None
+
+            if type == 'item': # -> multi = False
+                return item
+        
+            try:
+                if type == 'nviz':
+                    layer = self.tree.GetPyData(item)[0]['nviz']
+                else:
+                    layer = self.tree.GetPyData(item)[0]['maplayer']
+            except:
+                layer = None
+
+            if multi:
+                ret.append(layer)
+            else:
+                return layer
+            
+        return ret
+
+class BufferedWindow(MapWindow, wx.Window):
+    """
+    A Buffered window class.
+
+    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(self,file_name,file_type) method.
+    """
+
+    def __init__(self, parent, id,
+                 pos = wx.DefaultPosition,
+                 size = wx.DefaultSize,
+                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
+                 Map=None, tree=None, gismgr=None):
+
+        MapWindow.__init__(self, parent, id, pos, size, style,
+                           Map, tree, gismgr)
+        wx.Window.__init__(self, parent, id, pos, size, style)
+
+        self.Map = Map
+        self.tree = tree
+        self.gismanager = gismgr
+
+        book= self.GetParent()
+        q=book.GetParent()
+        r=q.GetParent()
+        splitter=r.GetParent()
+        self.gframe=splitter.GetParent()
+
+        #
+        # Flags
+        #
+        self.resize = False # indicates whether or not a resize event has taken place
+        self.dragimg = None # initialize variable for map panning
+
+        #
+        # Variable 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
+        
+        #
+        # Event bindings
+        #
+        self.Bind(wx.EVT_PAINT,        self.OnPaint)
+        self.Bind(wx.EVT_SIZE,         self.OnSize)
+        self.Bind(wx.EVT_IDLE,         self.OnIdle)
+        self.Bind(wx.EVT_MOTION,       self.MouseActions)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
+        self.processMouse = True
+        
+        #
+        # Render output objects
+        #
+        self.mapfile = None   # image file to be rendered
+        self.img = ""         # wx.Image object (self.mapfile)
+        # used in digitization tool (do not redraw vector map)
+        self.imgVectorMap = None
+        # decoration overlays
+        self.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
+        self.currtxtid = None # PseudoDC id for currently selected text
+
+        #
+        # 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)
+
+        # 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()
+        # 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 = ''
+
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
+
+        # vars for handling mouse clicks
+        self.dragid   = -1
+        self.lastpos  = (0, 0)
+
+    def Draw(self, pdc, img=None, drawid=None, pdctype='image', coords=[0, 0, 0, 0]):
+        """
+        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()
+        
+        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)
+        ### pdc.Clear()
+
+        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, (coords[0],coords[1], w, h))
+
+        elif pdctype == 'box': # draw a box on top of the map
+            if self.pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.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)
+                # self.ovlcoords[drawid] = coords
+
+        elif pdctype == 'line': # draw a line on top of the map
+            if self.pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.pen)
+                pdc.DrawLine(coords[0], coords[1], coords[2], coords[3])
+                pdc.SetIdBounds(drawid,(coords[0], coords[1], coords[2], coords[3]))
+                # self.ovlcoords[drawid] = coords
+
+        elif pdctype == 'polyline': # draw a polyline on top of the map
+            if self.polypen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.polypen)
+                pdc.DrawLines(coords)
+
+                # 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,(x1,y1,x2,y2))
+                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
+
+        elif pdctype == 'point': # draw point
+            if self.pen:
+                pdc.SetPen(self.pen)
+                pdc.DrawPoint(coords[0], coords[1])
+                coordsBound = (coords[0] - 5,
+                               coords[1] - 5,
+                               coords[0] + 5,
+                               coords[1] + 5)
+                pdc.SetIdBounds(drawid, coordsBound)
+                # self.ovlcoords[drawid] = coords
+
+        elif pdctype == 'text': # draw text on top of map
+            if not img['active']:
+                return #only draw active text
+            if img.has_key('rotation'):
+                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, w, h = 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, (coords[0], coords[1], w, h))
+            
+        pdc.EndDrawing()
+        
+        self.Refresh()
+        
+        return drawid
+
+    def TextBounds(self, textinfo):
+        """
+        Return text boundary data
+
+        @param textinfo text metadata (text, font, color, rotation)
+        @param coords reference point
+        """
+        if textinfo.has_key('rotation'):
+            rotation = float(textinfo['rotation'])
+        else:
+            rotation = 0.0
+        
+        coords = textinfo['coords']
+        
+        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
+                   (textinfo['text'], rotation))
+
+        self.Update()
+        ### self.Refresh()
+
+        self.SetFont(textinfo['font'])
+
+        w, h = self.GetTextExtent(textinfo['text'])
+
+        if rotation == 0:
+            coords[2], coords[3] = coords[0] + w, coords[1] + h
+            return coords, w, h
+
+        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
+        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
+        coords[2] = coords[0] + boxw
+        coords[3] = coords[1] + boxh
+        
+        return coords, boxw, boxh
+
+    def OnPaint(self, event):
+        """
+        Draw PseudoDC's to buffered paint DC
+
+        self.pdc for background and decorations
+        self.pdcVector for vector map which is edited
+        self.pdcTmp for temporaly drawn objects (self.polycoords)
+
+        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.SetBackground(wx.Brush("White"))
+        dc.Clear()
+
+        # use PrepareDC to set position correctly
+        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 self.pdcVector:
+                # 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 self.pdcVector:
+                    # 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))
+
+            pdcLast = wx.PseudoDC()
+            pdcLast.DrawBitmap(bmp=self.bufferLast, x=0, y=0)
+            pdcLast.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
+        """
+        Debug.msg(3, "BufferedWindow.OnSize():")
+
+        # set size of the input image
+        self.Map.ChangeMapSize(self.GetClientSize())
+        # align extent based on center point and display resolution
+        # this causes that image is not resized when display windows is resized
+        # self.Map.AlignExtentFromDisplay()
+
+        # 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 = 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
+        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
+            self.img = self.img.Scale(self.Map.width, self.Map.height)
+            if len(self.Map.GetListOfLayers()) > 0:
+                self.UpdateMap()
+
+        # re-render image on idle
+        self.resize = True
+
+        # reposition checkbox in statusbar
+        self.parent.StatusbarReposition()
+
+        # update statusbar
+        self.parent.StatusbarUpdate()
+
+    def OnIdle(self, event):
+        """
+        Only re-render a composite map image from GRASS during
+        idle time instead of multiple times during resizing.
+        """
+        if self.resize:
+            self.UpdateMap(render=True)
+
+        event.Skip()
+
+    def SaveToFile(self, FileName, FileType):
+        """
+        This draws the psuedo DC to a buffer that
+        can be saved to a file.
+        """
+        dc = wx.BufferedPaintDC(self, self.buffer)
+        self.pdc.DrawToDC(dc)
+        if self.pdcVector:
+            self.pdcVector.DrawToDC(dc)
+        self.buffer.SaveFile(FileName, FileType)
+
+    def GetOverlay(self):
+        """
+        Converts rendered overlay files to wx.Image
+
+        Updates self.imagedict
+
+        @return list of images
+        """
+        imgs = []
+        for overlay in self.Map.GetListOfLayers(l_type="overlay", l_active=True):
+            if os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
+                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
+                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.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
+
+        self.imagedict[img] = { 'id': imgId }
+
+        return img
+
+    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.
+
+        @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
+
+        # if len(self.Map.GetListOfLayers()) == 0:
+        #    return False
+        
+        if self.img is None:
+            render = True
+
+        #
+        # initialize process bar (only on 'render')
+        #
+        if render is True or renderVector is True:
+            self.parent.onRenderGauge.Show()
+            if self.parent.onRenderGauge.GetRange() > 0:
+                self.parent.onRenderGauge.SetValue(1)
+        
+        #
+        # render background image if needed
+        #
+        
+        # update layer dictionary if there has been a change in layers
+        if self.tree and self.tree.reorder == True:
+            self.tree.ReorderLayers()
+            
+        # reset flag for auto-rendering
+        if self.tree:
+            self.tree.rerender = False
+        
+        if render:
+            # update display size
+            self.Map.ChangeMapSize(self.GetClientSize())
+            if self.parent.compResolution.IsChecked():
+                # use computation region resolution for rendering
+                windres = True
+            else:
+                windres = False
+            self.mapfile = self.Map.Render(force=True, mapWindow=self.parent,
+                                           windres=windres)
+        else:
+            self.mapfile = self.Map.Render(force=False, mapWindow=self.parent)
+        
+        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
+        #
+        digitToolbar = self.parent.toolbars['vdigit']
+        if renderVector and digitToolbar and \
+                digitToolbar.GetLayer():
+            # set region
+            self.parent.digit.driver.UpdateRegion()
+            # re-calculate threshold for digitization tool
+            self.parent.digit.driver.GetThreshold()
+            # draw map
+            self.pdcVector.Clear()
+            self.pdcVector.RemoveAll()
+            try:
+                item = self.tree.FindItemByData('maplayer', digitToolbar.GetLayer())
+            except TypeError:
+                item = None
+            
+            if item and self.tree.IsItemChecked(item):
+                self.parent.digit.driver.DrawMap()
+
+            # translate tmp objects (pointer position)
+            if digitToolbar.GetAction() == 'moveLine':
+                if  hasattr(self, "vdigitMove") and \
+                        self.vdigitMove.has_key('beginDiff'):
+                    # move line
+                    for id in self.vdigitMove['id']:
+                        # print self.pdcTmp.GetIdBounds(id)
+                        self.pdcTmp.TranslateId(id,
+                                                self.vdigitMove['beginDiff'][0],
+                                                self.vdigitMove['beginDiff'][1])
+                    del self.vdigitMove['beginDiff']
+        
+        #
+        # 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
+        #
+        if len(self.polycoords) > 0:
+            self.DrawLines(self.pdcTmp)
+
+
+
+        if self.gframe.georectifying:
+            # -> georectifier (redraw GCPs)
+            if self.parent.toolbars['georect']:
+                coordtype = 'gcpcoord'
+            else:
+                coordtype = 'mapcoord'
+            self.gframe.georectifying.DrawGCP(coordtype)
+            
+        # 
+        # clear measurement
+        #
+        
+        if self.mouse["use"] == "measure":
+            self.ClearLines(pdc=self.pdcTmp)
+            self.polycoords = []
+            self.mouse['use'] = 'pointer'
+            self.mouse['box'] = 'point'
+            self.mouse['end'] = [0, 0]
+            self.SetCursor(self.parent.cursors["default"])
+            
+        stop = time.clock()
+
+        #
+        # hide process bar
+        #
+        self.parent.onRenderGauge.Hide()
+
+        #
+        # update statusbar
+        #
+        ### self.Map.SetRegion()
+        self.parent.StatusbarUpdate()
+        if grass.find_file(name = 'MASK', element = 'cell')['name']:
+            # mask found
+            self.parent.maskInfo.SetLabel(_('MASK'))
+        else:
+            self.parent.maskInfo.SetLabel('')
+        
+        Debug.msg (2, "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 hasattr(self, "regionCoords"):
+            compReg = self.Map.GetRegion()
+            dispReg = self.Map.GetCurrentRegion()
+            reg = None
+            if self.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
+            
+            self.regionCoords = []
+            self.regionCoords.append((reg['w'], reg['n']))
+            self.regionCoords.append((reg['e'], reg['n']))
+            self.regionCoords.append((reg['e'], reg['s']))
+            self.regionCoords.append((reg['w'], reg['s']))
+            self.regionCoords.append((reg['w'], reg['n']))
+            # draw region extent
+            self.DrawLines(pdc=self.pdcDec, polycoords=self.regionCoords)
+
+    def IsInRegion(self, region, refRegion):
+        """
+        Test if 'region' is inside of 'refRegion'
+
+        @param region input region
+        @param refRegion reference region (e.g. computational region)
+
+        @return True if region is inside of refRegion
+        @return False 
+        """
+        if region['s'] >= refRegion['s'] and \
+                region['n'] <= refRegion['n'] and \
+                region['w'] >= refRegion['w'] and \
+                region['e'] <= refRegion['e']:
+            return True
+
+        return False
+
+    def EraseMap(self):
+        """
+        Erase the canvas
+        """
+        self.Draw(self.pdc, pdctype='clear')
+                  
+        if self.pdcVector:
+            self.Draw(self.pdcVector, pdctype='clear')
+        
+        self.Draw(self.pdcDec, pdctype='clear')
+        self.Draw(self.pdcTmp, pdctype='clear')
+        
+    def DragMap(self, moveto):
+        """
+        Drag the entire map image for panning.
+        """
+
+        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()
+
+        return True
+
+    def DragItem(self, id, event):
+        """
+        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 = event.GetX() - x
+        dy = event.GetY() - y
+        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+        r = self.pdc.GetIdBounds(id)
+        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 id > 100: # text
+            self.textdict[id]['coords'] = r2
+        r = r.Union(r2)
+        r.Inflate(4,4)
+        self.RefreshRect(r, False)
+        self.lastpos = (event.GetX(), event.GetY())
+                
+    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'].
+
+        """
+        self.redrawAll = False
+        
+        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)
+            r.Inflate(4,4)
+            pdc.ClearId(boxid)
+            self.RefreshRect(r, False)
+            pdc.SetId(boxid)
+            self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords)
+        elif self.mouse['box'] == "line" or self.mouse['box'] == 'point':
+            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,
+                  text=None, textAlign='lr', textOffset=(5, 5)):
+        """Draw cross in PseudoDC
+
+        @todo implement rotation
+
+        @param pdc PseudoDC
+        @param coord center coordinates
+        @param rotation rotate symbol
+        @param text draw also text (text, font, color, rotation)
+        @param textAlign alignment (default 'lower-right')
+        @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)
+
+        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)
+
+        return self.lineid
+
+    def MouseActions(self, event):
+        """
+        Mouse motion and button click notifier
+        """
+        if not self.processMouse:
+            return
+        
+        ### if self.redrawAll is False:
+        ###    self.redrawAll = True
+        
+        # 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)
+
+        # right mouse button pressed
+        elif event.RightDown():
+            self.OnRightDown(event)
+
+        # right mouse button released
+        elif event.RightUp():
+            self.OnRightUp(event)
+
+        elif event.Moving():
+            self.OnMouseMoving(event)
+
+#        event.Skip()
+        
+    def OnMouseWheel(self, event):
+        """
+        Mouse wheel moved
+        """
+        self.processMouse = False
+        current  = event.GetPositionTuple()[:]
+        wheel = event.GetWheelRotation()
+        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
+        # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
+        begin = (current[0] - self.Map.width / 4,
+                 current[1] - self.Map.height / 4)
+        end   = (current[0] + self.Map.width / 4,
+                 current[1] + self.Map.height / 4)
+
+        if wheel > 0:
+            zoomtype = 1
+        else:
+            zoomtype = -1
+
+        # zoom
+        self.Zoom(begin, end, zoomtype)
+
+        # redraw map
+        self.UpdateMap()
+
+        ### self.OnPaint(None)
+
+        # update statusbar
+        self.parent.StatusbarUpdate()
+
+        self.Refresh()
+        self.processMouse = True
+#        event.Skip()
+
+    def OnDragging(self, event):
+        """
+        Mouse dragging with left button down
+        """
+        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
+        current  = event.GetPositionTuple()[:]
+        previous = self.mouse['begin']
+        move = (current[0] - previous[0],
+                current[1] - previous[1])
+
+        digitToolbar = self.parent.toolbars['vdigit']
+
+        # dragging or drawing box with left button
+        if self.mouse['use'] == 'pan':
+            self.DragMap(move)
+
+        # dragging decoration overlay item
+        elif (self.mouse['use'] == 'pointer' and 
+                not digitToolbar and 
+                self.dragid != None):
+            self.DragItem(self.dragid, event)
+
+        # dragging anything else - rubber band box or line
+        else:
+            if (self.mouse['use'] == 'pointer' and 
+                not digitToolbar): return
+            self.mouse['end'] = event.GetPositionTuple()[:]
+            digitClass = self.parent.digit
+            if (event.LeftIsDown() and 
+                not (digitToolbar and 
+                    digitToolbar.GetAction() in ("moveLine",) and 
+                    digitClass.driver.GetSelected() > 0)):
+                # draw box only when left mouse button is pressed
+                self.MouseDraw(pdc=self.pdcTmp)
+      
+#        event.Skip()
+
+    def OnLeftDown(self, event):
+        """
+        Left mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
+                   self.mouse["use"])
+
+        self.mouse['begin'] = event.GetPositionTuple()[:]
+
+        if self.mouse["use"] in ["measure", "profile"]:
+            # measure or profile
+            if len(self.polycoords) == 0:
+                self.mouse['end'] = self.mouse['begin']
+                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
+                self.ClearLines(pdc=self.pdcTmp)
+            else:
+                self.mouse['begin'] = self.mouse['end']
+        elif self.mouse['use'] == 'zoom':
+            pass
+        elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
+            # digitization
+            digitToolbar = self.parent.toolbars['vdigit']
+            digitClass   = self.parent.digit
+            east, north = self.Pixel2Cell(self.mouse['begin'])
+
+            try:
+                map = digitToolbar.GetLayer().GetName()
+            except:
+                map = None
+                wx.MessageBox(parent=self,
+                              message=_("No vector map selected for editing."),
+                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                event.Skip()
+                return
+
+            # calculate position of 'update record' dialog
+            position = self.mouse['begin']
+            posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
+                                             position[1] + self.dialogOffset))
+
+            if digitToolbar.GetAction() not in ("moveVertex", "addVertex",
+                                                "removeVertex", "editLine"):
+                # set pen
+                self.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+                self.polypen = wx.Pen(colour='dark green', width=2, style=wx.SOLID)
+
+            if digitToolbar.GetAction() in ("addVertex", "removeVertex"):
+                # unselect
+                digitClass.driver.SetSelected([])
+
+            if digitToolbar.GetAction() == "addLine":
+                if digitToolbar.GetAction('type') in ["point", "centroid"]:
+                    # add new point
+                    if digitToolbar.GetAction('type') == 'point':
+                        point = True
+                    else:
+                        point = False
+
+                    fid = digitClass.AddPoint(map, point, east, north)
+                    if fid < 0:
+                        return
+
+                    self.UpdateMap(render=False) # redraw map
+
+                    # add new record into atribute table
+                    if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled')  is True:
+                        # select attributes based on layer and category
+                        cats = { fid : {
+                                UserSettings.Get(group='vdigit', key="layer", subkey='value') :
+                                    (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
+                                }}
+                        addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
+                                                                   cats=cats,
+                                                                   pos=posWindow,
+                                                                   action="add")
+                        if addRecordDlg.mapDBInfo and \
+                               addRecordDlg.ShowModal() == wx.ID_OK:
+                            sqlfile = tempfile.NamedTemporaryFile(mode="w")
+                            for sql in addRecordDlg.GetSQLString():
+                                sqlfile.file.write(sql + ";\n")
+                            sqlfile.file.flush()
+                            executeCommand = gcmd.Command(cmd=["db.execute",
+                                                               "--q",
+                                                               "input=%s" % sqlfile.name])
+
+                elif digitToolbar.GetAction('type') in ["line", "boundary"]:
+                    # add new point to the line
+                    self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
+                    self.DrawLines(pdc=self.pdcTmp)
+            
+            elif digitToolbar.GetAction() == "editLine" and hasattr(self, "vdigitMove"):
+                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
+                self.vdigitMove['id'].append(wx.NewId())
+                self.DrawLines(pdc=self.pdcTmp)
+
+            elif digitToolbar.GetAction() == "deleteLine":
+                pass
+
+            elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
+                    not hasattr(self, "vdigitMove"):
+                self.vdigitMove = {}
+                # geographic coordinates of initial position (left-down)
+                self.vdigitMove['begin'] = None
+                # list of ids to modify    
+                self.vdigitMove['id'] = []
+                # ids geographic coordinates
+                self.vdigitMove['coord'] = {}
+                
+                if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
+                    # set pen
+                    pcolor = UserSettings.Get(group='vdigit', key="symbol",
+                                              subkey=["highlight", "color"])
+                    self.pen = self.polypen = wx.Pen(colour=pcolor,
+                                                     width=2, style=wx.SHORT_DASH)
+                    self.pdcTmp.SetPen(self.polypen)
+
+            elif digitToolbar.GetAction() == "splitLine":
+                # unselect
+                digitClass.driver.SetSelected([])
+
+            elif digitToolbar.GetAction() in ["displayAttrs", "displayCats"]:
+                qdist = digitClass.driver.GetThreshold(type='selectThresh')
+                coords = (east, north)
+                if digitClass.type == 'vdigit':
+                    # unselect
+                    digitClass.driver.SetSelected([])
+
+                    # select feature by point
+                    cats = {}
+                    if digitClass.driver.SelectLineByPoint(coords,
+                                                        digitClass.GetSelectType()) is not None:
+                        if UserSettings.Get(group='vdigit', key='checkForDupl',
+                                            subkey='enabled'):
+                            lines = digitClass.driver.GetSelected()
+                        else:
+                            lines = (digitClass.driver.GetSelected()[0],) # only first found
+                        
+                        for line in lines:
+                            cats[line] = digitClass.GetLineCats(line)
+                    
+                if digitToolbar.GetAction() == "displayAttrs":
+                    # select attributes based on coordinates (all layers)
+                    if self.parent.dialogs['attributes'] is None:
+                        if digitClass.type == 'vedit':
+                            self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
+                                                                                            query=(coords, qdist),
+                                                                                            pos=posWindow,
+                                                                                            action="update")
+                        else:
+                            self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
+                                                                                            cats=cats,
+                                                                                            action="update")
+                    else:
+                        # update currently open dialog
+                        if digitClass.type == 'vedit':
+                            self.parent.dialogs['attributes'].UpdateDialog(query=(coords, qdist))
+                        else:
+                            # upgrade dialog
+                            self.parent.dialogs['attributes'].UpdateDialog(cats=cats)
+
+                    if self.parent.dialogs['attributes']:
+                        if len(cats.keys()) > 0:
+                            # highlight feature & re-draw map
+                            if not self.parent.dialogs['attributes'].IsShown():
+                                self.parent.dialogs['attributes'].Show()
+                        else:
+                            if self.parent.dialogs['attributes'] and \
+                                   self.parent.dialogs['attributes'].IsShown():
+                                self.parent.dialogs['attributes'].Hide()
+
+                else: # displayCats
+                    if self.parent.dialogs['category'] is None:
+                        # open new dialog
+                        if digitClass.type == 'vedit':
+                            dlg = VDigitCategoryDialog(parent=self,
+                                                        map=map,
+                                                        query=(coords, qdist),
+                                                        pos=posWindow,
+                                                        title=_("Update categories"))
+                            self.parent.dialogs['category'] = dlg
+                        else:
+                            dlg = VDigitCategoryDialog(parent=self,
+                                                       map=map,
+                                                       cats=cats,
+                                                       pos=posWindow,
+                                                       title=_("Update categories"))
+                            self.parent.dialogs['category'] = dlg
+                    else:
+                        # update currently open dialog
+                        if digitClass.type == 'vedit':
+                            self.parent.dialogs['category'].UpdateDialog(query=(coords, qdist))
+                        else:
+                            # upgrade dialog
+                            self.parent.dialogs['category'].UpdateDialog(cats=cats)
+                            
+                    if self.parent.dialogs['category']:
+                        if len(cats.keys()) > 0:
+                            # highlight feature & re-draw map
+                            ### digitClass.driver.SetSelected(line)
+                            if not self.parent.dialogs['category'].IsShown():
+                                self.parent.dialogs['category'].Show()
+                        else:
+                            if self.parent.dialogs['category'].IsShown():
+                                self.parent.dialogs['category'].Hide()
+                
+                self.UpdateMap(render=False)
+
+            elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
+                if not hasattr(self, "copyCatsList"):
+                    self.copyCatsList = []
+                else:
+                    self.copyCatsIds = []
+                    self.mouse['box'] = 'box'
+
+            elif digitToolbar.GetAction() == "copyLine":
+                self.copyIds = []
+                self.layerTmp = None
+
+            elif digitToolbar.GetAction() == "zbulkLine":
+                if len(self.polycoords) > 1: # start new line
+                    self.polycoords = []
+                    self.ClearLines(pdc=self.pdcTmp)
+                self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
+                if len(self.polycoords) == 1:
+                    begin = self.Pixel2Cell(self.polycoords[-1])
+                    end   = self.Pixel2Cell(self.mouse['end'])
+                else:
+                    end   = self.Pixel2Cell(self.polycoords[-1])
+                    begin = self.Pixel2Cell(self.mouse['begin'])
+
+                    self.DrawLines(self.pdcTmp, polycoords = [begin, end])
+        elif self.mouse['use'] == 'pointer':
+            # get decoration or text id
+            self.idlist = []
+            self.dragid = ''
+            self.lastpos = self.mouse['begin']
+            idlist = self.pdc.FindObjects(x=self.lastpos[0], y=self.lastpos[1],
+                                          radius=self.hitradius)
+                                          
+            if 99 in idlist: idlist.remove(99)                             
+            if idlist != [] :
+                self.dragid = idlist[0] #drag whatever is on top
+        else:
+            pass
+
+        event.Skip()
+
+    def OnLeftUp(self, event):
+        """
+        Left mouse button released
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
+                   self.mouse["use"])
+
+        self.mouse['end'] = event.GetPositionTuple()[:]
+
+        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:
+                    # zoom 1/2 of the screen (TODO: settings)
+                    begin = (end[0] - self.Map.width / 4,
+                             end[1] - self.Map.height / 4)
+                    end   = (end[0] + self.Map.width / 4,
+                             end[1] + self.Map.height / 4)
+
+            self.Zoom(begin, end, self.zoomtype)
+
+            # redraw map
+            self.UpdateMap(render=True)
+
+            # update statusbar
+            self.parent.StatusbarUpdate()
+
+        elif self.mouse["use"] == "query":
+            # querying
+            self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
+
+        elif self.mouse["use"] == "queryVector":
+            # editable mode for vector map layers
+            self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
+
+            # clear temp canvas
+            self.UpdateMap(render=False, renderVector=False)
+            
+        elif self.mouse["use"] in ["measure", "profile"]:
+            # measure or profile
+            if self.mouse["use"] == "measure":
+                self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
+
+            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
+            self.ClearLines(pdc=self.pdcTmp)
+            self.DrawLines(pdc=self.pdcTmp)
+        
+        elif self.mouse["use"] == "pointer" and self.parent.gismanager.georectifying:
+            # -> georectifying
+            coord = self.Pixel2Cell(self.mouse['end'])
+            if self.parent.toolbars['georect']:
+                coordtype = 'gcpcoord'
+            else:
+                coordtype = 'mapcoord'
+
+            self.parent.gismanager.georectifying.SetGCPData(coordtype, coord, self)
+            self.UpdateMap(render=False, renderVector=False)
+
+        elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
+            # digitization tool active
+            digitToolbar = self.parent.toolbars['vdigit']
+            digitClass   = self.parent.digit
+
+            pos1 = self.Pixel2Cell(self.mouse['begin'])
+            pos2 = self.Pixel2Cell(self.mouse['end'])
+
+            if hasattr(self, "vdigitMove"):
+                if len(digitClass.driver.GetSelected()) == 0:
+                    self.vdigitMove['begin'] = pos1 # left down
+                ### else:
+                ###    dx = pos2[0] - pos1[0] ### ???
+                ###    dy = pos2[1] - pos1[1]
+                ###    self.vdigitMove = (self.vdigitMove['begin'][0] + dx,
+                ###                       self.vdigitMove['begin'][1] + dy)
+                
+                # eliminate initial mouse moving efect
+                self.mouse['begin'] = self.mouse['end'] 
+
+            if digitToolbar.GetAction() in ["deleteLine", "moveLine", "moveVertex",
+                                            "copyCats", "copyAttrs", "editLine", "flipLine",
+                                            "mergeLine", "snapLine",
+                                            "queryLine", "breakLine", "typeConv", "connectLine"]:
+                nselected = 0
+                # -> delete line || move line || move vertex
+                if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
+                    if len(digitClass.driver.GetSelected()) == 0:
+                        nselected = digitClass.driver.SelectLineByPoint(pos1, type=VDigit_Lines_Type)
+                        if digitToolbar.GetAction() == "editLine":
+                            try:
+                                selVertex = digitClass.driver.GetSelectedVertex(pos1)[0]
+                            except IndexError:
+                                selVertex = None
+
+                            if selVertex:
+                                # self.UpdateMap(render=False)
+                                ids = digitClass.driver.GetSelected(grassId=False)
+                                # move this line to tmp layer
+                                self.polycoords = []
+                                for id in ids:
+                                    if id % 2: # register only vertices
+                                        e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
+                                        self.polycoords.append((e, n))
+                                    # self.pdcVector.RemoveId(id)
+                                digitClass.driver.DrawSelected(False) 
+                                
+                                if selVertex < ids[-1] / 2:
+                                    # choose first or last node of line
+                                    self.vdigitMove['id'].reverse()
+                                    self.polycoords.reverse()
+                            else:
+                                # unselect
+                                digitClass.driver.SetSelected([])
+                                del self.vdigitMove
+                                
+                            self.UpdateMap(render=False)
+
+                        
+                elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
+                    if not hasattr(self, "copyCatsIds"):
+                        # 'from' -> select by point
+                        nselected = digitClass.driver.SelectLineByPoint(pos1, digitClass.GetSelectType())
+                        if nselected:
+                            self.copyCatsList = digitClass.driver.GetSelected()
+                    else:
+                        # -> 'to' -> select by bbox
+                        digitClass.driver.SetSelected([])
+                        # return number of selected features (by box/point)
+                        nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
+                                                                       digitClass.GetSelectType())
+                        if nselected == 0:
+                            if digitClass.driver.SelectLineByPoint(pos1,
+                                                                   digitClass.GetSelectType()) is not None:
+                                nselected = 1
+
+                        if nselected > 0:
+                            self.copyCatsIds = digitClass.driver.GetSelected()
+
+                elif digitToolbar.GetAction() == "queryLine":
+                    selected = digitClass.SelectLinesByQuery(pos1, pos2)
+                    nselected = len(selected)
+                    if nselected > 0:
+                        digitClass.driver.SetSelected(selected)
+
+                else:
+                    # -> moveLine || deleteLine, etc. (select by point/box)
+                    if digitToolbar.GetAction() == 'moveLine' and \
+                           len(digitClass.driver.GetSelected()) > 0:
+                        nselected = 0
+                    else:
+                        if digitToolbar.GetAction() == 'moveLine':
+                            drawSeg = True
+                        else:
+                            drawSeg = False
+                        nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
+                                                                       digitClass.GetSelectType(),
+                                                                       drawSeg)
+                        
+                        if nselected == 0:
+                            if digitClass.driver.SelectLineByPoint(pos1,
+                                                                   digitClass.GetSelectType()) is not None:
+                                nselected = 1
+                
+                if nselected > 0:
+                    if digitToolbar.GetAction() in ["moveLine", "moveVertex"]:
+                        # get pseudoDC id of objects which should be redrawn
+                        if digitToolbar.GetAction() == "moveLine":
+                            # -> move line
+                            self.vdigitMove['id'] = digitClass.driver.GetSelected(grassId=False)
+                            self.vdigitMove['coord'] = digitClass.driver.GetSelectedCoord()
+                        elif digitToolbar.GetAction() == "moveVertex":
+                            # -> move vertex
+                            self.vdigitMove['id'] = digitClass.driver.GetSelectedVertex(pos1)
+                            if len(self.vdigitMove['id']) == 0: # no vertex found
+                                digitClass.driver.SetSelected([])
+
+                                   
+                    #
+                    # check for duplicates
+                    #
+                    if UserSettings.Get(group='vdigit', key='checkForDupl', subkey='enabled') is True:
+                        dupl = digitClass.driver.GetDuplicates()
+                        self.UpdateMap(render=False)
+
+                        if dupl:
+                            posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
+                                                             self.mouse['end'][1] + self.dialogOffset))
+                            
+                            dlg = VDigitDuplicatesDialog(parent=self, data=dupl, pos=posWindow)
+
+                            if dlg.ShowModal() == wx.ID_OK:
+                                digitClass.driver.UnSelect(dlg.GetUnSelected())
+                                # update selected
+                                self.UpdateMap(render=False)
+
+                    if digitToolbar.GetAction() != "editLine":
+                        # -> move line || move vertex
+                        self.UpdateMap(render=False)
+
+                else: # no vector object found
+                    if not (digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
+                                len(self.vdigitMove['id']) > 0):
+                        # avoid left-click when features are already selected
+                        self.UpdateMap(render=False, renderVector=False)
+
+            elif digitToolbar.GetAction() in ["splitLine", "addVertex", "removeVertex"]:
+                pointOnLine = digitClass.driver.SelectLineByPoint(pos1,
+                                                                  type=VDigit_Lines_Type)
+                if pointOnLine:
+                    if digitToolbar.GetAction() in ["splitLine", "addVertex"]:
+                        self.UpdateMap(render=False) # highlight object
+                        self.DrawCross(pdc=self.pdcTmp, coords=self.Cell2Pixel(pointOnLine),
+                                       size=5)
+                    elif digitToolbar.GetAction() == "removeVertex":
+                        # get only id of vertex
+                        try:
+                            id = digitClass.driver.GetSelectedVertex(pos1)[0]
+                        except IndexError:
+                            id = None
+
+                        if id:
+                            x, y = self.pdcVector.GetIdBounds(id)[0:2]
+                            self.pdcVector.RemoveId(id)
+                            self.UpdateMap(render=False) # highlight object
+                            self.DrawCross(pdc=self.pdcTmp, coords=(x, y),
+                                           size=5)
+                        else:
+                            # unselect
+                            digitClass.driver.SetSelected([])
+                            self.UpdateMap(render=False)
+                            
+            elif digitToolbar.GetAction() == "copyLine":
+                if UserSettings.Get(group='vdigit', key='bgmap',
+                                    subkey='value', internal=True) == '':
+                    # no background map -> copy from current vector map layer
+                    nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
+                                                                   digitClass.GetSelectType())
+
+                    if nselected > 0:
+                        # highlight selected features
+                        self.UpdateMap(render=False)
+                    else:
+                        self.UpdateMap(render=False, renderVector=False)
+                else:
+                    # copy features from background map
+                    self.copyIds = digitClass.SelectLinesFromBackgroundMap(pos1, pos2)
+                    if len(self.copyIds) > 0:
+                        color = UserSettings.Get(group='vdigit', key='symbol',
+                                                 subkey=['highlight', 'color'])
+                        colorStr = str(color[0]) + ":" + \
+                            str(color[1]) + ":" + \
+                            str(color[2])
+                        dVectTmp = ['d.vect',
+                                    'map=%s' % UserSettings.Get(group='vdigit', key='bgmap',
+                                                                subkey='value', internal=True),
+                                    'cats=%s' % utils.ListOfCatsToRange(self.copyIds),
+                                    '-i',
+                                    'color=%s' % colorStr,
+                                    'fcolor=%s' % colorStr,
+                                    'type=point,line,boundary,centroid',
+                                    'width=2']
+                        
+                        self.layerTmp = self.Map.AddLayer(type='vector',
+                                                          name=globalvar.QUERYLAYER,
+                                                          command=dVectTmp)
+                        self.UpdateMap(render=True, renderVector=False)
+                    else:
+                        self.UpdateMap(render=False, renderVector=False)
+                    self.redrawAll = None
+
+            elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
+                # select lines to be labeled
+                pos1 = self.polycoords[0]
+                pos2 = self.polycoords[1]
+                nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
+                                                               digitClass.GetSelectType())
+
+                if nselected > 0:
+                    # highlight selected features
+                    self.UpdateMap(render=False)
+                    self.DrawLines(pdc=self.pdcTmp) # redraw temp line
+                else:
+                    self.UpdateMap(render=False, renderVector=False)
+
+            elif digitToolbar.GetAction() == "connectLine":
+                if len(digitClass.driver.GetSelected()) > 0:
+                    self.UpdateMap(render=False)
+                    
+            if len(digitClass.driver.GetSelected()) > 0:
+                self.redrawAll = None
+                ### self.OnPaint(None)
+                
+        elif (self.mouse['use'] == 'pointer' and 
+                self.dragid >= 0):
+            # end drag of overlay decoration
+            
+            if self.dragid < 99 and self.overlays.has_key(self.dragid):
+                self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
+            elif self.dragid > 100 and self.textdict.has_key(self.dragid):
+                self.textdict[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
+            else:
+                pass
+            self.dragid = None
+            self.currtxtid = None
+#            self.UpdateMap(render=True)
+            
+        else:
+            pass
+                                              
+#        event.Skip()
+
+    def OnButtonDClick(self, event):
+        """
+        Mouse button double click
+        """
+        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
+                   self.mouse["use"])
+
+        if self.mouse["use"] == "measure":
+            # measure
+            self.ClearLines(pdc=self.pdcTmp)
+            self.polycoords = []
+            self.mouse['use'] = 'pointer'
+            self.mouse['box'] = 'point'
+            self.mouse['end'] = [0, 0]
+            self.Refresh()
+            self.SetCursor(self.parent.cursors["default"])
+        elif self.mouse["use"] == "profile":
+            # profile
+            pass
+        #                self.pdc.ClearId(self.lineid)
+        #                self.pdc.ClearId(self.plineid)
+        #                print 'coordinates: ',self.polycoords
+        #                self.polycoords = []
+        #                self.mouse['begin'] = self.mouse['end'] = [0, 0]
+        #                self.Refresh()
+        elif self.mouse['use'] == 'pointer' and self.parent.toolbars['vdigit']:
+            # digitization tool
+            pass
+        else:
+            # select overlay decoration options dialog
+            clickposition = event.GetPositionTuple()[:]
+            idlist  = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
+            if idlist == []:
+                return
+            self.dragid = idlist[0]
+
+            # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
+            if self.dragid > 100:
+                self.currtxtid = self.dragid
+                self.parent.OnAddText(None)
+            elif self.dragid == 0:
+                self.parent.OnAddBarscale(None)
+            elif self.dragid == 1:
+                self.parent.OnAddLegend(None)
+                
+#        event.Skip()
+
+    def OnRightDown(self, event):
+        """
+        Right mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
+                   self.mouse["use"])
+                   
+        digitToolbar = self.parent.toolbars['vdigit']
+        if digitToolbar:
+            digitClass = self.parent.digit
+            # digitization tool (confirm action)
+            if digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
+                    hasattr(self, "vdigitMove"):
+
+                pFrom = self.vdigitMove['begin']
+                pTo = self.Pixel2Cell(event.GetPositionTuple())
+                
+                move = (pTo[0] - pFrom[0],
+                        pTo[1] - pFrom[1])
+                
+                if digitToolbar.GetAction() == "moveLine":
+                    # move line
+                    if digitClass.MoveSelectedLines(move) < 0:
+                        return
+                elif digitToolbar.GetAction() == "moveVertex":
+                    # move vertex
+                    if digitClass.MoveSelectedVertex(pFrom, move) < 0:
+                        return
+                
+                del self.vdigitMove
+                
+        event.Skip()
+
+    def OnRightUp(self, event):
+        """
+        Right mouse button released
+        """
+        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
+                   self.mouse["use"])
+
+        digitToolbar = self.parent.toolbars['vdigit']
+        if digitToolbar:
+            digitClass = self.parent.digit
+            # digitization tool (confirm action)
+            if digitToolbar.GetAction() == "addLine" and \
+                    digitToolbar.GetAction('type') in ["line", "boundary"]:
+                # -> add new line / boundary
+                try:
+                    map = digitToolbar.GetLayer().GetName()
+                except:
+                    map = None
+                    wx.MessageBox(parent=self,
+                                  message=_("No vector map selected for editing."),
+                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                    
+                if map:
+                    # mapcoords = []
+                    # xy -> EN
+                    # for coord in self.polycoords:
+                    #    mapcoords.append(self.Pixel2Cell(coord))
+                    if digitToolbar.GetAction('type') == 'line':
+                        line = True
+                    else:
+                        line = False
+
+                    if len(self.polycoords) < 2: # ignore 'one-point' lines
+                        return
+                    
+                    fid = digitClass.AddLine(map, line, self.polycoords)
+                    if fid < 0:
+                        return
+                    
+                    position = self.Cell2Pixel(self.polycoords[-1])
+                    self.polycoords = []
+                    self.UpdateMap(render=False)
+                    self.redrawAll = True
+                    self.Refresh()
+                    
+                    # add new record into atribute table
+                    if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled') is True:
+                        posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
+                                                         position[1] + self.dialogOffset))
+
+                        # select attributes based on layer and category
+                        cats = { fid : {
+                                UserSettings.Get(group='vdigit', key="layer", subkey='value') :
+                                    (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
+                                }}
+
+                        addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
+                                                                   cats=cats,
+                                                                   pos=posWindow,
+                                                                   action="add")
+                        if addRecordDlg.mapDBInfo and \
+                               addRecordDlg.ShowModal() == wx.ID_OK:
+                            sqlfile = tempfile.NamedTemporaryFile(mode="w")
+                            for sql in addRecordDlg.GetSQLString():
+                                sqlfile.file.write(sql + ";\n")
+                            sqlfile.file.flush()
+                            executeCommand = gcmd.Command(cmd=["db.execute",
+                                                              "--q",
+                                                              "input=%s" % sqlfile.name])
+            elif digitToolbar.GetAction() == "deleteLine":
+                # -> delete selected vector features
+                if digitClass.DeleteSelectedLines() < 0:
+                    return
+            elif digitToolbar.GetAction() == "splitLine":
+                # split line
+                if digitClass.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
+                    return
+            elif digitToolbar.GetAction() == "addVertex":
+                # add vertex
+                if digitClass.AddVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
+                    return
+            elif digitToolbar.GetAction() == "removeVertex":
+                # remove vertex
+                if digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
+                    return
+            elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
+                try:
+                    if digitToolbar.GetAction() == 'copyCats':
+                        if digitClass.CopyCats(self.copyCatsList,
+                                               self.copyCatsIds, copyAttrb=False) < 0:
+                            return
+                    else:
+                        if digitClass.CopyCats(self.copyCatsList,
+                                               self.copyCatsIds, copyAttrb=True) < 0:
+                            return
+                    
+                    del self.copyCatsList
+                    del self.copyCatsIds
+                except AttributeError:
+                    pass
+            elif digitToolbar.GetAction() == "editLine" and \
+                    hasattr(self, "vdigitMove"):
+                line = digitClass.driver.GetSelected()
+                if digitClass.EditLine(line, self.polycoords) < 0:
+                    return
+                
+                del self.vdigitMove
+                
+            elif digitToolbar.GetAction() == "flipLine":
+                if digitClass.FlipLine() < 0:
+                    return
+            elif digitToolbar.GetAction() == "mergeLine":
+                if digitClass.MergeLine() < 0:
+                    return
+            elif digitToolbar.GetAction() == "breakLine":
+                if digitClass.BreakLine() < 0:
+                    return
+            elif digitToolbar.GetAction() == "snapLine":
+                if digitClass.SnapLine() < 0:
+                    return
+            elif digitToolbar.GetAction() == "connectLine":
+                if len(digitClass.driver.GetSelected()) > 1:
+                    if digitClass.ConnectLine() < 0:
+                        return
+            elif digitToolbar.GetAction() == "copyLine":
+                if digitClass.CopyLine(self.copyIds) < 0:
+                    return
+                del self.copyIds
+                if self.layerTmp:
+                    self.Map.DeleteLayer(self.layerTmp)
+                    self.UpdateMap(render=True, renderVector=False)
+                del self.layerTmp
+
+            elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
+                pos1 = self.polycoords[0]
+                pos2 = self.polycoords[1]
+
+                selected = digitClass.driver.GetSelected()
+                dlg = VDigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"),
+                                        nselected=len(selected))
+                if dlg.ShowModal() == wx.ID_OK:
+                    if digitClass.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
+                                            dlg.step.GetValue()) < 0:
+                        return
+                self.UpdateMap(render=False, renderVector=True)
+            elif digitToolbar.GetAction() == "typeConv":
+                # -> feature type conversion
+                # - point <-> centroid
+                # - line <-> boundary
+                if digitClass.TypeConvForSelectedLines() < 0:
+                    return
+
+            if digitToolbar.GetAction() != "addLine":
+                # unselect and re-render
+                digitClass.driver.SetSelected([])
+                self.polycoords = []
+                self.UpdateMap(render=False)
+
+            self.redrawAll = True
+            self.Refresh()
+        
+        event.Skip()
+
+    def OnMiddleDown(self, event):
+        """
+        Middle mouse button pressed
+        """
+        digitToolbar = self.parent.toolbars['vdigit']
+        # digitization tool
+        if self.mouse["use"] == "pointer" and digitToolbar:
+            digitClass = self.parent.digit
+            if (digitToolbar.GetAction() == "addLine" and \
+                    digitToolbar.GetAction('type') in ["line", "boundary"]) or \
+                    digitToolbar.GetAction() == "editLine":
+                # add line or boundary -> remove last point from the line
+                try:
+                    removed = self.polycoords.pop()
+                    Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
+                                  [removed,])
+
+                    self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
+                except:
+                    pass
+
+                if digitToolbar.GetAction() == "editLine":
+                    # remove last vertex & line
+                    if len(self.vdigitMove['id']) > 1:
+                        self.vdigitMove['id'].pop()
+
+                self.UpdateMap(render=False, renderVector=False)
+
+            elif digitToolbar.GetAction() in ["deleteLine", "moveLine", "splitLine",
+                                              "addVertex", "removeVertex", "moveVertex",
+                                              "copyCats", "flipLine", "mergeLine",
+                                              "snapLine", "connectLine", "copyLine",
+                                              "queryLine", "breakLine", "typeConv"]:
+                # varios tools -> unselected selected features
+                digitClass.driver.SetSelected([])
+                if digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
+                        hasattr(self, "vdigitMove"):
+
+                    del self.vdigitMove
+                    
+                elif digitToolbar.GetAction() == "copyCats":
+                    try:
+                        del self.copyCatsList
+                        del self.copyCatsIds
+                    except AttributeError:
+                        pass
+                
+                elif digitToolbar.GetAction() == "copyLine":
+                    del self.copyIds
+                    if self.layerTmp:
+                        self.Map.DeleteLayer(self.layerTmp)
+                        self.UpdateMap(render=True, renderVector=False)
+                    del self.layerTmp
+
+                self.polycoords = []
+                self.UpdateMap(render=False) # render vector
+
+            elif digitToolbar.GetAction() == "zbulkLine":
+                # reset polyline
+                self.polycoords = []
+                digitClass.driver.SetSelected([])
+                self.UpdateMap(render=False)
+            
+            self.redrawAll = True
+            
+    def OnMouseMoving(self, event):
+        """
+        Motion event and no mouse buttons were pressed
+        """
+        digitToolbar = self.parent.toolbars['vdigit']
+        if self.mouse["use"] == "pointer" and digitToolbar:
+            digitClass = self.parent.digit
+            self.mouse['end'] = event.GetPositionTuple()[:]
+            Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
+                           (self.mouse['end'][0], self.mouse['end'][1]))
+            if digitToolbar.GetAction() == "addLine" and digitToolbar.GetAction('type') in ["line", "boundary"]:
+                if len(self.polycoords) > 0:
+                    self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1]))
+            elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] \
+                    and hasattr(self, "vdigitMove"):
+                dx = self.mouse['end'][0] - self.mouse['begin'][0]
+                dy = self.mouse['end'][1] - self.mouse['begin'][1]
+                
+                if len(self.vdigitMove['id']) > 0:
+                    # draw lines on new position
+                    if digitToolbar.GetAction() == "moveLine":
+                        # move line
+                        for id in self.vdigitMove['id']:
+                            self.pdcTmp.TranslateId(id, dx, dy)
+                    elif digitToolbar.GetAction() in ["moveVertex", "editLine"]:
+                        # move vertex ->
+                        # (vertex, left vertex, left line,
+                        # right vertex, right line)
+
+                        # do not draw static lines
+                        if digitToolbar.GetAction() == "moveVertex":
+                            self.polycoords = []
+                            ### self.pdcTmp.TranslateId(self.vdigitMove['id'][0], dx, dy)
+                            self.pdcTmp.RemoveId(self.vdigitMove['id'][0])
+                            if self.vdigitMove['id'][1] > 0: # previous vertex
+                                x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][1])[0:2])
+                                self.pdcTmp.RemoveId(self.vdigitMove['id'][1]+1)
+                                self.polycoords.append((x, y))
+                            ### x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][0])[0:2])
+                            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
+                            if self.vdigitMove['id'][2] > 0: # next vertex
+                                x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][2])[0:2])
+                                self.pdcTmp.RemoveId(self.vdigitMove['id'][2]-1)
+                                self.polycoords.append((x, y))
+                            
+                            self.ClearLines(pdc=self.pdcTmp)
+                            self.DrawLines(pdc=self.pdcTmp)
+
+                        else: # edit line
+                            try:
+                                if self.vdigitMove['id'][-1] > 0: # previous vertex
+                                    self.MouseDraw(pdc=self.pdcTmp,
+                                                   begin=self.Cell2Pixel(self.polycoords[-1]))
+                            except: # no line
+                                self.vdigitMove['id'] = []
+                                self.polycoords = []
+
+                self.Refresh() # TODO: use RefreshRect()
+                self.mouse['begin'] = self.mouse['end']
+
+            elif digitToolbar.GetAction() == "zbulkLine":
+                if len(self.polycoords) == 1:
+                    # draw mouse moving
+                    self.MouseDraw(self.pdcTmp)
+
+        event.Skip()
+
+    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))
+
+        ### self.Refresh()
+
+        return True
+
+    def Pixel2Cell(self, (x, y)):
+        """
+        Convert image coordinates to real word coordinates
+
+        Input : int x, int y
+        Output: float x, float y
+        """
+
+        try:
+            x = int(x)
+            y = int(y)
+        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
+
+        # extent does not correspond with whole map canvas area...
+        # east  = self.Map.region['w'] + x * self.Map.region["ewres"]
+        # north = self.Map.region['n'] - y * self.Map.region["nsres"]
+
+        return (east, north)
+
+    def Cell2Pixel(self, (east, north)):
+        """
+        Convert real word coordinates to image coordinates
+        """
+
+        try:
+            east  = float(east)
+            north = float(north)
+        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 = int((east  - w) / res)
+        # y = int((n - north) / 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
+            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.parent.Map.projinfo['proj'] == 'll':
+                if newreg['n'] > 90.0:
+                    newreg['n'] = 90.0
+                if newreg['s'] < -90.0:
+                    newreg['s'] = -90.0
+            
+            ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
+            cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
+            
+            if hasattr(self, "vdigitMove"):
+                # xo = self.Cell2Pixel((self.Map.region['center_easting'], self.Map.region['center_northing']))
+                # xn = self.Cell2Pixel(ce, cn))
+                tmp = self.Pixel2Cell(self.mouse['end'])
+            
+            # 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
+            self.Map.AlignExtentFromDisplay()
+
+            if hasattr(self, "vdigitMove"):
+                tmp1 = self.mouse['end']
+                tmp2 = self.Cell2Pixel(self.vdigitMove['begin'])
+                dx = tmp1[0] - tmp2[0]
+                dy = tmp1[1] - tmp2[1]
+                self.vdigitMove['beginDiff'] = (dx, dy)
+                for id in self.vdigitMove['id']:
+                    self.pdcTmp.RemoveId(id)
+            
+            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
+        """
+
+        zoom = []
+        if len(self.zoomhistory) > 1:
+            self.zoomhistory.pop()
+            zoom = self.zoomhistory[len(self.zoomhistory)-1]
+            # (n, s, e, w)
+        if zoom:
+            # zoom to selected region
+            self.Map.region['center_easting'] = zoom[3] + \
+                (zoom[2] - zoom[3]) / 2
+            self.Map.region['center_northing'] = zoom[1] + \
+                (zoom[0] - zoom[1]) / 2
+            self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width
+            self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height
+            self.Map.AlignExtentFromDisplay()
+
+            # update map
+            self.UpdateMap()
+
+            # update statusbar
+            self.parent.StatusbarUpdate()
+
+    def ZoomHistory(self, n, s, e, w):
+        """
+        Manages a list of last 10 zoom extents
+
+        Return removed history item if exists
+        """
+        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))
+
+        return removed
+
+    def OnZoomToMap(self, event):
+        """
+        Set display extents to match selected raster (including NULLs)
+        or vector map.
+        """
+        self.ZoomToMap()
+
+    def OnZoomToRaster(self, event):
+        """
+        Set display extents to match selected raster map (ignore NULLs)
+        """
+        self.ZoomToMap(zoom=True)
+        
+    def ZoomToMap(self, layer = None, zoom = False):
+        """
+        Set display extents to match selected raster
+        or vector map.
+        """
+        zoomreg = {}
+
+        if not layer:
+            layer = self.GetSelectedLayer(multi = True)
+        
+        if not layer:
+            return
+
+        rast = []
+        vect = []
+        updated = False
+        for l in layer:
+            # only raster/vector layers are currently supported
+            if l.type == 'raster':
+                rast.append(l.name)
+            elif l.type == 'vector':
+                if self.parent.digit and l.name == self.parent.digit.map and \
+                        self.parent.digit.type == 'vdigit':
+                    w, s, b, e, n, t = self.parent.digit.driver.GetMapBoundingBox()
+                    self.Map.GetRegion(n=n, s=s, w=w, e=e,
+                                       update=True)
+                    updated = True
+                else:
+                    vect.append(l.name)
+
+        if not updated:
+            self.Map.GetRegion(rast = rast,
+                               vect = vect,
+                               update = True)
+        
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+
+        self.UpdateMap()
+
+        self.parent.StatusbarUpdate()
+
+    def ZoomToWind(self, event):
+        """
+        Set display geometry to match computational
+        region settings (set with g.region)
+        """
+        self.Map.region = self.Map.GetRegion()
+        ### self.Map.SetRegion(windres=True)
+
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+
+        self.UpdateMap()
+
+        self.parent.StatusbarUpdate()
+
+    def ZoomToDefault(self, event):
+        """
+        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()
+
+        self.parent.StatusbarUpdate()
+        
+    def DisplayToWind(self, event):
+        """
+        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()
+        
+        cmdRegion = ["g.region", "--o",
+                     "n=%f"    % new['n'],
+                     "s=%f"    % new['s'],
+                     "e=%f"    % new['e'],
+                     "w=%f"    % new['w'],
+                     "rows=%d" % int(new['rows']),
+                     "cols=%d" % int(new['cols'])]
+        
+        p = gcmd.Command(cmdRegion)
+
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+
+    def ZoomToSaved(self, event):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
+                                   title = _("Zoom to saved region extents"),
+                                   pos=wx.DefaultPosition, size=wx.DefaultSize,
+                                   style=wx.DEFAULT_DIALOG_STYLE,
+                                   loadsave='load')
+        
+        if dlg.ShowModal() == wx.ID_CANCEL:
+            dlg.Destroy()
+            return
+        
+        wind = dlg.wind
+        
+        self.Map.GetRegion(regionName = wind,
+                           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 SaveDisplayRegion(self, event):
+        """
+        Save display extents to named region file.
+        """
+
+        dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
+                                   title = _("Save display extents to region file"),
+                                   pos=wx.DefaultPosition, size=wx.DefaultSize,
+                                   style=wx.DEFAULT_DIALOG_STYLE,
+                                   loadsave='save')
+        if dlg.ShowModal() == wx.ID_CANCEL:
+            dlg.Destroy()
+            return
+        
+        wind = dlg.wind
+        
+        # test to see if it already exists and ask permission to overwrite
+        windpath = os.path.join(self.Map.env["GISDBASE"], self.Map.env["LOCATION_NAME"],
+                                self.Map.env["MAPSET"], "windows", wind)
+        
+        if windpath and not os.path.exists(windpath):
+            self.SaveRegion(wind)
+        elif windpath and os.path.exists(windpath):
+            overwrite = wx.MessageBox(_("Region file <%s> already exists. "
+                                        "Do you want to overwrite it?") % (wind),
+                                      _("Warning"), wx.YES_NO | wx.CENTRE)
+            if (overwrite == wx.YES):
+                self.SaveRegion(wind)
+        else:
+            pass
+
+        dlg.Destroy()
+
+    def SaveRegion(self, wind):
+        """
+        Save region settings
+        """
+        ### new = self.Map.AlignResolution()
+        new = self.Map.GetCurrentRegion()
+        
+        cmdRegion = ["g.region",
+                     "-u",
+                     "n=%f" % new['n'],
+                     "s=%f" % new['s'],
+                     "e=%f" % new['e'],
+                     "w=%f" % new['w'],
+                     "rows=%d" % new['rows'],
+                     "cols=%d" % new['cols'],
+                     "save=%s" % wind,
+                     "--o"]
+
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        p = gcmd.Command(cmdRegion)
+
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+
+    def Distance(self, beginpt, endpt, screen=True):
+        """Calculete distance
+
+        LL-locations not supported
+
+        @todo Use m.distance
+
+        @param beginpt first point
+        @param endpt second point
+        @param screen True for screen coordinates otherwise EN
+        """
+        x1, y1 = beginpt
+        x2, y2 = endpt
+        if screen:
+            dEast  = (x2 - x1) * self.Map.region["ewres"]
+            dNorth = (y2 - y1) * self.Map.region["nsres"]
+        else:
+            dEast  = (x2 - x1)
+            dNorth = (y2 - y1)
+            
+
+        return (math.sqrt(math.pow((dEast),2) + math.pow((dNorth),2)), (dEast, dNorth))
+
+class MapFrame(wx.Frame):
+    """
+    Main frame for map display window. Drawing takes place in child double buffered
+    drawing window.
+    """
+
+    def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS - Map display"),
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.DEFAULT_FRAME_STYLE, toolbars=["map"],
+                 tree=None, notebook=None, gismgr=None, page=None,
+                 Map=None, auimgr=None):
+        """
+        Main map display window with toolbars, statusbar and
+        DrawWindow
+
+        @param toolbars array of activated toolbars, e.g. ['map', 'digit']
+        @param tree reference to layer tree
+        @param notebook control book ID in Layer Manager
+        @param gismgr Layer Manager panel
+        @param page notebook page with layer tree
+        @param Map instance of render.Map
+        """
+        self.gismanager = gismgr    # GIS Manager object
+        self.Map        = Map       # instance of render.Map
+        self.tree       = tree      # GIS Manager layer tree object
+        self.page       = page      # Notebook page holding the layer tree
+        self.layerbook  = notebook  # GIS Manager layer tree notebook
+        self.parent     = parent
+
+        #
+        # available cursors
+        #
+        self.cursors = {
+            # default: cross
+            # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
+            "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)
+            }
+
+        wx.Frame.__init__(self, parent, id, title, pos, size, style)
+        self.SetName("MapWindow")
+
+        #
+        # set the size & system icon
+        #
+        self.SetClientSize(size)
+        self.iconsize = (16, 16)
+
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
+
+        #
+        # Fancy gui
+        #
+        # self._mgr = auimgr
+        self._mgr = wx.aui.AuiManager(self)
+
+        #
+        # Add toolbars
+        #
+        self.toolbars = { 'map' : None,
+                          'vdigit' : None,
+                          'georect' : None, 
+                          'nviz' : None }
+        for toolb in toolbars:
+            self.AddToolbar(toolb)
+
+        #
+        # Add statusbar
+        #
+        self.statusbar = self.CreateStatusBar(number=4, style=0)
+        self.statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY,
+                                      choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
+        self.toggleStatus.SetSelection(UserSettings.Get(group='display', key='statusbarMode', subkey='selection'))
+        self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.toggleStatus)
+        # auto-rendering checkbox
+        self.autoRender = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                      label=_("Render"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.autoRender)
+        self.autoRender.SetValue(UserSettings.Get(group='display', key='autoRendering', subkey='enabled'))
+        self.autoRender.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
+        # show region
+        self.showRegion = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                      label=_("Show computational extent"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.showRegion)
+        
+        self.showRegion.SetValue(False)
+        self.showRegion.Hide()
+        self.showRegion.SetToolTip(wx.ToolTip (_("Show/hide computational "
+                                                 "region extent (set with g.region). "
+                                                 "Display region drawn as a blue box inside the "
+                                                 "computational region, "
+                                                 "computational region inside a display region "
+                                                 "as a red box).")))
+        # set resolution
+        self.compResolution = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                         label=_("Constrain display resolution to computational settings"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.compResolution)
+        self.compResolution.SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
+        self.compResolution.Hide()
+        self.compResolution.SetToolTip(wx.ToolTip (_("Constrain display resolution "
+                                                     "to computational region settings. "
+                                                     "Default value for new map displays can "
+                                                     "be set up in 'User GUI settings' dialog.")))
+        # map scale
+        self.mapScale = wx.TextCtrl(parent=self.statusbar, id=wx.ID_ANY,
+                                    value="", style=wx.TE_PROCESS_ENTER,
+                                    size=(150, -1))
+        self.mapScale.Hide()
+        self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.mapScale)
+
+        # mask
+        self.maskInfo = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
+                                                  label = '')
+        self.maskInfo.SetForegroundColour(wx.Colour(255, 0, 0))
+        
+
+        # on-render gauge
+        self.onRenderGauge = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
+                                      range=0, style=wx.GA_HORIZONTAL)
+        self.onRenderGauge.Hide()
+        
+        self.StatusbarReposition() # reposition statusbar
+
+        #
+        # Init map display (buffered DC & set default cursor)
+        #
+        self.MapWindow2D = BufferedWindow(self, id=wx.ID_ANY,
+                                          Map=self.Map, tree=self.tree, gismgr=self.gismanager)
+        # default is 2D display mode
+        self.MapWindow = self.MapWindow2D
+        self.MapWindow.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.MapWindow.SetCursor(self.cursors["default"])
+        # used by Nviz (3D display mode)
+        self.MapWindow3D = None 
+
+        #
+        # initialize region values
+        #
+        self.__InitDisplay() 
+
+        #
+        # Bind various events
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
+        self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
+        
+        #
+        # Update fancy gui style
+        #
+        self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
+                   Dockable(False).BestSize((-1,-1)).
+                   CloseButton(False).DestroyOnClose(True).
+                   Layer(0))
+        self._mgr.Update()
+
+        #
+        # Init print module and classes
+        #
+        self.printopt = disp_print.PrintOptions(self, self.MapWindow)
+        
+        #
+        # Initialization of digitization tool
+        #
+        self.digit = None
+
+        #
+        # Init zoom history
+        #
+        self.MapWindow.ZoomHistory(self.Map.region['n'],
+                                   self.Map.region['s'],
+                                   self.Map.region['e'],
+                                   self.Map.region['w'])
+
+        #
+        # Re-use dialogs
+        #
+        self.dialogs = {}
+        self.dialogs['attributes'] = None
+        self.dialogs['category'] = None
+        self.dialogs['barscale'] = None
+        self.dialogs['legend'] = None
+
+        self.decorationDialog = None # decoration/overlays
+
+    def AddToolbar(self, name):
+        """
+        Add defined toolbar to the window
+
+        Currently known toolbars are:
+         - map basic map toolbar
+         - digit vector digitizer
+         - georect georectifier
+        """
+        # default toolbar
+        if name == "map":
+            self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
+
+            self._mgr.AddPane(self.toolbars['map'].toolbar,
+                              wx.aui.AuiPaneInfo().
+                              Name("maptoolbar").Caption(_("Map Toolbar")).
+                              ToolbarPane().Top().
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2).
+                              BestSize((self.toolbars['map'].GetToolbar().GetSize())))
+	
+        # vector digitizer
+        elif name == "vdigit":
+            from vdigit import haveVDigit
+            if not haveVDigit:
+                from vdigit import errorMsg
+                msg = _("Unable to start vector digitizer.\nThe VDigit python extension "
+                        "was not found or loaded properly.\n"
+                        "Switching back to 2D display mode.\n\nDetails: %s" % errorMsg)
+                
+                self.toolbars['map'].combo.SetValue (_("2D view"))
+                wx.MessageBox(parent=self,
+                              message=msg,
+                              caption=_("Error"),
+                              style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                return
+            
+            self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent=self, map=self.Map,
+                                                             layerTree=self.tree,
+                                                             log=self.gismanager.goutput)
+
+            for toolRow in range(0, self.toolbars['vdigit'].numOfRows):
+                self._mgr.AddPane(self.toolbars['vdigit'].toolbar[toolRow],
+                                  wx.aui.AuiPaneInfo().
+                                  Name("vdigittoolbar" + str(toolRow)).Caption(_("Vector digitizer toolbar")).
+                                  ToolbarPane().Top().Row(toolRow + 1).
+                                  LeftDockable(False).RightDockable(False).
+                                  BottomDockable(False).TopDockable(True).
+                                  CloseButton(False).Layer(2).
+                                  BestSize((self.toolbars['vdigit'].GetToolbar().GetSize())))
+	
+            # change mouse to draw digitized line
+            self.MapWindow.mouse['box'] = "point"
+            self.MapWindow.zoomtype = 0
+            self.MapWindow.pen     = wx.Pen(colour='red',   width=2, style=wx.SOLID)
+            self.MapWindow.polypen = wx.Pen(colour='green', width=2, style=wx.SOLID)
+        # georectifier
+        elif name == "georect":
+            self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
+
+            self._mgr.AddPane(self.toolbars['georect'].toolbar,
+                              wx.aui.AuiPaneInfo().
+                              Name("georecttoolbar").Caption(_("Georectification toolbar")).
+                              ToolbarPane().Top().
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2))
+        # nviz
+        elif name == "nviz":
+            import nviz
+
+            # check for GLCanvas and OpenGL
+            msg = None
+            if not nviz.haveGLCanvas:
+                msg = _("Unable to switch to 3D display mode.\nThe GLCanvas class has not been "
+                        "included with this build "
+                        "of wxPython!\nSwitching back to "
+                        "2D display mode.\n\nDetails: %s" % nviz.errorMsg)
+            if not nviz.haveNviz:
+                msg = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
+                        "was not found or loaded properly.\n"
+                        "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg)
+
+            if msg:
+                self.toolbars['map'].combo.SetValue (_("2D view"))
+                wx.MessageBox(parent=self,
+                              message=msg,
+                              caption=_("Error"),
+                              style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                return
+
+            #
+            # add Nviz toolbar and disable 2D display mode tools
+            #
+            self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
+            self.toolbars['map'].Enable2D(False)
+
+            #
+            # update layer tree (-> enable 3d-rasters)
+            #
+            self.tree.EnableItemType(type='3d-raster', enable=True)
+            
+            #
+            # update status bar
+            #
+            self.toggleStatus.Enable(False)
+
+            #
+            # erase map window
+            #
+            self.MapWindow.EraseMap()
+
+            busy = wx.BusyInfo(message=_("Please wait, loading data..."),
+                               parent=self)
+            wx.Yield()
+        
+            #
+            # create GL window & NVIZ toolbar
+            #
+            if not self.MapWindow3D:
+                self.MapWindow3D = nviz.GLWindow(self, id=wx.ID_ANY,
+                                                 Map=self.Map, tree=self.tree, gismgr=self.gismanager)
+                self.nvizToolWin = nviz.NvizToolWindow(self, id=wx.ID_ANY,
+                                                       mapWindow=self.MapWindow3D)
+                self.MapWindow3D.OnPaint(None) # -> LoadData
+                self.MapWindow3D.Show()
+                self.MapWindow3D.UpdateView(None)
+
+            busy.Destroy()
+
+            self.nvizToolWin.Show()
+
+            #
+            # switch from MapWindow to MapWindowGL
+            # add nviz toolbar
+            #
+            self._mgr.DetachPane(self.MapWindow2D)
+            self.MapWindow2D.Hide()
+            self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
+                              Dockable(False).BestSize((-1,-1)).
+                              CloseButton(False).DestroyOnClose(True).
+                              Layer(0))
+            self._mgr.AddPane(self.toolbars['nviz'].toolbar,
+                              wx.aui.AuiPaneInfo().
+                              Name("nviztoolbar").Caption(_("Nviz toolbar")).
+                              ToolbarPane().Top().Row(1).
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2))
+            
+            self.MapWindow = self.MapWindow3D
+            self.SetStatusText("", 0)
+            
+        self._mgr.Update()
+
+    def RemoveToolbar (self, name):
+        """
+        Removes toolbar from the window
+
+        TODO: Only hide, activate by calling AddToolbar()
+        """
+
+        # cannot hide main toolbar
+        if name == "map":
+            return
+        elif name == "vdigit":
+            # TODO: not destroy only hide
+            for toolRow in range(0, self.toolbars['vdigit'].numOfRows):
+                self._mgr.DetachPane (self.toolbars['vdigit'].toolbar[toolRow])
+                self.toolbars['vdigit'].toolbar[toolRow].Destroy()
+        else:
+            self._mgr.DetachPane (self.toolbars[name].toolbar)
+            self.toolbars[name].toolbar.Destroy()
+
+        self.toolbars[name] = None
+
+        if name == 'nviz':
+            # hide nviz tools
+            self.nvizToolWin.Hide()
+            # unload data
+#            self.MapWindow3D.Reset()
+            # switch from MapWindowGL to MapWindow
+            self._mgr.DetachPane(self.MapWindow3D)
+            self.MapWindow3D.Hide()
+            self.MapWindow2D.Show()
+            self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
+                              Dockable(False).BestSize((-1,-1)).
+                              CloseButton(False).DestroyOnClose(True).
+                              Layer(0))
+            self.MapWindow = self.MapWindow2D
+  
+            #
+            # update layer tree (-> disable 3d-rasters)
+            #
+            self.tree.EnableItemType(type='3d-raster', enable=False)
+            self.MapWindow.UpdateMap()
+            
+        self.toolbars['map'].combo.SetValue (_("2D view"))
+        self.toolbars['map'].Enable2D(True)
+        self.toggleStatus.Enable(True)
+
+        self._mgr.Update()
+
+    def __InitDisplay(self):
+        """
+        Initialize map display, set dimensions and map region
+        """
+        self.width, self.height = self.GetClientSize()
+
+        Debug.msg(2, "MapFrame.__InitDisplay():")
+        self.Map.ChangeMapSize(self.GetClientSize())
+        self.Map.region = self.Map.GetRegion() # g.region -upgc
+        # self.Map.SetRegion() # adjust region to match display window
+
+    def OnUpdateProgress(self, event):
+        """
+        Update progress bar info
+        """
+        self.onRenderGauge.SetValue(event.value)
+        
+        event.Skip()
+        
+    def OnFocus(self, event):
+        """
+        Change choicebook page to match display.
+        Or set display for georectifying
+        """
+        if self.gismanager.georectifying:
+            # in georectifying session; display used to get get geographic
+            # coordinates for GCPs
+            self.OnPointer(event)
+        else:
+            # change bookcontrol page to page associated with display
+            if self.page:
+                pgnum = self.layerbook.GetPageIndex(self.page)
+                if pgnum > -1:
+                    self.layerbook.SetSelection(pgnum)
+        
+        event.Skip()
+
+    def OnMotion(self, event):
+        """
+        Mouse moved
+        Track mouse motion and update status bar
+        """
+        # update statusbar if required
+        if self.toggleStatus.GetSelection() == 0: # Coordinates
+            e, n = self.MapWindow.Pixel2Cell(event.GetPositionTuple())
+            if self.toolbars['vdigit'] and \
+                    self.toolbars['vdigit'].GetAction() == 'addLine' and \
+                    self.toolbars['vdigit'].GetAction('type') in ('line', 'boundary') and \
+                    len(self.MapWindow.polycoords) > 0:
+                # for linear feature show segment and total length
+                distance_seg = self.MapWindow.Distance(self.MapWindow.polycoords[-1],
+                                                       (e, n), screen=False)[0]
+                distance_tot = distance_seg
+                for idx in range(1, len(self.MapWindow.polycoords)):
+                    distance_tot += self.MapWindow.Distance(self.MapWindow.polycoords[idx-1],
+                                                            self.MapWindow.polycoords[idx],
+                                                            screen=False )[0]
+                self.statusbar.SetStatusText("%.2f, %.2f (seg: %.2f; tot: %.2f)" % \
+                                                 (e, n, distance_seg, distance_tot), 0)
+            else:
+                if self.Map.projinfo['proj'] == 'll':
+                    self.statusbar.SetStatusText("%s" % utils.Deg2DMS(e, n), 0)
+                else:
+                    self.statusbar.SetStatusText("%.2f, %.2f" % (e, n), 0)
+        
+        event.Skip()
+
+    def OnDraw(self, event):
+        """
+        Re-display current map composition
+        """
+        self.MapWindow.UpdateMap(render=False)
+        
+    def OnRender(self, event):
+        """
+        Re-render map composition (each map layer)
+        """
+        # delete tmp map layers (queries)
+        qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
+        for layer in qlayer:
+            self.Map.DeleteLayer(layer)
+
+        # delete tmp lines
+        if self.MapWindow.mouse["use"] in ["measure", "profile"]:
+            self.MapWindow.polycoords = []
+            self.MapWindow.ClearLines()
+        
+        # deselect features in vdigit
+        if self.toolbars['vdigit'] and self.digit:
+            self.digit.driver.SetSelected([])
+            self.MapWindow.UpdateMap(render=True, renderVector=True)
+        else:
+            self.MapWindow.UpdateMap(render=True)
+        
+        # update statusbar
+        self.StatusbarUpdate()
+
+    def OnPointer(self, event):
+        """
+        Pointer button clicked
+        """
+        if self.toolbars['map']:
+            if event:
+                self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "pointer"
+        self.MapWindow.mouse['box'] = "point"
+
+        # change the cursor
+        if self.toolbars['vdigit']:
+            # digitization tool activated
+            self.MapWindow.SetCursor(self.cursors["cross"])
+
+            # reset mouse['box'] if needed
+            if self.toolbars['vdigit'].GetAction() in ['addLine']:
+                if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
+                    self.MapWindow.mouse['box'] = 'point'
+                else: # line, boundary
+                    self.MapWindow.mouse['box'] = 'line'
+            elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
+                                                         'editLine', 'displayCats', 'displayAttrs',
+                                                         'copyCats']:
+                self.MapWindow.mouse['box'] = 'point'
+            else: # moveLine, deleteLine
+                self.MapWindow.mouse['box'] = 'box'
+        
+        elif self.gismanager.georectifying:
+            self.MapWindow.SetCursor(self.cursors["cross"])
+        
+        else:
+            self.MapWindow.SetCursor(self.cursors["default"])
+
+    def OnZoomIn(self, event):
+        """
+        Zoom in the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "zoom"
+        self.MapWindow.mouse['box'] = "box"
+        self.MapWindow.zoomtype = 1
+        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+
+    def OnZoomOut(self, event):
+        """
+        Zoom out the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "zoom"
+        self.MapWindow.mouse['box'] = "box"
+        self.MapWindow.zoomtype = -1
+        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+
+    def OnZoomBack(self, event):
+        """
+        Zoom last (previously stored position)
+        """
+        self.MapWindow.ZoomBack()
+
+    def OnPan(self, event):
+        """
+        Panning, set mouse to drag
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "pan"
+        self.MapWindow.mouse['box'] = "pan"
+        self.MapWindow.zoomtype = 0
+                
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["hand"])
+
+    def OnErase(self, event):
+        """
+        Erase the canvas
+        """
+        self.MapWindow.EraseMap()
+
+    def OnZoomRegion(self, event):
+        """
+        Zoom to region
+        """
+        self.Map.getRegion()
+        self.Map.getResolution()
+        self.UpdateMap()
+        # event.Skip()
+
+    def OnAlignRegion(self, event):
+        """
+        Align region
+        """
+        if not self.Map.alignRegion:
+            self.Map.alignRegion = True
+        else:
+            self.Map.alignRegion = False
+        # event.Skip()
+
+    def OnToggleRender(self, event):
+        """
+        Enable/disable auto-rendering
+        """
+        if self.autoRender.GetValue():
+            self.OnRender(None)
+
+    def OnToggleShowRegion(self, event):
+        """
+        Show/Hide extent in map canvas
+        """
+        if self.showRegion.GetValue():
+            # show extent
+            self.MapWindow.regionCoords = []
+        else:
+            del self.MapWindow.regionCoords
+
+        # redraw map if auto-rendering is enabled
+        if self.autoRender.GetValue():
+            self.OnRender(None)
+
+    def OnToggleResolution(self, event):
+        """
+        Use resolution of computation region settings
+        for redering image instead of display resolution
+        """
+        # redraw map if auto-rendering is enabled
+        if self.autoRender.GetValue():
+            self.OnRender(None)
+        
+    def OnToggleStatus(self, event):
+        """
+        Toggle status text
+        """
+        self.StatusbarUpdate()
+
+    def OnChangeMapScale(self, event):
+        """
+        Map scale changed by user
+        """
+        scale = event.GetString()
+
+        try:
+            if scale[:2] != '1:':
+                raise ValueError
+            value = int(scale[2:])
+        except ValueError:
+            self.mapScale.SetValue('1:%ld' % int(self.mapScaleValue))
+            return
+
+        dEW = value * (self.Map.region['cols'] / self.ppm[0])
+        dNS = value * (self.Map.region['rows'] / self.ppm[1])
+        self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
+        self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
+        self.Map.region['w'] = self.Map.region['center_easting']  - dEW / 2.
+        self.Map.region['e'] = self.Map.region['center_easting']  + dEW / 2.
+        
+        # add to zoom history
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                                   self.Map.region['e'], self.Map.region['w'])
+        
+        # redraw a map
+        self.MapWindow.UpdateMap()
+        self.mapScale.SetFocus()
+        
+    def StatusbarUpdate(self):
+        """Update statusbar content"""
+
+        self.showRegion.Hide()
+        self.compResolution.Hide()
+        self.mapScale.Hide()
+        self.mapScaleValue = self.ppm = None
+
+        if self.toggleStatus.GetSelection() == 0: # Coordinates
+            self.statusbar.SetStatusText("", 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.toggleStatus.GetSelection() == 1: # Extent
+            self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f" %
+                                         (self.Map.region["w"], self.Map.region["e"],
+                                          self.Map.region["s"], self.Map.region["n"]), 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.toggleStatus.GetSelection() == 2: # Comp. region
+            compregion = self.Map.GetRegion()
+            self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f (%.2f, %.2f)" %
+                                         (compregion["w"], compregion["e"],
+                                          compregion["s"], compregion["n"],
+                                          compregion["ewres"], compregion["nsres"]), 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.toggleStatus.GetSelection() == 3: # Show comp. extent
+            self.statusbar.SetStatusText("", 0)
+            self.showRegion.Show()
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        elif self.toggleStatus.GetSelection() == 4: # Display mode
+            self.statusbar.SetStatusText("", 0)
+            self.compResolution.Show()
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        elif self.toggleStatus.GetSelection() == 5: # Display geometry
+            self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
+                                         (self.Map.region["rows"], self.Map.region["cols"],
+                                          self.Map.region["nsres"], self.Map.region["ewres"]), 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.toggleStatus.GetSelection() == 6: # Map scale
+            # TODO: need to be fixed...
+            ### screen X region problem
+            ### user should specify ppm
+            dc = wx.ScreenDC()
+            dpSizePx = wx.DisplaySize()   # display size in pixels
+            dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
+            dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
+            sysPpi  = dc.GetPPI()
+            comPpi = (dpSizePx[0] / dpSizeIn[0],
+                      dpSizePx[1] / dpSizeIn[1])
+
+            ppi = comPpi                  # pixel per inch
+            self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
+                        (ppi[1] / 2.54) * 100)
+
+            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
+                      "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
+                          (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
+                           dpSizeIn[0], dpSizeIn[1],
+                           sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
+                           self.ppm[0], self.ppm[1]))
+
+            region = self.Map.region
+
+            heightCm = region['rows'] / self.ppm[1] * 100
+            widthCm  = region['cols'] / self.ppm[0] * 100
+
+            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
+                      (widthCm, heightCm))
+
+            xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
+            yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
+            scale = (xscale + yscale) / 2.
+            
+            Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
+                          (xscale, yscale, scale))
+
+            self.statusbar.SetStatusText("")
+            try:
+                self.mapScale.SetValue("1:%ld" % (scale + 0.5))
+            except TypeError:
+                pass
+            self.mapScaleValue = scale
+            self.mapScale.Show()
+
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        else:
+            self.statusbar.SetStatusText("", 1)
+
+    def StatusbarEnableLongHelp(self, enable=True):
+        """Enable/disable toolbars long help"""
+        for toolbar in self.toolbars.itervalues():
+            if toolbar:
+                toolbar.EnableLongHelp(enable)
+                
+    def StatusbarReposition(self):
+        """Reposition checkbox in statusbar"""
+        # reposition checkbox
+        widgets = [(0, self.showRegion),
+                   (0, self.compResolution),
+                   (0, self.mapScale),
+                   (0, self.onRenderGauge),
+                   (1, self.toggleStatus),
+                   (2, self.maskInfo),
+                   (3, self.autoRender)]
+        for idx, win in widgets:
+            rect = self.statusbar.GetFieldRect(idx)
+            if idx == 0: # show region / mapscale / process bar
+                # -> size
+                wWin, hWin = win.GetBestSize()
+                if win == self.onRenderGauge:
+                    wWin = rect.width - 6
+                # -> position
+                # if win == self.showRegion:
+                    # x, y = rect.x + rect.width - wWin, rect.y - 1
+                    # align left
+                # else:
+                x, y = rect.x + 3, rect.y - 1
+                w, h = wWin, rect.height + 2
+            else: # choice || auto-rendering
+                x, y = rect.x, rect.y - 1
+                w, h = rect.width, rect.height + 2
+                if idx == 2: # mask
+                    x += 5
+                    y += 4
+                elif idx == 3: # render
+                    x += 5
+            
+            win.SetPosition((x, y))
+            win.SetSize((w, h))
+
+    def SaveToFile(self, event):
+        """
+        Save image to file
+        """
+        filetype =  "PNG file (*.png)|*.png|"\
+                    "TIF file (*.tif)|*.tif|"\
+                    "GIF file (*.gif)|*.gif"
+
+        dlg = wx.FileDialog(self, "Choose a file name to save the image as a PNG to",
+            defaultDir = "",
+            defaultFile = "",
+            wildcard = filetype,
+            style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
+        if dlg.ShowModal() == wx.ID_OK:
+            base = os.path.splitext(dlg.GetPath())[0]
+            ext = os.path.splitext(dlg.GetPath())[1]
+            if dlg.GetFilterIndex() == 0:
+                type = wx.BITMAP_TYPE_PNG
+                path = dlg.GetPath()
+                if ext != '.png': path = base+'.png'
+            elif dlg.GetFilterIndex() == 1:
+                type = wx.BITMAP_TYPE_TIF
+                if ext != '.tif': path = base+'.tif'
+            elif dlg.GetFilterIndex() == 2:
+                type = wx.BITMAP_TYPE_TIF
+                if ext != '.gif': path = base+'.gif'
+            self.MapWindow.SaveToFile(path, type)
+
+        dlg.Destroy()
+
+    def PrintMenu(self, event):
+        """
+        Print options and output menu for map display
+        """
+        point = wx.GetMousePosition()
+        printmenu = wx.Menu()
+        # Add items to the menu
+        setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
+        printmenu.AppendItem(setup)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
+
+        preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
+        printmenu.AppendItem(preview)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
+
+        doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
+        printmenu.AppendItem(doprint)
+        self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(printmenu)
+        printmenu.Destroy()
+
+    def OnCloseWindow(self, event):
+        """
+        Window closed.
+        Also close associated layer tree page
+        """
+        pgnum = None
+        self.Map.Clean()
+        
+        # close edited map and 3D tools properly
+        if self.toolbars['vdigit']:
+            maplayer = self.toolbars['vdigit'].GetLayer()
+            if maplayer:
+                self.toolbars['vdigit'].OnExit()
+                self.imgVectorMap = None
+
+        if self.toolbars['nviz']:
+            self.toolbars['nviz'].OnExit()
+        
+        if self.page:
+            pgnum = self.layerbook.GetPageIndex(self.page)
+            if pgnum > -1:
+                self.layerbook.DeletePage(pgnum)
+        
+        ### self.Destroy()
+        # if event:
+        #    event.Skip() <- causes application crash
+        
+    def GetRender(self):
+        """
+        Returns the current instance of render.Map()
+        """
+        return self.Map
+
+    def OnQueryDisplay(self, event):
+        """
+        Query currrent raster/vector map layers (display mode)
+        """
+        if self.toolbars['map'].GetAction() == 'displayAttrb': # select previous action
+            self.toolbars['map'].SelectDefault(event)
+            return
+
+        self.toolbars['map'].action['desc'] = 'displayAttrb'
+        
+        # switch GIS Manager to output console to show query results
+        self.gismanager.notebook.SetSelection(1)
+
+        self.MapWindow.mouse['use'] = "query"
+        self.MapWindow.mouse['box'] = "point"
+        self.MapWindow.zoomtype = 0
+
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+
+    def OnQueryModify(self, event):
+        """
+        Query vector map layer (edit mode)
+        """
+        if self.toolbars['map'].GetAction() == 'modifyAttrb': # select previous action
+            self.toolbars['map'].SelectDefault(event)
+            return
+        
+        self.toolbars['map'].action['desc'] = 'modifyAttrb'
+        
+        self.MapWindow.mouse['use'] = "queryVector"
+        self.MapWindow.mouse['box'] = "point"
+        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        self.MapWindow.zoomtype = 0
+
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+        
+    def QueryMap(self, x, y):
+        """!Query map layer features
+
+        Currently only raster and vector map layers are supported.
+        
+        @param x,y coordinates
+        """
+        #set query snap distance for v.what at mapunit equivalent of 10 pixels
+        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
+        east, north = self.MapWindow.Pixel2Cell((x, y))
+
+        num = 0
+        for layer in self.tree.GetSelections():
+            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
+            if type in ('raster', 'rgb', 'his',
+                        'vector', 'thememap', 'themechart'):
+                num += 1
+        
+        if num < 1:
+            dlg = wx.MessageDialog(parent=self,
+                                   message=_('No raster or vector map layer selected for querying.'),
+                                   caption=_('No map layer selected'),
+                                   style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+        
+        mapname = None
+        raststr = ''
+        vectstr = ''
+        rcmd = []
+        vcmd = []
+        for layer in self.tree.GetSelections():
+            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
+            dcmd = self.tree.GetPyData(layer)[0]['cmd']
+            name = utils.GetLayerNameFromCmd(dcmd)
+            if name == '':
+                continue
+            if type in ('raster', 'rgb', 'his'):
+                raststr += "%s," % name
+            elif type in ('vector', 'thememap', 'themechart'):
+                vectstr += "%s," % name
+
+        # use display region settings instead of computation region settings
+        self.tmpreg = os.getenv("GRASS_REGION")
+        os.environ["GRASS_REGION"] = self.Map.SetRegion(windres=False)
+        
+        # build query commands for any selected rasters and vectors
+        if raststr != '':
+            rcmd = ['r.what', '--q',
+                    '-f',
+                    'input=%s' % raststr.rstrip(','),
+                    'east_north=%f,%f' % (float(east), float(north))]
+
+        if vectstr != '':
+            # check for vector maps open to be edited
+            digitToolbar = self.toolbars['vdigit']
+            if digitToolbar:
+                map = digitToolbar.GetLayer().GetName()
+                vect = []
+                for vector in vectstr.split(','):
+                    if map == vector:
+                        self.gismanager.goutput.WriteWarning("Vector map <%s> "
+                                                             "opened for editing - skipped." % map)
+                        continue
+                    vect.append(vector)
+                vectstr = ','.join(vect)
+                
+            if len(vectstr) <= 1:
+                self.gismanager.goutput.WriteCmdLog("Nothing to query.")
+                return
+            
+            vcmd = ['v.what', '--q',
+                    '-a',
+                    'map=%s' % vectstr.rstrip(','),
+                    'east_north=%f,%f' % (float(east), float(north)),
+                    'distance=%f' % qdist]
+
+        # parse query command(s)
+        if self.gismanager:
+            if rcmd:
+                self.gismanager.goutput.RunCmd(rcmd, compReg=False,
+                                               onDone = self._QueryMapDone)
+            if vcmd:
+                self.gismanager.goutput.RunCmd(vcmd,
+                                               onDone = self._QueryMapDone)
+        else:
+            if rcmd:
+                gcmd.Command(rcmd)
+            if vcmd:
+                gcmd.Command(vcmd)
+
+    def _QueryMapDone(self, returncode):
+        """!Restore settings after querying (restore GRASS_REGION)
+
+        @param returncode command return code
+        """
+        if hasattr(self, "tmpreg"):
+            if self.tmpreg:
+                os.environ["GRASS_REGION"] = self.tmpreg
+            elif os.environ.has_key('GRASS_REGION'):
+                del os.environ["GRASS_REGION"]
+        elif os.environ.has_key('GRASS_REGION'):
+            del os.environ["GRASS_REGION"]
+        
+        if hasattr(self, "tmpreg"):
+            del self.tmpreg
+        
+    def QueryVector(self, x, y):
+        """
+        Query vector map layer features
+
+        Attribute data of selected vector object are displayed in GUI dialog.
+        Data can be modified (On Submit)
+        """
+        if not self.tree.layer_selected or \
+                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
+            wx.MessageBox(parent=self,
+                          message=_("No vector map selected for querying."),
+                          caption=_("Vector querying"),
+                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            return
+        
+        if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
+                grass.gisenv()['MAPSET']:
+            wx.MessageBox(parent=self,
+                          message=_("Only vector map from the current mapset can be modified."),
+                          caption=_("Vector querying"),
+                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            return
+        
+        posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
+                                         y + self.MapWindow.dialogOffset))
+
+        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / \
+                            self.Map.width)
+        east, north = self.MapWindow.Pixel2Cell((x, y))
+
+        mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
+        
+        if self.dialogs['attributes'] is None:
+            self.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self.MapWindow,
+                                                                     map=mapName,
+                                                                     query=((east, north), qdist),
+                                                                     pos=posWindow,
+                                                                     action="update")
+        else:
+            # selection changed?
+            if not self.dialogs['attributes'].mapDBInfo or \
+                   self.dialogs['attributes'].mapDBInfo.map != mapName:
+                self.dialogs['attributes'].UpdateDialog(map=mapName, query=((east, north), qdist))
+            else:
+                self.dialogs['attributes'].UpdateDialog(query=((east, north), qdist))
+
+        cats = self.dialogs['attributes'].GetCats()
+        try:
+            qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)[0]
+        except IndexError:
+            qlayer = None
+        
+        if self.dialogs['attributes'].mapDBInfo and cats:
+            # highlight feature & re-draw map
+            if qlayer:
+                qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
+                                                        useId=False,
+                                                        addLayer=False))
+            else:
+                qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId=False)
+
+            # set opacity based on queried layer
+            opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float=True)
+            qlayer.SetOpacity(opacity)
+            
+            self.MapWindow.UpdateMap(render=False, renderVector=False)
+            if not self.dialogs['attributes'].IsShown():
+                self.dialogs['attributes'].Show()
+        else:
+            if qlayer:
+                self.Map.DeleteLayer(qlayer)
+                self.MapWindow.UpdateMap(render=False, renderVector=False)
+            if self.dialogs['attributes'].IsShown():
+                self.dialogs['attributes'].Hide()
+
+    def OnQuery(self, event):
+        """Query tools menu"""
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            action = self.toolbars['map'].GetAction()
+        
+        point = wx.GetMousePosition()
+        toolsmenu = wx.Menu()
+        # Add items to the menu
+        display = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
+                              text=_("Query raster/vector map(s) (display mode)"),
+                              kind=wx.ITEM_CHECK)
+        toolsmenu.AppendItem(display)
+        self.Bind(wx.EVT_MENU, self.OnQueryDisplay, display)
+        numLayers = 0
+        for layer in self.tree.GetSelections():
+            type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
+            if type in ('raster', 'rgb', 'his',
+                        'vector', 'thememap', 'themechart'):
+                numLayers += 1
+        if numLayers < 1:
+            display.Enable(False)
+        
+        if action == "displayAttrb":
+            display.Check(True)
+        
+        modify = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
+                             text=_("Query vector map (edit mode)"),
+                             kind=wx.ITEM_CHECK)
+        toolsmenu.AppendItem(modify)
+        self.Bind(wx.EVT_MENU, self.OnQueryModify, modify)
+        digitToolbar = self.toolbars['vdigit']
+        if self.tree.layer_selected:
+            layer_selected = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer']
+            if layer_selected.GetType() != 'vector' or \
+                    (digitToolbar and \
+                         digitToolbar.GetLayer() == layer_selected):
+                modify.Enable(False)
+            else:
+                if action == "modifyAttrb":
+                    modify.Check(True)
+        
+        self.PopupMenu(toolsmenu)
+        toolsmenu.Destroy()
+
+    def AddTmpVectorMapLayer(self, name, cats, useId=False, addLayer=True):
+        """
+        Add temporal vector map layer to map composition
+
+        @param name name of map layer
+        @param useId use feature id instead of category 
+        """
+        # color settings from ATM
+        color = UserSettings.Get(group='atm', key='highlight', subkey='color')
+        colorStr = str(color[0]) + ":" + \
+        str(color[1]) + ":" + \
+        str(color[2])
+
+        pattern = ["d.vect",
+                   "map=%s" % name,
+                   "color=%s" % colorStr,
+                   "fcolor=%s" % colorStr,
+                   "width=%d"  % UserSettings.Get(group='atm', key='highlight', subkey='width')]
+        
+        if useId:
+            cmd = pattern
+            cmd.append('-i')
+            cmd.append('cats=%s' % str(cats))
+        else:
+            cmd = []
+            for layer in cats.keys():
+                cmd.append(copy.copy(pattern))
+                lcats = cats[layer]
+                cmd[-1].append("layer=%d" % layer)
+                cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
+        
+        #     if self.icon:
+        #         cmd.append("icon=%s" % (self.icon))
+        #     if self.pointsize:
+        #         cmd.append("size=%s" % (self.pointsize))
+
+        if addLayer:
+            if useId:
+                return self.Map.AddLayer(type='vector', name=globalvar.QUERYLAYER, command=cmd,
+                                         l_active=True, l_hidden=True, l_opacity=1.0)
+            else:
+                return self.Map.AddLayer(type='command', name=globalvar.QUERYLAYER, command=cmd,
+                                         l_active=True, l_hidden=True, l_opacity=1.0)
+        else:
+            return cmd
+
+    def OnAnalyze(self, event):
+        """
+        Analysis tools menu
+        """
+        point = wx.GetMousePosition()
+        toolsmenu = wx.Menu()
+        # Add items to the menu
+        measure = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["measure"].GetLabel())
+        measure.SetBitmap(Icons["measure"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(measure)
+        self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
+
+        profile = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["profile"].GetLabel())
+        profile.SetBitmap(Icons["profile"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(profile)
+        self.Bind(wx.EVT_MENU, self.Profile, profile)
+
+        histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["histogram"].GetLabel())
+        histogram.SetBitmap(Icons["histogram"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(histogram)
+        self.Bind(wx.EVT_MENU, self.Histogram, histogram)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(toolsmenu)
+        toolsmenu.Destroy()
+
+    def OnMeasure(self, event):
+        """
+        Init measurement routine that calculates
+        map distance along transect drawn on
+        map display
+        """
+
+        self.totaldist = 0.0 # total measured distance
+
+        # switch GIS Manager to output console to show measure results
+        self.gismanager.notebook.SetSelection(1)
+
+        # change mouse to draw line for measurement
+        self.MapWindow.mouse['use'] = "measure"
+        self.MapWindow.mouse['box'] = "line"
+        self.MapWindow.zoomtype = 0
+        self.MapWindow.pen     = wx.Pen(colour='red', width=2, style=wx.SHORT_DASH)
+        self.MapWindow.polypen = wx.Pen(colour='green', width=2, style=wx.SHORT_DASH)
+
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["pencil"])
+
+        # initiating output
+        style = self.gismanager.goutput.cmd_output.StyleWarning
+        self.gismanager.goutput.WriteLog(_('Click and drag with left mouse button '
+                                           'to measure.%s'
+                                           'Double click with left button to clear.') % \
+                                             (os.linesep), style)
+        if self.Map.projinfo['proj'] != 'xy':
+            units = self.Map.projinfo['units']
+            style = self.gismanager.goutput.cmd_output.StyleCommand
+            self.gismanager.goutput.WriteLog(_('Measuring distance') + ' ('
+                                             + units + '):',
+                                             style)
+        else:
+            self.gismanager.goutput.WriteLog(_('Measuring distance:'),
+                                             style)
+
+    def MeasureDist(self, beginpt, endpt):
+        """
+        Calculate map distance from screen distance
+        and print to output window
+        """
+
+        if self.gismanager.notebook.GetSelection() != 1:
+            self.gismanager.notebook.SetSelection(1)
+
+        dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
+
+        dist = round(dist, 3)
+        d, dunits = self.FormatDist(dist)
+
+        self.totaldist += dist
+        td, tdunits = self.FormatDist(self.totaldist)
+
+        strdist = str(d)
+        strtotdist = str(td)
+
+        if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
+            angle = int(math.degrees(math.atan2(north,east)) + 0.5)
+            angle = 180 - angle
+            if angle < 0:
+                angle = 360+angle
+
+            mstring = 'segment = %s %s\ttotal distance = %s %s\tbearing = %d deg' \
+                % (strdist,dunits,strtotdist,tdunits,angle)
+        else:
+            mstring = 'segment = %s %s\ttotal distance = %s %s' \
+                % (strdist,dunits,strtotdist,tdunits)
+
+        self.gismanager.goutput.WriteLog(mstring)
+
+        return dist
+
+    def Profile(self, event):
+        """
+        Init profile canvas and tools
+        """
+        raster = []
+        if self.tree.layer_selected and \
+               self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
+            raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
+
+        self.profile = profile.ProfileFrame(self,
+                                            id=wx.ID_ANY, pos=wx.DefaultPosition, size=(700,300),
+                                            style=wx.DEFAULT_FRAME_STYLE, rasterList=raster)
+        self.profile.Show()
+        # Open raster select dialog to make sure that a raster (and the desired raster)
+        # is selected to be profiled
+        self.profile.OnSelectRaster(None)
+
+    def FormatDist(self, dist):
+        """Format length numbers and units in a nice way,
+        as a function of length. From code by Hamish Bowman
+        Grass Development Team 2006"""
+
+        mapunits = self.Map.projinfo['units']
+        if mapunits == 'metres': mapunits = 'meters'
+        outunits = mapunits
+        dist = float(dist)
+        divisor = 1.0
+
+        # figure out which units to use
+        if mapunits == 'meters':
+            if dist > 2500.0:
+                outunits = 'km'
+                divisor = 1000.0
+            else: outunits = 'm'
+        elif mapunits == 'feet':
+            # nano-bug: we match any "feet", but US Survey feet is really
+            #  5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
+            #  miles the tick markers are rounded to the nearest 10th of a
+            #  mile (528'), the difference in foot flavours is ignored.
+            if dist > 5280.0:
+                outunits = 'miles'
+                divisor = 5280.0
+            else:
+                outunits = 'ft'
+        elif 'degree' in mapunits:
+            if dist < 1:
+                outunits = 'min'
+                divisor = (1/60.0)
+            else:
+                outunits = 'deg'
+
+        # format numbers in a nice way
+        if (dist/divisor) >= 2500.0:
+            outdist = round(dist/divisor)
+        elif (dist/divisor) >= 1000.0:
+            outdist = round(dist/divisor,1)
+        elif (dist/divisor) > 0.0:
+            outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
+        else:
+            outdist = float(dist/divisor)
+
+        return (outdist, outunits)
+
+
+    def Histogram(self, event):
+        """
+        Init histogram display canvas and tools
+        """
+        self.histogram = histogram.HistFrame(self,
+                                             id=wx.ID_ANY, size=globalvar.HIST_WINDOW_SIZE,
+                                             style=wx.DEFAULT_FRAME_STYLE)
+
+        #show new display
+        self.histogram.Show()
+        self.histogram.Refresh()
+        self.histogram.Update()
+
+
+    def OnDecoration(self, event):
+        """
+        Decorations overlay menu
+        """
+        point = wx.GetMousePosition()
+        decmenu = wx.Menu()
+        # Add items to the menu
+        AddScale = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addbarscale"].GetLabel())
+        AddScale.SetBitmap(Icons["addbarscale"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddScale)
+        self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
+
+        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addlegend"].GetLabel())
+        AddLegend.SetBitmap(Icons["addlegend"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddLegend)
+        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
+
+        AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addtext"].GetLabel())
+        AddText.SetBitmap(Icons["addtext"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddText)
+        self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(decmenu)
+        decmenu.Destroy()
+
+    def OnAddBarscale(self, event):
+        """
+        Handler for scale/arrow map decoration menu selection.
+        """
+        if self.dialogs['barscale']:
+            return
+
+        id = 0 # unique index for overlay layer
+
+        # If location is latlon, only display north arrow (scale won't work)
+        #        proj = self.Map.projinfo['proj']
+        #        if proj == 'll':
+        #            barcmd = 'd.barscale -n'
+        #        else:
+        #            barcmd = 'd.barscale'
+
+        # decoration overlay control dialog
+        self.dialogs['barscale'] = \
+            gdialogs.DecorationDialog(parent=self, title=_('Scale and North arrow'),
+                                      size=(350, 200),
+                                      style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
+                                      cmd=['d.barscale', 'at=0,5'],
+                                      ovlId=id,
+                                      name='barscale',
+                                      checktxt = _("Show/hide scale and North arrow"),
+                                      ctrltxt = _("scale object"))
+
+        self.dialogs['barscale'].CentreOnParent()
+        ### dialog cannot be show as modal - in the result d.barscale is not selectable
+        ### self.dialogs['barscale'].ShowModal()
+        self.dialogs['barscale'].Show()
+        self.MapWindow.mouse['use'] = 'pointer'        
+
+    def OnAddLegend(self, event):
+        """
+        Handler for legend map decoration menu selection.
+        """
+        if self.dialogs['legend']:
+            return
+        
+        id = 1 # index for overlay layer in render
+
+        cmd = ['d.legend', 'at=5,50,2,5']
+        if self.tree.layer_selected and \
+               self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
+            cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
+
+        # Decoration overlay control dialog
+        self.dialogs['legend'] = \
+            gdialogs.DecorationDialog(parent=self, title=('Legend'),
+                                      size=(350, 200),
+                                      style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
+                                      cmd=cmd,
+                                      ovlId=id,
+                                      name='legend',
+                                      checktxt = _("Show/hide legend"),
+                                      ctrltxt = _("legend object")) 
+
+        self.dialogs['legend'].CentreOnParent() 
+        ### dialog cannot be show as modal - in the result d.legend is not selectable
+        ### self.dialogs['legend'].ShowModal()
+        self.dialogs['legend'].Show()
+        self.MapWindow.mouse['use'] = 'pointer'
+
+    def OnAddText(self, event):
+        """
+        Handler for text decoration menu selection.
+        """
+        if self.MapWindow.dragid > -1:
+            id = self.MapWindow.dragid
+        else:
+            # index for overlay layer in render
+            if len(self.MapWindow.textdict.keys()) > 0:
+                id = self.MapWindow.textdict.keys()[-1] + 1
+            else:
+                id = 101
+
+        self.dialogs['text'] = gdialogs.TextLayerDialog(parent=self, ovlId=id, 
+                                                    title=_('Add text layer'),
+                                                    size=(400, 200))
+        self.dialogs['text'].CenterOnParent()
+
+        # If OK button pressed in decoration control dialog
+        if self.dialogs['text'].ShowModal() == wx.ID_OK:
+            text = self.dialogs['text'].GetValues()['text']
+            active = self.dialogs['text'].GetValues()['active']
+            coords, w, h = self.MapWindow.TextBounds(self.dialogs['text'].GetValues())
+        
+            # delete object if it has no text or is not active
+            if text == '' or active == False:
+                try:
+                    self.MapWindow.pdc.ClearId(id)
+                    self.MapWindow.pdc.RemoveId(id)
+                    del self.MapWindow.textdict[id]
+                except:
+                    pass
+                return
+
+            self.MapWindow.pdc.ClearId(id)
+            self.MapWindow.pdc.SetId(id)
+            self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
+            
+            self.MapWindow.Draw(self.MapWindow.pdcDec, img=self.MapWindow.textdict[id],
+                                drawid=id, pdctype='text', coords=coords)
+            
+            self.MapWindow.UpdateMap(render=False, renderVector=False)
+            
+        self.MapWindow.mouse['use'] = 'pointer'
+
+    def GetOptData(self, dcmd, type, params, propwin):
+        """
+        Callback method for decoration overlay command generated by
+        dialog created in menuform.py
+        """
+        # Reset comand and rendering options in render.Map. Always render decoration.
+        # Showing/hiding handled by PseudoDC
+        self.Map.ChangeOverlay(ovltype=type, type='overlay', name='', command=dcmd,
+                               l_active=True, l_render=False)
+        self.params[type] = params
+        self.propwin[type] = propwin
+
+    def OnZoomMenu(self, event):
+        """
+        Zoom menu
+        """
+        point = wx.GetMousePosition()
+        zoommenu = wx.Menu()
+        # Add items to the menu
+        zoommap = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to selected map(s)'))
+        zoommenu.AppendItem(zoommap)
+        self.Bind(wx.EVT_MENU, self.MapWindow.OnZoomToMap, zoommap)
+
+        zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
+        zoommenu.AppendItem(zoomwind)
+        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToWind, zoomwind)
+
+        zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
+        zoommenu.AppendItem(zoomdefault)
+        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToDefault, zoomdefault)
+
+        zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
+        zoommenu.AppendItem(zoomsaved)
+        self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToSaved, zoomsaved)
+
+        savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
+        zoommenu.AppendItem(savewind)
+        self.Bind(wx.EVT_MENU, self.MapWindow.DisplayToWind, savewind)
+
+        savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
+        zoommenu.AppendItem(savezoom)
+        self.Bind(wx.EVT_MENU, self.MapWindow.SaveDisplayRegion, savezoom)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(zoommenu)
+        zoommenu.Destroy()
+
+    def SetProperties(self, render=False, mode=0, showCompExtent=False,
+                      constrainRes=False):
+        """Set properies of map display window"""
+        self.autoRender.SetValue(render)
+        self.toggleStatus.SetSelection(mode)
+        self.StatusbarUpdate()
+        self.showRegion.SetValue(showCompExtent)
+        self.compResolution.SetValue(constrainRes)
+        if showCompExtent:
+            self.MapWindow.regionCoords = []
+        
+    def IsStandalone(self):
+        """!Check if Map display is standalone"""
+        if self.gismanager:
+            return False
+        
+        return True
+    
+    def GetLayerManager(self):
+        """!Get reference to Layer Manager
+
+        @return window reference
+        @return None (if standalone)
+        """
+        return self.gismanager
+
+# end of class MapFrame
+
+class MapApp(wx.App):
+    """
+    MapApp class
+    """
+
+    def OnInit(self):
+        wx.InitAllImageHandlers()
+        if __name__ == "__main__":
+            Map = render.Map() # instance of Map class to render GRASS display output to PPM file
+        else:
+            Map = None
+
+        self.mapFrm = MapFrame(parent=None, id=wx.ID_ANY, Map=Map, size=(640,480))
+        #self.SetTopWindow(Map)
+        self.mapFrm.Show()
+
+        if __name__ == "__main__":
+            # redraw map, if new command appears
+            self.redraw = False
+            status = Command(self, Map)
+            status.start()
+            self.timer = wx.PyTimer(self.watcher)
+            # check each 0.1s
+            self.timer.Start(100)
+
+        return 1
+
+    def OnExit(self):
+        if __name__ == "__main__":
+            # stop the timer
+            self.timer.Stop()
+            # terminate thread (a bit ugly)
+            os.system("""echo "quit" >> %s""" % (cmdfilename))
+
+    def watcher(self):
+        """Redraw, if new layer appears"""
+        if self.redraw:
+            self.mapFrm.OnDraw(None)
+        self.redraw = False
+        return
+# end of class MapApp
+
+if __name__ == "__main__":
+
+    ###### SET command variable
+    if len(sys.argv) != 3:
+        print __doc__
+        sys.exit()
+
+    title = sys.argv[1]
+    cmdfilename = sys.argv[2]
+
+    import gettext
+    gettext.install("gm_map") # replace with the appropriate catalog name
+
+    print "Starting monitor <%s>" % (title)
+
+    gm_map = MapApp(0)
+    # set title
+    gm_map.mapFrm.SetTitle ("GRASS GIS - Map Display: " + title + " - Location: " + \
+                                grass.gisenv()['LOCATION_NAME'])
+    gm_map.MainLoop()
+
+    if grass.gisenv().has_key("MONITOR"):
+        os.system("d.mon sel=%s" % grass.gisenv()["MONITOR"])
+
+    os.remove(cmdfilename)
+    os.system("""g.gisenv set="GRASS_PYCMDFILE" """)
+
+    print "Stoping monitor <%s>" % (title)
+
+    sys.exit()



More information about the grass-commit mailing list