[GRASS-SVN] r50840 - in grass/branches/develbranch_6/gui/wxpython: . docs psmap

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Feb 17 01:45:00 EST 2012


Author: annakrat
Date: 2012-02-16 22:45:00 -0800 (Thu, 16 Feb 2012)
New Revision: 50840

Added:
   grass/branches/develbranch_6/gui/wxpython/psmap/instructions.py
   grass/branches/develbranch_6/gui/wxpython/psmap/utils.py
Modified:
   grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.PsMap.html
   grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py
   grass/branches/develbranch_6/gui/wxpython/psmap/frame.py
   grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py
   grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox
Log:
wxGUI/wxpsmap: backport of recent changes from trunk (r50797, r50798, r50829, r50836)

Modified: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.PsMap.html
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.PsMap.html	2012-02-17 00:41:01 UTC (rev 50839)
+++ grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.PsMap.html	2012-02-17 06:45:00 UTC (rev 50840)
@@ -43,6 +43,9 @@
   <li> text
   <li> scalebar
   <li> mapinfo
+  <li> point
+  <li> line
+  <li> rectangle
 </ul>
 
 

Modified: grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py	2012-02-17 00:41:01 UTC (rev 50839)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py	2012-02-17 06:45:00 UTC (rev 50840)
@@ -1,28 +1,12 @@
 """!
 @package psmap.dialogs
 
- at brief Map feature objects and dialogs for wxPsMap
+ at brief dialogs for wxPsMap
 
 Classes:
- - dialogs::UnitConversion
  - dialogs::TCValidator
  - dialogs::PenStyleComboBox
  - dialogs::CheckListCtrl
- - dialogs::Instruction
- - dialogs::InstructionObject
- - dialogs::InitMap
- - dialogs::MapFrame
- - dialogs::PageSetup
- - dialogs::Mapinfo
- - dialogs::Text
- - dialogs::Image
- - dialogs::NorthArrow
- - dialogs::Scalebar
- - dialogs::RasterLegend
- - dialogs::VectorLegend
- - dialogs::Raster
- - dialogs::Vector
- - dialogs::VProperties
  - dialogs::PsmapDialog
  - dialogs::PageSetupDialog
  - dialogs::MapDialog
@@ -38,8 +22,10 @@
  - dialogs::TextDialog
  - dialogs::ImageDialog
  - dialogs::NorthArrowDialog
+ - dialogs::PointDialog
+ - dialogs::RectangleDialog
 
-(C) 2011 by Anna Kratochvilova, and the GRASS Development Team
+(C) 2011-2012 by Anna Kratochvilova, and 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.
@@ -51,14 +37,7 @@
 import os
 import sys
 import string
-from math import ceil, floor, sin, cos, pi
 from copy import deepcopy
-from time import strftime, localtime
-try:
-    import Image as PILImage
-    havePILImage = True
-except ImportError:
-    havePILImage = False
 
 import wx
 import wx.lib.scrolledpanel    as scrolled
@@ -72,71 +51,20 @@
 
 import grass.script as grass
 
-from core             import globalvar
-from dbmgr.vinfo      import VectorDBInfo
-from core.utils       import CmdToTuple, GetCmdString
-from gui_core.gselect import Select
-from core.gcmd        import RunCommand, GError, GMessage, GWarning
-from gui_core.dialogs import SymbolDialog
+from core               import globalvar
+from dbmgr.vinfo        import VectorDBInfo
+from gui_core.gselect   import Select
+from core.gcmd          import RunCommand, GError, GMessage
+from gui_core.dialogs   import SymbolDialog
+from psmap.utils        import *
+from psmap.instructions import *
 
 # grass.set_raise_on_error(True)
 
 PSMAP_COLORS = ['aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'grey', 'green', 'indigo',
                 'magenta','orange', 'purple', 'red', 'violet', 'white', 'yellow']
 
-class UnitConversion:
-    """! Class for converting units"""
-    def __init__(self, parent = None):
-        self.parent = parent
-        if self.parent:
-            ppi = wx.ClientDC(self.parent).GetPPI()
-        else: 
-            ppi = (72, 72)
-        self._unitsPage = { 'inch'          : {'val': 1.0, 'tr' : _("inch")},
-                            'point'         : {'val': 72.0, 'tr' : _("point")},
-                            'centimeter'    : {'val': 2.54, 'tr' : _("centimeter")},
-                            'millimeter'    : {'val': 25.4, 'tr' : _("millimeter")}}
-        self._unitsMap = {  'meters'        : {'val': 0.0254, 'tr' : _("meters")},
-                            'kilometers'    : {'val': 2.54e-5, 'tr' : _("kilometers")},
-                            'feet'          : {'val': 1./12, 'tr' : _("feet")},
-                            'miles'         : {'val': 1./63360, 'tr' : _("miles")},
-                            'nautical miles': {'val': 1/72913.386, 'tr' : _("nautical miles")}}
-
-        self._units = { 'pixel'     : {'val': ppi[0], 'tr' : _("pixel")},
-                        'meter'     : {'val': 0.0254, 'tr' : _("meter")},
-                        'nautmiles' : {'val': 1/72913.386, 'tr' :_("nautical miles")},
-                        'degrees'   : {'val': 0.0254 , 'tr' : _("degree")} #like 1 meter, incorrect
-                        }
-        self._units.update(self._unitsPage)
-        self._units.update(self._unitsMap)
-
-    def getPageUnitsNames(self):
-        return sorted(self._unitsPage[unit]['tr'] for unit in self._unitsPage.keys())
     
-    def getMapUnitsNames(self):
-        return sorted(self._unitsMap[unit]['tr'] for unit in self._unitsMap.keys())
-    
-    def getAllUnits(self):
-        return sorted(self._units.keys())
-    
-    def findUnit(self, name):
-        """!Returns unit by its tr. string"""
-        for unit in self._units.keys():
-            if self._units[unit]['tr'] == name:
-                return unit
-        return None
-    
-    def findName(self, unit):
-        """!Returns tr. string of a unit"""
-        try:
-            return self._units[unit]['tr']
-        except KeyError:
-            return None
-    
-    def convert(self, value, fromUnit = None, toUnit = None):
-        return float(value)/self._units[fromUnit]['val']*self._units[toUnit]['val']
-    
-    
 class TCValidator(wx.PyValidator):
     """!validates input in textctrls, combobox, taken from wxpython demo"""
     def __init__(self, flag = None):
@@ -163,7 +91,7 @@
         if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
             event.Skip()
             return
-        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.':
+        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.-':
             event.Skip()
             return
 ##        if self.flag == 'SCALE' and chr(key) in string.digits + ':':
@@ -246,1579 +174,7 @@
         CheckListCtrlMixin.__init__(self) 
         ListCtrlAutoWidthMixin.__init__(self)
         
-class Instruction:
-    """!Class which represents instruction file"""
-    def __init__(self, parent, objectsToDraw):
-        
-        self.parent = parent
-        self.objectsToDraw = objectsToDraw
-        #here are kept objects like mapinfo, rasterlegend, etc.
-        self.instruction = list()
-        
-    def __str__(self):
-        """!Returns text for instruction file"""
-        comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
-        env = grass.gisenv()
-        comment += "# location: %s\n" % env['LOCATION_NAME']
-        comment += "# mapset: %s\n" % env['MAPSET']
-        comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
-        border = ''
-        if not self.FindInstructionByType('map'):
-            border = 'border n\n'
-        text = [str(each) for each in self.instruction]
-        return comment + border + '\n'.join(text) + '\nend'
-    
-    def __getitem__(self, id):
-        for each in self.instruction:
-            if each.id == id:
-                return each
-        return None
 
-    def __contains__(self, id):
-        """!Test if instruction is included"""
-        for each in self.instruction:
-            if each.id == id:
-                return True
-        return False
-    
-    def __delitem__(self, id):
-        """!Delete instruction"""
-        for each in self.instruction:
-            if each.id == id:
-                if each.type == 'map':
-                    #must remove raster, vector layers too
-                    vektor = self.FindInstructionByType('vector', list = True)
-                    vProperties = self.FindInstructionByType('vProperties', list = True)
-                    raster = self.FindInstructionByType('raster', list = True)
-                    for item in vektor + vProperties + raster:
-                        if item in self.instruction:
-                            self.instruction.remove(item)
-                            
-                self.instruction.remove(each)
-                if id in self.objectsToDraw:
-                    self.objectsToDraw.remove(id)
-                return
-            
-    def AddInstruction(self, instruction):
-        """!Add instruction"""
-        # add to instructions
-        if instruction.type == 'map':
-            self.instruction.insert(0, instruction)
-        else:
-            self.instruction.append(instruction)
-        # add to drawable objects
-        if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
-            if instruction.type == 'map':
-                self.objectsToDraw.insert(0, instruction.id) 
-            else:
-                self.objectsToDraw.append(instruction.id) 
-                
-            
-    def FindInstructionByType(self, type, list = False):
-        """!Find instruction(s) with the given type"""
-        inst = []
-        for each in self.instruction:
-            if each.type == type:
-                inst.append(each)
-        if len(inst) == 1 and not list:
-            return inst[0]
-        return inst
-    
-    def Read(self, filename):
-        """!Reads instruction file and creates instruction objects"""
-        self.filename = filename
-        # open file
-        try:
-            file = open(filename, 'r')
-        except IOError:
-            GError(message = _("Unable to open file\n%s") % filename)
-            return
-        # first read file to get information about region and scaletype
-        isRegionComment = False
-        orientation = 'Portrait'
-        for line in file:
-            if '# g.region' in line:
-                self.SetRegion(regionInstruction = line)
-                isRegionComment = True
-                break
-            if '# page orientation' in line:
-                orientation = line.split(':')[-1].strip()
-                
-        if not isRegionComment:
-            self.SetRegion(regionInstruction = None)
-        # then run ps.map -b to get information for maploc
-        # compute scale and center 
-        map = self.FindInstructionByType('map')
-        region = grass.region()
-        map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
-        mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
-        map['rect'] = mapRect
-        proj = projInfo()
-        toM = 1.0
-        if proj['units']:
-            toM = float(proj['meters'])
-        units = UnitConversion(self.parent)
-        w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
-        map['scale'] = w / abs((region['w'] - region['e']))
-        
-        SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
-        
-        # read file again, now with information about map bounds
-        isBuffer = False
-        buffer = []
-        instruction = None
-        vectorMapNumber = 1
-        file.seek(0)
-        for line in file:
-            if not line.strip(): 
-                continue
-            line = line.strip()
-            if isBuffer:
-                buffer.append(line)
-                if 'end' in line:
-                    isBuffer = False
-                    kwargs = {}
-                    if instruction == 'scalebar':
-                        kwargs['scale'] = map['scale']
-                    elif instruction in ('text', 'eps'):
-                        kwargs['mapInstruction'] = map
-                    elif instruction in ('vpoints', 'vlines', 'vareas'):
-                        kwargs['id'] = wx.NewId()
-                        kwargs['vectorMapNumber'] = vectorMapNumber
-                        vectorMapNumber += 1
-                    elif instruction == 'paper':
-                        kwargs['Orientation'] = orientation
-                        
-                    ok = self.SendToRead(instruction, buffer, **kwargs)
-                    if not ok: return False
-                    buffer = []
-                continue 
-            
-            elif line.startswith('paper'):
-                instruction = 'paper'
-                isBuffer = True
-                buffer.append(line)
-            
-            elif line.startswith('border'):
-                if line.split()[1].lower() in ('n', 'no', 'none'):
-                    ok = self.SendToRead('border', [line])
-                    if not ok: return False
-                elif line.split()[1].lower() in ('y', 'yes'):
-                    instruction = 'border'
-                    isBuffer = True
-                    buffer.append(line)
-            
-            elif line.startswith('scale '):
-                if isBuffer:
-                    continue
-                ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
-                if not ok: return False
-            
-            elif line.startswith('maploc'):
-                ok = self.SendToRead(instruction = 'maploc', text = line)
-                if not ok: return False
-                
-            elif line.startswith('raster'):
-                ok = self.SendToRead(instruction = 'raster', text = line)
-                if not ok: return False
-            
-            elif line.startswith('mapinfo'):
-                instruction = 'mapinfo'
-                isBuffer = True
-                buffer.append(line)
-
-
-            elif line.startswith('scalebar'):
-                instruction = 'scalebar'
-                isBuffer = True
-                buffer.append(line) 
-            
-            elif line.startswith('text'):
-                instruction = 'text'
-                isBuffer = True
-                buffer.append(line)
-                
-            elif line.startswith('eps'):
-                instruction = 'eps'
-                isBuffer = True
-                buffer.append(line) 
-            
-            elif line.startswith('colortable'):
-                if len(line.split()) == 2 and line.split()[1].lower() in ('n', 'no', 'none'):
-                    break
-                instruction = 'colortable'
-                isBuffer = True
-                buffer.append(line) 
-        
-            elif line.startswith('vlegend'):
-                instruction = 'vlegend'
-                isBuffer = True
-                buffer.append(line) 
-                
-            elif line.startswith('vpoints'):
-                instruction = 'vpoints'
-                isBuffer = True
-                buffer.append(line) 
-                
-            elif line.startswith('vlines'):
-                instruction = 'vlines'
-                isBuffer = True
-                buffer.append(line)
-                
-            elif line.startswith('vareas'):
-                instruction = 'vareas'
-                isBuffer = True
-                buffer.append(line)
-
-
-        
-        rasterLegend = self.FindInstructionByType('rasterLegend')
-        raster = self.FindInstructionByType('raster')
-        page = self.FindInstructionByType('page')
-        vector = self.FindInstructionByType('vector')
-        vectorLegend = self.FindInstructionByType('vectorLegend')
-        vectorMaps = self.FindInstructionByType('vProperties', list = True)
-
-        # check (in case of scaletype 0) if map is drawn also
-        map['drawMap'] = False
-        if map['scaleType'] == 0:
-            mapForRegion = map['map']
-            if map['mapType'] == 'raster' and raster:
-                if mapForRegion == raster['raster']:
-                    map['drawMap'] = True
-            elif map['mapType'] == 'vector' and vector:
-                for vmap in vector['list']:
-                    if mapForRegion == vmap[0]:
-                        map['drawMap'] = True
-
-        # rasterLegend
-        if rasterLegend:
-            if rasterLegend['rasterDefault'] and raster:
-                rasterLegend['raster'] = raster['raster']
-                if not rasterLegend['discrete']:
-                    rasterType = getRasterType(map = rasterLegend['raster'])
-                    if rasterType == 'CELL':
-                        rasterLegend['discrete'] = 'y'
-                    else:
-                        rasterLegend['discrete'] = 'n'
-            
-            #estimate size
-            height = rasterLegend.EstimateHeight(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
-                                                 fontsize = rasterLegend['fontsize'],
-                                                 cols = rasterLegend['cols'], 
-                                                 height = rasterLegend['height'])
-            width = rasterLegend.EstimateWidth(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
-                                               fontsize = rasterLegend['fontsize'],
-                                               cols = rasterLegend['cols'] , 
-                                               width = rasterLegend['width'],
-                                               paperInstr = page)
-            rasterLegend['rect'] = wx.Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
-                                             w = width, h = height)
-            
-        # vectors, vlegend        
-        
-        if vector:
-            for vmap in vectorMaps:
-                for i, each in enumerate(vector['list']):
-                    if each[2] == vmap.id:
-                        
-                        vector['list'][i][4] = vmap['label']
-                        vector['list'][i][3] = vmap['lpos']
-            if vectorLegend:
-                size = vectorLegend.EstimateSize(vectorInstr = vector, fontsize = vectorLegend['fontsize'],
-                                                 width = vectorLegend['width'], cols = vectorLegend['cols'])                            
-                vectorLegend['rect'] = wx.Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
-                                                 w = size[0], h = size[1])
-        
-        
-        page = self.FindInstructionByType('page')
-        if not page:
-            page = PageSetup(wx.NewId())
-            self.AddInstruction(page)
-        else:
-            page['Orientation'] = orientation
-
-
-        #
-        return True
-    
-    def SendToRead(self, instruction, text, **kwargs):
-        psmapInstrDict = dict(paper = ['page'],
-                              maploc = ['map'],
-                              scale = ['map'],
-                              border = ['map'],
-                              raster = ['raster'],
-                              mapinfo = ['mapinfo'],
-                              scalebar = ['scalebar'],
-                              text = ['text'],
-                              eps = ['image', 'northArrow'],
-                              vpoints = ['vector', 'vProperties'],
-                              vlines = ['vector', 'vProperties'],
-                              vareas = ['vector', 'vProperties'],
-                              colortable = ['rasterLegend'],
-                              vlegend = ['vectorLegend']
-                              )
-        
-        myInstrDict = dict(page = PageSetup,
-                           map = MapFrame,
-                           raster = Raster,
-                           mapinfo = Mapinfo,
-                           scalebar = Scalebar,
-                           text = Text,
-                           image = Image,
-                           northArrow = NorthArrow,
-                           rasterLegend = RasterLegend,
-                           vectorLegend = VectorLegend,
-                           vector = Vector,
-                           vProperties = VProperties
-                           )
-        
-        myInstruction = psmapInstrDict[instruction]
-        
-        for i in myInstruction:
-            instr = self.FindInstructionByType(i)
-            if i in ('text', 'vProperties', 'image', 'northArrow') or not instr:
-                
-                id = wx.NewId() #!vProperties expect subtype
-                if i == 'vProperties':
-                    id = kwargs['id']
-                    newInstr = myInstrDict[i](id, subType = instruction[1:])
-                elif i in ('image', 'northArrow'):
-                    commentFound = False
-                    for line in text:
-                        if line.find("# north arrow") >= 0:
-                            commentFound = True
-                    if i == 'image' and commentFound or \
-                       i == 'northArrow' and not commentFound:
-                        continue
-                    newInstr = myInstrDict[i](id, settings = self)
-                else:
-                    newInstr = myInstrDict[i](id)
-                ok = newInstr.Read(instruction, text, **kwargs)
-                if ok:
-                    self.AddInstruction(newInstr)
-                else:
-                    return False
-
-            else:
-                ok = instr.Read(instruction, text, **kwargs)
-
-                if not ok:
-                    return False
-        return True
-    
-    def SetRegion(self, regionInstruction):
-        """!Sets region from file comment or sets current region in case of no comment"""
-        map = MapFrame(wx.NewId())
-        self.AddInstruction(map)
-        if regionInstruction:
-            cmd = CmdToTuple(regionInstruction.strip('# ').split())
-            
-            # define scaleType
-            if len(cmd[1]) <= 3:
-                if 'rast' in cmd[1]:
-                    map['scaleType'] = 0
-                    map['mapType'] = 'raster'   
-                    map['map'] = cmd[1]['rast']  
-                elif 'vect' in cmd[1]:
-                    map['scaleType'] = 0
-                    map['mapType'] = 'vector' 
-                    map['map'] = cmd[1]['vect']  
-                elif 'region' in cmd[1]:
-                    map['scaleType'] = 1  
-                    map['region'] = cmd[1]['region']
-                    
-            else:
-                map['scaleType'] = 2  
-        else:
-            map['scaleType'] = 2
-            grass.del_temp_region()
-            region = grass.region()
-            grass.use_temp_region()    
-            cmd = ['g.region', region]
-        cmdString = GetCmdString(cmd).replace('g.region', '')
-        GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
-        try:
-            RunCommand(cmd[0], **cmd[1])
-            
-        except grass.ScriptError, e:
-            GError(_("Region cannot be set\n%s") % e)
-            return False
-        
-
-class InstructionObject:
-    """!Abtract class representing single instruction"""
-    def __init__(self, id): 
-        self.id = id
-        
-        # default values
-        self.defaultInstruction = dict()
-        # current values
-        self.instruction = self.defaultInstruction   
-        # converting units
-        self.unitConv = UnitConversion() 
-    
-    def __str__(self):
-        """!Returns particular part of text instruction"""
-        return ''
-    
-    def __getitem__(self, key):
-        for each in self.instruction.keys():
-            if each == key:
-                return self.instruction[key]
-        return None
-    
-    def __setitem__(self, key, value):
-        self.instruction[key] = value
-    
-    def GetInstruction(self):
-        """!Get current values"""
-        return self.instruction
-    
-    def SetInstruction(self, instruction):
-        """!Set default values"""
-        self.instruction = instruction
-        
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save them"""
-        pass
-    
-class InitMap(InstructionObject):
-    """!Class representing virtual map"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'initMap'
-        
-        # default values
-        self.defaultInstruction = dict(rect = None, scale =  None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    
-class MapFrame(InstructionObject):
-    """!Class representing map (instructions maploc, scale, border)"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'map'
-        # default values
-        self.defaultInstruction = dict(map = None, mapType = None, drawMap = True, region = None,
-                                       rect = wx.Rect2D(), scaleType = 0, scale = None, center = None,
-                                       resolution = 300, border = 'y', width = 1, color = '0:0:0') 
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = ''
-        comment = ''
-        
-        #region settings
-        region = grass.region()
-        if self.instruction['scaleType'] == 0: #match map
-            map = self.instruction['map']
-            if self.instruction['mapType'] == 'raster':
-                comment = "# g.region rast=%s nsres=%s ewres=%s\n" % (map, region['nsres'], region['ewres'])
-            else:
-                comment = "# g.region vect=%s\n" % (map)
-        elif self.instruction['scaleType'] == 1:# saved region
-            region = self.instruction['region']
-            comment = "# g.region region=%s\n" % region
-        elif self.instruction['scaleType'] in (2, 3): #current region, fixed scale
-            comment = string.Template("# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region)
-        
-        instr += comment
-        instr += '\n'
-        # maploc
-        maplocInstruction = "maploc %.3f %.3f" % (self.instruction['rect'].x, self.instruction['rect'].y)
-        if self.instruction['scaleType'] != 3:
-            maplocInstruction += "  %.3f %.3f"% (self.instruction['rect'].width, self.instruction['rect'].height)
-        instr += maplocInstruction
-        instr += '\n'
-        
-        # scale
-        if self.instruction['scaleType'] == 3: #fixed scale
-            scaleInstruction = "scale 1:%.0f" % (1/self.instruction['scale'])
-            instr += scaleInstruction
-            instr += '\n'
-        # border
-        borderInstruction = ''
-        if self.instruction['border'] == 'n':
-            borderInstruction = "border n"
-        else:
-            borderInstruction = "border y\n"
-            borderInstruction += string.Template("    width $width\n    color $color\n").substitute(self.instruction)
-            borderInstruction += "    end"
-        instr += borderInstruction
-        instr += '\n'
-
-        return instr  
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        if 'isRegionComment' in kwargs:
-            isRegionComment = kwargs['isRegionComment']
-        instr = {}
-        
-        if instruction == 'border':
-            for line in text:
-                if line.startswith('end'):
-                    break
-                try:
-                    if line.split()[1].lower() in ('n', 'no', 'none'):
-                        instr['border'] = 'n'
-                        break
-                    elif line.split()[1].lower() in ('y', 'yes'):
-                        instr['border'] = 'y'
-                    elif line.startswith('width'):
-                        instr['width'] = line.split()[1]
-                    elif line.startswith('color'):
-                        instr['color'] = line.split()[1]
-                except IndexError:
-                    GError(_("Failed to read instruction %s") % instruction)
-                    return False
-                
-        elif instruction == 'scale':
-            try:
-                scaleText = text.strip('scale ').split(':')[1]
-                # when scale instruction given and region comment also, then scaletype is fixed scale
-                if not isRegionComment:
-                    instr['scaleType'] = 2 
-                else:
-                    instr['scaleType'] = 3
-
-                scale = 1/float(scaleText)
-                if abs(scale - self.instruction['scale']) > (0.01 * scale):
-                    GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % \
-                                 { 'old' : scale, 'new' : self.instruction['scale'] })
-            except (ValueError, IndexError):
-                GError(_("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction)
-                return False
-        
-        elif instruction == 'maploc':
-            maploc = text.strip('maploc ').split()
-            if len(maploc) >= 2:
-                if  abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \
-                        abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5:
-                    GWarning(_("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
-                                 { 'old1' : maploc[0], 'old2' : maploc[1],
-                                   'new1' : self.instruction['rect'].Get()[0], 'new2' : self.instruction['rect'].Get()[1] })
-                    
-                #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3])
-            if len(maploc) == 4:
-                if  abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \
-                        abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5:
-                    GWarning(_("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
-                                 { 'old1' : maploc[2], 'old2' : maploc[3],
-                                   'new1' : self.instruction['rect'].Get()[2], 'new2' : self.instruction['rect'].Get()[3] })
-                #instr['rect'] = wx.Rect2D(*map(float, maploc))
-        self.instruction.update(instr)   
-        return True 
-    
-class PageSetup(InstructionObject):
-    """!Class representing page instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'page'
-        # default values
-        self.defaultInstruction = dict(Units = 'inch', Format = 'a4', Orientation = 'Portrait',
-                                       Width = 8.268, Height = 11.693, Left = 0.5, Right = 0.5, Top = 1, Bottom = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        if self.instruction['Format'] == 'custom':
-            instr = string.Template("paper\n    width $Width\n    height $Height\n").substitute(self.instruction)
-        else:
-            instr = string.Template("paper $Format\n").substitute(self.instruction)
-        instr += string.Template("    left $Left\n    right $Right\n    bottom $Bottom\n    top $Top\n    end").substitute(self.instruction)
-
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
-        self.subInstr = dict(zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats))
-        
-        if instruction == 'paper': # just for sure
-            for line in text:
-                if line.startswith('paper'): 
-                    if len(line.split()) > 1:
-                        pformat = line.split()[1]
-                        availableFormats = self._toDict(grass.read_command('ps.map', flags = 'p',
-                                                                           quiet = True))
-                        # e.g. paper a3 
-                        try:
-                            instr['Format'] = pformat
-                            for key, value in availableFormats[pformat].iteritems():
-                                instr[key] = float(value)
-                            break
-                        except KeyError:
-                            GError(_("Failed to read instruction %(file)s.\nUnknown format %(for)s") % \
-                                       { 'file' : instruction, 'for' : format })
-                            return False
-                    else:
-                        # paper
-                        # width ...
-                        instr['Format'] = 'custom'
-                # read subinstructions
-                elif instr['Format'] == 'custom' and not line.startswith('end'):
-                    text = line.split()
-                    try:
-                        instr[self.subInstr[text[0]]] = float(text[1])
-                    except  (IndexError, KeyError):
-                        GError(_("Failed to read instruction %s.") % instruction)
-                        return False
-                    
-            if 'Orientation' in kwargs and kwargs['Orientation'] == 'Landscape':
-                instr['Width'], instr['Height'] = instr['Height'], instr['Width']
-                
-            self.instruction.update(instr)
-        return True  
-    
-    def _toDict(self, paperStr):    
-        sizeDict = dict()
-#     cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
-        for line in paperStr.strip().split('\n'):
-            d = dict(zip(self.cats, line.split()[1:]))
-            sizeDict[line.split()[0]] = d
-            
-        return sizeDict    
-    
-class Mapinfo(InstructionObject):
-    """!Class representing mapinfo instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'mapinfo'
-        # default values
-        self.defaultInstruction = dict(unit = 'inch', where = (0, 0),
-                                       font = 'Helvetica', fontsize = 10, color = '0:0:0', background = 'none', 
-                                       border = 'none', rect = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "mapinfo\n"
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").substitute(self.instruction)            
-        instr += string.Template("    background $background\n    border $border\n").substitute(self.instruction)  
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text):
-        """!Read instruction and save information"""
-        instr = {}
-        try:
-            for line in text:
-                sub = line.split(None,1)
-                if sub[0] == 'font':
-                    instr['font'] = sub[1]
-                elif sub[0] == 'fontsize':
-                    instr['fontsize'] = int(sub[1])
-                elif sub[0] == 'color':
-                    instr['color'] = sub[1]
-                elif sub[0] == 'background':
-                    instr['background'] = sub[1]
-                elif sub[0] == 'border':
-                    instr['border'] = sub[1]
-                elif sub[0] == 'where':
-                    instr['where'] = float(sub[1].split()[0]), float(sub[1].split()[1])
-        except (ValueError, IndexError):
-            GError(_("Failed to read instruction %s") % instruction)
-            return False
-        self.instruction.update(instr)
-        self.instruction['rect'] = self.EstimateRect(mapinfoDict = self.instruction)
-        return True
-    
-    def EstimateRect(self, mapinfoDict):
-        """!Estimate size to draw mapinfo"""
-        w = mapinfoDict['fontsize'] * 20 # any better estimation? 
-        h = mapinfoDict['fontsize'] * 7
-        width = self.unitConv.convert(value = w, fromUnit = 'point', toUnit = 'inch')
-        height = self.unitConv.convert(value = h, fromUnit = 'point', toUnit = 'inch')
-        return wx.Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]), w = width, h = height)
-    
-class Text(InstructionObject):
-    """!Class representing text instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'text'
-        # default values
-        self.defaultInstruction = dict(text = "", font = "Helvetica", fontsize = 10, color = 'black', background = 'none',
-                                       hcolor = 'none', hwidth = 1, border = 'none', width = '1', XY = True,
-                                       where = (0,0), unit = 'inch', rotate = None, 
-                                       ref = "center center", xoffset = 0, yoffset = 0, east = None, north = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        text = self.instruction['text'].replace('\n','\\n')
-        instr = u"text %s %s" % (self.instruction['east'], self.instruction['north'])
-        instr += " %s\n" % text
-        instr += (string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").
-                                                                   substitute(self.instruction))
-        instr += string.Template("    hcolor $hcolor\n").substitute(self.instruction)
-        if self.instruction['hcolor'] != 'none':
-            instr += string.Template("    hwidth $hwidth\n").substitute(self.instruction)
-        instr += string.Template("    border $border\n").substitute(self.instruction)
-        if self.instruction['border'] != 'none':
-            instr += string.Template("    width $width\n").substitute(self.instruction)
-        instr += string.Template("    background $background\n").substitute(self.instruction)
-        if self.instruction["ref"] != '0':
-            instr += string.Template("    ref $ref\n").substitute(self.instruction)
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
-        if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
-            instr += (string.Template("    xoffset $xoffset\n    yoffset $yoffset\n").
-                                                            substitute(self.instruction))
-        instr += "    end"
-        try:
-            instr = instr.encode('latin1')
-        except UnicodeEncodeError, err:
-            try:
-                print err
-                pos = str(err).split('position')[1].split(':')[0].strip()
-            except IndexError:
-                pos = ''
-            if pos:
-                message = _("Characters on position %s are not supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.") % pos
-            else:
-                message = _("Not all characters are supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.")
-            GMessage(message = message)
-            return ''
-        
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        map = kwargs['mapInstruction']
-        instr = {}
-        for line in text:
-            try:
-                sub = line.split(None, 1)[0]
-                if sub == 'text':
-                    e, n = line.split(None, 3)[1:3]
-                    if '%' in e and '%' in n:
-                        instr['XY'] = True
-                        instr['east'], instr['north'] = self.PercentToReal(e, n)
-                    else:
-                        instr['XY'] = False
-                        instr['east'], instr['north'] = float(e), float(n)
-                        
-                    instr['text'] = line.split(None, 3)[3].decode('latin_1')
-                
-                elif sub == 'font':
-                    instr['font'] = line.split(None, 1)[1]
-                elif sub == 'fontsize':
-                    instr['fontsize'] = float(line.split(None, 1)[1])
-                elif sub == 'color':
-                    instr['color'] = line.split(None, 1)[1]
-                elif sub == 'width':
-                    instr['width'] = line.split(None, 1)[1]
-                elif sub == 'hcolor':
-                    instr['hcolor'] = line.split(None, 1)[1]
-                elif sub == 'hwidth':
-                    instr['hwidth'] = line.split(None, 1)[1]
-                elif sub == 'background':
-                    instr['background'] = line.split(None, 1)[1]
-                elif sub == 'border':
-                    instr['border'] = line.split(None, 1)[1]
-                elif sub == 'ref':
-                    instr['ref'] = line.split(None, 1)[1]
-                elif sub == 'rotate':
-                    instr['rotate'] = float(line.split(None, 1)[1])
-                elif sub == 'xoffset':
-                    instr['xoffset'] = int(line.split(None, 1)[1])
-                elif sub == 'yoffset':
-                    instr['yoffset'] = int(line.split(None, 1)[1])
-                elif sub == 'opaque':
-                    if line.split(None, 1)[1].lower() in ('n', 'none'):
-                        instr['background'] = 'none'
-                        
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-        instr['where'] = PaperMapCoordinates(map = map, x = instr['east'], y = instr['north'], paperToMap = False)       
-        self.instruction.update(instr)
-
-        return True 
-    
-    def PercentToReal(self, e, n):
-        """!Converts text coordinates from percent of region to map coordinates"""
-        e, n = float(e.strip('%')), float(n.strip('%'))
-        region = grass.region()
-        N = region['s'] + (region['n'] - region['s']) / 100 * n
-        E = region['w'] + (region['e'] - region['w']) / 100 * e
-        return E, N
-        
-class Image(InstructionObject):
-    """!Class representing eps instruction - image"""
-    def __init__(self, id, settings):
-        InstructionObject.__init__(self, id = id)
-        self.settings = settings
-        self.type = 'image'
-        # default values
-        self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
-                                       east = None, north = None,
-                                       rotate = None, scale = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        self.ChangeRefPoint(toCenter = True)
-        
-        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
-        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
-        if self.instruction["scale"]:
-            instr += string.Template("    scale $scale\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        mapInstr = kwargs['mapInstruction']
-        instr = {}
-        for line in text:
-            try:
-                sub = line.split(None, 1)[0]
-                if sub == 'eps':
-                    e, n = line.split(None, 3)[1:3]
-                    if '%' in e and '%' in n:
-                        instr['XY'] = True
-                        instr['east'], instr['north'] = self.PercentToReal(e, n)
-                    else:
-                        instr['XY'] = False
-                        instr['east'], instr['north'] = float(e), float(n)
-                
-                elif sub == 'epsfile':
-                    instr['epsfile'] = line.split(None, 1)[1]
-                elif sub == 'rotate':
-                    instr['rotate'] = float(line.split(None, 1)[1])
-                elif sub == 'scale':
-                    instr['scale'] = float(line.split(None, 1)[1])
-                        
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-        if not os.path.exists(instr['epsfile']):
-            GError(_("Failed to read instruction %(inst)s: "
-                     "file %(file)s not found.") % { 'inst' : instruction,
-                                                     'file' : instr['epsfile'] })
-            return False
-        
-        instr['epsfile'] = os.path.abspath(instr['epsfile'])
-        instr['size'] = self.GetImageOrigSize(instr['epsfile'])
-        if 'rotate' in instr:
-            instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
-        self.instruction.update(instr)
-        self.ChangeRefPoint(toCenter = False)
-        instr['where'] = PaperMapCoordinates(map = mapInstr, x = self.instruction['east'],
-                                             y = self.instruction['north'], paperToMap = False)       
-        w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
-        h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
-        instr['rect'] = wx.Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
-                                  w = w * self.instruction['scale'], h = h * self.instruction['scale'])
-        self.instruction.update(instr)
-
-        return True 
-    
-    def PercentToReal(self, e, n):
-        """!Converts eps coordinates from percent of region to map coordinates"""
-        e, n = float(e.strip('%')), float(n.strip('%'))
-        region = grass.region()
-        N = region['s'] + (region['n'] - region['s']) / 100 * n
-        E = region['w'] + (region['e'] - region['w']) / 100 * e
-        return E, N
-        
-    def ChangeRefPoint(self, toCenter):
-        """!Change reference point (left top x center)"""
-        mapInstr = self.settings.FindInstructionByType('map')
-        if not mapInstr:
-            mapInstr = self.settings.FindInstructionByType('initMap')
-        mapId = mapInstr.id
-        if toCenter:
-            center = self.instruction['rect'].GetCentre()
-            ENCenter = PaperMapCoordinates(map = self.settings[mapId],
-                                           x = center[0], y = center[1], paperToMap = True)
-                                           
-            self.instruction['east'], self.instruction['north'] = ENCenter
-        else:
-            x, y = PaperMapCoordinates(map = self.settings[mapId], x = self.instruction['east'],
-                                       y = self.instruction['north'], paperToMap = False)
-            w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
-            h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
-            x -= w * self.instruction['scale'] / 2
-            y -= h * self.instruction['scale'] / 2
-            e, n = PaperMapCoordinates(map = self.settings[mapId], x = x, y = y, paperToMap = True)
-            self.instruction['east'], self.instruction['north'] = e, n
-
-    def GetImageOrigSize(self, imagePath):
-        """!Get image size.
-        
-        If eps, size is read from image header.
-        """
-        fileName = os.path.split(imagePath)[1]
-        # if eps, read info from header
-        if os.path.splitext(fileName)[1].lower() == '.eps':
-            bbInfo = "%%BoundingBox"
-            file = open(imagePath,"r")
-            w = h = 0
-            while file:
-                line = file.readline()
-                if line.find(bbInfo) == 0:
-                    w, h = line.split()[3:5]
-                    break
-            file.close()
-            return float(w), float(h)
-        else: # we can use wx.Image
-            img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
-            return img.GetWidth(), img.GetHeight()
-            
-class NorthArrow(Image):
-    """!Class representing eps instruction -- North Arrow"""
-    def __init__(self, id, settings):
-        Image.__init__(self, id = id, settings = settings)
-        self.type = 'northArrow'
-        
-    def __str__(self):
-        self.ChangeRefPoint(toCenter = True)
-        
-        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
-        instr += "# north arrow\n"
-        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
-        if self.instruction["scale"]:
-            instr += string.Template("    scale $scale\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-        
-class Scalebar(InstructionObject):
-    """!Class representing scalebar instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'scalebar'
-        # default values
-        self.defaultInstruction = dict(unit = 'inch', where = (1,1),
-                                       unitsLength = 'auto', unitsHeight = 'inch',
-                                       length = None, height = 0.1, rect = None,
-                                       fontsize = 10, background = 'y',
-                                       scalebar = 'f', segment = 4, numbers = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = string.Template("scalebar $scalebar\n").substitute(self.instruction)
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    length $length\n    units $unitsLength\n").substitute(self.instruction)
-        instr += string.Template("    height $height\n").substitute(self.instruction)
-        instr += string.Template("    segment $segment\n    numbers $numbers\n").substitute(self.instruction)
-        instr += string.Template("    fontsize $fontsize\n    background $background\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        scale = kwargs['scale']
-        instr = {}
-        for line in text:
-            try:
-                if line.startswith('scalebar'):
-                    if 'scalebar s' in line:
-                        instr['scalebar'] = 's'
-                    else:
-                        instr['scalebar'] = 'f'
-                elif line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('length'):
-                    instr['length'] = float(line.split()[1])
-                elif line.startswith('units'):
-                    if line.split()[1] in ['auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']:
-                        instr['unitsLength'] = line.split()[1]
-                elif line.startswith('height'):
-                    instr['height'] = float(line.split()[1])
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('numbers'):
-                    instr['numbers'] = int(line.split()[1])
-                elif line.startswith('segment'):
-                    instr['segment'] = int(line.split()[1])
-                elif line.startswith('background'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['background'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['background'] = 'n'
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        self.instruction.update(instr)
-        w, h = self.EstimateSize(scalebarDict = self.instruction, scale = scale)
-        x = self.instruction['where'][0] - w / 2 
-        y = self.instruction['where'][1] - h / 2
-        self.instruction['rect'] = wx.Rect2D(x, y, w, h)
-        return True 
-    
-    def EstimateSize(self, scalebarDict, scale):
-        """!Estimate size to draw scalebar"""
-        units = projInfo()['units']
-        if not units or units not in self.unitConv.getAllUnits():
-            units = 'meters'
-        if scalebarDict['unitsLength'] != 'auto':
-            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = scalebarDict['unitsLength'], toUnit = 'inch')
-        else:
-            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = units, toUnit = 'inch')
-            
-        length *= scale
-        length *= 1.1 #for numbers on the edge
-        height = scalebarDict['height'] + 2 * self.unitConv.convert(value = scalebarDict['fontsize'], fromUnit = 'point', toUnit = 'inch')     
-        return (length, height)
-    
-class RasterLegend(InstructionObject):
-    """!Class representing colortable instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'rasterLegend'
-        # default values
-        self.defaultInstruction = dict(rLegend = False, unit = 'inch', rasterDefault = True, raster = None,
-                                       discrete = None, type = None,
-                                       where = (0, 0),
-                                       width = None, height = None, cols = 1, font = "Helvetica", fontsize = 10,
-                                       #color = '0:0:0', tickbar = False, range = False, min = 0, max = 0,
-                                       color = 'black', tickbar = 'n', range = False, min = 0, max = 0,
-                                       nodata = 'n')
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "colortable y\n"
-        instr += string.Template("    raster $raster\n").substitute(self.instruction)
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        if self.instruction['width']:
-            instr += string.Template("    width $width\n").substitute(self.instruction)
-        instr += string.Template("    discrete $discrete\n").substitute(self.instruction)
-        if self.instruction['discrete'] == 'n':
-            if self.instruction['height']:
-                instr += string.Template("    height $height\n").substitute(self.instruction)
-            instr += string.Template("    tickbar $tickbar\n").substitute(self.instruction)
-            if self.instruction['range']:
-                instr += string.Template("    range $min $max\n").substitute(self.instruction)
-        else:
-            instr += string.Template("    cols $cols\n").substitute(self.instruction)
-            instr += string.Template("    nodata $nodata\n").substitute(self.instruction)
-        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n")\
-            .substitute(self.instruction)
-        instr += "    end"
-        return instr    
-    
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['rLegend'] = True
-        for line in text:
-            try:
-                if line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('font '):
-                    instr['font'] = line.split()[1]
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('color '):
-                    instr['color'] = line.split()[1]
-                elif line.startswith('raster'):
-                    instr['raster'] = line.split()[1]
-                elif line.startswith('width'):
-                    instr['width'] = float(line.split()[1])
-                elif line.startswith('height'):
-                    instr['height'] = float(line.split()[1])
-                elif line.startswith('cols'):
-                    instr['cols'] = int(line.split()[1])                    
-                elif line.startswith('range'):
-                    instr['range'] = True
-                    instr['min'] = float(line.split()[1])
-                    instr['max'] = float(line.split()[2])
-                elif line.startswith('nodata'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['nodata'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['nodata'] = 'n'
-                elif line.startswith('tickbar'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['tickbar'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['tickbar'] = 'n'
-                elif line.startswith('discrete'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['discrete'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['discrete'] = 'n'            
-
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        if 'raster' in instr:
-            instr['rasterDefault'] = False
-            if 'discrete' not in instr:
-                rasterType = getRasterType(map = instr['raster'])
-                instr['type'] = rasterType
-                if rasterType == 'CELL':
-                    instr['discrete'] = 'y'
-                else:
-                    instr['discrete'] = 'n'
-            
-        else:
-            instr['rasterDefault'] = True
-        self.instruction.update(instr)
-        # add 'rect' in the end
-            
-        return True 
-    
-    def EstimateHeight(self, raster, discrete, fontsize, cols = None,  height = None):
-        """!Estimate height to draw raster legend"""
-        if discrete == 'n':
-            if height:
-                height = height
-            else:
-                height = self.unitConv.convert(value = fontsize * 10,
-                                                    fromUnit = 'point', toUnit = 'inch')
-                                                    
-        if discrete == 'y':
-            if cols:
-                cols = cols 
-            else:
-                cols = 1 
-
-            rinfo = grass.raster_info(raster)
-            if rinfo['datatype'] in ('DCELL', 'FCELL'):
-                minim, maxim = rinfo['min'], rinfo['max']
-                rows = ceil(maxim / cols )
-            else:
-                cat = grass.read_command('r.category', map = raster,
-                                    fs = ':').strip().split('\n')
-                rows = ceil(float(len(cat)) / cols )
-                            
-                
-            height = self.unitConv.convert(value =  1.5 * rows * fontsize, fromUnit = 'point', toUnit = 'inch')
-            
-        return height
-        
-    def EstimateWidth(self, raster, discrete, fontsize, cols = None, width = None, paperInstr = None):
-        """!Estimate size to draw raster legend"""
-        
-        if discrete == 'n':
-            rinfo = grass.raster_info(raster)
-            minim, maxim = rinfo['min'], rinfo['max']
-            if width:
-                width = width
-            else:
-                width = self.unitConv.convert(value = fontsize * 2,
-                                                    fromUnit = 'point', toUnit = 'inch')
-            text = len(max(str(minim), str(maxim), key = len))
-            textPart = self.unitConv.convert(value = text * fontsize / 2,
-                                                    fromUnit = 'point', toUnit = 'inch')
-            width += textPart
-                                                    
-        elif discrete == 'y':
-            if cols:
-                cols = cols 
-            else:
-                cols = 1    
-
-            if width:
-                width = width
-            else:
-                paperWidth = paperInstr['Width'] - paperInstr['Right'] - paperInstr['Left']
-                width = (paperWidth / cols) * (cols - 1) + 1
-                
-        return width    
-             
-class VectorLegend(InstructionObject):
-    """!Class representing colortable instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vectorLegend'
-        # default values
-        self.defaultInstruction = dict(vLegend = False, unit = 'inch', where = (0, 0),
-                                                defaultSize = True, width = 0.4, cols = 1, span = None,
-                                                font = "Helvetica", fontsize = 10,
-                                                border = 'none')
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "vlegend\n"
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    font $font\n    fontsize $fontsize\n").substitute(self.instruction)
-        instr += string.Template("    width $width\n    cols $cols\n").substitute(self.instruction)
-        if self.instruction['span']:
-            instr += string.Template("    span $span\n").substitute(self.instruction)
-        instr += string.Template("    border $border\n").substitute(self.instruction)  
-        instr += "    end"  
-        return instr
-
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['vLegend'] = True
-        for line in text:
-            try:
-                if line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('font '):
-                    instr['font'] = line.split()[1]
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('width'):
-                    instr['width'] = float(line.split()[1])
-                elif line.startswith('cols'):
-                    instr['cols'] = int(line.split()[1]) 
-                elif line.startswith('span'):
-                    instr['span'] = float(line.split()[1])
-                elif line.startswith('border'):
-                    instr['border'] = line.split()[1]
-                    
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        self.instruction.update(instr)
-            
-        return True 
-    
-    def EstimateSize(self, vectorInstr, fontsize, width = None, cols = None):
-        """!Estimate size to draw vector legend"""
-        if width:
-            width = width 
-        else:
-            width = fontsize/24.0
-
-        if cols:
-            cols = cols 
-        else:
-            cols = 1
-
-        vectors = vectorInstr['list']
-        labels = [vector[4] for vector in vectors if vector[3] != 0]
-        extent = (len(max(labels, key = len)) * fontsize / 2, fontsize)
-        wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'point', toUnit = 'inch')
-        hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'point', toUnit = 'inch')
-        w = (width + wExtent) * cols
-        h = len(labels) * hExtent / cols
-        h *= 1.1
-        return (w, h)
-            
-   
-class Raster(InstructionObject):
-    """!Class representing raster instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'raster'
-        # default values
-        self.defaultInstruction = dict(isRaster = False, raster = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = string.Template("raster $raster").substitute(self.instruction)
-        return instr
-    
-    def Read(self, instruction, text):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['isRaster'] = True
-        try:
-            map = text.split()[1]
-        except IndexError:
-            GError(_("Failed to read instruction %s") % instruction)
-            return False
-        try:
-            info = grass.find_file(map, element = 'cell')
-        except grass.ScriptError, e:
-            GError(message = e.value)
-            return False
-        instr['raster'] = info['fullname']
-
-        
-        self.instruction.update(instr)
-        return True
-    
-class Vector(InstructionObject):
-    """!Class keeps vector layers"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vector'
-        # default values
-        self.defaultInstruction = dict(list = None)# [vmap, type, id, lpos, label] 
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-    def __str__(self):
-        return ''
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        
-        for line in text:
-            if line.startswith('vpoints') or line.startswith('vlines') or line.startswith('vareas'):
-                # subtype
-                if line.startswith('vpoints'):
-                    subType = 'points'
-                elif line.startswith('vlines'):
-                    subType = 'lines'
-                elif line.startswith('vareas'):
-                    subType = 'areas'
-                # name of vector map
-                vmap = line.split()[1]
-                try:
-                    info = grass.find_file(vmap, element = 'vector')
-                except grass.ScriptError, e:
-                    GError(message = e.value)
-                    return False
-                vmap = info['fullname']
-                # id
-                id = kwargs['id']
-                # lpos
-                lpos = kwargs['vectorMapNumber']
-                #label
-                label = '('.join(vmap.split('@')) + ')'
-                break
-        instr = [vmap, subType, id, lpos, label] 
-        if not self.instruction['list']:
-            self.instruction['list'] = []
-        self.instruction['list'].append(instr)
-        
-        return True    
-    
-class VProperties(InstructionObject):
-    """!Class represents instructions vareas, vlines, vpoints"""
-    def __init__(self, id, subType):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vProperties'
-        self.subType = subType
-        # default values
-        if self.subType == 'points':
-            dd = dict(subType  = 'points', name = None, type = 'point or centroid', connection = False, layer = '1',
-                        masked = 'n', color = '0:0:0', width = 1,
-                        fcolor = '255:0:0', rgbcolumn = None, symbol = os.path.join('basic', 'x'), eps = None,
-                        size = 5, sizecolumn = None, scale = None,
-                        rotation = False, rotate = 0, rotatecolumn = None, label = None, lpos = None)
-        elif self.subType == 'lines':
-            dd = dict(subType = 'lines', name = None, type = 'line or boundary', connection = False, layer = '1',
-                        masked = 'n', color = '0:0:0', hwidth = 1,
-                        hcolor = 'none', rgbcolumn = None,
-                        width = 1, cwidth = None,
-                        style = 'solid', linecap = 'butt', label = None, lpos = None)
-        else: # areas
-            dd = dict(subType = 'areas', name = None, connection = False, layer = '1',    
-                        masked = 'n', color = '0:0:0', width = 1,
-                        fcolor = 'none', rgbcolumn = None,
-                        pat = None, pwidth = 1, scale = 1, label = None, lpos = None)
-        self.defaultInstruction = dd
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        dic = self.instruction
-        vInstruction = string.Template("v$subType $name\n").substitute(dic)
-        #data selection
-        if self.subType in ('points', 'lines'):
-           vInstruction += string.Template("    type $type\n").substitute(dic) 
-        if dic['connection']:
-            vInstruction += string.Template("    layer $layer\n").substitute(dic)
-            if dic.has_key('cats'):
-                vInstruction += string.Template("    cats $cats\n").substitute(dic)
-            elif dic.has_key('where'):
-                    vInstruction += string.Template("    where $where\n").substitute(dic)
-        vInstruction += string.Template("    masked $masked\n").substitute(dic)
-        #colors
-        vInstruction += string.Template("    color $color\n").substitute(dic)
-        if self.subType in ('points', 'areas'):
-            if dic['color'] != 'none':
-                vInstruction += string.Template("    width $width\n").substitute(dic)
-            if dic['rgbcolumn']:
-                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
-            vInstruction += string.Template("    fcolor $fcolor\n").substitute(dic)
-        else:
-            if dic['rgbcolumn']:
-                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
-            elif dic['hcolor'] != 'none':
-                vInstruction += string.Template("    hwidth $hwidth\n").substitute(dic)
-                vInstruction += string.Template("    hcolor $hcolor\n").substitute(dic)
-        
-        # size and style
-        if self.subType == 'points':
-            if not dic['eps']:
-                vInstruction += string.Template("    symbol $symbol\n").substitute(dic)
-            else: #eps
-                vInstruction += string.Template("    eps $eps\n").substitute(dic)
-            if dic['size']:
-                vInstruction += string.Template("    size $size\n").substitute(dic)            
-            else: # sizecolumn
-                vInstruction += string.Template("    sizecolumn $sizecolumn\n").substitute(dic)
-                vInstruction += string.Template("    scale $scale\n").substitute(dic)
-            if dic['rotation']:
-                if dic['rotate'] is not None:
-                    vInstruction += string.Template("    rotate $rotate\n").substitute(dic)
-                else:
-                    vInstruction += string.Template("    rotatecolumn $rotatecolumn\n").substitute(dic)
-                    
-        if self.subType == 'areas':
-            if dic['pat'] is not None:
-                vInstruction += string.Template("    pat $pat\n").substitute(dic)
-                vInstruction += string.Template("    pwidth $pwidth\n").substitute(dic)
-                vInstruction += string.Template("    scale $scale\n").substitute(dic)
-                
-        if self.subType == 'lines':
-            if dic['width'] is not None:
-                vInstruction += string.Template("    width $width\n").substitute(dic)
-            else:
-                vInstruction += string.Template("    cwidth $cwidth\n").substitute(dic)
-            vInstruction += string.Template("    style $style\n").substitute(dic)
-            vInstruction += string.Template("    linecap $linecap\n").substitute(dic)
-        #position and label in vlegend
-        vInstruction += string.Template("    label $label\n    lpos $lpos\n").substitute(dic)
-        
-        vInstruction += "    end"
-        try:
-            vInstruction = vInstruction.encode('Latin_1')
-        except UnicodeEncodeError, err:
-            try:
-                print err
-                pos = str(err).split('position')[1].split(':')[0].strip()
-            except IndexError:
-                pos = ''
-            if pos:
-                message = _("Characters on position %s are not supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.") % pos
-            else:
-                message = _("Not all characters are supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.")
-            GMessage(message = message)
-            return ''
-        return vInstruction
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        try:
-            info = grass.find_file(name = text[0].split()[1], element = 'vector')
-        except grass.ScriptError, e:
-            GError(message = e.value)
-            return False
-        instr['name'] = info['fullname']
-        #connection
-        instr['connection'] = True
-        self.mapDBInfo = VectorDBInfo(instr['name'])
-        self.layers = self.mapDBInfo.layers.keys()
-        if not self.layers:
-            instr['connection'] = False
-            
-        # points
-        if text[0].startswith('vpoints'):
-            for line in text[1:]:
-                if line.startswith('type'):
-                    tp = []
-                    if line.find('point') != -1:
-                        tp.append('point')
-                    if line.find('centroid') != -1:
-                        tp.append('centroid')
-                    instr['type'] = ' or '.join(tp)
-                elif line.startswith('fcolor'):
-                    instr['fcolor'] = line.split()[1]
-                elif line.startswith('rgbcolumn'):
-                    instr['rgbcolumn'] = line.split()[1]
-                elif line.startswith('symbol'):
-                    instr['symbol'] = line.split()[1]
-                elif line.startswith('eps'):
-                    instr['eps'] = line.split()[1]
-                elif line.startswith('size '):
-                    instr['size'] = line.split()[1]
-                elif line.startswith('sizecolumn'):
-                    instr['size'] = None
-                    instr['sizecolumn'] = line.split()[1]
-                elif line.startswith('scale '):
-                    instr['scale'] = float(line.split()[1])
-                elif line.startswith('rotate '):
-                    instr['rotation'] = True
-                    instr['rotate'] = line.split()[1]
-                elif line.startswith('rotatecolumn'):
-                    instr['rotatecolumn'] = line.split()[1]
-                    instr['rotation'] = True
-                    instr['rotate'] = None
-                    
-        # lines            
-        elif text[0].startswith('vlines'):
-            for line in text[1:]:
-                if line.startswith('type'):
-                    tp = []
-                    if line.find('line') != -1:
-                        tp.append('line')
-                    if line.find('boundary') != -1:
-                        tp.append('boundary')
-                    instr['type'] = ' or '.join(tp)
-                elif line.startswith('hwidth'):
-                    instr['hwidth'] = float(line.split()[1])
-                elif line.startswith('hcolor'):
-                    instr['hcolor'] = line.split()[1]
-                elif line.startswith('rgbcolumn'):
-                    instr['rgbcolumn'] = line.split()[1]                    
-                elif line.startswith('cwidth'):
-                    instr['cwidth'] = float(line.split()[1])
-                    instr['width'] = None
-                elif line.startswith('style'):
-                    instr['style'] = line.split()[1]       
-                elif line.startswith('linecap'):
-                    instr['linecap'] = line.split()[1]
-         
-        elif text[0].startswith('vareas'):
-            for line in text[1:]:
-                if line.startswith('fcolor'):
-                    instr['fcolor'] = line.split()[1]    
-                elif line.startswith('pat'):
-                    instr['pat'] = line.split()[1]
-                elif line.startswith('pwidth'):
-                    instr['pwidth'] = float(line.split()[1])
-                elif line.startswith('scale'):
-                    instr['scale'] = float(line.split()[1])
-            
-            
-        # same properties for all    
-        for line in text[1:]:
-            if line.startswith('lpos'):
-                instr['lpos'] = int(line.split()[1])
-            elif line.startswith('label'):
-                instr['label'] = line.split(None, 1)[1].decode('latin_1')
-            elif line.startswith('layer'):
-                instr['layer'] = line.split()[1]
-            elif line.startswith('masked'):
-                if line.split()[1].lower() in ('y', 'yes'):
-                    instr['masked'] = 'y'
-                else:
-                    instr['masked'] = 'n'
-            elif line.startswith('color'):
-                instr['color'] = line.split()[1]
-            elif line.startswith('rgbcolumn'):
-                instr['rgbcolumn'] = line.split()[1] 
-            elif line.startswith('width'):
-                instr['width'] = float(line.split()[1])
-                
-        if 'label' not in instr:
-            instr['label'] = '('.join(instr['name'].split('@')) + ')'
-        if 'lpos' not in instr:
-            instr['lpos'] = kwargs['vectorMapNumber']
-        self.instruction.update(instr)
-        
-        return True
-        
 class PsmapDialog(wx.Dialog):
     def __init__(self, parent, id,  title, settings, apply = True):
         wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, 
@@ -1903,7 +259,7 @@
         northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
         panel.position['eCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
         panel.position['nCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
+        east, north = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
         panel.position['eCtrl'].SetValue(str(east))
         panel.position['nCtrl'].SetValue(str(north))
         
@@ -4679,7 +3035,7 @@
             drawWidth = self.rasterLegend.EstimateWidth(raster = self.rLegendDict['raster'], discrete = self.rLegendDict['discrete'],
                                             fontsize = self.rLegendDict['fontsize'], cols = self.rLegendDict['cols'],
                                             width = self.rLegendDict['width'], paperInstr = self.instruction[self.pageId])
-            self.rLegendDict['rect'] = wx.Rect2D(x = x, y = y, w = drawWidth, h = drawHeight)
+            self.rLegendDict['rect'] = Rect2D(x = x, y = y, width = drawWidth, height = drawHeight)
                         
             # no data
             if self.rLegendDict['discrete'] == 'y':
@@ -4782,7 +3138,7 @@
                 w = (width + wExtent) * self.vLegendDict['cols']
                 h = len(labels) * hExtent / self.vLegendDict['cols']
                 h *= 1.1
-                self.vLegendDict['rect'] = wx.Rect2D(x, y, w, h)
+                self.vLegendDict['rect'] = Rect2D(x, y, w, h)
                 
                 #border
                 if self.borderCheck.GetValue():
@@ -4862,7 +3218,7 @@
              
 class MapinfoDialog(PsmapDialog):
     def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Mapinfo settings", settings = settings)
+        PsmapDialog.__init__(self, parent = parent, id = id, title = _("Mapinfo settings"), settings = settings)
         
         self.objectType = ('mapinfo',)
         if self.id is not None:
@@ -5290,7 +3646,7 @@
          
         rectSize = self.scalebar.EstimateSize(scalebarDict = self.scalebarDict,
                                                                 scale = self.instruction[mapId]['scale'])
-        self.scalebarDict['rect'] = wx.Rect2D(x = x, y = y, w = rectSize[0], h = rectSize[1])
+        self.scalebarDict['rect'] = Rect2D(x = x, y = y, width = rectSize[0], height = rectSize[1])
         self.scalebarDict['where'] = self.scalebarDict['rect'].GetCentre() 
 
         if self.id not in self.instruction:
@@ -5331,7 +3687,7 @@
             map = self.instruction.FindInstructionByType('initMap')
         self.mapId = map.id
 
-        self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(map = map, x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
+        self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(mapInstr = map, x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
         
         notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)     
         self.textPanel = self._textPanel(notebook)
@@ -5659,7 +4015,7 @@
             else:
                 self.textDict['north'] = self.textDict['north']
 
-            self.textDict['where'] = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.textDict['east']),
+            self.textDict['where'] = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.textDict['east']),
                                                             y = float(self.textDict['north']), paperToMap = False)
         #rotation
         if self.rotCtrl.GetValue():
@@ -5722,7 +4078,7 @@
             map = self.instruction.FindInstructionByType('initMap')
         self.mapId = map.id
 
-        self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(map = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
+        self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(mapInstr = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
         
         notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
         self.imagePanelName = imagePanelName
@@ -6037,7 +4393,7 @@
         selected = self.imagePanel.image['list'].GetStringSelection()
         basePath = self.imagePanel.image['dir'].GetValue()
         if not selected:
-            gcmd.GMessage(parent = self, message = _("No image selected."))
+            GMessage(parent = self, message = _("No image selected."))
             return False
             
         self.imageDict['epsfile'] = os.path.join(basePath, selected)
@@ -6073,7 +4429,7 @@
             else:
                 self.imageDict['north'] = self.imageDict['north']
 
-            x, y = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.imageDict['east']),
+            x, y = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.imageDict['east']),
                                        y = float(self.imageDict['north']), paperToMap = False)
 
         #rotation
