[GRASS-SVN] r49671 - in grass/branches/develbranch_6/gui: icons/grass2 wxpython/icons wxpython/mapdisp wxpython/psmap wxpython/xml

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Dec 12 04:40:29 EST 2011


Author: annakrat
Date: 2011-12-12 01:40:28 -0800 (Mon, 12 Dec 2011)
New Revision: 49671

Added:
   grass/branches/develbranch_6/gui/icons/grass2/image-add.png
   grass/branches/develbranch_6/gui/icons/grass2/north-arrow-add.png
Modified:
   grass/branches/develbranch_6/gui/wxpython/icons/icon.py
   grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py
   grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py
   grass/branches/develbranch_6/gui/wxpython/psmap/frame.py
   grass/branches/develbranch_6/gui/wxpython/xml/menudata_psmap.xml
Log:
wxGUI: map composer: merge recent changes from trunk

Added: grass/branches/develbranch_6/gui/icons/grass2/image-add.png
===================================================================
(Binary files differ)


Property changes on: grass/branches/develbranch_6/gui/icons/grass2/image-add.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass/branches/develbranch_6/gui/icons/grass2/north-arrow-add.png
===================================================================
(Binary files differ)


Property changes on: grass/branches/develbranch_6/gui/icons/grass2/north-arrow-add.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: grass/branches/develbranch_6/gui/wxpython/icons/icon.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/icons/icon.py	2011-12-12 09:12:29 UTC (rev 49670)
+++ grass/branches/develbranch_6/gui/wxpython/icons/icon.py	2011-12-12 09:40:28 UTC (rev 49671)
@@ -179,6 +179,8 @@
                                 label = _('Add scalebar and north arrow')),
         'addLegend'  : MetaIcon(img = iconSet.get('legend-add', wx.ART_ERROR),
                                 label = _('Add legend')),
+        'addNorthArrow': MetaIcon(img = iconSet.get('north-arrow-add', wx.ART_ERROR),
+                                label = _('North Arrow')),
         'saveFile'   : MetaIcon(img = iconSet.get('map-export', wx.ART_ERROR),
                                 label = _('Save display to graphic file')),
         'print'      : MetaIcon(img = iconSet.get('print', wx.ART_ERROR),
@@ -461,13 +463,17 @@
         'quit'       : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
                                 label = _('Quit Cartographic Composer')),
         'addText'    : MetaIcon(img = iconSet.get('text-add', wx.ART_ERROR),
-                                label = _('Add text')),
+                                label = _('Text')),
         'addMapinfo' : MetaIcon(img = iconSet.get('map-info', wx.ART_ERROR),
-                                label = _('Add map info')),
+                                label = _('Map info')),
         'addLegend'  : MetaIcon(img = iconSet.get('legend-add', wx.ART_ERROR),
-                                label = _('Add legend')),
+                                label = _('Legend')),
         'addScalebar' : MetaIcon(img = iconSet.get('scalebar-add', wx.ART_ERROR),
-                                 label = _('Add scale bar')),
+                                 label = _('Scale bar')),
+        'addImage'   : MetaIcon(img = iconSet.get('image-add', wx.ART_ERROR),
+                                 label = _('Image')),
+        'addNorthArrow': MetaIcon(img = iconSet.get('north-arrow-add', wx.ART_ERROR),
+                                 label = _('North Arrow')),
         }
     }
 

Modified: grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py	2011-12-12 09:12:29 UTC (rev 49670)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py	2011-12-12 09:40:28 UTC (rev 49671)
@@ -1097,8 +1097,8 @@
         # temporary
         if self.IsPaneShown('3d'):
             AddScale.Enable(False)
-            AddArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("Add north arrow"))
-            AddArrow.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
+            AddArrow = wx.MenuItem(decmenu, wx.ID_ANY, icons['addNorthArrow'].GetLabel())
+            AddArrow.SetBitmap(icons['addNorthArrow'].GetBitmap(self.iconsize))
             decmenu.AppendItem(AddArrow)
             self.Bind(wx.EVT_MENU, self.OnAddArrow, AddArrow)
         

Modified: grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py	2011-12-12 09:12:29 UTC (rev 49670)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py	2011-12-12 09:40:28 UTC (rev 49671)
@@ -379,7 +379,7 @@
                     kwargs = {}
                     if instruction == 'scalebar':
                         kwargs['scale'] = map['scale']
-                    elif instruction == 'text':
+                    elif instruction in ('text', 'eps'):
                         kwargs['mapInstruction'] = map
                     elif instruction in ('vpoints', 'vlines', 'vareas'):
                         kwargs['id'] = wx.NewId()
@@ -408,6 +408,8 @@
                     buffer.append(line)
             
             elif line.startswith('scale '):
+                if isBuffer:
+                    continue
                 ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
                 if not ok: return False
             
@@ -433,6 +435,11 @@
             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'):
@@ -543,6 +550,7 @@
                               mapinfo = ['mapinfo'],
                               scalebar = ['scalebar'],
                               text = ['text'],
+                              eps = ['image', 'northArrow'],
                               vpoints = ['vector', 'vProperties'],
                               vlines = ['vector', 'vProperties'],
                               vareas = ['vector', 'vProperties'],
@@ -556,6 +564,8 @@
                            mapinfo = Mapinfo,
                            scalebar = Scalebar,
                            text = Text,