@@ -6099,9 +4455,9 @@
                                   fromUnit = 'point', toUnit = 'inch')
                                   
     
-        self.imageDict['rect'] = wx.Rect2D(x = x, y = y,
-                                       w = w * self.imageDict['scale'],
-                                       h = h * self.imageDict['scale'])
+        self.imageDict['rect'] = Rect2D(x = x, y = y,
+                                        width = w * self.imageDict['scale'],
+                                        height = h * self.imageDict['scale'])
         
         if self.id not in self.instruction:
             image = self._newObject()
@@ -6161,297 +4517,453 @@
                 self.imagePanel.image['rotate'].SetValue(360 - convergence)
             
         
-def convertRGB(rgb):
-    """!Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color,
-            or named color/r:g:b string to wx.Colour, depending on input""" 
-    # transform a wx.Colour tuple into an r:g:b string    
-    if type(rgb) == wx.Colour:
-        for name, color in grass.named_colors.items(): 
-            if  rgb.Red() == int(color[0] * 255) and\
-                rgb.Green() == int(color[1] * 255) and\
-                rgb.Blue() == int(color[2] * 255):
-                return name
-        return str(rgb.Red()) + ':' + str(rgb.Green()) + ':' + str(rgb.Blue())
-    # transform a GRASS named color or an r:g:b string into a wx.Colour tuple
-    else:
-        color = (grass.parse_color(rgb)[0]*255,
-                 grass.parse_color(rgb)[1]*255,
-                 grass.parse_color(rgb)[2]*255)
-        color = wx.Color(*color)
-        if color.IsOk():
-            return color
-        else:  
-            return None
+class PointDialog(PsmapDialog):
+    """!Dialog for setting point properties."""
+    def __init__(self, parent, id, settings, coordinates = None, pointPanelName = _("Point")):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Point settings",
+                             settings = settings)
         
-def PaperMapCoordinates(map, x, y, paperToMap = True):
-    """!Converts paper (inch) coordinates -> map coordinates"""
-    unitConv = UnitConversion()
-    currRegionDict = grass.region()
-    cornerEasting, cornerNorthing = currRegionDict['w'], currRegionDict['n']
-    xMap = map['rect'][0]
-    yMap = map['rect'][1]
-    widthMap = map['rect'][2] * 0.0254 # to meter
-    heightMap = map['rect'][3] * 0.0254
-    xScale = widthMap / abs(currRegionDict['w'] - currRegionDict['e'])
-    yScale = heightMap / abs(currRegionDict['n'] - currRegionDict['s'])
-    currScale = (xScale + yScale) / 2
- 
-    if not paperToMap:
-        textEasting, textNorthing = x, y
-        eastingDiff = textEasting - cornerEasting 
-        if currRegionDict['w'] > currRegionDict['e']:
-            eastingDiff = - eastingDiff
+        self.objectType = ('point',)
+        if self.id is not None:
+            self.pointObj = self.instruction[self.id]
+            self.pointDict = self.instruction[id].GetInstruction()
         else:
-            eastingDiff = eastingDiff
+            self.id = wx.NewId()
+            self.pointObj = Point(self.id)
+            self.pointDict = self.pointObj.GetInstruction()
+            self.pointDict['where'] = coordinates 
+        self.defaultDict = self.pointObj.defaultInstruction
+                
+        mapObj = self.instruction.FindInstructionByType('map')
+        if not mapObj:
+            mapObj = self.instruction.FindInstructionByType('initMap')
+        self.mapId = mapObj.id
+        
+        self.pointDict['east'], self.pointDict['north'] = PaperMapCoordinates(mapInstr = mapObj, x = self.pointDict['where'][0], y = self.pointDict['where'][1], paperToMap = True)
+        
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.pointPanelName = pointPanelName
+        self.pointPanel = self._pointPanel(notebook)
+        self.positionPanel = self._positionPanel(notebook)
+        self.OnPositionType(None)
+        
+     
+        self._layout(notebook)
+        
+    def _pointPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = self.pointPanelName)
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # choose image
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Symbol"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridSizer.AddGrowableCol(1)
 
-        northingDiff = textNorthing - cornerNorthing
-        if currRegionDict['n'] > currRegionDict['s']:
-            northingDiff = - northingDiff 
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select symbol:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        self.symbolLabel = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                          label = self.pointDict['symbol'])
+        gridSizer.Add(item = self.symbolLabel, pos = (0, 1),
+                      flag = wx.ALIGN_CENTER_VERTICAL )
+        bitmap = wx.Bitmap(os.path.join(globalvar.ETCSYMBOLDIR,
+                                        self.pointDict['symbol']) + '.png')
+        self.symbolButton = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bitmap)
+        self.symbolButton.Bind(wx.EVT_BUTTON, self.OnSymbolSelection)
+
+        gridSizer.Add(self.symbolButton, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        self.noteLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, 
+                                       label = _("Note: Selected symbol is not displayed\n"
+                                                 "in draft mode (only in preview mode)"))
+        gridSizer.Add(self.noteLabel, pos = (1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #
+        # outline/fill color
+        #
+
+        # outline
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Color"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        outlineLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Outline color:"))
+        self.outlineColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.outlineTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+        if self.pointDict['color'] != 'none':
+            self.outlineTranspCtrl.SetValue(False)
+            self.outlineColorCtrl.SetColour(convertRGB(self.pointDict['color']))
         else:
-            northingDiff = northingDiff
+            self.outlineTranspCtrl.SetValue(True)
+            self.outlineColorCtrl.SetColour(convertRGB(self.defaultDict['color']))
 