+                           image = Image,
+                           northArrow = NorthArrow,
                            rasterLegend = RasterLegend,
                            vectorLegend = VectorLegend,
                            vector = Vector,
@@ -566,12 +576,21 @@
         
         for i in myInstruction:
             instr = self.FindInstructionByType(i)
-            if i in ('text', 'vProperties') or not instr:
+            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)
@@ -932,11 +951,30 @@
         
     def __str__(self):
         text = self.instruction['text'].replace('\n','\\n')
-        instr = "text %s %s" % (self.instruction['east'], self.instruction['north'])
+        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 += " %s\n" % text.encode('latin_1')
+            instr = instr.encode('latin1')
         except UnicodeEncodeError, err:
             try:
+                print err
                 pos = str(err).split('position')[1].split(':')[0].strip()
             except IndexError:
                 pos = ''
@@ -950,24 +988,7 @@
                             "which is required by module ps.map.")
             GMessage(message = message)
             return ''
-        instr += (string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").
-                                                                   substitute(self.instruction).
-                                                                   encode('latin_1'))
-        instr += string.Template("    hcolor $hcolor\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction['hcolor'] != 'none':
-            instr += string.Template("    hwidth $hwidth\n").substitute(self.instruction).encode('latin_1')
-        instr += string.Template("    border $border\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction['border'] != 'none':
-            instr += string.Template("    width $width\n").substitute(self.instruction).encode('latin_1')
-        instr += string.Template("    background $background\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction["ref"] != '0':
-            instr += string.Template("    ref $ref\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction).encode('latin_1')
-        if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
-            instr += (string.Template("    xoffset $xoffset\n    yoffset $yoffset\n").
-                                                            substitute(self.instruction).encode('latin_1'))
-        instr += "    end"
+        
         return instr
     
     def Read(self, instruction, text, **kwargs):
@@ -986,7 +1007,7 @@
                         instr['XY'] = False
                         instr['east'], instr['north'] = float(e), float(n)
                         
-                    instr['text'] = line.split(None, 3)[3]
+                    instr['text'] = line.split(None, 3)[3].decode('latin_1')
                 
                 elif sub == 'font':
                     instr['font'] = line.split(None, 1)[1]
@@ -1031,7 +1052,149 @@
         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 %s: file %s not found.") % instruction, 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):
@@ -1520,6 +1683,24 @@
         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):
@@ -1533,7 +1714,7 @@
         instr['name'] = info['fullname']
         #connection
         instr['connection'] = True
-        self.mapDBInfo = dbm_base.VectorDBInfo(instr['name'])
+        self.mapDBInfo = VectorDBInfo(instr['name'])
         self.layers = self.mapDBInfo.layers.keys()
         if not self.layers:
             instr['connection'] = False
@@ -1612,7 +1793,7 @@
             if line.startswith('lpos'):
                 instr['lpos'] = int(line.split()[1])
             elif line.startswith('label'):
-                instr['label'] = line.split(None, 1)[1]
+                instr['label'] = line.split(None, 1)[1].decode('latin_1')
             elif line.startswith('layer'):
                 instr['layer'] = line.split()[1]
             elif line.startswith('masked'):
@@ -1646,7 +1827,7 @@
         self.instruction = settings
         self.objectType = None
         self.unitConv = UnitConversion(self)
-        self.spinCtrlSize = (50, -1)
+        self.spinCtrlSize = (65, -1)
         
         self.Bind(wx.EVT_CLOSE, self.OnClose)
         
@@ -1660,7 +1841,8 @@
         parent.units['unitsCtrl'].SetStringSelection(self.unitConv.findName(dialogDict['unit']))
           
     def AddPosition(self, parent, dialogDict):
-        parent.position = dict()
+        if not hasattr(parent, "position"):
+            parent.position = dict()
         parent.position['comment'] = wx.StaticText(parent, id = wx.ID_ANY,\
                     label = _("Position of the top left corner\nfrom the top left edge of the paper"))
         parent.position['xLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("X:"))
@@ -1673,6 +1855,63 @@
             parent.position['xCtrl'].SetValue("%5.3f" % x)
             parent.position['yCtrl'].SetValue("%5.3f" % y)
         
+    def AddExtendedPosition(self, panel, gridBagSizer, dialogDict):
+        """!Add widgets for setting position relative to paper and to map"""
+        panel.position = dict()
+        positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
+        panel.position['toPaper'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
+        panel.position['toMap'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
+        panel.position['toPaper'].SetValue(dialogDict['XY'])
+        panel.position['toMap'].SetValue(not dialogDict['XY'])
+        
+        gridBagSizer.Add(positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toPaper'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toMap'], pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        
+        # first box - paper coordinates
+        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
+        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerP.AddGrowableCol(1)
+        self.gridBagSizerP.AddGrowableRow(3)
+        
+        self.AddPosition(parent = panel, dialogDict = dialogDict)
+        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
+        self.AddUnits(parent = panel, dialogDict = dialogDict)
+        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
+        
+        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+        
+        # second box - map coordinates
+        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
+        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerM.AddGrowableCol(0)
+        self.gridBagSizerM.AddGrowableCol(1)
+        
+        eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
+        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)
+        panel.position['eCtrl'].SetValue(str(east))
+        panel.position['nCtrl'].SetValue(str(north))
+        
+        self.gridBagSizerM.Add(eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['eCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['nCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+        
     def AddFont(self, parent, dialogDict, color = True):
         parent.font = dict()
 ##        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:"))
@@ -2607,24 +2846,31 @@
         
     def update(self):
         #draw raster
-        map = self.instruction.FindInstructionByType('map')
+        mapInstr = self.instruction.FindInstructionByType('map')
+        if not mapInstr: # no map frame
+            GMessage(message = _("Please, create map frame first."))
+            return
+            
         if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
             self.rasterDict['isRaster'] = False
             self.rasterDict['raster'] = None
-            map['drawMap'] = False
+            mapInstr['drawMap'] = False
             if self.id in self.instruction:
                 del self.instruction[self.id]
 
         else:
             self.rasterDict['isRaster'] = True
             self.rasterDict['raster'] = self.rasterSelect.GetValue()
-            if self.rasterDict['raster'] != map['drawMap']:
-                map['drawMap'] = False
-            
-            if self.id not in self.instruction:
+            if self.rasterDict['raster'] != mapInstr['drawMap']:
+                mapInstr['drawMap'] = False
+
+            raster = self.instruction.FindInstructionByType('raster')
+            if not raster:
                 raster = Raster(self.id)
                 self.instruction.AddInstruction(raster)
-            self.instruction[self.id].SetInstruction(self.rasterDict)
+                self.instruction[self.id].SetInstruction(self.rasterDict)
+            else:
+                self.instruction[raster.id].SetInstruction(self.rasterDict)
             
         if 'map' in self.mainDialog.parent.openDialogs:
             self.mainDialog.parent.openDialogs['map'].updateDialog()
@@ -2983,7 +3229,7 @@
         #vector map info
         self.connection = True
         try:
-            self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
+            self.mapDBInfo = VectorDBInfo(self.vectorName)
             self.layers = self.mapDBInfo.layers.keys()
         except grass.ScriptError:
             self.connection = False
@@ -5176,74 +5422,22 @@
         panel.Fit()
         
         return panel 
-    
+        
     def _positionPanel(self, notebook):
         panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
         notebook.AddPage(page = panel, text = _("Position"))
 
         border = wx.BoxSizer(wx.VERTICAL) 
 
-        #Position
         box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
         sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
         gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
         gridBagSizer.AddGrowableCol(0)
         gridBagSizer.AddGrowableCol(1)
         
-        self.positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
-        self.paperPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
-        self.mapPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
-        self.paperPositionCtrl.SetValue(self.textDict['XY'])
-        self.mapPositionCtrl.SetValue(not self.textDict['XY'])
+        #Position
+        self.AddExtendedPosition(panel, gridBagSizer, self.textDict)
         
-        gridBagSizer.Add(self.positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(self.paperPositionCtrl, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(self.mapPositionCtrl, pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        
-        # first box - paper coordinates
-        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
-        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerP.AddGrowableCol(1)
-        self.gridBagSizerP.AddGrowableRow(3)
-        
-        self.AddPosition(parent = panel, dialogDict = self.textDict)
-        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
-        self.AddUnits(parent = panel, dialogDict = self.textDict)
-        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
-        
-        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
-        
-        # second box - map coordinates
-        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
-        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerM.AddGrowableCol(0)
-        self.gridBagSizerM.AddGrowableCol(1)
-        
-        self.eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
-        self.northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
-        self.eastingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        self.northingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
-        self.eastingCtrl.SetValue(str(east))
-        self.northingCtrl.SetValue(str(north))
-        
-        self.gridBagSizerM.Add(self.eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.eastingCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.northingCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
-        
         #offset
         box3   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Offset"))
         sizerO = wx.StaticBoxSizer(box3, wx.VERTICAL)
@@ -5307,8 +5501,8 @@
         panel.SetSizer(border)
         panel.Fit()
           
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.paperPositionCtrl) 
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.mapPositionCtrl)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
         self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotCtrl)
         
         return panel
@@ -5323,7 +5517,7 @@
             self.rotValue.Disable()
             
     def OnPositionType(self, event):
-        if self.paperPositionCtrl.GetValue():
+        if self.positionPanel.position['toPaper'].GetValue():
             for widget in self.gridBagSizerP.GetChildren():
                 widget.GetWindow().Enable()
             for widget in self.gridBagSizerM.GetChildren():
@@ -5404,7 +5598,7 @@
         self.textDict['yoffset'] = self.yoffCtrl.GetValue()
 
         #position
-        if self.paperPositionCtrl.GetValue():
+        if self.positionPanel.position['toPaper'].GetValue():
             self.textDict['XY'] = True
             currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
             self.textDict['unit'] = currUnit
@@ -5424,13 +5618,13 @@
             self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(self.instruction[self.mapId], x, y, paperToMap = True)
         else:
             self.textDict['XY'] = False
-            if self.eastingCtrl.GetValue():
-                self.textDict['east'] = self.eastingCtrl.GetValue() 
+            if self.positionPanel.position['eCtrl'].GetValue():
+                self.textDict['east'] = self.positionPanel.position['eCtrl'].GetValue() 
             else:
                 self.textDict['east'] = self.textDict['east']
 
-            if self.northingCtrl.GetValue():
-                self.textDict['north'] = self.northingCtrl.GetValue() 
+            if self.positionPanel.position['nCtrl'].GetValue():
+                self.textDict['north'] = self.positionPanel.position['nCtrl'].GetValue() 
             else:
                 self.textDict['north'] = self.textDict['north']
 
@@ -5469,9 +5663,471 @@
         self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
         # EN coordinates
         e, n = self.textDict['east'], self.textDict['north']
-        self.eastingCtrl.SetValue(str(self.textDict['east']))
-        self.northingCtrl.SetValue(str(self.textDict['north']))
+        self.positionPanel.position['eCtrl'].SetValue(str(self.textDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.textDict['north']))
         
+class ImageDialog(PsmapDialog):
+    """!Dialog for setting image properties.
+    
+    It's base dialog for North Arrow dialog.
+    """
+    def __init__(self, parent, id, settings, imagePanelName = _("Image")):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Image settings",
+                             settings = settings)
+        
+        self.objectType = ('image',)
+        if self.id is not None:
+            self.imageObj = self.instruction[self.id]
+            self.imageDict = self.instruction[id].GetInstruction()
+        else:
+            self.id = wx.NewId()
+            self.imageObj = self._newObject()
+            self.imageDict = self.imageObj.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.imageDict['where'] = page['Left'], page['Top'] 
+                
+        map = self.instruction.FindInstructionByType('map')
+        if not map:
+            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)
+        
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.imagePanelName = imagePanelName
+        self.imagePanel = self._imagePanel(notebook)
+        self.positionPanel = self._positionPanel(notebook)
+        self.OnPositionType(None)
+        
+        if self.imageDict['epsfile']:
+            self.imagePanel.image['dir'].SetValue(os.path.dirname(self.imageDict['epsfile']))
+        else:
+            self.imagePanel.image['dir'].SetValue(self._getImageDirectory())
+        self.OnDirChanged(None)
+     
+        self._layout(notebook)
+        
+        
+    def _newObject(self):
+        """!Create corresponding instruction object"""
+        return Image(self.id, self.instruction)
+        
+    def _imagePanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = self.imagePanelName)
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # choose image
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Image"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        # choose directory
+        panel.image = {}
+        if self.imageDict['epsfile']:
+            startDir = os.path.dirname(self.imageDict['epsfile'])
+        else:
+            startDir = self._getImageDirectory()
+        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+                                         labelText = _("Choose a directory:"),
+                                         dialogTitle = _("Choose a directory with images"),
+                                         buttonText = _('Browse'),
+                                         startDirectory = startDir,
+                                         changeCallback = self.OnDirChanged)
+        panel.image['dir'] = dir
+       
+        
+        sizer.Add(item = dir, proportion = 0, flag = wx.EXPAND, border = 0)
+        
+        # image list
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        imageList = wx.ListBox(parent = panel, id = wx.ID_ANY)
+        panel.image['list'] = imageList
+        imageList.Bind(wx.EVT_LISTBOX, self.OnImageSelectionChanged)
+        
+        hSizer.Add(item = imageList, proportion = 1, flag = wx.EXPAND | wx.RIGHT, border = 10)
+        
+        # image preview
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        self.previewSize = (150, 150)
+        img = wx.EmptyImage(*self.previewSize)
+        panel.image['preview'] = wx.StaticBitmap(parent = panel, id = wx.ID_ANY,
+                                                bitmap = wx.BitmapFromImage(img))
+        vSizer.Add(item = panel.image['preview'], proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+        panel.image['sizeInfo'] = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        vSizer.Add(item = panel.image['sizeInfo'], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+        
+        hSizer.Add(item = vSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+        sizer.Add(item = hSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        epsInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                label = _("Note: only EPS format supported"))
+        sizer.Add(item = epsInfo, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 3)
+        
+        
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #
+        # rotation
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Scale And Rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        scaleLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Scale:"))
+        if fs:
+            panel.image['scale'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+                                          increment = 0.5, value = 1, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['scale'].SetFormat("%f")
+            panel.image['scale'].SetDigits(1)
+        else:
+            panel.image['scale'] = wx.TextCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                  validator = TCValidator(flag = 'DIGIT_ONLY'))
+        
+        if self.imageDict['scale']:
+            if fs:
+                value = float(self.imageDict['scale'])
+            else:
+                value = str(self.imageDict['scale'])
+        else:
+            if fs:
+                value = 0
+            else:
+                value = '0'
+        panel.image['scale'].SetValue(value)
+            
+        gridSizer.Add(item = scaleLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = panel.image['scale'], pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        
+        rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+        if fs:
+            panel.image['rotate'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 360,
+                                          increment = 0.5, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['rotate'].SetFormat("%f")
+            panel.image['rotate'].SetDigits(1)
+        else:
+            panel.image['rotate'] = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                min = 0, max = 359, initial = 0)
+        panel.image['rotate'].SetToolTipString(_("Counterclockwise rotation in degrees"))
+        if self.imageDict['rotate']:
+            panel.image['rotate'].SetValue(int(self.imageDict['rotate']))
+        else:
+            panel.image['rotate'].SetValue(0)
+            
+        gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridSizer.Add(item = panel.image['rotate'], pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        self._addConvergence(panel = panel, gridBagSizer = gridSizer)
+        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.imageDict)
+        
+        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 OnDirChanged(self, event):
+        """!Image directory changed"""
+        path = self.imagePanel.image['dir'].GetValue()
+        try:
+            files = os.listdir(path)
+        except OSError: # no such directory
+            files = []
+        imageList = []
+        
+        # no setter for startDirectory?
+        try:
+            self.imagePanel.image['dir'].startDirectory = path
+        except AttributeError: # for sure
+            pass
+        for file in files:
+            if os.path.splitext(file)[1].lower() == '.eps':
+                imageList.append(file)
+        
+        imageList.sort()
+        self.imagePanel.image['list'].SetItems(imageList)
+        if self.imageDict['epsfile']:
+            file = os.path.basename(self.imageDict['epsfile'])
+            self.imagePanel.image['list'].SetStringSelection(file)
+        elif imageList:
+            self.imagePanel.image['list'].SetSelection(0)
+        self.OnImageSelectionChanged(None)
+        
+    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 _getImageDirectory(self):
+        """!Default image directory"""
+        return os.getcwd()
+        
+    def _addConvergence(self, panel, gridBagSizer):
+        pass
+        
+    def OnImageSelectionChanged(self, event):
+        """!Image selected, show preview and size"""
+        if not self.imagePanel.image['dir']: # event is emitted when closing dialog an it causes error
+            return
+            
+        if not havePILImage:
+            self.DrawWarningText(_("PIL\nmissing"))
+            return
+        
+        imageName = self.imagePanel.image['list'].GetStringSelection()
+        if not imageName:
+            self.ClearPreview()
+            return
+        basePath = self.imagePanel.image['dir'].GetValue()
+        file = os.path.join(basePath, imageName)
+        if not os.path.exists(file):
+            return
+            
+        if os.path.splitext(file)[1].lower() == '.eps':
+            try:
+                pImg = PILImage.open(file)
+                img = PilImageToWxImage(pImg)
+            except IOError, e:
+                GError(message = _("Unable to read file %s") % file)
+                self.ClearPreview()
+                return
+            self.SetSizeInfoLabel(img)
+            img = self.ScaleToPreview(img)
+            bitmap = img.ConvertToBitmap()
+            self.DrawBitmap(bitmap)
+            
+        else:
+            # TODO: read other formats and convert by PIL to eps
+            pass
+    
+    def ScaleToPreview(self, img):
+        """!Scale image to preview size"""
+        w = img.GetWidth()
+        h = img.GetHeight()
+        if w <= self.previewSize[0] and h <= self.previewSize[1]:
+            return img
+        if w > h:
+            newW = self.previewSize[0]
+            newH = self.previewSize[0] * h / w
+        else:
+            newH = self.previewSize[0]
+            newW = self.previewSize[0] * w / h
+        return img.Scale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+        
+    def DrawWarningText(self, warning):
+        """!Draw text on preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.Brush(wx.Color(250, 250, 250)))
+        dc.Clear()
+        extent = dc.GetTextExtent(warning)
+        posX = self.previewSize[0] / 2 - extent[0] / 2
+        posY = self.previewSize[1] / 2 - extent[1] / 2
+        dc.DrawText(warning, posX, posY)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def DrawBitmap(self, bitmap):
+        """!Draw bitmap, center it if smaller than preview size"""
+        if bitmap.GetWidth() <= self.previewSize[0] and bitmap.GetHeight() <= self.previewSize[1]:
+            buffer = wx.EmptyBitmap(*self.previewSize)
+            dc = wx.MemoryDC()
+            dc.SelectObject(buffer)
+            dc.SetBrush(dc.GetBrush())
+            dc.Clear()
+            posX = self.previewSize[0] / 2 - bitmap.GetWidth() / 2
+            posY = self.previewSize[1] / 2 - bitmap.GetHeight() / 2
+            dc.DrawBitmap(bitmap, posX, posY)
+            self.imagePanel.image['preview'].SetBitmap(buffer)
+            dc.SelectObject(wx.NullBitmap)
+        else:
+            self.imagePanel.image['preview'].SetBitmap(bitmap)
+            
+    def SetSizeInfoLabel(self, image):
+        """!Update image size label"""
+        self.imagePanel.image['sizeInfo'].SetLabel(_("size: %s x %s pts") % (image.GetWidth(), image.GetHeight()))
+        self.imagePanel.image['sizeInfo'].GetContainingSizer().Layout()
+        
+    def ClearPreview(self):
+        """!Clear preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.WHITE_BRUSH)
+        dc.Clear()
+        mask = wx.Mask(buffer, wx.WHITE)
+        buffer.SetMask(mask)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def update(self): 
+        # epsfile
+        selected = self.imagePanel.image['list'].GetStringSelection()
+        basePath = self.imagePanel.image['dir'].GetValue()
+        if not selected:
+            gcmd.GMessage(parent = self, message = _("No image selected."))
+            return False
+            
+        self.imageDict['epsfile'] = os.path.join(basePath, selected)
+        
+        #position
+        if self.positionPanel.position['toPaper'].GetValue():
+            self.imageDict['XY'] = True
+            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+            self.imageDict['unit'] = currUnit
+            if self.positionPanel.position['xCtrl'].GetValue():
+                x = self.positionPanel.position['xCtrl'].GetValue() 
+            else:
+                x = self.imageDict['where'][0]
+
+            if self.positionPanel.position['yCtrl'].GetValue():
+                y = self.positionPanel.position['yCtrl'].GetValue() 
+            else:
+                y = self.imageDict['where'][1]
+
+            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+            self.imageDict['where'] = x, y
+            
+        else:
+            self.imageDict['XY'] = False
+            if self.positionPanel.position['eCtrl'].GetValue():
+                e = self.positionPanel.position['eCtrl'].GetValue() 
+            else:
+                self.imageDict['east'] = self.imageDict['east']
+
+            if self.positionPanel.position['nCtrl'].GetValue():
+                n = self.positionPanel.position['nCtrl'].GetValue() 
+            else:
+                self.imageDict['north'] = self.imageDict['north']
+
+            x, y = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.imageDict['east']),
+                                       y = float(self.imageDict['north']), paperToMap = False)
+
+        #rotation
+        rot = self.imagePanel.image['rotate'].GetValue()
+        if rot == 0:
+            self.imageDict['rotate'] = None
+        else:
+            self.imageDict['rotate'] = rot
+        
+        #scale
+        self.imageDict['scale'] = self.imagePanel.image['scale'].GetValue()
+                
+        # scale
+        w, h = self.imageObj.GetImageOrigSize(self.imageDict['epsfile'])
+        if self.imageDict['rotate']:
+            self.imageDict['size'] = BBoxAfterRotation(w, h, self.imageDict['rotate'])
+        else:
+            self.imageDict['size'] = w, h
+            
+        w = self.unitConv.convert(value = self.imageDict['size'][0],
+                                  fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = self.imageDict['size'][1],
+                                  fromUnit = 'point', toUnit = 'inch')
+                                  
+    
+        self.imageDict['rect'] = wx.Rect2D(x = x, y = y,
+                                       w = w * self.imageDict['scale'],
+                                       h = h * self.imageDict['scale'])
+        
+        if self.id not in self.instruction:
+            image = self._newObject()
+            self.instruction.AddInstruction(image)
+        self.instruction[self.id].SetInstruction(self.imageDict)
+        
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+
+        return True
+        
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        # XY coordinates
+        x, y = self.imageDict['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.imageDict['east'], self.imageDict['north']
+        self.positionPanel.position['eCtrl'].SetValue(str(self.imageDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.imageDict['north']))
+        
+        
+class NorthArrowDialog(ImageDialog):
+    def __init__(self, parent, id, settings):
+        ImageDialog.__init__(self, parent = parent, id = id, settings = settings,
+                             imagePanelName = _("North Arrow"))
+        
+        self.objectType = ('northArrow',)
+        self.SetTitle(_("North Arrow settings"))
+    
+    def _newObject(self):
+        return NorthArrow(self.id, self.instruction)
+        
+    def _getImageDirectory(self):
+        gisbase = os.getenv("GISBASE")
+        return os.path.join(gisbase, 'etc', 'paint', 'decorations')
+    
+    def _addConvergence(self, panel, gridBagSizer):
+        convergence = wx.Button(parent = panel, id = wx.ID_ANY,
+                                               label = _("Compute convergence"))
+        gridBagSizer.Add(item = convergence, pos = (1, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+        convergence.Bind(wx.EVT_BUTTON, self.OnConvergence)
+        panel.image['convergence'] = convergence
+        
+    def OnConvergence(self, event):
+        ret = RunCommand('g.region', read = True, flags = 'ng')
+        if ret:
+            convergence = float(ret.strip().split('=')[1])
+            if convergence < 0:
+                self.imagePanel.image['rotate'].SetValue(abs(convergence))
+            else:
+                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""" 
@@ -5701,3 +6357,68 @@
         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/psmap/frame.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/frame.py	2011-12-12 09:12:29 UTC (rev 49670)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/frame.py	2011-12-12 09:40:28 UTC (rev 49671)
@@ -99,18 +99,22 @@
             'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
             'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
             '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),
             '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)
             }
         self.brush = {
             'paper': wx.WHITE_BRUSH,
-            'margins': wx.TRANSPARENT_BRUSH,            
+            'margins': wx.TRANSPARENT_BRUSH,
             'map': wx.Brush(wx.Color(151, 214, 90)),
             'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
             'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
             'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
             'scalebar': wx.Brush(wx.Color(200, 200, 200)),
+            'image': wx.Brush(wx.Color(255, 200, 50)),
+            'northArrow': wx.Brush(wx.Color(255, 255, 255)),
             'box': wx.TRANSPARENT_BRUSH,
             'select':wx.TRANSPARENT_BRUSH,
             'resize': wx.BLACK_BRUSH
@@ -213,7 +217,7 @@
         """!Launch ps.map dialog
         """
         GUI(parent = self).ParseCommand(cmd = ['ps.map'])
-        
+
     def OnPDFFile(self, event):
         """!Generate PDF from PS with ps2pdf if available"""
         try:
@@ -302,13 +306,13 @@
                        message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
                 
         # show preview only when user doesn't want to create ps or pdf 
-        if haveImage and event.userData['temp'] and not event.userData['pdfname']:
+        if havePILImage and event.userData['temp'] and not event.userData['pdfname']:
             RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
 ## wx.BusyInfo does not display the message
 ##            busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
 
             try:
-                im = Image.open(event.userData['filename'])
+                im = PILImage.open(event.userData['filename'])
                 if self.instruction[self.pageId]['Orientation'] == 'Landscape':
                     im = im.rotate(270)
                 
@@ -600,6 +604,16 @@
         AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
         decmenu.AppendItem(AddText)
         self.Bind(wx.EVT_MENU, self.OnAddText, AddText) 
+        # eps image
+        AddImage = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addImage"].GetLabel())
+        AddImage.SetBitmap(Icons['psMap']["addImage"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddImage)
+        self.Bind(wx.EVT_MENU, self.OnAddImage, AddImage) 
+        # north arrow image
+        AddNorthArrow = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addNorthArrow"].GetLabel())
+        AddNorthArrow.SetBitmap(Icons['psMap']["addNorthArrow"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddNorthArrow)
+        self.Bind(wx.EVT_MENU, self.OnAddNorthArrow, AddNorthArrow) 
         # Popup the menu.  If an item is selected then its handler
         # will be called before PopupMenu returns.
         self.PopupMenu(decmenu)
@@ -645,6 +659,30 @@
             self.openDialogs['mapinfo'] = dlg
         self.openDialogs['mapinfo'].Show()
         
+    def OnAddImage(self, event, id = None):
+        """!Show dialog for image adding and editing"""
+        position = None
+        if 'image' in self.openDialogs:
+            position = self.openDialogs['image'].GetPosition()
+            self.openDialogs['image'].OnApply(event = None)
+            self.openDialogs['image'].Destroy()
+        dlg = ImageDialog(self, id = id, settings = self.instruction)
+        self.openDialogs['image'] = dlg 
+        if position: 
+            dlg.SetPosition(position)
+        dlg.Show()
+        
+    def OnAddNorthArrow(self, event, id = None):
+        """!Show dialog for north arrow adding and editing"""
+        if self.instruction.FindInstructionByType('northArrow'):
+            id = self.instruction.FindInstructionByType('northArrow').id
+        else: id = None
+        
+        if 'northArrow' not in self.openDialogs:
+            dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
+            self.openDialogs['northArrow'] = dlg
+        self.openDialogs['northArrow'].Show()
+        
     def OnAddText(self, event, id = None):
         """!Show dialog for text adding and editing"""
         position = None
@@ -658,6 +696,7 @@
             dlg.SetPosition(position)
         dlg.Show()
         
+        
     def getModifiedTextBounds(self, x, y, textExtent, rotation):
         """!computes bounding box of rotated text, not very precisely"""
         w, h = textExtent
@@ -792,12 +831,18 @@
         for id in ids:
             itype = self.instruction[id].type
             
-            if itype in ('scalebar', 'mapinfo'):
+            if itype in ('scalebar', 'mapinfo', 'image'):
                 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                self.canvas.UpdateLabel(itype = itype, id = id)
                 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
                 self.canvas.RedrawSelectBox(id)
-                
+            if itype == 'northArrow':
+                self.canvas.UpdateLabel(itype = itype, id = id)
+                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                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 == 'text':
                 
                 if self.instruction[id]['rotate']:
@@ -833,9 +878,8 @@
             if itype in ('map', 'vector', 'raster'):
                 
                 if itype == 'raster':#set resolution
-                    resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
-                    resol = grass.parse_key_val(resol, val_type = float)
-                    RunCommand('g.region', nsres = resol['nsres'], ewres = resol['ewres'])
+                    info = grass.raster_info(self.instruction[id]['raster'])
+                    RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
                     # change current raster in raster legend
                     
                 if 'rasterLegend' in self.openDialogs:
@@ -862,6 +906,7 @@
                 
             if itype == 'rasterLegend':
                 if self.instruction[id]['rLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
@@ -873,6 +918,7 @@
                 if not self.instruction.FindInstructionByType('vector'):
                     self.deleteObject(id)
                 elif self.instruction[id]['vLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
@@ -924,6 +970,8 @@
         grass.set_raise_on_error(False)
         self.Destroy()
 
+
+
 class PsMapBufferedWindow(wx.Window):
     """!A buffered window class.
     
@@ -960,11 +1008,14 @@
         
         
         #labels
-        self.itemLabels = { 'map': ['MAP FRAME'],
-                            'rasterLegend': ['RASTER LEGEND'],
-                            'vectorLegend': ['VECTOR LEGEND'],
-                            'mapinfo': ['MAP INFO'],
-                            'scalebar': ['SCALE BAR']}
+        self.itemLabelsDict = { 'map': 'MAP FRAME',
+                                'rasterLegend': 'RASTER LEGEND',
+                                'vectorLegend': 'VECTOR LEGEND',
+                                'mapinfo': 'MAP INFO',
+                                'scalebar': 'SCALE BAR',
+                                'image': 'IMAGE',
+                                'northArrow': 'NORTH ARROW'}
+        self.itemLabels = {}
         
         # define PseudoDC
         self.pdc = wx.PseudoDC()
@@ -1086,13 +1137,14 @@
             mapId = self.instruction.FindInstructionByType('map').id
         except AttributeError:
             mapId = self.instruction.FindInstructionByType('initMap').id
-            
-        texts = self.instruction.FindInstructionByType('text', list = True)
-        for text in texts:
-            e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
-                                       y = self.instruction[text.id]['where'][1], paperToMap = True)
-            self.instruction[text.id]['east'], self.instruction[text.id]['north'] = e, n
-            
+        
+        for itemType in ('text', 'image', 'northArrow'):
+            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
+                
     def OnPaint(self, event):
         """!Draw pseudo DC to buffer
         """
@@ -1330,11 +1382,13 @@
         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,
+                                '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),
+                            '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
@@ -1351,11 +1405,13 @@
                                                                            canvasToPaper = True)
                 self.RecalculateEN()
                 
-            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend'):
+            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
                 self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                            canvasToPaper = True)[:2]            
+                                                                            canvasToPaper = True)[:2] 
+                if itype in ('image', 'northArrow'):
+                    self.RecalculateEN()
             elif  itype == 'scalebar':
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
@@ -1464,6 +1520,9 @@
 
                     self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
                     self.pdcObj.SetIdBounds(id, bounds)
+                elif type == 'northArrow':
+                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
+                              drawid = id, pdctype = 'bitmap', bb = oRect)
                 else:
                     self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
                               drawid = id, pdctype = 'rectText', bb = oRect)
@@ -1498,8 +1557,18 @@
         pdc.SetId(drawid)
         pdc.SetPen(pen)
         pdc.SetBrush(brush)
+        
+        if pdctype == 'bitmap':
+            if havePILImage:
+                file = self.instruction[drawid]['epsfile']
+                rotation = self.instruction[drawid]['rotate']
+                self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
+            else: # draw only rectangle with label
+                pdctype = 'rectText'
+                
         if pdctype in ('rect', 'rectText'):
             pdc.DrawRectangle(*bb)
+            
         if pdctype == 'rectText':
             dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
             font = self.font
@@ -1508,7 +1577,7 @@
             font.SetStyle(wx.ITALIC)
             dc.SetFont(font)
             pdc.SetFont(font)
-            text = '\n'.join(self.itemLabels[self.instruction[drawid].type])
+            text = '\n'.join(self.itemLabels[drawid])
             w,h,lh = dc.GetMultiLineTextExtent(text)
             textExtent = (w,h)
             textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
@@ -1523,19 +1592,35 @@
             pdc.SetTextForeground(wx.Color(100,100,100,200)) 
             pdc.SetBackgroundMode(wx.TRANSPARENT)
             pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
-            
+                
         pdc.SetIdBounds(drawid, bb)
         pdc.EndDrawing()
         self.Refresh()
 
         return drawid
     
+    def DrawBitmap(self, pdc, filePath, rotation, bbox):
+        """!Draw bitmap using PIL"""
+        pImg = PILImage.open(filePath)
+        if rotation:
+            # get rid of black background
+            pImg = pImg.convert("RGBA")
+            rot = pImg.rotate(rotation, expand = 1)
+            new = PILImage.new('RGBA', rot.size, (255,) * 4)
+            pImg = PILImage.composite(rot, new, rot)
+        pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
+        img = PilImageToWxImage(pImg)
+        bitmap = img.ConvertToBitmap()
+        mask = wx.Mask(bitmap, wx.WHITE)
+        bitmap.SetMask(mask)
+        pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask = True)
+        
     def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
         if textDict['rotate']:
             rot = float(textDict['rotate']) 
         else:
             rot = 0
-        
+
         fontsize = textDict['fontsize'] * self.currScale
         if textDict['background'] != 'none':
             background = textDict['background'] 
@@ -1561,7 +1646,7 @@
             pdc.SetBackgroundMode(wx.TRANSPARENT)
         
         fn = self.parent.makePSFont(textDict)
-        
+
         pdc.SetFont(fn)
         pdc.SetTextForeground(convertRGB(textDict['color']))        
         pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
@@ -1661,12 +1746,21 @@
         if rasterId:
             rasterName = self.instruction[rasterId]['raster'].split('@')[0]
             
-        self.itemLabels['map'] = self.itemLabels['map'][0:1]
-        self.itemLabels['map'].append("raster: " + rasterName)
+        mapId = self.instruction.FindInstructionByType('map').id
+        self.itemLabels[mapId] = []
+        self.itemLabels[mapId].append(self.itemLabelsDict['map'])
+        self.itemLabels[mapId].append("raster: " + rasterName)
         if vectorId: 
             for map in self.instruction[vectorId]['list']:
-                self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
+                self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
             
+    def UpdateLabel(self, itype, id):
+        self.itemLabels[id] = []
+        self.itemLabels[id].append(self.itemLabelsDict[itype])
+        if itype == 'image':
+            file = os.path.basename(self.instruction[id]['epsfile'])
+            self.itemLabels[id].append(file)
+        
     def OnSize(self, event):
         """!Init image size to match window size
         """

Modified: grass/branches/develbranch_6/gui/wxpython/xml/menudata_psmap.xml
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/xml/menudata_psmap.xml	2011-12-12 09:12:29 UTC (rev 49670)
+++ grass/branches/develbranch_6/gui/wxpython/xml/menudata_psmap.xml	2011-12-12 09:40:28 UTC (rev 49671)
@@ -94,6 +94,18 @@
 	  <handler>OnAddText</handler>
 	  <shortcut>Ctrl+T</shortcut>
 	</menuitem>
+	<menuitem>
+	  <label>Image</label>
+	  <help>Add image</help>
+	  <handler>OnAddImage</handler>
+	  <shortcut></shortcut>
+	</menuitem>
+	<menuitem>
+	  <label>North Arrow</label>
+	  <help>Add north arrow</help>
+	  <handler>OnAddNorthArrow</handler>
+	  <shortcut></shortcut>
+	</menuitem>
 	<separator/>
 	<menuitem>
 	  <label>Delete</label>



More information about the grass-commit mailing list