-        xPaper = xMap + unitConv.convert(value = eastingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
-        yPaper = yMap + unitConv.convert(value = northingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
-        return xPaper, yPaper
-    else:
-        if currRegionDict['w'] < currRegionDict['e']:
-            eastingDiff = (x - xMap) 
+        gridSizer.Add(item = outlineLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.outlineColorCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.outlineTranspCtrl, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+        fillLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Fill color:"))
+        self.fillColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.fillTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+        if self.pointDict['fcolor'] != 'none':
+            self.fillTranspCtrl.SetValue(False)
+            self.fillColorCtrl.SetColour(convertRGB(self.pointDict['fcolor']))
         else:
-            eastingDiff = (xMap - x)
-        if currRegionDict['n'] < currRegionDict['s']:
-            northingDiff = (y - yMap) 
+            self.fillTranspCtrl.SetValue(True)
+            self.fillColorCtrl.SetColour(convertRGB(self.defaultDict['fcolor']))
+
+        gridSizer.Add(item = fillLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.fillColorCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.fillTranspCtrl, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        #
+        # size and rotation
+        #
+
+        # size
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size and Rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        sizeLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Size (pt):"))
+        self.sizeCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize)
+        self.sizeCtrl.SetToolTipString(_("Symbol size in points"))
+        self.sizeCtrl.SetValue(self.pointDict['size'])
+        
+        gridSizer.Add(item = sizeLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.sizeCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        # rotation
+        rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+        if fs:
+            self.rotCtrl = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = -360, max_val = 360,
+                                          increment = 1, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            self.rotCtrl.SetFormat("%f")
+            self.rotCtrl.SetDigits(1)
         else:
-            northingDiff = (yMap - y)
+            self.rotCtrl = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                min = -360, max = 360, initial = 0)
+        self.rotCtrl.SetToolTipString(_("Counterclockwise rotation in degrees"))
+        self.rotCtrl.SetValue(float(self.pointDict['rotate']))
+            
+        gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridSizer.Add(item = self.rotCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def _positionPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Position"))
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # set position
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddExtendedPosition(panel, gridBagSizer, self.pointDict)
+        
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+        
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def OnPositionType(self, event):
+        if self.positionPanel.position['toPaper'].GetValue():
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Disable()
+        else:
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Disable()
+                
+    def OnSymbolSelection(self, event):
+        dlg = SymbolDialog(self, symbolPath = globalvar.ETCSYMBOLDIR,
+                           currentSymbol = self.symbolLabel.GetLabel())
+        if dlg.ShowModal() == wx.ID_OK:
+            img = dlg.GetSelectedSymbol(fullPath = True)
+            name = dlg.GetSelectedSymbol(fullPath = False)
+            self.symbolButton.SetBitmapLabel(wx.Bitmap(img + '.png'))
+            self.symbolLabel.SetLabel(name)
+            
+        dlg.Destroy()
+        
+    def update(self): 
+        # symbol
+        self.pointDict['symbol'] = self.symbolLabel.GetLabel()
 
-        textEasting = cornerEasting + unitConv.convert(value = eastingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
-        textNorthing = cornerNorthing + unitConv.convert(value = northingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
-        return int(textEasting), int(textNorthing)
         
-def AutoAdjust(self, scaleType,  rect, map = None, mapType = None, region = None):
-    """!Computes map scale, center and map frame rectangle to fit region (scale is not fixed)"""
-    currRegionDict = {}
-    if scaleType == 0 and map:# automatic, region from raster or vector
-        res = ''
-        if mapType == 'raster': 
-            try:
-                res = grass.read_command("g.region", flags = 'gu', rast = map)
-            except grass.ScriptError:
-                pass
-        elif mapType == 'vector':
-            res = grass.read_command("g.region", flags = 'gu', vect = map)
-        currRegionDict = grass.parse_key_val(res, val_type = float)
-    elif scaleType == 1 and region: # saved region
-        res = grass.read_command("g.region", flags = 'gu', region = region)
-        currRegionDict = grass.parse_key_val(res, val_type = float)
-    elif scaleType == 2: # current region
-        env = grass.gisenv()
-        windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
-        try:
-            windFile = open(windFilePath, 'r').read()
-        except IOError:
-            currRegionDict = grass.region()
-        regionDict = grass.parse_key_val(windFile, sep = ':', val_type = float)
-        region = grass.read_command("g.region", flags = 'gu', n = regionDict['north'], s = regionDict['south'],
-                                    e = regionDict['east'], w = regionDict['west'])
-        currRegionDict = grass.parse_key_val(region, val_type = float)
-                                                                
-    else:
-        return None, None, None
-    
-    if not currRegionDict:
-        return None, None, None
-    rX = rect.x
-    rY = rect.y
-    rW = rect.width
-    rH = rect.height
-    if not hasattr(self, 'unitConv'):
-        self.unitConv = UnitConversion(self)
-    toM = 1
-    if projInfo()['proj'] != 'xy':
-        toM = float(projInfo()['meters'])
+        #position
+        if self.positionPanel.position['toPaper'].GetValue():
+            self.pointDict['XY'] = True
+            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+            self.pointDict['unit'] = currUnit
+            if self.positionPanel.position['xCtrl'].GetValue():
+                x = self.positionPanel.position['xCtrl'].GetValue() 
+            else:
+                x = self.pointDict['where'][0]
 
-    mW = self.unitConv.convert(value = (currRegionDict['e'] - currRegionDict['w']) * toM, fromUnit = 'meter', toUnit = 'inch')
-    mH = self.unitConv.convert(value = (currRegionDict['n'] - currRegionDict['s']) * toM, fromUnit = 'meter', toUnit = 'inch')
-    scale = min(rW/mW, rH/mH)
-    
-    if rW/rH > mW/mH:
-        x = rX - (rH*(mW/mH) - rW)/2
-        y = rY
-        rWNew = rH*(mW/mH)
-        rHNew = rH
-    else:
-        x = rX
-        y = rY - (rW*(mH/mW) - rH)/2
-        rHNew = rW*(mH/mW)
-        rWNew = rW
+            if self.positionPanel.position['yCtrl'].GetValue():
+                y = self.positionPanel.position['yCtrl'].GetValue() 
+            else:
+                y = self.pointDict['where'][1]
 
-    # center
-    cE = (currRegionDict['w'] + currRegionDict['e'])/2
-    cN = (currRegionDict['n'] + currRegionDict['s'])/2
-    return scale, (cE, cN), wx.Rect2D(x, y, rWNew, rHNew) #inch
+            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+            self.pointDict['where'] = x, y
+            
+        else:
+            self.pointDict['XY'] = False
+            if self.positionPanel.position['eCtrl'].GetValue():
+                e = self.positionPanel.position['eCtrl'].GetValue() 
+            else:
+                self.pointDict['east'] = self.pointDict['east']
 
-def SetResolution(dpi, width, height):
-    """!If resolution is too high, lower it
-    
-    @param dpi max DPI
-    @param width map frame width
-    @param height map frame height
-    """
-    region = grass.region()
-    if region['cols'] > width * dpi or region['rows'] > height * dpi:
-        rows = height * dpi
-        cols = width * dpi
-        RunCommand('g.region', rows = rows, cols = cols)
-               
-def ComputeSetRegion(self, mapDict):
-    """!Computes and sets region from current scale, map center coordinates and map rectangle"""
+            if self.positionPanel.position['nCtrl'].GetValue():
+                n = self.positionPanel.position['nCtrl'].GetValue() 
+            else:
+                self.pointDict['north'] = self.pointDict['north']
 
-    if mapDict['scaleType'] == 3: # fixed scale
-        scale = mapDict['scale']
+            x, y = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.pointDict['east']),
+                                       y = float(self.pointDict['north']), paperToMap = False)
+
+        #rotation
+        self.pointDict['rotate'] = self.rotCtrl.GetValue()
+        
+        # size
+        self.pointDict['size'] = self.sizeCtrl.GetValue()
             
-        if not hasattr(self, 'unitConv'):
-            self.unitConv = UnitConversion(self)
+        w = h = self.unitConv.convert(value = self.pointDict['size'],
+                                  fromUnit = 'point', toUnit = 'inch')
+                                  
+        # outline color
+        if self.outlineTranspCtrl.GetValue():
+            self.pointDict['color'] = 'none'
+        else:
+            self.pointDict['color'] = convertRGB(self.outlineColorCtrl.GetColour())
+
+        # fill color
+        if self.fillTranspCtrl.GetValue():
+            self.pointDict['fcolor'] = 'none'
+        else:
+            self.pointDict['fcolor'] = convertRGB(self.fillColorCtrl.GetColour())
+
+        self.pointDict['rect'] = Rect2D(x = x - w / 2, y = y - h / 2, width = w, height = h)
         
-        fromM = 1
-        if projInfo()['proj'] != 'xy':
-            fromM = float(projInfo()['meters'])
-        rectHalfInch = (mapDict['rect'].width/2, mapDict['rect'].height/2)
-        rectHalfMeter = (self.unitConv.convert(value = rectHalfInch[0], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale,
-                         self.unitConv.convert(value = rectHalfInch[1], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale) 
+        if self.id not in self.instruction:
+            point = Point(self.id)
+            self.instruction.AddInstruction(point)
+        self.instruction[self.id].SetInstruction(self.pointDict)
         
-        centerE = mapDict['center'][0]
-        centerN = mapDict['center'][1]
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+
+        return True
         
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            rasterId = raster.id 
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        # XY coordinates
+        x, y = self.pointDict['where'][:2]
+        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+        # EN coordinates
+        e, n = self.pointDict['east'], self.pointDict['north']
+        self.positionPanel.position['eCtrl'].SetValue(str(self.pointDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.pointDict['north']))
+        
+class RectangleDialog(PsmapDialog):
+    def __init__(self, parent, id, settings, type = 'rectangle', coordinates = None):
+        """!
+
+        @param coordinates begin and end point coordinate (wx.Point, wx.Point)
+        """
+        if type == 'rectangle':
+            title = _("Rectangle settings")
         else:
-            rasterId = None
+            title = _("Line settings")
+        PsmapDialog.__init__(self, parent = parent, id = id, title = title, settings = settings)
+        
+        self.objectType = (type,)
 
-        if rasterId:
-            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
-                       s = floor(centerN - rectHalfMeter[1]),
-                       e = ceil(centerE + rectHalfMeter[0]),
-                       w = floor(centerE - rectHalfMeter[0]),
-                       rast = self.instruction[rasterId]['raster'])
+        if self.id is not None:
+            self.rectObj = self.instruction[self.id]
+            self.rectDict = self.rectObj.GetInstruction()
         else:
-            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
-                       s = floor(centerN - rectHalfMeter[1]),
-                       e = ceil(centerE + rectHalfMeter[0]),
-                       w = floor(centerE - rectHalfMeter[0]))
-                    
-def projInfo():
-    """!Return region projection and map units information,
-    taken from render.py"""
-    
-    projinfo = dict()
-    
-    ret = RunCommand('g.proj', read = True, flags = 'p')
-    
-    if not ret:
-        return projinfo
-    
-    for line in ret.splitlines():
-        if ':' in line:
-            key, val = line.split(':')
-            projinfo[key.strip()] = val.strip()
-        elif "XY location (unprojected)" in line:
-            projinfo['proj'] = 'xy'
-            projinfo['units'] = ''
-            break
-    
-    return projinfo
+            self.id = wx.NewId()
+            if type == 'rectangle':
+                self.rectObj = Rectangle(self.id)
+            else:
+                self.rectObj = Line(self.id)
+            self.rectDict = self.rectObj.GetInstruction()
 
-def GetMapBounds(filename, portrait = True):
-    """!Run ps.map -b to get information about map bounding box
-    
-        @param filename psmap input file
-        @param portrait page orientation"""
-    orient = ''
-    if not portrait:
-        orient = 'r'
-    try:
-        bb = map(float, grass.read_command('ps.map',
-                                           flags = 'b' + orient,
-                                           quiet = True,
-                                           input = filename).strip().split('=')[1].split(','))
-    except (grass.ScriptError, IndexError):
-        GError(message = _("Unable to run `ps.map -b`"))
-        return None
-    return wx.Rect2D(bb[0], bb[3], bb[2] - bb[0], bb[1] - bb[3])
+            self.rectDict['rect'] = Rect2DPP(coordinates[0], coordinates[1])
+            self.rectDict['where'] = coordinates
 
-def getRasterType(map):
-    """!Returns type of raster map (CELL, FCELL, DCELL)"""
-    if map is None:
-        map = ''
-    file = grass.find_file(name = map, element = 'cell')
-    if file['file']:
-        rasterType = grass.raster_info(map)['datatype']
-        return rasterType
-    else:
-        return None
-   
-def PilImageToWxImage(pilImage, copyAlpha = True):
-    """!Convert PIL image to wx.Image
-    
-    Based on http://wiki.wxpython.org/WorkingWithImages
-    """
-    hasAlpha = pilImage.mode[-1] == 'A'
-    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.
-        wxImage = wx.EmptyImage( *pilImage.size )
-        pilImageCopyRGBA = pilImage.copy()
-        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
-        pilImageRgbData = pilImageCopyRGB.tostring()
-        wxImage.SetData(pilImageRgbData)
-        wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4])  # Create layer and insert alpha values.
+        self.defaultDict = self.rectObj.defaultInstruction
+        self.panel = self._rectPanel()
+        
+        self._layout(self.panel)
 
-    else :    # The resulting image will not have alpha.
-        wxImage = wx.EmptyImage(*pilImage.size)
-        pilImageCopy = pilImage.copy()
-        pilImageCopyRGB = pilImageCopy.convert('RGB')    # Discard any alpha from the PIL image.
-        pilImageRgbData = pilImageCopyRGB.tostring()
-        wxImage.SetData(pilImageRgbData)
+    def _rectPanel(self):
+        panel = wx.Panel(parent = self, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        border = wx.BoxSizer(wx.VERTICAL)
+                
+        # color
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Color"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        
+        outlineLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Outline color:"))
+        self.outlineColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.outlineTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
 
-    return wxImage
+        if self.rectDict['color'] != 'none':
+            self.outlineTranspCtrl.SetValue(False)
+            self.outlineColorCtrl.SetColour(convertRGB(self.rectDict['color']))
+        else:
+            self.outlineTranspCtrl.SetValue(True)
+            self.outlineColorCtrl.SetColour(convertRGB(self.defaultDict['color']))
 
-def BBoxAfterRotation(w, h, angle):
-    """!Compute bounding box or rotated rectangle
-    
-    @param w rectangle width
-    @param h rectangle height
-    @param angle angle (0, 360) in degrees
-    """
-    angleRad = angle / 180. * pi
-    ct = cos(angleRad)
-    st = sin(angleRad)
-    
-    hct = h * ct
-    wct = w * ct
-    hst = h * st
-    wst = w * st
-    y = x = 0
-    
-    if 0 < angle <= 90:
-        y_min = y
-        y_max = y + hct + wst
-        x_min = x - hst
-        x_max = x + wct
-    elif 90 < angle <= 180:
-        y_min = y + hct
-        y_max = y + wst
-        x_min = x - hst + wct
-        x_max = x
-    elif 180 < angle <= 270:
-        y_min = y + wst + hct
-        y_max = y
-        x_min = x + wct
-        x_max = x - hst
-    elif 270 < angle <= 360:
-        y_min = y + wst
-        y_max = y + hct
-        x_min = x
-        x_max = x + wct - hst
+        # transparent outline makes sense only for rectangle
+        if self.objectType == ('line',):
+            self.outlineTranspCtrl.Hide()
+
+        gridSizer.Add(item = outlineLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.outlineColorCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.outlineTranspCtrl, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+        # fill color only in rectangle
+        if self.objectType == ('rectangle',):
+            fillLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Fill color:"))
+            self.fillColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+            self.fillTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+            if self.rectDict['fcolor'] != 'none':
+                self.fillTranspCtrl.SetValue(False)
+                self.fillColorCtrl.SetColour(convertRGB(self.rectDict['fcolor']))
+            else:
+                self.fillTranspCtrl.SetValue(True)
+                self.fillColorCtrl.SetColour(wx.WHITE)
+
+            gridSizer.Add(item = fillLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+            gridSizer.Add(item = self.fillColorCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+            gridSizer.Add(item = self.fillTranspCtrl, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+        sizer.Add(gridSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+        # width
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Line style"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
         
-    width = int(ceil(abs(x_max) + abs(x_min)))
-    height = int(ceil(abs(y_max) + abs(y_min)))
-    return width, height
+        widthLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width:"))
+        if fs:
+            self.widthCtrl = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+                                          increment = 1, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            self.widthCtrl.SetFormat("%f")
+            self.widthCtrl.SetDigits(1)
+        else:
+            self.widthCtrl = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                min = -360, max = 360, initial = 0)
+        self.widthCtrl.SetToolTipString(_("Line width in points"))
+        self.widthCtrl.SetValue(float(self.rectDict['width']))
+
+        gridSizer.Add(item = widthLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.widthCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+        sizer.Add(gridSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        panel.SetSizer(border)
+        
+        return panel
+        
+
+    def update(self):
+        mapInstr = self.instruction.FindInstructionByType('map')
+        if not mapInstr:
+            mapInstr = self.instruction.FindInstructionByType('initMap')
+        self.mapId = mapInstr.id
+        point1 = self.rectDict['where'][0]
+        point2 = self.rectDict['where'][1]
+        self.rectDict['east1'], self.rectDict['north1'] = PaperMapCoordinates(mapInstr = mapInstr,
+                                                                                x = point1[0],
+                                                                                y = point1[1],
+                                                                                paperToMap = True)
+        self.rectDict['east2'], self.rectDict['north2'] = PaperMapCoordinates(mapInstr = mapInstr,
+                                                                                x = point2[0],
+                                                                                y = point2[1],
+                                                                                paperToMap = True)
+        # width
+        self.rectDict['width'] = self.widthCtrl.GetValue()
+        
+        # outline color
+        if self.outlineTranspCtrl.GetValue():
+            self.rectDict['color'] = 'none'
+        else:
+            self.rectDict['color'] = convertRGB(self.outlineColorCtrl.GetColour())
+
+        # fill color
+        if self.objectType == ('rectangle',):
+            if self.fillTranspCtrl.GetValue():
+                self.rectDict['fcolor'] = 'none'
+            else:
+                self.rectDict['fcolor'] = convertRGB(self.fillColorCtrl.GetColour())
+
+        if self.id not in self.instruction:
+            if self.objectType == ('rectangle',):
+                rect = Rectangle(self.id)
+            else:
+                rect = Line(self.id)
+            self.instruction.AddInstruction(rect)
+            
+        self.instruction[self.id].SetInstruction(self.rectDict)
+
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+            
+        self.updateDialog()
+
+        return True
+
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        pass
+

Modified: grass/branches/develbranch_6/gui/wxpython/psmap/frame.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/frame.py	2012-02-17 00:41:01 UTC (rev 50839)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/frame.py	2012-02-17 06:45:00 UTC (rev 50840)
@@ -7,7 +7,7 @@
  - frame::PsMapFrame
  - frame::PsMapBufferedWindow
 
-(C) 2011 by Anna Kratochvilova, and the GRASS Development Team
+(C) 2011-2012 by Anna Kratochvilova, and 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.
 
@@ -19,12 +19,7 @@
 import sys
 import textwrap
 import Queue
-from math import sin, cos, pi
-try:
-    import Image as PILImage
-    havePILImage = True
-except ImportError:
-    havePILImage = False
+from math import sin, cos, pi, sqrt
 
 if __name__ == "__main__":
     sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
@@ -38,15 +33,17 @@
 
 import grass.script as grass
 
-from gui_core.menu    import Menu
-from gui_core.goutput import CmdThread, EVT_CMD_DONE
-from psmap.toolbars   import PsMapToolbar
-from core.gcmd        import RunCommand, GError, GMessage
-from core.settings    import UserSettings
-from gui_core.forms   import GUI
-from psmap.menudata   import PsMapData
+from gui_core.menu      import Menu
+from gui_core.goutput   import CmdThread, EVT_CMD_DONE
+from psmap.toolbars     import PsMapToolbar
+from core.gcmd          import RunCommand, GError, GMessage
+from core.settings      import UserSettings
+from gui_core.forms     import GUI
+from psmap.menudata     import PsMapData
 
-from psmap.dialogs    import *
+from psmap.dialogs      import *
+from psmap.instructions import *
+from psmap.utils        import *
 
 class PsMapFrame(wx.Frame):
     def __init__(self, parent = None, id = wx.ID_ANY,
@@ -101,6 +98,8 @@
             'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
             'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
             'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
+            'point': wx.Pen(colour = wx.Color(100, 100, 100), width = 2),
+            'line': wx.Pen(colour = wx.Color(0, 0, 0), width = 2),
             'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
             'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
             'resize': wx.Pen(colour = 'BLACK', width = 1)
@@ -115,6 +114,8 @@
             'scalebar': wx.Brush(wx.Color(200, 200, 200)),
             'image': wx.Brush(wx.Color(255, 200, 50)),
             'northArrow': wx.Brush(wx.Color(255, 255, 255)),
+            'point': wx.Brush(wx.Color(200, 200, 200)),
+            'line': wx.TRANSPARENT_BRUSH,
             'box': wx.TRANSPARENT_BRUSH,
             'select':wx.TRANSPARENT_BRUSH,
             'resize': wx.BLACK_BRUSH
@@ -657,7 +658,81 @@
             dlg.SetPosition(position)
         dlg.Show()
         
+    def OnAddPoint(self, event):
+        """!Add point action selected"""
+        self.mouse["use"] = "addPoint"
+        self.canvas.SetCursor(self.cursors["cross"])
         
+    def AddPoint(self, id = None, coordinates = None):
+        """!Add point and open property dialog.
+
+        @param id id point id (None if creating new point)
+        @param coordinates coordinates of new point
+        """
+        position = None
+        if 'point' in self.openDialogs:
+            position = self.openDialogs['point'].GetPosition()
+            self.openDialogs['point'].OnApply(event = None)
+            self.openDialogs['point'].Destroy()
+        dlg = PointDialog(self, id = id, settings = self.instruction,
+                          coordinates = coordinates)
+        self.openDialogs['point'] = dlg
+        if position: 
+            dlg.SetPosition(position)
+        if coordinates:
+            dlg.OnApply(event = None)
+        dlg.Show()
+        
+    def OnAddLine(self, event):
+        """!Add line action selected"""
+        self.mouse["use"] = "addLine"
+        self.canvas.SetCursor(self.cursors["cross"])
+
+    def AddLine(self, id = None, coordinates = None):
+        """!Add line and open property dialog.
+        
+        @param id id line id (None if creating new line)
+        @param coordinates coordinates of new line
+        """
+        position = None
+        if 'line' in self.openDialogs:
+            position = self.openDialogs['line'].GetPosition()
+            self.openDialogs['line'].OnApply(event = None)
+            self.openDialogs['line'].Destroy()
+        dlg = RectangleDialog(self, id = id, settings = self.instruction,
+                              type = 'line', coordinates = coordinates)
+        self.openDialogs['line'] = dlg
+        if position: 
+            dlg.SetPosition(position)
+        if coordinates:
+            dlg.OnApply(event = None)
+        dlg.Show()
+
+    def OnAddRectangle(self, event):
+        """!Add rectangle action selected"""
+        self.mouse["use"] = "addRectangle"
+        self.canvas.SetCursor(self.cursors["cross"])
+
+    def AddRectangle(self, id = None, coordinates = None):
+        """!Add rectangle and open property dialog.
+        
+        @param id id rectangle id (None if creating new rectangle)
+        @param coordinates coordinates of new rectangle
+        """
+        position = None
+        if 'rectangle' in self.openDialogs:
+            position = self.openDialogs['rectangle'].GetPosition()
+            self.openDialogs['rectangle'].OnApply(event = None)
+            self.openDialogs['rectangle'].Destroy()
+        dlg = RectangleDialog(self, id = id, settings = self.instruction,
+                              type = 'rectangle', coordinates = coordinates)
+        self.openDialogs['rectangle'] = dlg
+        if position: 
+            dlg.SetPosition(position)
+        if coordinates:
+            dlg.OnApply(event = None)
+        dlg.Show()
+
     def getModifiedTextBounds(self, x, y, textExtent, rotation):
         """!computes bounding box of rotated text, not very precisely"""
         w, h = textExtent
@@ -804,6 +879,32 @@
                 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'bitmap', bb = drawRectangle)
                 self.canvas.RedrawSelectBox(id)
+
+            if itype in ('point', 'line', 'rectangle'):
+                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                # coords only for line
+                coords = None
+                if itype == 'line':
+                    point1 = self.instruction[id]['where'][0]
+                    point2 = self.instruction[id]['where'][1]
+                    point1Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)), canvasToPaper = False)[:2]
+                    point2Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)), canvasToPaper = False)[:2]
+                    coords = (point1Coords, point2Coords)
+
+                # fill color is not in line
+                fcolor = None
+                if 'fcolor' in self.instruction[id].GetInstruction():
+                    fcolor = self.instruction[id]['fcolor']
+                # width is not in point
+                width = None
+                if 'width' in self.instruction[id].GetInstruction():
+                    width = self.instruction[id]['width']
+
+                self.canvas.DrawGraphics(drawid = id, color = self.instruction[id]['color'], shape = itype,
+                                       fcolor = fcolor, width = width, bb = drawRectangle, lineCoords = coords)
+
+                self.canvas.RedrawSelectBox(id)
+
             if itype == 'text':
                 
                 if self.instruction[id]['rotate']:
@@ -812,7 +913,7 @@
                     rot = 0
 
                 extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
-                rect = wx.Rect2D(self.instruction[id]['where'][0], self.instruction[id]['where'][1], 0, 0)
+                rect = Rect2DPS(self.instruction[id]['where'], (0, 0))
                 self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
                 
                 #computes text coordinates according to reference point, not precisely
@@ -993,6 +1094,9 @@
         self.idBoxTmp = wx.NewId()
         self.idZoomBoxTmp = wx.NewId()
         self.idResizeBoxTmp = wx.NewId()
+        self.idLinePointsTmp = (wx.NewId(), wx.NewId()) # ids of marks for moving line vertices
+
+        self.resizeBoxSize = wx.Size(8, 8)
         
         
 
@@ -1014,7 +1118,8 @@
         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_MOUSE_EVENTS, self.OnMouse)
+        # self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
 
 
     def Clear(self):
@@ -1051,12 +1156,12 @@
             scale = self.currScale
             pRectx = units.convert(value =  - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
             pRecty = units.convert(value =  - pRect.y, fromUnit = 'pixel', toUnit = 'inch' ) /scale 
-        Width = units.convert(value = rect.width, fromUnit = fromU, toUnit = toU) * scale
-        Height = units.convert(value = rect.height, fromUnit = fromU, toUnit = toU) * scale
-        X = units.convert(value = (rect.x - pRectx), fromUnit = fromU, toUnit = toU) * scale
-        Y = units.convert(value = (rect.y - pRecty), fromUnit = fromU, toUnit = toU) * scale
+        Width = units.convert(value = rect.GetWidth(), fromUnit = fromU, toUnit = toU) * scale
+        Height = units.convert(value = rect.GetHeight(), fromUnit = fromU, toUnit = toU) * scale
+        X = units.convert(value = (rect.GetX() - pRectx), fromUnit = fromU, toUnit = toU) * scale
+        Y = units.convert(value = (rect.GetY() - pRecty), fromUnit = fromU, toUnit = toU) * scale
 
-        return wx.Rect2D(X, Y, Width, Height)
+        return Rect2D(X, Y, Width, Height)
 
     
     
@@ -1099,12 +1204,29 @@
         except AttributeError:
             mapId = self.instruction.FindInstructionByType('initMap').id
         
-        for itemType in ('text', 'image', 'northArrow'):
+        for itemType in ('text', 'image', 'northArrow', 'point', 'line', 'rectangle'):
             items = self.instruction.FindInstructionByType(itemType, list = True)
             for item in items:
-                e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[item.id]['where'][0],
-                                           y = self.instruction[item.id]['where'][1], paperToMap = True)
-                self.instruction[item.id]['east'], self.instruction[item.id]['north'] = e, n
+                instr = self.instruction[item.id]
+                if itemType in ('line', 'rectangle'):
+                    if itemType == 'line':
+                        e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0][0],
+                                                     y = instr['where'][0][1], paperToMap = True)
+                        e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][1][0],
+                                                     y = instr['where'][1][1], paperToMap = True)
+                    else: 
+                        e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetLeft(),
+                                                     y = instr['rect'].GetTop(), paperToMap = True)
+                        e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetRight(),
+                                                     y = instr['rect'].GetBottom(), paperToMap = True)
+                    instr['east1'] = e1
+                    instr['north1'] = n1
+                    instr['east2'] = e2
+                    instr['north2'] = n2
+                else:
+                    e, n = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0],
+                                               y = instr['where'][1], paperToMap = True)
+                    instr['east'], instr['north'] = e, n
                 
     def OnPaint(self, event):
         """!Draw pseudo DC to buffer
@@ -1131,243 +1253,400 @@
             self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
         self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
         
-    def OnMouse(self, event):
+    def MouseActions(self, event):
+        """!Mouse motion and button click notifier
+        """
+        # 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)
+        
+        elif event.Moving():
+            self.OnMouseMoving(event)
+                
+    def OnMouseWheel(self, event):
+        """!Mouse wheel scrolled.
 
-        if event.GetWheelRotation() and UserSettings.Get(group = 'display',
-                                                         key = 'mouseWheelZoom',
-                                                         subkey = 'enabled'):
-            zoom = event.GetWheelRotation()
-            use = self.mouse['use']
-            self.mouse['begin'] = event.GetPosition()
+        Changes zoom."""
+        if not UserSettings.Get(group = 'display',
+                                key = 'mouseWheelZoom',
+                                subkey = 'enabled'):
+            event.Skip()
+            return
+
+        zoom = event.GetWheelRotation()
+        oldUse = self.mouse['use']
+        self.mouse['begin'] = event.GetPosition()
+        
+        if UserSettings.Get(group = 'display',
+                            key = 'mouseWheelZoom',
+                            subkey = 'selection'):
+            zoom *= -1
             
-            if UserSettings.Get(group = 'display',
-                                key = 'mouseWheelZoom',
-                                subkey = 'selection'):
-                zoom *= -1
+        if zoom > 0:
+            self.mouse['use'] = 'zoomin'
+        else:
+            self.mouse['use'] = 'zoomout'
+            
+        zoomFactor, view = self.ComputeZoom(wx.Rect(0, 0, 0, 0))
+        self.Zoom(zoomFactor, view)
+        self.mouse['use'] = oldUse
+
+    def OnMouseMoving(self, event):
+        """!Mouse cursor moving.
+
+        Change cursor when moving over resize marker.
+        """
+        if self.mouse['use'] in ('pointer', 'resize'):
+            pos = event.GetPosition()
+            foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
+            if foundResize and foundResize[0] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
+                self.SetCursor(self.cursors["sizenwse"])
+                self.parent.SetStatusText(_('Click and drag to resize object'), 0)
+            else:
+                self.parent.SetStatusText('', 0)
+                self.SetCursor(self.cursors["default"])
                 
-            if zoom > 0:
-                self.mouse['use'] = 'zoomin'
+    def OnLeftDown(self, event):
+        """!Left mouse button pressed.
+
+        Select objects, redraw, prepare for moving/resizing.
+        """
+        self.mouse['begin'] = event.GetPosition()
+        self.begin = self.mouse['begin']
+        
+        # select
+        if self.mouse['use'] == 'pointer':
+            found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
+            foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
+
+            if foundResize and foundResize[0] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
+                self.mouse['use'] = 'resize'
+                
+                # when resizing, proportions match region
+                if self.instruction[self.dragId].type == 'map':
+                    self.constraint = False
+                    self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
+                    if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
+                        self.constraint = True
+                        self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
+
+                if self.instruction[self.dragId].type == 'line':
+                    self.currentLinePoint = self.idLinePointsTmp.index(foundResize[0])
+                
+            elif found:
+                self.dragId = found[0]
+                self.RedrawSelectBox(self.dragId)
+                if self.instruction[self.dragId].type not in ('map', 'rectangle'):
+                    self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+                    self.Refresh()
+                if self.instruction[self.dragId].type != 'line':
+                    for id in self.idLinePointsTmp:
+                        self.pdcTmp.RemoveId(id)
+                    self.Refresh()
+                    
             else:
-                self.mouse['use'] = 'zoomout'
-                
-            zoomFactor, view = self.ComputeZoom(wx.Rect(0,0,0,0))
+                self.dragId = -1
+                self.pdcTmp.RemoveId(self.idBoxTmp)
+                self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+                for id in self.idLinePointsTmp:
+                    self.pdcTmp.RemoveId(id)
+                self.Refresh()
+
+    def OnLeftUp(self, event):
+        """!Left mouse button released.
+
+        Recalculate zooming/resizing/moving and redraw.
+        """
+        # zoom in, zoom out
+        if self.mouse['use'] in ('zoomin','zoomout'):
+            zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
+            self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+            self.Refresh()
+            zoomFactor, view = self.ComputeZoom(zoomR)
             self.Zoom(zoomFactor, view)
-            self.mouse['use'] = use
+
+        # draw map frame
+        if self.mouse['use'] == 'addMap':
+            rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
+            # too small rectangle, it's usually some mistake
+            if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
+                self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+                self.Refresh()
+                return
+            rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)
+
+            dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction, 
+                            rect = rectPaper)
+            self.openDialogs['map'] = dlg
+            self.openDialogs['map'].Show()
             
-        if event.Moving():
-            if self.mouse['use'] in ('pointer', 'resize'):
-                pos = event.GetPosition()
-                foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
-                if foundResize and foundResize[0] == self.idResizeBoxTmp:
-                    self.SetCursor(self.cursors["sizenwse"])
-                    self.parent.SetStatusText(_('Click and drag to resize object'), 0)
-                else:
-                    self.parent.SetStatusText('', 0)
-                    self.SetCursor(self.cursors["default"])
+            self.mouse['use'] = self.parent.mouseOld
+
+            self.SetCursor(self.parent.cursorOld)
+            self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
+            self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
+            self.parent.toolbar.action['id'] = self.parent.actionOld
+            return
+
+        # resize resizable objects (map, line, rectangle)
+        if self.mouse['use'] == 'resize':
+            mapObj = self.instruction.FindInstructionByType('map')
+            if not mapObj:
+                mapObj = self.instruction.FindInstructionByType('initMap')
+            mapId = mapObj.id
+            
+            if self.dragId == mapId:
+                # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
+                newRectCanvas = self.pdcObj.GetIdBounds(mapId)
+                newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
+                self.instruction[mapId]['rect'] = newRectPaper
+                
+                if self.instruction[mapId]['scaleType'] in (0, 1, 2):
+                    if self.instruction[mapId]['scaleType'] == 0:
+                        
+                        scale, foo, rect = AutoAdjust(self, scaleType = 0,
+                                                      map = self.instruction[mapId]['map'],
+                                                      mapType = self.instruction[mapId]['mapType'], 
+                                                      rect = self.instruction[mapId]['rect'])
+                        
+                    elif self.instruction[mapId]['scaleType'] == 1:
+                        scale, foo, rect = AutoAdjust(self, scaleType = 1,
+                                                      region = self.instruction[mapId]['region'],
+                                                      rect = self.instruction[mapId]['rect'])
+                    else:
+                        scale, foo, rect = AutoAdjust(self, scaleType = 2,
+                                                      rect = self.instruction[mapId]['rect'])
+                    self.instruction[mapId]['rect'] = rect
+                    self.instruction[mapId]['scale'] = scale
                     
-        elif event.MiddleDown():
-            self.mouse['begin'] = event.GetPosition()
+                    rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
+                    self.Draw(pen = self.pen['map'], brush = self.brush['map'],
+                              pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
+                    
+                elif self.instruction[mapId]['scaleType'] == 3:
+                    ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
+                #check resolution
+                SetResolution(dpi = self.instruction[mapId]['resolution'],
+                              width = self.instruction[mapId]['rect'].width,
+                              height = self.instruction[mapId]['rect'].height)
+                
+                self.RedrawSelectBox(mapId)
+                self.Zoom(zoomFactor = 1, view = (0, 0))
+
+            elif self.instruction[self.dragId].type == 'line':
+                points = self.instruction[self.dragId]['where']
+                self.instruction[self.dragId]['rect'] = Rect2DPP(points[0], points[1])
+                self.RecalculatePosition(ids = [self.dragId])
+
+            elif self.instruction[self.dragId].type == 'rectangle':
+                self.RecalculatePosition(ids = [self.dragId])
+
+            self.mouse['use'] = 'pointer'
             
-        elif event.LeftDown():
-            self.mouse['begin'] = event.GetPosition()
-            self.begin = self.mouse['begin']
-            if self.mouse['use'] in ('pan', 'zoomin', 'zoomout', 'addMap'):
-                pass
-            
-            #select
-            if self.mouse['use'] == 'pointer':
-                found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
-                foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
+        # recalculate the position of objects after dragging
+        if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
+            if self.mouse['begin'] != event.GetPosition(): #for double click
+                
+                self.RecalculatePosition(ids = [self.dragId])
+                if self.instruction[self.dragId].type in self.openDialogs:
+                    self.openDialogs[self.instruction[self.dragId].type].updateDialog()
+        
+        elif self.mouse['use'] in ('addPoint', 'addLine', 'addRectangle'):
+            endCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(event.GetX(), event.GetY(), 0, 0),
+                                                         canvasToPaper = True)[:2]
 
-                if foundResize and foundResize[0] == self.idResizeBoxTmp:
-                    self.mouse['use'] = 'resize'
-                    
-                    # when resizing, proportions match region
-                    if self.instruction[self.dragId].type == 'map':
-                        self.constraint = False
-                        self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
-                        if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
-                            self.constraint = True
-                            self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
-                    
-                elif found:
-                    self.dragId = found[0]  
-                    self.RedrawSelectBox(self.dragId)
-                    if self.instruction[self.dragId].type != 'map':
-                        self.pdcTmp.RemoveId(self.idResizeBoxTmp)
-                        self.Refresh()
-                        
+            diffX = event.GetX() - self.mouse['begin'][0]
+            diffY = event.GetY() - self.mouse['begin'][1]
+
+            if self.mouse['use'] == 'addPoint':
+                self.parent.AddPoint(coordinates = endCoordinates)
+            elif self.mouse['use'] in ('addLine', 'addRectangle'):
+                # not too small lines/rectangles
+                if sqrt(diffX * diffX + diffY * diffY) < 5:
+                    self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+                    self.Refresh()
+                    return
+
+                beginCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(self.mouse['begin'][0],
+                                                                              self.mouse['begin'][1], 0, 0),
+                                                               canvasToPaper = True)[:2]
+                if self.mouse['use'] == 'addLine':
+                    self.parent.AddLine(coordinates = [beginCoordinates, endCoordinates])
                 else:
-                    self.dragId = -1
-                    self.pdcTmp.RemoveId(self.idBoxTmp)
-                    self.pdcTmp.RemoveId(self.idResizeBoxTmp)
-                    self.Refresh()           
-                    
-        elif event.Dragging() and event.MiddleIsDown():
+                    self.parent.AddRectangle(coordinates = [beginCoordinates, endCoordinates])
+                self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+                self.Refresh()
+
+    def OnButtonDClick(self, event):
+        """!Open object dialog for editing."""
+        if self.mouse['use'] == 'pointer' and self.dragId != -1:
+            itemCall = {'text':self.parent.OnAddText,
+                        'mapinfo': self.parent.OnAddMapinfo,
+                        'scalebar': self.parent.OnAddScalebar,
+                        'image': self.parent.OnAddImage,
+                        'northArrow' : self.parent.OnAddNorthArrow,
+                        'point': self.parent.AddPoint,
+                        'line': self.parent.AddLine,
+                        'rectangle': self.parent.AddRectangle,
+                        'rasterLegend': self.parent.OnAddLegend,
+                        'vectorLegend': self.parent.OnAddLegend,
+                        'map': self.parent.OnAddMap}
+
+            itemArg = { 'text': dict(event = None, id = self.dragId),
+                        'mapinfo': dict(event = None),
+                        'scalebar': dict(event = None),
+                        'image': dict(event = None, id = self.dragId),
+                        'northArrow': dict(event = None, id = self.dragId),
+                        'point': dict(id = self.dragId),
+                        'line': dict(id = self.dragId),
+                        'rectangle': dict(id = self.dragId),
+                        'rasterLegend': dict(event = None),
+                        'vectorLegend': dict(event = None, page = 1),
+                        'map': dict(event = None, notebook = True)}
+
+            type = self.instruction[self.dragId].type
+            itemCall[type](**itemArg[type])
+
+    def OnDragging(self, event):
+        """!Process panning/resizing/drawing/moving."""
+        if event.MiddleIsDown():
+            # panning
             self.mouse['end'] = event.GetPosition()
             self.Pan(begin = self.mouse['begin'], end = self.mouse['end'])
             self.mouse['begin'] = event.GetPosition()
-            
-        elif event.Dragging() and event.LeftIsDown():
-            #draw box when zooming, creating map 
-            if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap'):
+
+        elif event.LeftIsDown():
+            # draw box when zooming, creating map 
+            if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap', 'addLine', 'addRectangle'):
                 self.mouse['end'] = event.GetPosition()
                 r = wx.Rect(self.mouse['begin'][0], self.mouse['begin'][1],
                             self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
                 r = self.modifyRectangle(r)
-                self.Draw(pen = self.pen['box'], brush = self.brush['box'], pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
-                          pdctype = 'rect', bb = r)
-                
+
+                if self.mouse['use'] in ('addLine', 'addRectangle'):
+                    if self.mouse['use'] == 'addLine':
+                        pdcType = 'line'
+                        lineCoords = (self.mouse['begin'], self.mouse['end'])
+                    else:
+                        pdcType = 'rect'
+                        lineCoords = None
+                        if r[2] < 2 or r[3] < 2:
+                            # to avoid strange behavoiur
+                            return
+
+                    self.Draw(pen = self.pen['line'], brush = self.brush['line'],
+                              pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
+                              pdctype = pdcType, bb = r, lineCoords = lineCoords)
+
+                else:
+                    self.Draw(pen = self.pen['box'], brush = self.brush['box'],
+                              pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
+                              pdctype = 'rect', bb = r)
+
             # panning
             if self.mouse["use"] == 'pan':
                 self.mouse['end'] = event.GetPosition()
                 self.Pan(begin = self.mouse['begin'], end = self.mouse['end'])
                 self.mouse['begin'] = event.GetPosition()
-                
-            #move object
+
+            # move object
             if self.mouse['use'] == 'pointer' and self.dragId != -1:
-                
                 self.mouse['end'] = event.GetPosition()
                 dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
                 self.pdcObj.TranslateId(self.dragId, dx, dy)
                 self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
                 self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
+                for id in self.idLinePointsTmp:
+                    self.pdcTmp.TranslateId(id, dx, dy)
                 if self.instruction[self.dragId].type == 'text': 
                     self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
                         self.instruction[self.dragId]['coords'][1] + dy
                 self.begin = event.GetPosition()
                 self.Refresh()
-                
+
             # resize object
             if self.mouse['use'] == 'resize':
-                type = self.instruction[self.dragId].type
                 pos = event.GetPosition()
-                x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
-                width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
                 diffX = pos[0] - self.mouse['begin'][0]
                 diffY = pos[1] - self.mouse['begin'][1]
-                # match given region
-                if self.constraint:
-                    if width > height:
+                if self.instruction[self.dragId].type == 'map':
+                    x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
+                    width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
+                    # match given region
+                    if self.constraint:
+                        if width > height:
+                            newWidth = width + diffX
+                            newHeight = height + diffX * (float(height) / width)
+                        else:
+                            newWidth = width + diffY * (float(width) / height)
+                            newHeight = height + diffY
+                    else:
                         newWidth = width + diffX
-                        newHeight = height + diffX * (float(height) / width)
-                    else:
-                        newWidth = width + diffY * (float(width) / height)
                         newHeight = height + diffY
-                else:
-                    newWidth = width + diffX
-                    newHeight = height + diffY
-                    
-                if newWidth < 10 or newHeight < 10:
-                    return
-                
-                bounds = wx.Rect(x, y, newWidth, newHeight)    
-                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj, drawid = self.dragId,
-                          pdctype = 'rectText', bb = bounds)
-                self.RedrawSelectBox(self.dragId)
-                
-        elif event.LeftUp():
-            # zoom in, zoom out
-            if self.mouse['use'] in ('zoomin','zoomout'):
-                zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
-                self.pdcTmp.RemoveId(self.idZoomBoxTmp)
-                self.Refresh()
-                zoomFactor, view = self.ComputeZoom(zoomR)
-                self.Zoom(zoomFactor, view)
+                        
+                    if newWidth < 10 or newHeight < 10:
+                        return
 
-                
-            # draw map frame    
-            if self.mouse['use'] == 'addMap':
-                rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
-                # too small rectangle, it's usually some mistake
-                if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
-                    self.pdcTmp.RemoveId(self.idZoomBoxTmp)
-                    self.Refresh()
-                    return
-                rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)                
-                
-                dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction, 
-                                rect = rectPaper)
-                self.openDialogs['map'] = dlg
-                self.openDialogs['map'].Show()
-                
-                
-                self.mouse['use'] = self.parent.mouseOld
+                    bounds = wx.Rect(x, y, newWidth, newHeight)
+                    self.Draw(pen = self.pen['map'], brush = self.brush['map'], pdc = self.pdcObj, drawid = self.dragId,
+                              pdctype = 'rectText', bb = bounds)
 
-                self.SetCursor(self.parent.cursorOld)
-                self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
-                self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
-                self.parent.toolbar.action['id'] = self.parent.actionOld
-                
+                elif self.instruction[self.dragId].type == 'rectangle':
+                    instr = self.instruction[self.dragId]
+                    rect = self.CanvasPaperCoordinates(rect = instr['rect'], canvasToPaper = False)
+                    rect.SetWidth(rect.GetWidth() + diffX)
+                    rect.SetHeight(rect.GetHeight() + diffY)
 
+                    if rect.GetWidth() < 5 or rect.GetHeight() < 5:
+                        return
 
-            # resize resizable objects (only map sofar)
-            if self.mouse['use'] == 'resize':
-                mapId = self.instruction.FindInstructionByType('map').id
-                
-                if self.dragId == mapId:
-                    # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
-                    newRectCanvas = self.pdcObj.GetIdBounds(mapId)
-                    newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
-                    self.instruction[mapId]['rect'] = newRectPaper
-                    
-                    if self.instruction[mapId]['scaleType'] in (0, 1, 2):
-                        if self.instruction[mapId]['scaleType'] == 0:
-                            
-                            scale, foo, rect = AutoAdjust(self, scaleType = 0,
-                                                          map = self.instruction[mapId]['map'],
-                                                          mapType = self.instruction[mapId]['mapType'], 
-                                                          rect = self.instruction[mapId]['rect'])
-                            
-                        elif self.instruction[mapId]['scaleType'] == 1:
-                            scale, foo, rect = AutoAdjust(self, scaleType = 1,
-                                                          region = self.instruction[mapId]['region'],
-                                                          rect = self.instruction[mapId]['rect'])
-                        else:
-                            scale, foo, rect = AutoAdjust(self, scaleType = 2,
-                                                          rect = self.instruction[mapId]['rect'])
-                        self.instruction[mapId]['rect'] = rect
-                        self.instruction[mapId]['scale'] = scale
-                        
-                        rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
-                        self.Draw(pen = self.pen['map'], brush = self.brush['map'],
-                                  pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
-                        
-                    elif self.instruction[mapId]['scaleType'] == 3:
-                        ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
-                    #check resolution
-                    SetResolution(dpi = self.instruction[mapId]['resolution'],
-                                  width = self.instruction[mapId]['rect'].width,
-                                  height = self.instruction[mapId]['rect'].height)
-                    
-                    self.RedrawSelectBox(mapId)
-                    self.Zoom(zoomFactor = 1, view = (0, 0))
-                self.mouse['use'] = 'pointer'
-                
-            # recalculate the position of objects after dragging    
-            if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
-                if self.mouse['begin'] != event.GetPosition(): #for double click
-                    
-                    self.RecalculatePosition(ids = [self.dragId])
-                    if self.instruction[self.dragId].type in self.openDialogs:
-                        self.openDialogs[self.instruction[self.dragId].type].updateDialog()
+                    self.DrawGraphics(drawid = self.dragId, shape = 'rectangle', color = instr['color'],
+                                      fcolor = instr['fcolor'], width = instr['width'], bb = rect)
 
-        # double click launches dialogs
-        elif event.LeftDClick():
-            if self.mouse['use'] == 'pointer' and self.dragId != -1:
-                itemCall = {    'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
-                                'scalebar': self.parent.OnAddScalebar, 'image': self.parent.OnAddImage,
-                                'northArrow' : self.parent.OnAddNorthArrow,
-                                'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,  
-                                'map': self.parent.OnAddMap}
-                itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
-                            'scalebar': dict(event = None), 'image': dict(event = None, id = self.dragId),
-                            'northArrow': dict(event = None, id = self.dragId),
-                            'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
-                            'map': dict(event = None, notebook = True)}
-                type = self.instruction[self.dragId].type
-                itemCall[type](**itemArg[type])
+                elif self.instruction[self.dragId].type == 'line':
+                    instr = self.instruction[self.dragId]
+                    points = instr['where']
+                    # moving point
+                    if self.currentLinePoint == 0:
+                        pPaper = points[1]
+                    else:
+                        pPaper = points[0]
+                    pCanvas = self.CanvasPaperCoordinates(rect = Rect2DPS(pPaper, (0, 0)),
+                                                          canvasToPaper = False)[:2]
+                    bounds = wx.RectPP(pCanvas, pos)
+                    self.DrawGraphics(drawid = self.dragId, shape = 'line', color = instr['color'],
+                                      width = instr['width'], bb = bounds, lineCoords = (pos, pCanvas))
 
+                    # update paper coordinates
+                    points[self.currentLinePoint] = self.CanvasPaperCoordinates(rect = wx.RectPS(pos, (0, 0)),
+                                                                                canvasToPaper = True)[:2]
+
+                self.RedrawSelectBox(self.dragId)
+
+    def OnMiddleDown(self, event):
+        """!Middle mouse button pressed."""
+        self.mouse['begin'] = event.GetPosition()
+
     def Pan(self, begin, end):
         """!Move canvas while dragging.
         
@@ -1381,7 +1660,7 @@
     def RecalculatePosition(self, ids):
         for id in ids:
             itype = self.instruction[id].type
-            if itype == 'map':
+            if itype in ('map', 'rectangle'):
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
                 self.RecalculateEN()
@@ -1393,6 +1672,30 @@
                                                                             canvasToPaper = True)[:2] 
                 if itype in ('image', 'northArrow'):
                     self.RecalculateEN()
+
+            elif itype == 'point':
+                rect = self.pdcObj.GetIdBounds(id)
+                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = rect,
+                                                                           canvasToPaper = True)
+                rect.OffsetXY(rect.GetWidth()/2, rect.GetHeight()/2)
+                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = rect,
+                                                                            canvasToPaper = True)[:2]
+                self.RecalculateEN()
+
+            elif itype == 'line':
+                rect = self.pdcObj.GetIdBounds(id)
+                oldRect = self.instruction[id]['rect']
+                newRect = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = True)
+                xDiff = newRect[0] - oldRect[0]
+                yDiff = newRect[1] - oldRect[1]
+                self.instruction[id]['rect'] = newRect
+
+                point1 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][0]
+                point2 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][1]
+                self.instruction[id]['where'] = [point1, point2]
+                
+                self.RecalculateEN()
+
             elif  itype == 'scalebar':
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
@@ -1420,7 +1723,7 @@
                     x += extent[0]/2 * cos(rot)
                     y -= extent[0]/2 * sin(rot)
                 
-                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = wx.Rect2D(x, y, 0, 0),
+                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = Rect2D(x, y, 0, 0),
                                                                             canvasToPaper = True)[:2]
                 self.RecalculateEN()
         
@@ -1510,6 +1813,27 @@
                 elif type == 'northArrow':
                     self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
                               drawid = id, pdctype = 'bitmap', bb = oRect)
+
+                elif type in ('point', 'line', 'rectangle'):
+                    instr = self.instruction[id]
+                    color = self.instruction[id]['color']
+                    width = fcolor = coords = None
+
+                    if type in ('point', 'rectangle'):
+                        fcolor = self.instruction[id]['fcolor']
+                    if type in ('line', 'rectangle'):
+                        width = self.instruction[id]['width']
+                    if type in ('line'):
+                        point1, point2 = instr['where'][0], instr['where'][1]
+                        point1 = self.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)),
+                                                             canvasToPaper = False)[:2]
+                        point2 = self.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)),
+                                                             canvasToPaper = False)[:2]
+                        coords = (point1, point2)
+
+                    self.DrawGraphics(drawid = id, shape = type, bb = oRect, lineCoords = coords,
+                                    color = color, fcolor = fcolor, width = width)
+
                 else:
                     self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
                               drawid = id, pdctype = 'rectText', bb = oRect)
@@ -1534,8 +1858,14 @@
         zoomFactor, view = self.ComputeZoom(zoomP)
         self.Zoom(zoomFactor, view)
         
-    def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0)): 
-        """! Draw object"""    
+    def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0), lineCoords = None): 
+        """! Draw object with given pen and brush.
+
+        @param pdc PseudoDC
+        @param pdctype 'bitmap'/'rectText'/'rect'/'point'/'line'
+        @param bb bounding box
+        @param lineCoords coordinates of line start, end points (wx.Point, wx.Point)
+        """    
         if drawid is None:
             drawid = wx.NewId()
         bb = bb.Get()
@@ -1580,12 +1910,53 @@
             pdc.SetBackgroundMode(wx.TRANSPARENT)
             pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
                 
+        elif pdctype == 'point':
+            pdc.DrawCircle(x = bb[0] + bb[2] / 2,
+                           y = bb[1] + bb[3] / 2,
+                           radius = bb[2] / 2)
+                           
+        elif pdctype == 'line':
+            pdc.DrawLinePoint(lineCoords[0], lineCoords[1])
+
         pdc.SetIdBounds(drawid, bb)
         pdc.EndDrawing()
         self.Refresh()
 
         return drawid
     
+    def DrawGraphics(self, drawid, shape, color, bb, width = None, fcolor = None, lineCoords = None):
+        """!Draw point/line/rectangle with given color and width
+
+        @param drawid id of drawn object
+        @param shape drawn shape: 'point'/'line'/'rectangle'
+        @param color pen outline color ('RRR:GGG:BBB')
+        @param fcolor brush fill color, if meaningful ('RRR:GGG:BBB')
+        @param width pen width
+        @param bb bounding box
+        @param lineCoords line coordinates (for line only)
+        """
+        pdctype = {'point'     : 'point',
+                   'line'      : 'line',
+                   'rectangle' : 'rect'}
+
+        if color == 'none':
+            pen = wx.TRANSPARENT_PEN
+        else:
+            if width is not None:
+                units = UnitConversion(self)
+                width = int(units.convert(value = width, fromUnit = 'point', toUnit = 'pixel') * self.currScale)
+            else:
+                width = 2
+            pen = wx.Pen(colour = convertRGB(color), width = width)
+            pen.SetCap(wx.CAP_BUTT) # this is how ps.map draws
+
+        brush = wx.TRANSPARENT_BRUSH
+        if fcolor and fcolor != 'none':
+            brush = wx.Brush(colour = convertRGB(fcolor))
+        
+        self.Draw(pen = pen, brush = brush, pdc = self.pdcObj, pdctype = pdctype[shape],
+                  drawid = drawid, bb = bb, lineCoords = lineCoords)
+
     def DrawBitmap(self, pdc, filePath, rotation, bbox):
         """!Draw bitmap using PIL"""
         pImg = PILImage.open(filePath)
@@ -1702,17 +2073,32 @@
     def RedrawSelectBox(self, id):
         """!Redraws select box when selected object changes its size"""
         if self.dragId == id:
-            rect = [self.pdcObj.GetIdBounds(id).Inflate(3,3)]
-            type = ['select']
-            ids = [self.idBoxTmp]
-            if self.instruction[id].type == 'map':
+            rect = self.pdcObj.GetIdBounds(id)
+            if self.instruction[id].type != 'line':
+                rect = rect.Inflate(3,3)
+            # draw select box around object
+            self.Draw(pen = self.pen['select'], brush = self.brush['select'], pdc = self.pdcTmp,
+                      drawid = self.idBoxTmp, pdctype = 'rect', bb = rect)
+            
+            # draw small marks signalizing resizing
+            if self.instruction[id].type in ('map', 'rectangle'):
                 controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
-                rect.append(wx.Rect(controlP.x, controlP.y, 10,10))
-                type.append('resize')
-                ids.append(self.idResizeBoxTmp)
-            for id, type, rect in zip(ids, type, rect):
-                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcTmp,
-                          drawid = id, pdctype = 'rect', bb = rect)
+                rect  = wx.RectPS(controlP, self.resizeBoxSize)
+                self.Draw(pen = self.pen['resize'], brush = self.brush['resize'], pdc = self.pdcTmp,
+                          drawid = self.idResizeBoxTmp, pdctype = 'rect', bb = rect)
+
+            elif self.instruction[id].type == 'line':
+                p1Paper = self.instruction[id]['where'][0]
+                p2Paper = self.instruction[id]['where'][1]
+                p1Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p1Paper, (0, 0)), canvasToPaper = False)[:2]
+                p2Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p2Paper, (0, 0)), canvasToPaper = False)[:2]
+                rect = []
+                box = wx.RectS(self.resizeBoxSize)
+                rect.append(box.CenterIn(wx.RectPS(p1Canvas, wx.Size())))
+                rect.append(box.CenterIn(wx.RectPS(p2Canvas, wx.Size())))
+                for i, point in enumerate((p1Canvas, p2Canvas)):
+                    self.Draw(pen = self.pen['resize'], brush = self.brush['resize'], pdc = self.pdcTmp,
+                              drawid = self.idLinePointsTmp[i], pdctype = 'rect', bb = rect[i])
         
     def UpdateMapLabel(self):
         """!Updates map frame label"""

Copied: grass/branches/develbranch_6/gui/wxpython/psmap/instructions.py (from rev 50798, grass/trunk/gui/wxpython/psmap/instructions.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/instructions.py	                        (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/instructions.py	2012-02-17 06:45:00 UTC (rev 50840)
@@ -0,0 +1,1811 @@
+"""!
+ at package psmap.instructions
+
+ at brief Map feature objects
+
+Classes:
+ - dialogs::Instruction
+ - dialogs::InstructionObject
+ - dialogs::InitMap
+ - dialogs::MapFrame
+ - dialogs::PageSetup
+ - dialogs::Mapinfo
+ - dialogs::Text
+ - dialogs::Image
+ - dialogs::NorthArrow
+ - dialogs::Point
+ - dialogs::Line
+ - dialogs::Rectangle
+ - dialogs::Scalebar
+ - dialogs::RasterLegend
+ - dialogs::VectorLegend
+ - dialogs::Raster
+ - dialogs::Vector
+ - dialogs::VProperties
+
+(C) 2011-2012 by Anna Kratochvilova, and the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
+ at author Martin Landa <landa.martin gmail.com> (mentor)
+"""
+
+import os
+import string
+from math import ceil
+from time import strftime, localtime
+
+import wx
+import grass.script as grass
+
+from core.gcmd          import RunCommand, GError, GMessage, GWarning
+from core.utils         import CmdToTuple, GetCmdString
+from dbmgr.vinfo        import VectorDBInfo
+from psmap.utils        import *
+
+class Instruction:
+    """!Class which represents instruction file"""
+    def __init__(self, parent, objectsToDraw):
+        
+        self.parent = parent
+        self.objectsToDraw = objectsToDraw
+        #here are kept objects like mapinfo, rasterlegend, etc.
+        self.instruction = list()
+        
+    def __str__(self):
+        """!Returns text for instruction file"""
+        comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
+        env = grass.gisenv()
+        comment += "# location: %s\n" % env['LOCATION_NAME']
+        comment += "# mapset: %s\n" % env['MAPSET']
+        comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
+        border = ''
+        if not self.FindInstructionByType('map'):
+            border = 'border n\n'
+        text = [str(each) for each in self.instruction]
+        return comment + border + '\n'.join(text) + '\nend'
+    
+    def __getitem__(self, id):
+        for each in self.instruction:
+            if each.id == id:
+                return each
+        return None
+
+    def __contains__(self, id):
+        """!Test if instruction is included"""
+        for each in self.instruction:
+            if each.id == id:
+                return True
+        return False
+    
+    def __delitem__(self, id):
+        """!Delete instruction"""
+        for each in self.instruction:
+            if each.id == id:
+                if each.type == 'map':
+                    #must remove raster, vector layers too
+                    vektor = self.FindInstructionByType('vector', list = True)
+                    vProperties = self.FindInstructionByType('vProperties', list = True)
+                    raster = self.FindInstructionByType('raster', list = True)
+                    for item in vektor + vProperties + raster:
+                        if item in self.instruction:
+                            self.instruction.remove(item)
+                            
+                self.instruction.remove(each)
+                if id in self.objectsToDraw:
+                    self.objectsToDraw.remove(id)
+                return
+            
+    def AddInstruction(self, instruction):
+        """!Add instruction"""
+        # add to instructions
+        if instruction.type == 'map':
+            self.instruction.insert(0, instruction)
+        else:
+            self.instruction.append(instruction)
+        # add to drawable objects
+        if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
+            if instruction.type == 'map':
+                self.objectsToDraw.insert(0, instruction.id) 
+            else:
+                self.objectsToDraw.append(instruction.id) 
+                
+            
+    def FindInstructionByType(self, type, list = False):
+        """!Find instruction(s) with the given type"""
+        inst = []
+        for each in self.instruction:
+            if each.type == type:
+                inst.append(each)
+        if len(inst) == 1 and not list:
+            return inst[0]
+        return inst
+    
+    def Read(self, filename):
+        """!Reads instruction file and creates instruction objects"""
+        self.filename = filename
+        # open file
+        try:
+            file = open(filename, 'r')
+        except IOError:
+            GError(message = _("Unable to open file\n%s") % filename)
+            return
+        # first read file to get information about region and scaletype
+        isRegionComment = False
+        orientation = 'Portrait'
+        for line in file:
+            if '# g.region' in line:
+                self.SetRegion(regionInstruction = line)
+                isRegionComment = True
+                break
+            if '# page orientation' in line:
+                orientation = line.split(':')[-1].strip()
+                
+        if not isRegionComment:
+            self.SetRegion(regionInstruction = None)
+        # then run ps.map -b to get information for maploc
+        # compute scale and center 
+        map = self.FindInstructionByType('map')
+        region = grass.region()
+        map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
+        mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
+        map['rect'] = mapRect
+        proj = projInfo()
+        toM = 1.0
+        if proj['units']:
+            toM = float(proj['meters'])
+        units = UnitConversion(self.parent)
+        w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
+        map['scale'] = w / abs((region['w'] - region['e']))
+        
+        SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
+        
+        # read file again, now with information about map bounds
+        isBuffer = False
+        buffer = []
+        instruction = None
+        vectorMapNumber = 1
+        file.seek(0)
+        for line in file:
+            if not line.strip(): 
+                continue
+            line = line.strip()
+            if isBuffer:
+                buffer.append(line)
+                if 'end' in line:
+                    isBuffer = False
+                    kwargs = {}
+                    if instruction == 'scalebar':
+                        kwargs['scale'] = map['scale']
+                    elif instruction in ('text', 'eps', 'point', 'line', 'rectangle'):
+                        kwargs['mapInstruction'] = map
+                    elif instruction in ('vpoints', 'vlines', 'vareas'):
+                        kwargs['id'] = wx.NewId()
+                        kwargs['vectorMapNumber'] = vectorMapNumber
+                        vectorMapNumber += 1
+                    elif instruction == 'paper':
+                        kwargs['Orientation'] = orientation
+                        
+                    ok = self.SendToRead(instruction, buffer, **kwargs)
+                    if not ok: return False
+                    buffer = []
+                continue 
+            
+            elif line.startswith('paper'):
+                instruction = 'paper'
+                isBuffer = True
+                buffer.append(line)
+            
+            elif line.startswith('border'):
+                if line.split()[1].lower() in ('n', 'no', 'none'):
+                    ok = self.SendToRead('border', [line])
+                    if not ok: return False
+                elif line.split()[1].lower() in ('y', 'yes'):
+                    instruction = 'border'
+                    isBuffer = True
+                    buffer.append(line)
+            
+            elif line.startswith('scale '):
+                if isBuffer:
+                    continue
+                ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
+                if not ok: return False
+            
+            elif line.startswith('maploc'):
+                ok = self.SendToRead(instruction = 'maploc', text = line)
+                if not ok: return False
+                
+            elif line.startswith('raster'):
+                ok = self.SendToRead(instruction = 'raster', text = line)
+                if not ok: return False
+            
+            elif line.startswith('mapinfo'):
+                instruction = 'mapinfo'
+                isBuffer = True
+                buffer.append(line)
+
+
+            elif line.startswith('scalebar'):
+                instruction = 'scalebar'
+                isBuffer = True
+                buffer.append(line) 
+            
+            elif line.startswith('text'):
+                instruction = 'text'
+                isBuffer = True
+                buffer.append(line)
+                
+            elif line.startswith('eps'):
+                instruction = 'eps'
+                isBuffer = True
+                buffer.append(line)
+
+            elif line.startswith('point'):
+                instruction = 'point'
+                isBuffer = True
+                buffer.append(line)
+
+            elif line.startswith('line'):
+                instruction = 'line'
+                isBuffer = True
+                buffer.append(line)
+
+            elif line.startswith('rectangle'):
+                instruction = 'rectangle'
+                isBuffer = True
+                buffer.append(line) 
+            
+            elif line.startswith('colortable'):
+                if len(line.split()) == 2 and line.split()[1].lower() in ('n', 'no', 'none'):
+                    break
+                instruction = 'colortable'
+                isBuffer = True
+                buffer.append(line) 
+        
+            elif line.startswith('vlegend'):
+                instruction = 'vlegend'
+                isBuffer = True
+                buffer.append(line) 
+                
+            elif line.startswith('vpoints'):
+                instruction = 'vpoints'
+                isBuffer = True
+                buffer.append(line) 
+                
+            elif line.startswith('vlines'):
+                instruction = 'vlines'
+                isBuffer = True
+                buffer.append(line)
+                
+            elif line.startswith('vareas'):
+                instruction = 'vareas'
+                isBuffer = True
+                buffer.append(line)
+
+
+        
+        rasterLegend = self.FindInstructionByType('rasterLegend')
+        raster = self.FindInstructionByType('raster')
+        page = self.FindInstructionByType('page')
+        vector = self.FindInstructionByType('vector')
+        vectorLegend = self.FindInstructionByType('vectorLegend')
+        vectorMaps = self.FindInstructionByType('vProperties', list = True)
+
+        # check (in case of scaletype 0) if map is drawn also
+        map['drawMap'] = False
+        if map['scaleType'] == 0:
+            mapForRegion = map['map']
+            if map['mapType'] == 'raster' and raster:
+                if mapForRegion == raster['raster']:
+                    map['drawMap'] = True
+            elif map['mapType'] == 'vector' and vector:
+                for vmap in vector['list']:
+                    if mapForRegion == vmap[0]:
+                        map['drawMap'] = True
+
+        # rasterLegend
+        if rasterLegend:
+            if rasterLegend['rasterDefault'] and raster:
+                rasterLegend['raster'] = raster['raster']
+                if not rasterLegend['discrete']:
+                    rasterType = getRasterType(map = rasterLegend['raster'])
+                    if rasterType == 'CELL':
+                        rasterLegend['discrete'] = 'y'
+                    else:
+                        rasterLegend['discrete'] = 'n'
+            
+            #estimate size
+            height = rasterLegend.EstimateHeight(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
+                                                 fontsize = rasterLegend['fontsize'],
+                                                 cols = rasterLegend['cols'], 
+                                                 height = rasterLegend['height'])
+            width = rasterLegend.EstimateWidth(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
+                                               fontsize = rasterLegend['fontsize'],
+                                               cols = rasterLegend['cols'] , 
+                                               width = rasterLegend['width'],
+                                               paperInstr = page)
+            rasterLegend['rect'] = Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
+                                          width = width, height = height)
+            
+        # vectors, vlegend        
+        
+        if vector:
+            for vmap in vectorMaps:
+                for i, each in enumerate(vector['list']):
+                    if each[2] == vmap.id:
+                        
+                        vector['list'][i][4] = vmap['label']
+                        vector['list'][i][3] = vmap['lpos']
+            if vectorLegend:
+                size = vectorLegend.EstimateSize(vectorInstr = vector, fontsize = vectorLegend['fontsize'],
+                                                 width = vectorLegend['width'], cols = vectorLegend['cols'])                            
+                vectorLegend['rect'] = Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
+                                              width = size[0], height = size[1])
+        
+        
+        page = self.FindInstructionByType('page')
+        if not page:
+            page = PageSetup(wx.NewId())
+            self.AddInstruction(page)
+        else:
+            page['Orientation'] = orientation
+
+
+        #
+        return True
+    
+    def SendToRead(self, instruction, text, **kwargs):
+        psmapInstrDict = dict(paper = ['page'],
+                              maploc = ['map'],
+                              scale = ['map'],
+                              border = ['map'],
+                              raster = ['raster'],
+                              mapinfo = ['mapinfo'],
+                              scalebar = ['scalebar'],
+                              text = ['text'],
+                              eps = ['image', 'northArrow'],
+                              point = ['point'],
+                              line = ['line'],
+                              rectangle = ['rectangle'],
+                              vpoints = ['vector', 'vProperties'],
+                              vlines = ['vector', 'vProperties'],
+                              vareas = ['vector', 'vProperties'],
+                              colortable = ['rasterLegend'],
+                              vlegend = ['vectorLegend']
+                              )
+        
+        myInstrDict = dict(page = PageSetup,
+                           map = MapFrame,
+                           raster = Raster,
+                           mapinfo = Mapinfo,
+                           scalebar = Scalebar,
+                           text = Text,
+                           image = Image,
+                           northArrow = NorthArrow,
+                           point = Point,
+                           line = Line,
+                           rectangle = Rectangle,
+                           rasterLegend = RasterLegend,
+                           vectorLegend = VectorLegend,
+                           vector = Vector,
+                           vProperties = VProperties
+                           )
+        
+        myInstruction = psmapInstrDict[instruction]
+        
+        for i in myInstruction:
+            instr = self.FindInstructionByType(i)
+            if i in ('text', 'vProperties', 'image', 'northArrow', 'point', 'line', 'rectangle') or not instr:
+                
+                id = wx.NewId() #!vProperties expect subtype
+                if i == 'vProperties':
+                    id = kwargs['id']
+                    newInstr = myInstrDict[i](id, subType = instruction[1:])
+                elif i in ('image', 'northArrow'):
+                    commentFound = False
+                    for line in text:
+                        if line.find("# north arrow") >= 0:
+                            commentFound = True
+                    if i == 'image' and commentFound or \
+                       i == 'northArrow' and not commentFound:
+                        continue
+                    newInstr = myInstrDict[i](id, settings = self)
+                else:
+                    newInstr = myInstrDict[i](id)
+                ok = newInstr.Read(instruction, text, **kwargs)
+                if ok:
+                    self.AddInstruction(newInstr)
+                else:
+                    return False
+
+            else:
+                ok = instr.Read(instruction, text, **kwargs)
+
+                if not ok:
+                    return False
+        return True
+    
+    def SetRegion(self, regionInstruction):
+        """!Sets region from file comment or sets current region in case of no comment"""
+        map = MapFrame(wx.NewId())
+        self.AddInstruction(map)
+        if regionInstruction:
+            cmd = CmdToTuple(regionInstruction.strip('# ').split())
+            
+            # define scaleType
+            if len(cmd[1]) <= 3:
+                if 'rast' in cmd[1]:
+                    map['scaleType'] = 0
+                    map['mapType'] = 'raster'   
+                    map['map'] = cmd[1]['rast']  
+                elif 'vect' in cmd[1]:
+                    map['scaleType'] = 0
+                    map['mapType'] = 'vector' 
+                    map['map'] = cmd[1]['vect']  
+                elif 'region' in cmd[1]:
+                    map['scaleType'] = 1  
+                    map['region'] = cmd[1]['region']
+                    
+            else:
+                map['scaleType'] = 2  
+        else:
+            map['scaleType'] = 2
+            grass.del_temp_region()
+            region = grass.region()
+            grass.use_temp_region()    
+            cmd = ['g.region', region]
+        cmdString = GetCmdString(cmd).replace('g.region', '')
+        GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
+        try:
+            RunCommand(cmd[0], **cmd[1])
+            
+        except grass.ScriptError, e:
+            GError(_("Region cannot be set\n%s") % e)
+            return False
+        
+
+class InstructionObject:
+    """!Abtract class representing single instruction"""
+    def __init__(self, id): 
+        self.id = id
+        
+        # default values
+        self.defaultInstruction = dict()
+        # current values
+        self.instruction = self.defaultInstruction   
+        # converting units
+        self.unitConv = UnitConversion() 
+    
+    def __str__(self):
+        """!Returns particular part of text instruction"""
+        return ''
+    
+    def __getitem__(self, key):
+        for each in self.instruction.keys():
+            if each == key:
+                return self.instruction[key]
+        return None
+    
+    def __setitem__(self, key, value):
+        self.instruction[key] = value
+    
+    def GetInstruction(self):
+        """!Get current values"""
+        return self.instruction
+    
+    def SetInstruction(self, instruction):
+        """!Set default values"""
+        self.instruction = instruction
+        
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save them"""
+        pass
+        
+    def PercentToReal(self, e, n):
+        """!Converts text coordinates from percent of region to map coordinates"""
+        e, n = float(e.strip('%')), float(n.strip('%'))
+        region = grass.region()
+        N = region['s'] + (region['n'] - region['s']) / 100 * n
+        E = region['w'] + (region['e'] - region['w']) / 100 * e
+        return E, N
+
+class InitMap(InstructionObject):
+    """!Class representing virtual map"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'initMap'
+        
+        # default values
+        self.defaultInstruction = dict(rect = None, scale =  None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    
+class MapFrame(InstructionObject):
+    """!Class representing map (instructions maploc, scale, border)"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'map'
+        # default values
+        self.defaultInstruction = dict(map = None, mapType = None, drawMap = True, region = None,
+                                       rect = Rect2D(), scaleType = 0, scale = None, center = None,
+                                       resolution = 300, border = 'y', width = 1, color = '0:0:0') 
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = ''
+        comment = ''
+        
+        #region settings
+        region = grass.region()
+        if self.instruction['scaleType'] == 0: #match map
+            map = self.instruction['map']
+            if self.instruction['mapType'] == 'raster':
+                comment = "# g.region rast=%s nsres=%s ewres=%s\n" % (map, region['nsres'], region['ewres'])
+            else:
+                comment = "# g.region vect=%s\n" % (map)
+        elif self.instruction['scaleType'] == 1:# saved region
+            region = self.instruction['region']
+            comment = "# g.region region=%s\n" % region
+        elif self.instruction['scaleType'] in (2, 3): #current region, fixed scale
+            comment = string.Template("# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region)
+        
+        instr += comment
+        instr += '\n'
+        # maploc
+        maplocInstruction = "maploc %.3f %.3f" % (self.instruction['rect'].x, self.instruction['rect'].y)
+        if self.instruction['scaleType'] != 3:
+            maplocInstruction += "  %.3f %.3f"% (self.instruction['rect'].width, self.instruction['rect'].height)
+        instr += maplocInstruction
+        instr += '\n'
+        
+        # scale
+        if self.instruction['scaleType'] == 3: #fixed scale
+            scaleInstruction = "scale 1:%.0f" % (1/self.instruction['scale'])
+            instr += scaleInstruction
+            instr += '\n'
+        # border
+        borderInstruction = ''
+        if self.instruction['border'] == 'n':
+            borderInstruction = "border n"
+        else:
+            borderInstruction = "border y\n"
+            borderInstruction += string.Template("    width $width\n    color $color\n").substitute(self.instruction)
+            borderInstruction += "    end"
+        instr += borderInstruction
+        instr += '\n'
+
+        return instr  
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        if 'isRegionComment' in kwargs:
+            isRegionComment = kwargs['isRegionComment']
+        instr = {}
+        
+        if instruction == 'border':
+            for line in text:
+                if line.startswith('end'):
+                    break
+                try:
+                    if line.split()[1].lower() in ('n', 'no', 'none'):
+                        instr['border'] = 'n'
+                        break
+                    elif line.split()[1].lower() in ('y', 'yes'):
+                        instr['border'] = 'y'
+                    elif line.startswith('width'):
+                        instr['width'] = line.split()[1]
+                    elif line.startswith('color'):
+                        instr['color'] = line.split()[1]
+                except IndexError:
+                    GError(_("Failed to read instruction %s") % instruction)
+                    return False
+                
+        elif instruction == 'scale':
+            try:
+                scaleText = text.strip('scale ').split(':')[1]
+                # when scale instruction given and region comment also, then scaletype is fixed scale
+                if not isRegionComment:
+                    instr['scaleType'] = 2 
+                else:
+                    instr['scaleType'] = 3
+
+                scale = 1/float(scaleText)
+                if abs(scale - self.instruction['scale']) > (0.01 * scale):
+                    GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % \
+                                 { 'old' : scale, 'new' : self.instruction['scale'] })
+            except (ValueError, IndexError):
+                GError(_("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction)
+                return False
+        
+        elif instruction == 'maploc':
+            maploc = text.strip('maploc ').split()
+            if len(maploc) >= 2:
+                if  abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \
+                        abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5:
+                    GWarning(_("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
+                                 { 'old1' : maploc[0], 'old2' : maploc[1],
+                                   'new1' : self.instruction['rect'].Get()[0], 'new2' : self.instruction['rect'].Get()[1] })
+                    
+                #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3])
+            if len(maploc) == 4:
+                if  abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \
+                        abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5:
+                    GWarning(_("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
+                                 { 'old1' : maploc[2], 'old2' : maploc[3],
+                                   'new1' : self.instruction['rect'].Get()[2], 'new2' : self.instruction['rect'].Get()[3] })
+                #instr['rect'] = wx.Rect2D(*map(float, maploc))
+        self.instruction.update(instr)   
+        return True 
+    
+class PageSetup(InstructionObject):
+    """!Class representing page instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'page'
+        # default values
+        self.defaultInstruction = dict(Units = 'inch', Format = 'a4', Orientation = 'Portrait',
+                                       Width = 8.268, Height = 11.693, Left = 0.5, Right = 0.5, Top = 1, Bottom = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        if self.instruction['Format'] == 'custom':
+            instr = string.Template("paper\n    width $Width\n    height $Height\n").substitute(self.instruction)
+        else:
+            instr = string.Template("paper $Format\n").substitute(self.instruction)
+        instr += string.Template("    left $Left\n    right $Right\n    bottom $Bottom\n    top $Top\n    end").substitute(self.instruction)
+
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+        self.subInstr = dict(zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats))
+        
+        if instruction == 'paper': # just for sure
+            for line in text:
+                if line.startswith('paper'): 
+                    if len(line.split()) > 1:
+                        pformat = line.split()[1]
+                        availableFormats = self._toDict(grass.read_command('ps.map', flags = 'p',
+                                                                           quiet = True))
+                        # e.g. paper a3 
+                        try:
+                            instr['Format'] = pformat
+                            for key, value in availableFormats[pformat].iteritems():
+                                instr[key] = float(value)
+                            break
+                        except KeyError:
+                            GError(_("Failed to read instruction %(file)s.\nUnknown format %(for)s") % \
+                                       { 'file' : instruction, 'for' : format })
+                            return False
+                    else:
+                        # paper
+                        # width ...
+                        instr['Format'] = 'custom'
+                # read subinstructions
+                elif instr['Format'] == 'custom' and not line.startswith('end'):
+                    text = line.split()
+                    try:
+                        instr[self.subInstr[text[0]]] = float(text[1])
+                    except  (IndexError, KeyError):
+                        GError(_("Failed to read instruction %s.") % instruction)
+                        return False
+                    
+            if 'Orientation' in kwargs and kwargs['Orientation'] == 'Landscape':
+                instr['Width'], instr['Height'] = instr['Height'], instr['Width']
+                
+            self.instruction.update(instr)
+        return True  
+    
+    def _toDict(self, paperStr):    
+        sizeDict = dict()
+#     cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+        for line in paperStr.strip().split('\n'):
+            d = dict(zip(self.cats, line.split()[1:]))
+            sizeDict[line.split()[0]] = d
+            
+        return sizeDict    
+    
+class Mapinfo(InstructionObject):
+    """!Class representing mapinfo instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'mapinfo'
+        # default values
+        self.defaultInstruction = dict(unit = 'inch', where = (0, 0),
+                                       font = 'Helvetica', fontsize = 10, color = '0:0:0', background = 'none', 
+                                       border = 'none', rect = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "mapinfo\n"
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").substitute(self.instruction)            
+        instr += string.Template("    background $background\n    border $border\n").substitute(self.instruction)  
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text):
+        """!Read instruction and save information"""
+        instr = {}
+        try:
+            for line in text:
+                sub = line.split(None,1)
+                if sub[0] == 'font':
+                    instr['font'] = sub[1]
+                elif sub[0] == 'fontsize':
+                    instr['fontsize'] = int(sub[1])
+                elif sub[0] == 'color':
+                    instr['color'] = sub[1]
+                elif sub[0] == 'background':
+                    instr['background'] = sub[1]
+                elif sub[0] == 'border':
+                    instr['border'] = sub[1]
+                elif sub[0] == 'where':
+                    instr['where'] = float(sub[1].split()[0]), float(sub[1].split()[1])
+        except (ValueError, IndexError):
+            GError(_("Failed to read instruction %s") % instruction)
+            return False
+        self.instruction.update(instr)
+        self.instruction['rect'] = self.EstimateRect(mapinfoDict = self.instruction)
+        return True
+    
+    def EstimateRect(self, mapinfoDict):
+        """!Estimate size to draw mapinfo"""
+        w = mapinfoDict['fontsize'] * 20 # any better estimation? 
+        h = mapinfoDict['fontsize'] * 7
+        width = self.unitConv.convert(value = w, fromUnit = 'point', toUnit = 'inch')
+        height = self.unitConv.convert(value = h, fromUnit = 'point', toUnit = 'inch')
+        return Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]),
+                      width = width, height = height)
+    
+class Text(InstructionObject):
+    """!Class representing text instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'text'
+        # default values
+        self.defaultInstruction = dict(text = "", font = "Helvetica", fontsize = 10, color = 'black', background = 'none',
+                                       hcolor = 'none', hwidth = 1, border = 'none', width = '1', XY = True,
+                                       where = (0,0), unit = 'inch', rotate = None, 
+                                       ref = "center center", xoffset = 0, yoffset = 0, east = None, north = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        text = self.instruction['text'].replace('\n','\\n')
+        instr = u"text %s %s" % (self.instruction['east'], self.instruction['north'])
+        instr += " %s\n" % text
+        instr += (string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").
+                                                                   substitute(self.instruction))
+        instr += string.Template("    hcolor $hcolor\n").substitute(self.instruction)
+        if self.instruction['hcolor'] != 'none':
+            instr += string.Template("    hwidth $hwidth\n").substitute(self.instruction)
+        instr += string.Template("    border $border\n").substitute(self.instruction)
+        if self.instruction['border'] != 'none':
+            instr += string.Template("    width $width\n").substitute(self.instruction)
+        instr += string.Template("    background $background\n").substitute(self.instruction)
+        if self.instruction["ref"] != '0':
+            instr += string.Template("    ref $ref\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
+            instr += (string.Template("    xoffset $xoffset\n    yoffset $yoffset\n").
+                                                            substitute(self.instruction))
+        instr += "    end"
+        try:
+            instr = instr.encode('latin1')
+        except UnicodeEncodeError, err:
+            try:
+                pos = str(err).split('position')[1].split(':')[0].strip()
+            except IndexError:
+                pos = ''
+            if pos:
+                message = _("Characters on position %s are not supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.") % pos
+            else:
+                message = _("Not all characters are supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.")
+            GMessage(message = message)
+            return ''
+        
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        map = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'text':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                        
+                    instr['text'] = line.split(None, 3)[3].decode('latin_1')
+                
+                elif sub == 'font':
+                    instr['font'] = line.split(None, 1)[1]
+                elif sub == 'fontsize':
+                    instr['fontsize'] = float(line.split(None, 1)[1])
+                elif sub == 'color':
+                    instr['color'] = line.split(None, 1)[1]
+                elif sub == 'width':
+                    instr['width'] = line.split(None, 1)[1]
+                elif sub == 'hcolor':
+                    instr['hcolor'] = line.split(None, 1)[1]
+                elif sub == 'hwidth':
+                    instr['hwidth'] = line.split(None, 1)[1]
+                elif sub == 'background':
+                    instr['background'] = line.split(None, 1)[1]
+                elif sub == 'border':
+                    instr['border'] = line.split(None, 1)[1]
+                elif sub == 'ref':
+                    instr['ref'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'xoffset':
+                    instr['xoffset'] = int(line.split(None, 1)[1])
+                elif sub == 'yoffset':
+                    instr['yoffset'] = int(line.split(None, 1)[1])
+                elif sub == 'opaque':
+                    if line.split(None, 1)[1].lower() in ('n', 'none'):
+                        instr['background'] = 'none'
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        instr['where'] = PaperMapCoordinates(mapInstr = map, x = instr['east'], y = instr['north'], paperToMap = False)       
+        self.instruction.update(instr)
+
+        return True 
+        
+class Image(InstructionObject):
+    """!Class representing eps instruction - image"""
+    def __init__(self, id, settings):
+        InstructionObject.__init__(self, id = id)
+        self.settings = settings
+        self.type = 'image'
+        # default values
+        self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
+                                       east = None, north = None,
+                                       rotate = None, scale = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'eps':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                
+                elif sub == 'epsfile':
+                    instr['epsfile'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'scale':
+                    instr['scale'] = float(line.split(None, 1)[1])
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        if not os.path.exists(instr['epsfile']):
+            GError(_("Failed to read instruction %(inst)s: "
+                     "file %(file)s not found.") % { 'inst' : instruction,
+                                                     'file' : instr['epsfile'] })
+            return False
+        
+        instr['epsfile'] = os.path.abspath(instr['epsfile'])
+        instr['size'] = self.GetImageOrigSize(instr['epsfile'])
+        if 'rotate' in instr:
+            instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
+        self.instruction.update(instr)
+        self.ChangeRefPoint(toCenter = False)
+        instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
+                                             y = self.instruction['north'], paperToMap = False)       
+        w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
+        instr['rect'] = Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
+                               width = w * self.instruction['scale'], height = h * self.instruction['scale'])
+        self.instruction.update(instr)
+
+        return True 
+        
+    def ChangeRefPoint(self, toCenter):
+        """!Change reference point (left top x center)"""
+        mapInstr = self.settings.FindInstructionByType('map')
+        if not mapInstr:
+            mapInstr = self.settings.FindInstructionByType('initMap')
+        mapId = mapInstr.id
+        if toCenter:
+            center = self.instruction['rect'].GetCentre()
+            ENCenter = PaperMapCoordinates(mapInstr = self.settings[mapId],
+                                           x = center[0], y = center[1], paperToMap = True)
+                                           
+            self.instruction['east'], self.instruction['north'] = ENCenter
+        else:
+            x, y = PaperMapCoordinates(mapInstr = self.settings[mapId], x = self.instruction['east'],
+                                       y = self.instruction['north'], paperToMap = False)
+            w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
+            h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
+            x -= w * self.instruction['scale'] / 2
+            y -= h * self.instruction['scale'] / 2
+            e, n = PaperMapCoordinates(mapInstr = self.settings[mapId], x = x, y = y, paperToMap = True)
+            self.instruction['east'], self.instruction['north'] = e, n
+
+    def GetImageOrigSize(self, imagePath):
+        """!Get image size.
+        
+        If eps, size is read from image header.
+        """
+        fileName = os.path.split(imagePath)[1]
+        # if eps, read info from header
+        if os.path.splitext(fileName)[1].lower() == '.eps':
+            bbInfo = "%%BoundingBox"
+            file = open(imagePath,"r")
+            w = h = 0
+            while file:
+                line = file.readline()
+                if line.find(bbInfo) == 0:
+                    w, h = line.split()[3:5]
+                    break
+            file.close()
+            return float(w), float(h)
+        else: # we can use wx.Image
+            img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
+            return img.GetWidth(), img.GetHeight()
+            
+class NorthArrow(Image):
+    """!Class representing eps instruction -- North Arrow"""
+    def __init__(self, id, settings):
+        Image.__init__(self, id = id, settings = settings)
+        self.type = 'northArrow'
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += "# north arrow\n"
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+        
+class Point(InstructionObject):
+    """!Class representing point instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'point'
+        # default values
+        self.defaultInstruction = dict(symbol = os.path.join('basic', 'x'),
+                                       color = '0:0:0', fcolor = '200:200:200',
+                                       rotate = 0, size = 10,
+                                       XY = True, where = (0,0), unit = 'inch',
+                                       east = None, north = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("point $east $north\n").substitute(self.instruction)
+        instr += string.Template("    symbol $symbol\n").substitute(self.instruction)
+        instr += string.Template("    color $color\n").substitute(self.instruction)
+        instr += string.Template("    fcolor $fcolor\n").substitute(self.instruction)
+        instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        instr += string.Template("    size $size\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'point':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                
+                elif sub == 'symbol':
+                    instr['symbol'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'size':
+                    instr['size'] = float(line.split(None, 1)[1])
+                elif sub == 'color':
+                    instr['color'] = line.split(None, 1)[1]
+                elif sub == 'fcolor':
+                    instr['fcolor'] = line.split(None, 1)[1]
+
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        
+        self.instruction.update(instr)
+        instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
+                                             y = self.instruction['north'], paperToMap = False)
+        w = h = self.unitConv.convert(value = instr['size'], fromUnit = 'point', toUnit = 'inch')
+        instr['rect'] = Rect2D(x = float(instr['where'][0]) - w / 2, y = float(instr['where'][1] - h / 2),
+                               width = w, height = h)
+        self.instruction.update(instr)
+
+        return True
+
+class Line(InstructionObject):
+    """!Class representing line instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'line'
+        # default values
+        self.defaultInstruction = dict(color = '0:0:0', width = 2,
+                                       where = [wx.Point2D(), wx.Point2D()],
+                                       east1 = None, north1 = None,
+                                       east2 = None, north2 = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("line $east1 $north1 $east2 $north2\n").substitute(self.instruction)
+        instr += string.Template("    color $color\n").substitute(self.instruction)
+        instr += string.Template("    width $width\n").substitute(self.instruction)
+        instr += "    end\n"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'line':
+                    e1, n1, e2, n2 = line.split(None, 5)[1:5]
+                    if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
+                        instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
+                        instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
+                    else:
+                        instr['east1'], instr['north1'] = float(e1), float(n1)
+                        instr['east2'], instr['north2'] = float(e2), float(n2)
+                
+                elif sub == 'width':
+                    instr['width'] = float(line.split(None, 1)[1])
+                elif sub == 'color':
+                    instr['color'] = line.split(None, 1)[1]
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        
+        self.instruction.update(instr)
+        e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
+                                     y = self.instruction['north1'], paperToMap = False)
+        e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
+                                     y = self.instruction['north2'], paperToMap = False)
+        instr['where'] = [wx.Point2D(e1, n1), wx.Point2D(e2, n2)]
+        instr['rect'] = Rect2DPP(instr['where'][0], instr['where'][1])
+        self.instruction.update(instr)
+
+        return True
+
+class Rectangle(InstructionObject):
+    """!Class representing rectangle instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'rectangle'
+        # default values
+        self.defaultInstruction = dict(color = '0:0:0', fcolor = 'none', width = 2,
+                                       east1 = None, north1 = None,
+                                       east2 = None, north2 = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("rectangle $east1 $north1 $east2 $north2\n").substitute(self.instruction)
+        instr += string.Template("    color $color\n").substitute(self.instruction)
+        instr += string.Template("    fcolor $fcolor\n").substitute(self.instruction)
+        instr += string.Template("    width $width\n").substitute(self.instruction)
+        instr += "    end\n"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'rectangle':
+                    e1, n1, e2, n2 = line.split(None, 5)[1:5]
+                    if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
+                        instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
+                        instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
+                    else:
+                        instr['east1'], instr['north1'] = float(e1), float(n1)
+                        instr['east2'], instr['north2'] = float(e2), float(n2)
+                
+                elif sub == 'width':
+                    instr['width'] = float(line.split(None, 1)[1])
+                elif sub == 'color':
+                    instr['color'] = line.split(None, 1)[1]
+                elif sub == 'fcolor':
+                    instr['fcolor'] = line.split(None, 1)[1]
+
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        
+        self.instruction.update(instr)
+        e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
+                                       y = self.instruction['north1'], paperToMap = False)
+        e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
+                                       y = self.instruction['north2'], paperToMap = False)
+        instr['rect'] = Rect2DPP(wx.Point2D(e1, n1), wx.Point2D(e2, n2))
+        self.instruction.update(instr)
+
+        return True
+        
+class Scalebar(InstructionObject):
+    """!Class representing scalebar instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'scalebar'
+        # default values
+        self.defaultInstruction = dict(unit = 'inch', where = (1,1),
+                                       unitsLength = 'auto', unitsHeight = 'inch',
+                                       length = None, height = 0.1, rect = None,
+                                       fontsize = 10, background = 'y',
+                                       scalebar = 'f', segment = 4, numbers = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("scalebar $scalebar\n").substitute(self.instruction)
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    length $length\n    units $unitsLength\n").substitute(self.instruction)
+        instr += string.Template("    height $height\n").substitute(self.instruction)
+        instr += string.Template("    segment $segment\n    numbers $numbers\n").substitute(self.instruction)
+        instr += string.Template("    fontsize $fontsize\n    background $background\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        scale = kwargs['scale']
+        instr = {}
+        for line in text:
+            try:
+                if line.startswith('scalebar'):
+                    if 'scalebar s' in line:
+                        instr['scalebar'] = 's'
+                    else:
+                        instr['scalebar'] = 'f'
+                elif line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('length'):
+                    instr['length'] = float(line.split()[1])
+                elif line.startswith('units'):
+                    if line.split()[1] in ['auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']:
+                        instr['unitsLength'] = line.split()[1]
+                elif line.startswith('height'):
+                    instr['height'] = float(line.split()[1])
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('numbers'):
+                    instr['numbers'] = int(line.split()[1])
+                elif line.startswith('segment'):
+                    instr['segment'] = int(line.split()[1])
+                elif line.startswith('background'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['background'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['background'] = 'n'
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        self.instruction.update(instr)
+        w, h = self.EstimateSize(scalebarDict = self.instruction, scale = scale)
+        x = self.instruction['where'][0] - w / 2 
+        y = self.instruction['where'][1] - h / 2
+        self.instruction['rect'] = Rect2D(x, y, w, h)
+        return True 
+    
+    def EstimateSize(self, scalebarDict, scale):
+        """!Estimate size to draw scalebar"""
+        units = projInfo()['units']
+        if not units or units not in self.unitConv.getAllUnits():
+            units = 'meters'
+        if scalebarDict['unitsLength'] != 'auto':
+            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = scalebarDict['unitsLength'], toUnit = 'inch')
+        else:
+            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = units, toUnit = 'inch')
+            
+        length *= scale
+        length *= 1.1 #for numbers on the edge
+        height = scalebarDict['height'] + 2 * self.unitConv.convert(value = scalebarDict['fontsize'], fromUnit = 'point', toUnit = 'inch')     
+        return (length, height)
+    
+class RasterLegend(InstructionObject):
+    """!Class representing colortable instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'rasterLegend'
+        # default values
+        self.defaultInstruction = dict(rLegend = False, unit = 'inch', rasterDefault = True, raster = None,
+                                       discrete = None, type = None,
+                                       where = (0, 0),
+                                       width = None, height = None, cols = 1, font = "Helvetica", fontsize = 10,
+                                       #color = '0:0:0', tickbar = False, range = False, min = 0, max = 0,
+                                       color = 'black', tickbar = 'n', range = False, min = 0, max = 0,
+                                       nodata = 'n')
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "colortable y\n"
+        instr += string.Template("    raster $raster\n").substitute(self.instruction)
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        if self.instruction['width']:
+            instr += string.Template("    width $width\n").substitute(self.instruction)
+        instr += string.Template("    discrete $discrete\n").substitute(self.instruction)
+        if self.instruction['discrete'] == 'n':
+            if self.instruction['height']:
+                instr += string.Template("    height $height\n").substitute(self.instruction)
+            instr += string.Template("    tickbar $tickbar\n").substitute(self.instruction)
+            if self.instruction['range']:
+                instr += string.Template("    range $min $max\n").substitute(self.instruction)
+        else:
+            instr += string.Template("    cols $cols\n").substitute(self.instruction)
+            instr += string.Template("    nodata $nodata\n").substitute(self.instruction)
+        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n")\
+            .substitute(self.instruction)
+        instr += "    end"
+        return instr    
+    
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['rLegend'] = True
+        for line in text:
+            try:
+                if line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('font '):
+                    instr['font'] = line.split()[1]
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('color '):
+                    instr['color'] = line.split()[1]
+                elif line.startswith('raster'):
+                    instr['raster'] = line.split()[1]
+                elif line.startswith('width'):
+                    instr['width'] = float(line.split()[1])
+                elif line.startswith('height'):
+                    instr['height'] = float(line.split()[1])
+                elif line.startswith('cols'):
+                    instr['cols'] = int(line.split()[1])                    
+                elif line.startswith('range'):
+                    instr['range'] = True
+                    instr['min'] = float(line.split()[1])
+                    instr['max'] = float(line.split()[2])
+                elif line.startswith('nodata'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['nodata'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['nodata'] = 'n'
+                elif line.startswith('tickbar'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['tickbar'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['tickbar'] = 'n'
+                elif line.startswith('discrete'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['discrete'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['discrete'] = 'n'            
+
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        if 'raster' in instr:
+            instr['rasterDefault'] = False
+            if 'discrete' not in instr:
+                rasterType = getRasterType(map = instr['raster'])
+                instr['type'] = rasterType
+                if rasterType == 'CELL':
+                    instr['discrete'] = 'y'
+                else:
+                    instr['discrete'] = 'n'
+            
+        else:
+            instr['rasterDefault'] = True
+        self.instruction.update(instr)
+        # add 'rect' in the end
+            
+        return True 
+    
+    def EstimateHeight(self, raster, discrete, fontsize, cols = None,  height = None):
+        """!Estimate height to draw raster legend"""
+        if discrete == 'n':
+            if height:
+                height = height
+            else:
+                height = self.unitConv.convert(value = fontsize * 10,
+                                                    fromUnit = 'point', toUnit = 'inch')
+                                                    
+        if discrete == 'y':
+            if cols:
+                cols = cols 
+            else:
+                cols = 1 
+
+            rinfo = grass.raster_info(raster)
+            if rinfo['datatype'] in ('DCELL', 'FCELL'):
+                minim, maxim = rinfo['min'], rinfo['max']
+                rows = ceil(maxim / cols )
+            else:
+                cat = grass.read_command('r.category', map = raster,
+                                    fs = ':').strip().split('\n')
+                rows = ceil(float(len(cat)) / cols )
+                            
+                
+            height = self.unitConv.convert(value =  1.5 * rows * fontsize, fromUnit = 'point', toUnit = 'inch')
+            
+        return height
+        
+    def EstimateWidth(self, raster, discrete, fontsize, cols = None, width = None, paperInstr = None):
+        """!Estimate size to draw raster legend"""
+        
+        if discrete == 'n':
+            rinfo = grass.raster_info(raster)
+            minim, maxim = rinfo['min'], rinfo['max']
+            if width:
+                width = width
+            else:
+                width = self.unitConv.convert(value = fontsize * 2,
+                                                    fromUnit = 'point', toUnit = 'inch')
+            text = len(max(str(minim), str(maxim), key = len))
+            textPart = self.unitConv.convert(value = text * fontsize / 2,
+                                                    fromUnit = 'point', toUnit = 'inch')
+            width += textPart
+                                                    
+        elif discrete == 'y':
+            if cols:
+                cols = cols 
+            else:
+                cols = 1    
+
+            if width:
+                width = width
+            else:
+                paperWidth = paperInstr['Width'] - paperInstr['Right'] - paperInstr['Left']
+                width = (paperWidth / cols) * (cols - 1) + 1
+                
+        return width    
+             
+class VectorLegend(InstructionObject):
+    """!Class representing colortable instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vectorLegend'
+        # default values
+        self.defaultInstruction = dict(vLegend = False, unit = 'inch', where = (0, 0),
+                                                defaultSize = True, width = 0.4, cols = 1, span = None,
+                                                font = "Helvetica", fontsize = 10,
+                                                border = 'none')
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "vlegend\n"
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    font $font\n    fontsize $fontsize\n").substitute(self.instruction)
+        instr += string.Template("    width $width\n    cols $cols\n").substitute(self.instruction)
+        if self.instruction['span']:
+            instr += string.Template("    span $span\n").substitute(self.instruction)
+        instr += string.Template("    border $border\n").substitute(self.instruction)  
+        instr += "    end"  
+        return instr
+
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['vLegend'] = True
+        for line in text:
+            try:
+                if line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('font '):
+                    instr['font'] = line.split()[1]
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('width'):
+                    instr['width'] = float(line.split()[1])
+                elif line.startswith('cols'):
+                    instr['cols'] = int(line.split()[1]) 
+                elif line.startswith('span'):
+                    instr['span'] = float(line.split()[1])
+                elif line.startswith('border'):
+                    instr['border'] = line.split()[1]
+                    
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        self.instruction.update(instr)
+            
+        return True 
+    
+    def EstimateSize(self, vectorInstr, fontsize, width = None, cols = None):
+        """!Estimate size to draw vector legend"""
+        if width:
+            width = width 
+        else:
+            width = fontsize/24.0
+
+        if cols:
+            cols = cols 
+        else:
+            cols = 1
+
+        vectors = vectorInstr['list']
+        labels = [vector[4] for vector in vectors if vector[3] != 0]
+        extent = (len(max(labels, key = len)) * fontsize / 2, fontsize)
+        wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'point', toUnit = 'inch')
+        hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'point', toUnit = 'inch')
+        w = (width + wExtent) * cols
+        h = len(labels) * hExtent / cols
+        h *= 1.1
+        return (w, h)
+            
+   
+class Raster(InstructionObject):
+    """!Class representing raster instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'raster'
+        # default values
+        self.defaultInstruction = dict(isRaster = False, raster = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("raster $raster").substitute(self.instruction)
+        return instr
+    
+    def Read(self, instruction, text):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['isRaster'] = True
+        try:
+            map = text.split()[1]
+        except IndexError:
+            GError(_("Failed to read instruction %s") % instruction)
+            return False
+        try:
+            info = grass.find_file(map, element = 'cell')
+        except grass.ScriptError, e:
+            GError(message = e.value)
+            return False
+        instr['raster'] = info['fullname']
+
+        
+        self.instruction.update(instr)
+        return True
+    
+class Vector(InstructionObject):
+    """!Class keeps vector layers"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vector'
+        # default values
+        self.defaultInstruction = dict(list = None)# [vmap, type, id, lpos, label] 
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+    def __str__(self):
+        return ''
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        
+        for line in text:
+            if line.startswith('vpoints') or line.startswith('vlines') or line.startswith('vareas'):
+                # subtype
+                if line.startswith('vpoints'):
+                    subType = 'points'
+                elif line.startswith('vlines'):
+                    subType = 'lines'
+                elif line.startswith('vareas'):
+                    subType = 'areas'
+                # name of vector map
+                vmap = line.split()[1]
+                try:
+                    info = grass.find_file(vmap, element = 'vector')
+                except grass.ScriptError, e:
+                    GError(message = e.value)
+                    return False
+                vmap = info['fullname']
+                # id
+                id = kwargs['id']
+                # lpos
+                lpos = kwargs['vectorMapNumber']
+                #label
+                label = '('.join(vmap.split('@')) + ')'
+                break
+        instr = [vmap, subType, id, lpos, label] 
+        if not self.instruction['list']:
+            self.instruction['list'] = []
+        self.instruction['list'].append(instr)
+        
+        return True    
+    
+class VProperties(InstructionObject):
+    """!Class represents instructions vareas, vlines, vpoints"""
+    def __init__(self, id, subType):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vProperties'
+        self.subType = subType
+        # default values
+        if self.subType == 'points':
+            dd = dict(subType  = 'points', name = None, type = 'point or centroid', connection = False, layer = '1',
+                        masked = 'n', color = '0:0:0', width = 1,
+                        fcolor = '255:0:0', rgbcolumn = None, symbol = os.path.join('basic', 'x'), eps = None,
+                        size = 5, sizecolumn = None, scale = None,
+                        rotation = False, rotate = 0, rotatecolumn = None, label = None, lpos = None)
+        elif self.subType == 'lines':
+            dd = dict(subType = 'lines', name = None, type = 'line or boundary', connection = False, layer = '1',
+                        masked = 'n', color = '0:0:0', hwidth = 1,
+                        hcolor = 'none', rgbcolumn = None,
+                        width = 1, cwidth = None,
+                        style = 'solid', linecap = 'butt', label = None, lpos = None)
+        else: # areas
+            dd = dict(subType = 'areas', name = None, connection = False, layer = '1',    
+                        masked = 'n', color = '0:0:0', width = 1,
+                        fcolor = 'none', rgbcolumn = None,
+                        pat = None, pwidth = 1, scale = 1, label = None, lpos = None)
+        self.defaultInstruction = dd
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        dic = self.instruction
+        vInstruction = string.Template("v$subType $name\n").substitute(dic)
+        #data selection
+        if self.subType in ('points', 'lines'):
+           vInstruction += string.Template("    type $type\n").substitute(dic) 
+        if dic['connection']:
+            vInstruction += string.Template("    layer $layer\n").substitute(dic)
+            if dic.has_key('cats'):
+                vInstruction += string.Template("    cats $cats\n").substitute(dic)
+            elif dic.has_key('where'):
+                    vInstruction += string.Template("    where $where\n").substitute(dic)
+        vInstruction += string.Template("    masked $masked\n").substitute(dic)
+        #colors
+        vInstruction += string.Template("    color $color\n").substitute(dic)
+        if self.subType in ('points', 'areas'):
+            if dic['color'] != 'none':
+                vInstruction += string.Template("    width $width\n").substitute(dic)
+            if dic['rgbcolumn']:
+                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
+            vInstruction += string.Template("    fcolor $fcolor\n").substitute(dic)
+        else:
+            if dic['rgbcolumn']:
+                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
+            elif dic['hcolor'] != 'none':
+                vInstruction += string.Template("    hwidth $hwidth\n").substitute(dic)
+                vInstruction += string.Template("    hcolor $hcolor\n").substitute(dic)
+        
+        # size and style
+        if self.subType == 'points':
+            if not dic['eps']:
+                vInstruction += string.Template("    symbol $symbol\n").substitute(dic)
+            else: #eps
+                vInstruction += string.Template("    eps $eps\n").substitute(dic)
+            if dic['size']:
+                vInstruction += string.Template("    size $size\n").substitute(dic)            
+            else: # sizecolumn
+                vInstruction += string.Template("    sizecolumn $sizecolumn\n").substitute(dic)
+                vInstruction += string.Template("    scale $scale\n").substitute(dic)
+            if dic['rotation']:
+                if dic['rotate'] is not None:
+                    vInstruction += string.Template("    rotate $rotate\n").substitute(dic)
+                else:
+                    vInstruction += string.Template("    rotatecolumn $rotatecolumn\n").substitute(dic)
+                    
+        if self.subType == 'areas':
+            if dic['pat'] is not None:
+                vInstruction += string.Template("    pat $pat\n").substitute(dic)
+                vInstruction += string.Template("    pwidth $pwidth\n").substitute(dic)
+                vInstruction += string.Template("    scale $scale\n").substitute(dic)
+                
+        if self.subType == 'lines':
+            if dic['width'] is not None:
+                vInstruction += string.Template("    width $width\n").substitute(dic)
+            else:
+                vInstruction += string.Template("    cwidth $cwidth\n").substitute(dic)
+            vInstruction += string.Template("    style $style\n").substitute(dic)
+            vInstruction += string.Template("    linecap $linecap\n").substitute(dic)
+        #position and label in vlegend
+        vInstruction += string.Template("    label $label\n    lpos $lpos\n").substitute(dic)
+        
+        vInstruction += "    end"
+        try:
+            vInstruction = vInstruction.encode('Latin_1')
+        except UnicodeEncodeError, err:
+            try:
+                pos = str(err).split('position')[1].split(':')[0].strip()
+            except IndexError:
+                pos = ''
+            if pos:
+                message = _("Characters on position %s are not supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.") % pos
+            else:
+                message = _("Not all characters are supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.")
+            GMessage(message = message)
+            return ''
+        return vInstruction
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        try:
+            info = grass.find_file(name = text[0].split()[1], element = 'vector')
+        except grass.ScriptError, e:
+            GError(message = e.value)
+            return False
+        instr['name'] = info['fullname']
+        #connection
+        instr['connection'] = True
+        self.mapDBInfo = VectorDBInfo(instr['name'])
+        self.layers = self.mapDBInfo.layers.keys()
+        if not self.layers:
+            instr['connection'] = False
+            
+        # points
+        if text[0].startswith('vpoints'):
+            for line in text[1:]:
+                if line.startswith('type'):
+                    tp = []
+                    if line.find('point') != -1:
+                        tp.append('point')
+                    if line.find('centroid') != -1:
+                        tp.append('centroid')
+                    instr['type'] = ' or '.join(tp)
+                elif line.startswith('fcolor'):
+                    instr['fcolor'] = line.split()[1]
+                elif line.startswith('rgbcolumn'):
+                    instr['rgbcolumn'] = line.split()[1]
+                elif line.startswith('symbol'):
+                    instr['symbol'] = line.split()[1]
+                elif line.startswith('eps'):
+                    instr['eps'] = line.split()[1]
+                elif line.startswith('size '):
+                    instr['size'] = line.split()[1]
+                elif line.startswith('sizecolumn'):
+                    instr['size'] = None
+                    instr['sizecolumn'] = line.split()[1]
+                elif line.startswith('scale '):
+                    instr['scale'] = float(line.split()[1])
+                elif line.startswith('rotate '):
+                    instr['rotation'] = True
+                    instr['rotate'] = line.split()[1]
+                elif line.startswith('rotatecolumn'):
+                    instr['rotatecolumn'] = line.split()[1]
+                    instr['rotation'] = True
+                    instr['rotate'] = None
+                    
+        # lines            
+        elif text[0].startswith('vlines'):
+            for line in text[1:]:
+                if line.startswith('type'):
+                    tp = []
+                    if line.find('line') != -1:
+                        tp.append('line')
+                    if line.find('boundary') != -1:
+                        tp.append('boundary')
+                    instr['type'] = ' or '.join(tp)
+                elif line.startswith('hwidth'):
+                    instr['hwidth'] = float(line.split()[1])
+                elif line.startswith('hcolor'):
+                    instr['hcolor'] = line.split()[1]
+                elif line.startswith('rgbcolumn'):
+                    instr['rgbcolumn'] = line.split()[1]                    
+                elif line.startswith('cwidth'):
+                    instr['cwidth'] = float(line.split()[1])
+                    instr['width'] = None
+                elif line.startswith('style'):
+                    instr['style'] = line.split()[1]       
+                elif line.startswith('linecap'):
+                    instr['linecap'] = line.split()[1]
+         
+        elif text[0].startswith('vareas'):
+            for line in text[1:]:
+                if line.startswith('fcolor'):
+                    instr['fcolor'] = line.split()[1]    
+                elif line.startswith('pat'):
+                    instr['pat'] = line.split()[1]
+                elif line.startswith('pwidth'):
+                    instr['pwidth'] = float(line.split()[1])
+                elif line.startswith('scale'):
+                    instr['scale'] = float(line.split()[1])
+            
+            
+        # same properties for all    
+        for line in text[1:]:
+            if line.startswith('lpos'):
+                instr['lpos'] = int(line.split()[1])
+            elif line.startswith('label'):
+                instr['label'] = line.split(None, 1)[1].decode('latin_1')
+            elif line.startswith('layer'):
+                instr['layer'] = line.split()[1]
+            elif line.startswith('masked'):
+                if line.split()[1].lower() in ('y', 'yes'):
+                    instr['masked'] = 'y'
+                else:
+                    instr['masked'] = 'n'
+            elif line.startswith('color'):
+                instr['color'] = line.split()[1]
+            elif line.startswith('rgbcolumn'):
+                instr['rgbcolumn'] = line.split()[1] 
+            elif line.startswith('width'):
+                instr['width'] = float(line.split()[1])
+                
+        if 'label' not in instr:
+            instr['label'] = '('.join(instr['name'].split('@')) + ')'
+        if 'lpos' not in instr:
+            instr['lpos'] = kwargs['vectorMapNumber']
+        self.instruction.update(instr)
+        
+        return True

Modified: grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py	2012-02-17 00:41:01 UTC (rev 50839)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py	2012-02-17 06:45:00 UTC (rev 50840)
@@ -83,6 +83,14 @@
                                     label = _('Image')),
             'addNorthArrow': MetaIcon(img = 'north-arrow-add',
                                       label = _('North Arrow')),
+            'drawGraphics': MetaIcon(img = 'edit',
+                                     label = _('Add simple graphics')),
+            'pointAdd'    : MetaIcon(img = '',
+                                     label = _('Point')),
+            'lineAdd'     : MetaIcon(img = '',
+                                     label = _('Line')),
+            'rectangleAdd': MetaIcon(img = '',
+                                     label = _('Rectangle')),
             }
         self.icons = icons
         
@@ -113,6 +121,8 @@
                                       self.parent.OnAddVect),
                                      ("dec", BaseIcons["overlay"],
                                       self.OnDecoration),
+                                     ("drawGraphics", icons["drawGraphics"],
+                                      self.OnDrawGraphics, wx.ITEM_CHECK),
                                      ("delete", icons["deleteObj"],
                                       self.parent.OnDelete),
                                      (None, ),
@@ -138,3 +148,15 @@
                       (self.icons["addText"],       self.parent.OnAddText),
                       (self.icons["addImage"],      self.parent.OnAddImage),
                       (self.icons["addNorthArrow"], self.parent.OnAddNorthArrow)))
+
+    def OnDrawGraphics(self, event):
+        """!Simple geometry features (point, line, rectangle) overlay menu
+        """
+        # we need the previous id
+        self.actionOld = self.action['id']
+        self.OnTool(event)
+        self.action['id'] = self.actionOld
+        self._onMenu(((self.icons["pointAdd"],      self.parent.OnAddPoint),
+                      (self.icons["lineAdd"],       self.parent.OnAddLine),
+                      (self.icons["rectangleAdd"],  self.parent.OnAddRectangle),
+                    ))

Copied: grass/branches/develbranch_6/gui/wxpython/psmap/utils.py (from rev 50797, grass/trunk/gui/wxpython/psmap/utils.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/utils.py	                        (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/utils.py	2012-02-17 06:45:00 UTC (rev 50840)
@@ -0,0 +1,422 @@
+"""!
+ at package psmap.utils
+
+ at brief utilities for wxpsmap (classes, functions)
+
+Classes:
+ - utils::Rect2D
+ - utils::Rect2DPP
+ - utils::Rect2DPS
+ - utils::UnitConversion
+
+(C) 2012 by Anna Kratochvilova, and the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import wx
+from math import ceil, floor, sin, cos, pi
+
+try:
+    import Image as PILImage
+    havePILImage = True
+except ImportError:
+    havePILImage = False
+
+import grass.script as grass
+from core.gcmd          import RunCommand
+
+class Rect2D(wx.Rect2D):
+    """!Class representing rectangle with floating point values.
+
+    Overrides wx.Rect2D to unify Rect access methods, which are
+    different (e.g. wx.Rect.GetTopLeft() x wx.Rect2D.GetLeftTop()).
+    More methods can be added depending on needs.
+    """
+    def __init__(self, x = 0, y = 0, width = 0, height = 0):
+        wx.Rect2D.__init__(self, x = x, y = y, w = width, h = height)
+
+    def GetX(self):
+        return self.x
+        
+    def GetY(self):
+        return self.y
+
+    def GetWidth(self):
+        return self.width
+
+    def SetWidth(self, width):
+        self.width = width
+        
+    def GetHeight(self):
+        return self.height
+
+    def SetHeight(self, height):
+        self.height = height
+
+class Rect2DPP(Rect2D):
+    """!Rectangle specified by 2 points (with floating point values).
+
+    @see Rect2D, Rect2DPS
+    """
+    def __init__(self, topLeft = wx.Point2D(), bottomRight = wx.Point2D()):
+        Rect2D.__init__(self, x = 0, y = 0, width = 0, height = 0)
+
+        x1, y1 = topLeft[0], topLeft[1]
+        x2, y2 = bottomRight[0], bottomRight[1]
+
+        self.SetLeft(min(x1, x2))
+        self.SetTop(min(y1, y2))
+        self.SetRight(max(x1, x2))
+        self.SetBottom(max(y1, y2))
+
+class Rect2DPS(Rect2D):
+    """!Rectangle specified by point and size (with floating point values).
+
+    @see Rect2D, Rect2DPP
+    """
+    def __init__(self, pos = wx.Point2D(), size = (0, 0)):
+        Rect2D.__init__(self, x = pos[0], y = pos[1], width = size[0], height = size[1])
+
+class UnitConversion:
+    """! Class for converting units"""
+    def __init__(self, parent = None):
+        self.parent = parent
+        if self.parent:
+            ppi = wx.ClientDC(self.parent).GetPPI()
+        else: 
+            ppi = (72, 72)
+        self._unitsPage = { 'inch'          : {'val': 1.0, 'tr' : _("inch")},
+                            'point'         : {'val': 72.0, 'tr' : _("point")},
+                            'centimeter'    : {'val': 2.54, 'tr' : _("centimeter")},
+                            'millimeter'    : {'val': 25.4, 'tr' : _("millimeter")}}
+        self._unitsMap = {  'meters'        : {'val': 0.0254, 'tr' : _("meters")},
+                            'kilometers'    : {'val': 2.54e-5, 'tr' : _("kilometers")},
+                            'feet'          : {'val': 1./12, 'tr' : _("feet")},
+                            'miles'         : {'val': 1./63360, 'tr' : _("miles")},
+                            'nautical miles': {'val': 1/72913.386, 'tr' : _("nautical miles")}}
+
+        self._units = { 'pixel'     : {'val': ppi[0], 'tr' : _("pixel")},
+                        'meter'     : {'val': 0.0254, 'tr' : _("meter")},
+                        'nautmiles' : {'val': 1/72913.386, 'tr' :_("nautical miles")},
+                        'degrees'   : {'val': 0.0254 , 'tr' : _("degree")} #like 1 meter, incorrect
+                        }
+        self._units.update(self._unitsPage)
+        self._units.update(self._unitsMap)
+
+    def getPageUnitsNames(self):
+        return sorted(self._unitsPage[unit]['tr'] for unit in self._unitsPage.keys())
+    
+    def getMapUnitsNames(self):
+        return sorted(self._unitsMap[unit]['tr'] for unit in self._unitsMap.keys())
+    
+    def getAllUnits(self):
+        return sorted(self._units.keys())
+    
+    def findUnit(self, name):
+        """!Returns unit by its tr. string"""
+        for unit in self._units.keys():
+            if self._units[unit]['tr'] == name:
+                return unit
+        return None
+    
+    def findName(self, unit):
+        """!Returns tr. string of a unit"""
+        try:
+            return self._units[unit]['tr']
+        except KeyError:
+            return None
+    
+    def convert(self, value, fromUnit = None, toUnit = None):
+        return float(value)/self._units[fromUnit]['val']*self._units[toUnit]['val']
+
+def convertRGB(rgb):
+    """!Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color,
+            or named color/r:g:b string to wx.Colour, depending on input""" 
+    # transform a wx.Colour tuple into an r:g:b string    
+    if type(rgb) == wx.Colour:
+        for name, color in grass.named_colors.items(): 
+            if  rgb.Red() == int(color[0] * 255) and\
+                rgb.Green() == int(color[1] * 255) and\
+                rgb.Blue() == int(color[2] * 255):
+                return name
+        return str(rgb.Red()) + ':' + str(rgb.Green()) + ':' + str(rgb.Blue())
+    # transform a GRASS named color or an r:g:b string into a wx.Colour tuple
+    else:
+        color = (grass.parse_color(rgb)[0]*255,
+                 grass.parse_color(rgb)[1]*255,
+                 grass.parse_color(rgb)[2]*255)
+        color = wx.Color(*color)
+        if color.IsOk():
+            return color
+        else:  
+            return None
+        
+        
+def PaperMapCoordinates(mapInstr, x, y, paperToMap = True):
+    """!Converts paper (inch) coordinates <-> map coordinates.
+
+    @param mapInstr map frame instruction
+    @param x,y paper coords in inches or mapcoords in map units
+    @param paperToMap specify conversion direction
+    """
+    region = grass.region()
+    mapWidthPaper = mapInstr['rect'].GetWidth()
+    mapHeightPaper = mapInstr['rect'].GetHeight()
+    mapWidthEN = region['e'] - region['w']
+    mapHeightEN = region['n'] - region['s']
+
+    if paperToMap:
+        diffX = x - mapInstr['rect'].GetX()
+        diffY = y - mapInstr['rect'].GetY()
+        diffEW = diffX * mapWidthEN / mapWidthPaper
+        diffNS = diffY * mapHeightEN / mapHeightPaper
+        e = region['w'] + diffEW
+        n = region['n'] - diffNS
+
+        if projInfo()['proj'] == 'll':
+            return e, n
+        else:
+            return int(e), int(n)
+
+    else:
+        diffEW = x - region['w']
+        diffNS = region['n'] - y
+        diffX = mapWidthPaper * diffEW / mapWidthEN
+        diffY = mapHeightPaper * diffNS / mapHeightEN
+        xPaper = mapInstr['rect'].GetX() + diffX
+        yPaper = mapInstr['rect'].GetY() + diffY
+
+        return xPaper, yPaper
+
+
+def AutoAdjust(self, scaleType,  rect, map = None, mapType = None, region = None):
+    """!Computes map scale, center and map frame rectangle to fit region (scale is not fixed)"""
+    currRegionDict = {}
+    if scaleType == 0 and map:# automatic, region from raster or vector
+        res = ''
+        if mapType == 'raster': 
+            try:
+                res = grass.read_command("g.region", flags = 'gu', rast = map)
+            except grass.ScriptError:
+                pass
+        elif mapType == 'vector':
+            res = grass.read_command("g.region", flags = 'gu', vect = map)
+        currRegionDict = grass.parse_key_val(res, val_type = float)
+    elif scaleType == 1 and region: # saved region
+        res = grass.read_command("g.region", flags = 'gu', region = region)
+        currRegionDict = grass.parse_key_val(res, val_type = float)
+    elif scaleType == 2: # current region
+        env = grass.gisenv()
+        windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
+        try:
+            windFile = open(windFilePath, 'r').read()
+        except IOError:
+            currRegionDict = grass.region()
+        regionDict = grass.parse_key_val(windFile, sep = ':', val_type = float)
+        region = grass.read_command("g.region", flags = 'gu', n = regionDict['north'], s = regionDict['south'],
+                                    e = regionDict['east'], w = regionDict['west'])
+        currRegionDict = grass.parse_key_val(region, val_type = float)
+                                                                
+    else:
+        return None, None, None
+    
+    if not currRegionDict:
+        return None, None, None
+    rX = rect.x
+    rY = rect.y
+    rW = rect.width
+    rH = rect.height
+    if not hasattr(self, 'unitConv'):
+        self.unitConv = UnitConversion(self)
+    toM = 1
+    if projInfo()['proj'] != 'xy':
+        toM = float(projInfo()['meters'])
+
+    mW = self.unitConv.convert(value = (currRegionDict['e'] - currRegionDict['w']) * toM, fromUnit = 'meter', toUnit = 'inch')
+    mH = self.unitConv.convert(value = (currRegionDict['n'] - currRegionDict['s']) * toM, fromUnit = 'meter', toUnit = 'inch')
+    scale = min(rW/mW, rH/mH)
+    
+    if rW/rH > mW/mH:
+        x = rX - (rH*(mW/mH) - rW)/2
+        y = rY
+        rWNew = rH*(mW/mH)
+        rHNew = rH
+    else:
+        x = rX
+        y = rY - (rW*(mH/mW) - rH)/2
+        rHNew = rW*(mH/mW)
+        rWNew = rW
+
+    # center
+    cE = (currRegionDict['w'] + currRegionDict['e'])/2
+    cN = (currRegionDict['n'] + currRegionDict['s'])/2
+    return scale, (cE, cN), Rect2D(x, y, rWNew, rHNew) #inch
+
+def SetResolution(dpi, width, height):
+    """!If resolution is too high, lower it
+    
+    @param dpi max DPI
+    @param width map frame width
+    @param height map frame height
+    """
+    region = grass.region()
+    if region['cols'] > width * dpi or region['rows'] > height * dpi:
+        rows = height * dpi
+        cols = width * dpi
+        RunCommand('g.region', rows = rows, cols = cols)
+               
+def ComputeSetRegion(self, mapDict):
+    """!Computes and sets region from current scale, map center coordinates and map rectangle"""
+
+    if mapDict['scaleType'] == 3: # fixed scale
+        scale = mapDict['scale']
+            
+        if not hasattr(self, 'unitConv'):
+            self.unitConv = UnitConversion(self)
+        
+        fromM = 1
+        if projInfo()['proj'] != 'xy':
+            fromM = float(projInfo()['meters'])
+        rectHalfInch = (mapDict['rect'].width/2, mapDict['rect'].height/2)
+        rectHalfMeter = (self.unitConv.convert(value = rectHalfInch[0], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale,
+                         self.unitConv.convert(value = rectHalfInch[1], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale) 
+        
+        centerE = mapDict['center'][0]
+        centerN = mapDict['center'][1]
+        
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            rasterId = raster.id 
+        else:
+            rasterId = None
+
+        if rasterId:
+            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
+                       s = floor(centerN - rectHalfMeter[1]),
+                       e = ceil(centerE + rectHalfMeter[0]),
+                       w = floor(centerE - rectHalfMeter[0]),
+                       rast = self.instruction[rasterId]['raster'])
+        else:
+            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
+                       s = floor(centerN - rectHalfMeter[1]),
+                       e = ceil(centerE + rectHalfMeter[0]),
+                       w = floor(centerE - rectHalfMeter[0]))
+                    
+def projInfo():
+    """!Return region projection and map units information,
+    taken from render.py"""
+    
+    projinfo = dict()
+    
+    ret = RunCommand('g.proj', read = True, flags = 'p')
+    
+    if not ret:
+        return projinfo
+    
+    for line in ret.splitlines():
+        if ':' in line:
+            key, val = line.split(':')
+            projinfo[key.strip()] = val.strip()
+        elif "XY location (unprojected)" in line:
+            projinfo['proj'] = 'xy'
+            projinfo['units'] = ''
+            break
+    
+    return projinfo
+
+def GetMapBounds(filename, portrait = True):
+    """!Run ps.map -b to get information about map bounding box
+    
+        @param filename psmap input file
+        @param portrait page orientation"""
+    orient = ''
+    if not portrait:
+        orient = 'r'
+    try:
+        bb = map(float, grass.read_command('ps.map',
+                                           flags = 'b' + orient,
+                                           quiet = True,
+                                           input = filename).strip().split('=')[1].split(','))
+    except (grass.ScriptError, IndexError):
+        GError(message = _("Unable to run `ps.map -b`"))
+        return None
+    return Rect2D(bb[0], bb[3], bb[2] - bb[0], bb[1] - bb[3])
+
+def getRasterType(map):
+    """!Returns type of raster map (CELL, FCELL, DCELL)"""
+    if map is None:
+        map = ''
+    file = grass.find_file(name = map, element = 'cell')
+    if file['file']:
+        rasterType = grass.raster_info(map)['datatype']
+        return rasterType
+    else:
+        return None
+   
+def PilImageToWxImage(pilImage, copyAlpha = True):
+    """!Convert PIL image to wx.Image
+    
+    Based on http://wiki.wxpython.org/WorkingWithImages
+    """
+    hasAlpha = pilImage.mode[-1] == 'A'
+    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.
+        wxImage = wx.EmptyImage( *pilImage.size )
+        pilImageCopyRGBA = pilImage.copy()
+        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+        wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4])  # Create layer and insert alpha values.
+
+    else :    # The resulting image will not have alpha.
+        wxImage = wx.EmptyImage(*pilImage.size)
+        pilImageCopy = pilImage.copy()
+        pilImageCopyRGB = pilImageCopy.convert('RGB')    # Discard any alpha from the PIL image.
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+
+    return wxImage
+
+def BBoxAfterRotation(w, h, angle):
+    """!Compute bounding box or rotated rectangle
+    
+    @param w rectangle width
+    @param h rectangle height
+    @param angle angle (0, 360) in degrees
+    """
+    angleRad = angle / 180. * pi
+    ct = cos(angleRad)
+    st = sin(angleRad)
+    
+    hct = h * ct
+    wct = w * ct
+    hst = h * st
+    wst = w * st
+    y = x = 0
+    
+    if 0 < angle <= 90:
+        y_min = y
+        y_max = y + hct + wst
+        x_min = x - hst
+        x_max = x + wct
+    elif 90 < angle <= 180:
+        y_min = y + hct
+        y_max = y + wst
+        x_min = x - hst + wct
+        x_max = x
+    elif 180 < angle <= 270:
+        y_min = y + wst + hct
+        y_max = y
+        x_min = x + wct
+        x_max = x - hst
+    elif 270 < angle <= 360:
+        y_min = y + wst
+        y_max = y + hct
+        x_min = x
+        x_max = x + wct - hst
+        
+    width = int(ceil(abs(x_max) + abs(x_min)))
+    height = int(ceil(abs(y_max) + abs(y_min)))
+    return width, height

Modified: grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox	2012-02-17 00:41:01 UTC (rev 50839)
+++ grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox	2012-02-17 06:45:00 UTC (rev 50840)
@@ -353,10 +353,25 @@
 \subsection psmap Cartograpic Composer
 
 - psmap::dialogs
- - dialogs::UnitConversion
  - dialogs::TCValidator
  - dialogs::PenStyleComboBox
  - dialogs::CheckListCtrl
+ - dialogs::PsmapDialog
+ - dialogs::PageSetupDialog
+ - dialogs::MapDialog
+ - dialogs::MapFramePanel
+ - dialogs::RasterPanel
+ - dialogs::VectorPanel
+ - dialogs::RasterDialog
+ - dialogs::MainVectorDialog
+ - dialogs::VPropertiesDialog
+ - dialogs::LegendDialog
+ - dialogs::MapinfoDialog
+ - dialogs::ScalebarDialog
+ - dialogs::TextDialog
+ - dialogs::ImageDialog
+ - dialogs::NorthArrowDialog
+- psmap::instructions
  - dialogs::Instruction
  - dialogs::InstructionObject
  - dialogs::InitMap
@@ -366,27 +381,20 @@
  - dialogs::Text
  - dialogs::Image
  - dialogs::NorthArrow
+ - dialogs::Point
+ - dialogs::Line
+ - dialogs::Rectangle
  - dialogs::Scalebar
  - dialogs::RasterLegend
  - dialogs::VectorLegend
  - dialogs::Raster
  - dialogs::Vector
  - dialogs::VProperties
- - dialogs::PsmapDialog
- - dialogs::PageSetupDialog
- - dialogs::MapDialog
- - dialogs::MapFramePanel
- - dialogs::RasterPanel
- - dialogs::VectorPanel
- - dialogs::RasterDialog
- - dialogs::MainVectorDialog
- - dialogs::VPropertiesDialog
- - dialogs::LegendDialog
- - dialogs::MapinfoDialog
- - dialogs::ScalebarDialog
- - dialogs::TextDialog
- - dialogs::ImageDialog
- - dialogs::NorthArrowDialog
+- psmap::utils
+ - utils::Rect2D
+ - utils::Rect2DPP
+ - utils::Rect2DPS
+ - utils::UnitConversion
 - psmap::frame
  - frame::PsMapFrame
  - frame::PsMapBufferedWindow



More information about the grass-commit mailing list