GRASS Programmer's Manual  6.4.2(2012)
psmap.py
Go to the documentation of this file.
00001 """!
00002 @package psmap.py
00003 
00004 @brief GUI for ps.map
00005 
00006 Classes:
00007  - PsMapFrame
00008  - PsMapBufferedWindow
00009 
00010 (C) 2011 by Anna Kratochvilova, and the GRASS Development Team
00011 This program is free software under the GNU General Public License
00012 (>=v2). Read the file COPYING that comes with GRASS for details.
00013 
00014 @author Anna Kratochvilova <anna.kratochvilova fsv.cvut.cz> (bachelor's project)
00015 @author Martin Landa <landa.martin gmail.com> (mentor)
00016 """
00017 
00018 import os
00019 import sys
00020 import textwrap
00021 import Queue
00022 try:
00023     import Image
00024     haveImage = True
00025 except ImportError:
00026     haveImage = False
00027 from math import sin, cos, pi
00028 
00029 import grass.script as grass
00030 if int(grass.version()['version'].split('.')[0]) > 6:
00031     sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython',
00032                                  'gui_modules'))
00033 else:
00034     sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython',
00035                                  'gui_modules'))
00036 import globalvar
00037 import menu
00038 from   goutput    import CmdThread, EVT_CMD_DONE
00039 from   menudata   import PsMapData
00040 from   toolbars   import PsMapToolbar
00041 from   icon       import Icons, MetaIcon, iconSet
00042 from   gcmd       import RunCommand, GError, GMessage
00043 from   menuform   import GUI
00044 from psmap_dialogs import *
00045 
00046 import wx
00047 
00048 try:
00049     import wx.lib.agw.flatnotebook as fnb
00050 except ImportError:
00051     import wx.lib.flatnotebook as fnb
00052     
00053 class PsMapFrame(wx.Frame):
00054     def __init__(self, parent = None, id = wx.ID_ANY,
00055                  title = _("GRASS GIS Cartographic Composer (experimental prototype)"), **kwargs):
00056         """!Main window of ps.map GUI
00057         
00058         @param parent parent window
00059         @param id window id
00060         @param title window title
00061         
00062         @param kwargs wx.Frames' arguments
00063         """
00064         self.parent = parent
00065 
00066         wx.Frame.__init__(self, parent = parent, id = id, title = title, name = "PsMap", **kwargs)
00067         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00068         #menubar
00069         self.menubar = menu.Menu(parent = self, data = PsMapData())
00070         self.SetMenuBar(self.menubar)
00071         #toolbar
00072 
00073         self.toolbar = PsMapToolbar(parent = self)
00074         self.SetToolBar(self.toolbar)
00075         
00076         self.actionOld = self.toolbar.action['id']
00077         self.iconsize = (16, 16)
00078         #satusbar
00079         self.statusbar = self.CreateStatusBar(number = 1)
00080         
00081         # mouse attributes -- position on the screen, begin and end of
00082         # dragging, and type of drawing
00083         self.mouse = {
00084             'begin': [0, 0], # screen coordinates
00085             'end'  : [0, 0],
00086             'use'  : "pointer",
00087             }
00088         # available cursors
00089         self.cursors = {
00090             "default" : wx.StockCursor(wx.CURSOR_ARROW),
00091             "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
00092             "hand"    : wx.StockCursor(wx.CURSOR_HAND),
00093             "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
00094             }
00095         # pen and brush
00096         self.pen = {
00097             'paper': wx.Pen(colour = "BLACK", width = 1),
00098             'margins': wx.Pen(colour = "GREY", width = 1),
00099             'map': wx.Pen(colour = wx.Color(86, 122, 17), width = 2),
00100             'rasterLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
00101             'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
00102             'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
00103             'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
00104             'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
00105             'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
00106             'resize': wx.Pen(colour = 'BLACK', width = 1)
00107             }
00108         self.brush = {
00109             'paper': wx.WHITE_BRUSH,
00110             'margins': wx.TRANSPARENT_BRUSH,            
00111             'map': wx.Brush(wx.Color(151, 214, 90)),
00112             'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
00113             'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
00114             'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
00115             'scalebar': wx.Brush(wx.Color(200, 200, 200)),
00116             'box': wx.TRANSPARENT_BRUSH,
00117             'select':wx.TRANSPARENT_BRUSH,
00118             'resize': wx.BLACK_BRUSH
00119             } 
00120         
00121 
00122         # list of objects to draw
00123         self.objectId = []
00124         
00125         # instructions
00126         self.instruction = Instruction(parent = self, objectsToDraw = self.objectId)
00127         # open dialogs
00128         self.openDialogs = dict()
00129         
00130         self.pageId = wx.NewId()
00131         #current page of flatnotebook
00132         self.currentPage = 0
00133         #canvas for draft mode
00134         self.canvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, pen = self.pen,
00135                                           brush = self.brush, cursors = self.cursors, 
00136                                           instruction = self.instruction, openDialogs = self.openDialogs,
00137                                           pageId = self.pageId, objectId = self.objectId,
00138                                           preview = False)
00139         
00140         self.canvas.SetCursor(self.cursors["default"])
00141         self.getInitMap()
00142         
00143         
00144         # image path
00145         env = grass.gisenv()
00146         self.imgName = grass.tempfile()
00147         
00148         #canvas for preview
00149         self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
00150                                                  pen = self.pen, brush = self.brush, preview = True)
00151         
00152         # set WIND_OVERRIDE
00153         grass.use_temp_region()
00154         
00155         # create queues
00156         self.requestQ = Queue.Queue()
00157         self.resultQ = Queue.Queue()
00158         # thread
00159         self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
00160         
00161         self._layout()
00162         self.SetMinSize(wx.Size(750, 600))
00163         
00164         self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
00165         self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
00166         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
00167         self.Bind(EVT_CMD_DONE, self.OnCmdDone)
00168         
00169         if not haveImage:
00170             wx.CallAfter(self._showErrMsg)
00171         
00172     def _showErrMsg(self):
00173         """!Show error message (missing preview)
00174         """
00175         GError(parent = self,
00176                message = _("Python Imaging Library is not available.\n"
00177                            "'Preview' functionality won't work."),
00178                showTraceback = False)
00179         
00180     def _layout(self):
00181         """!Do layout
00182         """
00183         mainSizer = wx.BoxSizer(wx.VERTICAL)
00184         if globalvar.hasAgw:
00185             self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
00186                                          agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
00187                                          fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
00188         else:
00189             self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
00190                                          style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
00191                                          fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
00192         #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
00193         self.book.AddPage(self.canvas, "Draft mode")
00194         self.book.AddPage(self.previewCanvas, "Preview")
00195         self.book.SetSelection(0)
00196         
00197         mainSizer.Add(self.book,1, wx.EXPAND)
00198         
00199         self.SetSizer(mainSizer)
00200         mainSizer.Fit(self)
00201 
00202         
00203     def InstructionFile(self):
00204         """!Creates mapping instructions"""
00205         
00206         return str(self.instruction)
00207 
00208     def OnPSFile(self, event):
00209         """!Generate PostScript"""
00210         filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
00211         if filename:
00212             self.PSFile(filename)
00213     
00214     def OnPsMapDialog(self, event):
00215         """!Launch ps.map dialog
00216         """
00217         GUI(parent = self).ParseCommand(cmd = ['ps.map'])
00218         
00219     def OnPDFFile(self, event):
00220         """!Generate PDF from PS with ps2pdf if available"""
00221         try:
00222             p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
00223             p.stderr.close()
00224         
00225         except OSError:
00226             GMessage(parent = self,
00227                      message = _("Program ps2pdf is not available. Please install it first to create PDF."))
00228             return
00229         
00230         filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
00231         if filename:  
00232             self.PSFile(filename, pdf = True)   
00233             
00234     def OnPreview(self, event):
00235         """!Run ps.map and show result"""
00236         self.PSFile()
00237         
00238     def PSFile(self, filename = None, pdf = False):
00239         """!Create temporary instructions file and run ps.map with output = filename"""
00240         instrFile = grass.tempfile()
00241         instrFileFd = open(instrFile, mode = 'w')
00242         instrFileFd.write(self.InstructionFile())
00243         instrFileFd.flush()
00244         instrFileFd.close()
00245         
00246         temp = False
00247         regOld = grass.region()
00248         
00249         if pdf:
00250             pdfname = filename
00251         else:
00252             pdfname = None
00253         #preview or pdf
00254         if not filename or (filename and pdf):
00255             temp = True
00256             filename = grass.tempfile()
00257             if not pdf: # lower resolution for preview
00258                 if self.instruction.FindInstructionByType('map'):
00259                     mapId = self.instruction.FindInstructionByType('map').id
00260                     SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
00261                                   height = self.instruction[mapId]['rect'][3])
00262         
00263         cmd = ['ps.map', '--overwrite']
00264         if os.path.splitext(filename)[1] == '.eps':
00265             cmd.append('-e')
00266         if self.instruction[self.pageId]['Orientation'] == 'Landscape':
00267             cmd.append('-r')
00268         cmd.append('input=%s' % instrFile)
00269         cmd.append('output=%s' % filename)
00270         if pdf:
00271             self.SetStatusText(_('Generating PDF...'), 0)
00272         elif not temp:
00273             self.SetStatusText(_('Generating PostScript...'), 0)
00274         else:
00275             self.SetStatusText(_('Generating preview...'), 0)
00276             
00277         self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
00278                                                'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
00279         
00280     def OnCmdDone(self, event):
00281         """!ps.map process finished"""
00282         
00283         if event.returncode != 0:
00284             GMessage(parent = self,
00285                      message = _("Ps.map exited with return code %s") % event.returncode)
00286             
00287             grass.try_remove(event.userData['instrFile'])
00288             if event.userData['temp']:
00289                 grass.try_remove(event.userData['filename']) 
00290             return
00291         
00292         if event.userData['pdfname']:
00293             try:
00294                 proc = grass.Popen(['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200', 
00295                                     event.userData['filename'], event.userData['pdfname']])
00296                 
00297                 ret = proc.wait()                        
00298                 if ret > 0:
00299                     GMessage(parent = self,
00300                              message = _("ps2pdf exited with return code %s") % ret)
00301 
00302             except OSError, e:
00303                 GError(parent = self,
00304                        message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
00305                 
00306         # show preview only when user doesn't want to create ps or pdf 
00307         if haveImage and event.userData['temp'] and not event.userData['pdfname']:
00308             RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
00309 ## wx.BusyInfo does not display the message
00310 ##            busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
00311 
00312             try:
00313                 im = Image.open(event.userData['filename'])
00314                 if self.instruction[self.pageId]['Orientation'] == 'Landscape':
00315                     im = im.rotate(270)
00316                 
00317                 im.save(self.imgName, format = 'PNG')
00318                 
00319             except IOError, e:
00320                 GError(parent = self,
00321                        message = _("Unable to generate preview. %s") % e)
00322                 return
00323             
00324                 
00325             rect = self.previewCanvas.ImageRect()
00326             self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
00327             self.previewCanvas.DrawImage(rect = rect)
00328             
00329 ##            busy.Destroy()
00330             self.SetStatusText(_('Preview generated'), 0)
00331             self.book.SetSelection(1)
00332             self.currentPage = 1
00333         
00334         grass.try_remove(event.userData['instrFile'])
00335         if event.userData['temp']:
00336             grass.try_remove(event.userData['filename'])
00337         
00338     def getFile(self, wildcard):
00339         suffix = []
00340         for filter in wildcard.split('|')[1::2]:
00341             s = filter.strip('*').split('.')[1]
00342             if s:
00343                 s = '.' + s
00344             suffix.append(s)
00345         raster = self.instruction.FindInstructionByType('raster')
00346         if raster:
00347             rasterId = raster.id 
00348         else:
00349             rasterId = None
00350 
00351 
00352         if rasterId and self.instruction[rasterId]['raster']:
00353             mapName = self.instruction[rasterId]['raster'].split('@')[0] + suffix[0]
00354         else:
00355             mapName = ''
00356             
00357         filename = ''
00358         dlg = wx.FileDialog(self, message = _("Save file as"), defaultDir = "", 
00359                             defaultFile = mapName, wildcard = wildcard,
00360                             style = wx.CHANGE_DIR | wx.SAVE | wx.OVERWRITE_PROMPT)
00361         if dlg.ShowModal() == wx.ID_OK:
00362             filename = dlg.GetPath()
00363             suffix = suffix[dlg.GetFilterIndex()]
00364             if not os.path.splitext(filename)[1]:
00365                 filename = filename + suffix
00366             elif os.path.splitext(filename)[1] != suffix and suffix != '':
00367                 filename = os.path.splitext(filename)[0] + suffix
00368             
00369         dlg.Destroy()
00370         return filename
00371     
00372     def OnInstructionFile(self, event):
00373         filename = self.getFile(wildcard = "*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")        
00374         if filename:    
00375             instrFile = open(filename, "w")
00376             instrFile.write(self.InstructionFile())
00377             instrFile.close()   
00378             
00379     def OnLoadFile(self, event):
00380         """!Load file and read instructions"""
00381         #find file
00382         filename = ''
00383         dlg = wx.FileDialog(self, message = "Find instructions file", defaultDir = "", 
00384                             defaultFile = '', wildcard = "All files (*.*)|*.*",
00385                             style = wx.CHANGE_DIR|wx.OPEN)
00386         if dlg.ShowModal() == wx.ID_OK:
00387             filename = dlg.GetPath()
00388         dlg.Destroy()
00389         if not filename:
00390             return
00391         # load instructions
00392         readObjectId = []
00393         readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
00394         ok = readInstruction.Read(filename)
00395         if not ok:
00396             GMessage(_("Failed to read file %s.") % filename)
00397         else:
00398             self.instruction = self.canvas.instruction = readInstruction
00399             self.objectId = self.canvas.objectId = readObjectId
00400             self.pageId = self.canvas.pageId = self.instruction.FindInstructionByType('page').id
00401             self.canvas.UpdateMapLabel()
00402             self.canvas.dragId = -1
00403             self.canvas.Clear()
00404             self.canvas.SetPage()
00405             #self.canvas.ZoomAll()
00406             
00407             self.DialogDataChanged(self.objectId)
00408             
00409     def OnPageSetup(self, event = None):
00410         """!Specify paper size, margins and orientation"""
00411         id = self.instruction.FindInstructionByType('page').id
00412         dlg = PageSetupDialog(self, id = id, settings = self.instruction) 
00413         dlg.CenterOnScreen()
00414         val = dlg.ShowModal()
00415         if val == wx.ID_OK:
00416             self.canvas.SetPage()
00417             self.getInitMap()
00418             self.canvas.RecalculatePosition(ids = self.objectId)
00419         dlg.Destroy()
00420         
00421     def OnPointer(self, event):
00422         self.toolbar.OnTool(event)
00423         self.mouse["use"] = "pointer"
00424         self.canvas.SetCursor(self.cursors["default"])
00425         self.previewCanvas.SetCursor(self.cursors["default"])
00426         
00427     def OnPan(self, event):
00428         self.toolbar.OnTool(event)
00429         self.mouse["use"] = "pan"
00430         self.canvas.SetCursor(self.cursors["hand"])
00431         self.previewCanvas.SetCursor(self.cursors["hand"])
00432         
00433     def OnZoomIn(self, event):
00434         self.toolbar.OnTool(event)
00435         self.mouse["use"] = "zoomin"
00436         self.canvas.SetCursor(self.cursors["cross"])
00437         self.previewCanvas.SetCursor(self.cursors["cross"])
00438         
00439     def OnZoomOut(self, event):
00440         self.toolbar.OnTool(event)
00441         self.mouse["use"] = "zoomout"
00442         self.canvas.SetCursor(self.cursors["cross"])
00443         self.previewCanvas.SetCursor(self.cursors["cross"])
00444         
00445     def OnZoomAll(self, event):
00446         self.mouseOld = self.mouse['use']
00447         if self.currentPage == 0:
00448             self.cursorOld = self.canvas.GetCursor() 
00449         else:
00450             self.cursorOld = self.previewCanvas.GetCursor()
00451             self.previewCanvas.GetCursor()
00452         self.mouse["use"] = "zoomin"
00453         if self.currentPage == 0:
00454             self.canvas.ZoomAll()
00455         else:
00456             self.previewCanvas.ZoomAll()
00457         self.mouse["use"] = self.mouseOld 
00458         if self.currentPage == 0:
00459             self.canvas.SetCursor(self.cursorOld)
00460         else:
00461             self.previewCanvas.SetCursor(self.cursorOld)
00462         
00463         
00464     def OnAddMap(self, event, notebook = False):
00465         """!Add or edit map frame"""
00466         if event is not None:
00467             if event.GetId() != self.toolbar.action['id']:
00468                 self.actionOld = self.toolbar.action['id']
00469                 self.mouseOld = self.mouse['use']
00470                 self.cursorOld = self.canvas.GetCursor()
00471             self.toolbar.OnTool(event)
00472         
00473         if self.instruction.FindInstructionByType('map'):
00474             mapId = self.instruction.FindInstructionByType('map').id
00475         else: mapId = None
00476         id = [mapId, None, None]
00477         
00478         if notebook:
00479             if self.instruction.FindInstructionByType('vector'):
00480                 vectorId = self.instruction.FindInstructionByType('vector').id
00481             else: vectorId = None
00482             if self.instruction.FindInstructionByType('raster'):
00483                 rasterId = self.instruction.FindInstructionByType('raster').id
00484             else: rasterId = None
00485             id[1] = rasterId
00486             id[2] = vectorId
00487         
00488         
00489         if mapId: # map exists
00490             
00491             self.toolbar.ToggleTool(self.actionOld, True)
00492             self.toolbar.ToggleTool(self.toolbar.action['id'], False)
00493             self.toolbar.action['id'] = self.actionOld
00494             try:
00495                 self.canvas.SetCursor(self.cursorOld) 
00496             except AttributeError:
00497                 pass
00498             
00499 ##            dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
00500 ##                            notebook = notebook)
00501 ##            dlg.ShowModal()  
00502             if notebook:
00503                 #check map, raster, vector and save, destroy them
00504                 if 'map' in self.openDialogs:
00505                     self.openDialogs['map'].OnOK(event = None)
00506                 if 'raster' in self.openDialogs:
00507                     self.openDialogs['raster'].OnOK(event = None)
00508                 if 'vector' in self.openDialogs:
00509                     self.openDialogs['vector'].OnOK(event = None)
00510                     
00511                 if 'mapNotebook' not in self.openDialogs:
00512                     dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
00513                                     notebook = notebook)
00514                     self.openDialogs['mapNotebook'] = dlg
00515                 self.openDialogs['mapNotebook'].Show()
00516             else:
00517                 if 'mapNotebook' in self.openDialogs:
00518                     self.openDialogs['mapNotebook'].notebook.ChangeSelection(0)
00519                 else:
00520                     if 'map' not in self.openDialogs:
00521                         dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
00522                                         notebook = notebook)
00523                         self.openDialogs['map'] = dlg
00524                     self.openDialogs['map'].Show()
00525                     
00526 
00527         else:    # sofar no map
00528             self.mouse["use"] = "addMap"
00529             self.canvas.SetCursor(self.cursors["cross"])
00530             if self.currentPage == 1:
00531                 self.book.SetSelection(0)
00532                 self.currentPage = 0
00533                 
00534     def OnAddRaster(self, event):
00535         """!Add raster map"""
00536         if self.instruction.FindInstructionByType('raster'):
00537             id = self.instruction.FindInstructionByType('raster').id
00538         else: id = None
00539         if self.instruction.FindInstructionByType('map'):
00540             mapId = self.instruction.FindInstructionByType('map').id
00541         else: mapId = None
00542 
00543         if not id:
00544             if not mapId:
00545                 GMessage(message = _("Please, create map frame first."))
00546                 return
00547             
00548 ##        dlg = RasterDialog(self, id = id, settings = self.instruction)
00549 ##        dlg.ShowModal()
00550         if 'mapNotebook' in self.openDialogs:
00551             self.openDialogs['mapNotebook'].notebook.ChangeSelection(1)
00552         else:
00553             if 'raster' not in self.openDialogs:
00554                 dlg = RasterDialog(self, id = id, settings = self.instruction)
00555                 self.openDialogs['raster'] = dlg
00556             self.openDialogs['raster'].Show()
00557             
00558     def OnAddVect(self, event):
00559         """!Add vector map"""
00560         if self.instruction.FindInstructionByType('vector'):
00561             id = self.instruction.FindInstructionByType('vector').id
00562         else: id = None
00563         if self.instruction.FindInstructionByType('map'):
00564             mapId = self.instruction.FindInstructionByType('map').id
00565         else: mapId = None
00566         if not id:
00567             if not mapId:
00568                 GMessage(message = _("Please, create map frame first."))
00569                 return
00570             
00571 ##        dlg = MainVectorDialog(self, id = id, settings = self.instruction)
00572 ##        dlg.ShowModal()
00573         if 'mapNotebook' in self.openDialogs:
00574             self.openDialogs['mapNotebook'].notebook.ChangeSelection(2)
00575         else:
00576             if 'vector' not in self.openDialogs:
00577                 dlg =  MainVectorDialog(self, id = id, settings = self.instruction)
00578                 self.openDialogs['vector'] = dlg
00579             self.openDialogs['vector'].Show()
00580         
00581     def OnDecoration(self, event):
00582         """!Decorations overlay menu
00583         """
00584         decmenu = wx.Menu()
00585         # legend
00586         AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addLegend"].GetLabel())
00587         AddLegend.SetBitmap(Icons['psMap']["addLegend"].GetBitmap(self.iconsize))
00588         decmenu.AppendItem(AddLegend)
00589         self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
00590         # mapinfo
00591         AddMapinfo = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addMapinfo"].GetLabel())
00592         AddMapinfo.SetBitmap(Icons['psMap']["addMapinfo"].GetBitmap(self.iconsize))
00593         decmenu.AppendItem(AddMapinfo)
00594         self.Bind(wx.EVT_MENU, self.OnAddMapinfo, AddMapinfo) 
00595         # scalebar
00596         AddScalebar = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addScalebar"].GetLabel())
00597         AddScalebar.SetBitmap(Icons['psMap']["addScalebar"].GetBitmap(self.iconsize))
00598         decmenu.AppendItem(AddScalebar)
00599         self.Bind(wx.EVT_MENU, self.OnAddScalebar, AddScalebar) 
00600         # text
00601         AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addText"].GetLabel())
00602         AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
00603         decmenu.AppendItem(AddText)
00604         self.Bind(wx.EVT_MENU, self.OnAddText, AddText) 
00605         # Popup the menu.  If an item is selected then its handler
00606         # will be called before PopupMenu returns.
00607         self.PopupMenu(decmenu)
00608         decmenu.Destroy()
00609         
00610     def OnAddScalebar(self, event):
00611         """!Add scalebar"""
00612         if projInfo()['proj'] == 'll':
00613             GMessage(message = _("Scalebar is not appropriate for this projection"))
00614             return
00615         if self.instruction.FindInstructionByType('scalebar'):
00616             id = self.instruction.FindInstructionByType('scalebar').id
00617         else: id = None
00618         
00619         if 'scalebar' not in self.openDialogs:
00620             dlg = ScalebarDialog(self, id = id, settings = self.instruction)
00621             self.openDialogs['scalebar'] = dlg
00622         self.openDialogs['scalebar'].Show()
00623         
00624     def OnAddLegend(self, event, page = 0):
00625         """!Add raster or vector legend"""
00626         if self.instruction.FindInstructionByType('rasterLegend'):
00627             idR = self.instruction.FindInstructionByType('rasterLegend').id
00628         else: idR = None
00629         if self.instruction.FindInstructionByType('vectorLegend'):
00630             idV = self.instruction.FindInstructionByType('vectorLegend').id
00631         else: idV = None
00632 
00633         if 'rasterLegend' not in self.openDialogs:    
00634             dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
00635             self.openDialogs['rasterLegend'] = dlg
00636             self.openDialogs['vectorLegend'] = dlg
00637         self.openDialogs['rasterLegend'].notebook.ChangeSelection(page)
00638         self.openDialogs['rasterLegend'].Show()
00639 
00640     def OnAddMapinfo(self, event):
00641         if self.instruction.FindInstructionByType('mapinfo'):
00642             id = self.instruction.FindInstructionByType('mapinfo').id
00643         else: id = None
00644         
00645         if 'mapinfo' not in self.openDialogs:
00646             dlg = MapinfoDialog(self, id = id, settings = self.instruction)
00647             self.openDialogs['mapinfo'] = dlg
00648         self.openDialogs['mapinfo'].Show()
00649         
00650     def OnAddText(self, event, id = None):
00651         """!Show dialog for text adding and editing"""
00652         position = None
00653         if 'text' in self.openDialogs:
00654             position = self.openDialogs['text'].GetPosition()
00655             self.openDialogs['text'].OnApply(event = None)
00656             self.openDialogs['text'].Destroy()
00657         dlg = TextDialog(self, id = id, settings = self.instruction)
00658         self.openDialogs['text'] = dlg 
00659         if position: 
00660             dlg.SetPosition(position)
00661         dlg.Show()
00662         
00663     def getModifiedTextBounds(self, x, y, textExtent, rotation):
00664         """!computes bounding box of rotated text, not very precisely"""
00665         w, h = textExtent
00666         rotation = float(rotation)/180*pi
00667         H = float(w) * sin(rotation)
00668         W = float(w) * cos(rotation)
00669         X, Y = x, y
00670         if pi/2 < rotation <= 3*pi/2:
00671             X = x + W 
00672         if 0 < rotation < pi:
00673             Y = y - H
00674         if rotation == 0:
00675             return wx.Rect(x,y, *textExtent)
00676         else:
00677             return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h) 
00678 
00679     def makePSFont(self, textDict):
00680         """!creates a wx.Font object from selected postscript font. To be
00681         used for estimating bounding rectangle of text"""
00682         
00683         fontsize = textDict['fontsize'] * self.canvas.currScale
00684         fontface = textDict['font'].split('-')[0]
00685         try:
00686             fontstyle = textDict['font'].split('-')[1]
00687         except IndexError:
00688             fontstyle = ''
00689         
00690         if fontface == "Times":
00691             family = wx.FONTFAMILY_ROMAN
00692             face = "times"
00693         elif fontface == "Helvetica":
00694             family = wx.FONTFAMILY_SWISS
00695             face = 'helvetica'
00696         elif fontface == "Courier":
00697             family = wx.FONTFAMILY_TELETYPE
00698             face = 'courier'
00699         else:
00700             family = wx.FONTFAMILY_DEFAULT
00701             face = ''
00702             
00703         style = wx.FONTSTYLE_NORMAL
00704         weight = wx.FONTWEIGHT_NORMAL
00705             
00706         if 'Oblique' in fontstyle:
00707             style =  wx.FONTSTYLE_SLANT
00708             
00709         if 'Italic' in fontstyle:
00710             style =  wx.FONTSTYLE_ITALIC
00711             
00712         if 'Bold' in fontstyle:
00713             weight = wx.FONTWEIGHT_BOLD
00714         
00715         try:
00716             fn = wx.Font(pointSize = fontsize, family = family, style = style,
00717                          weight = weight, face = face)
00718         except:
00719             fn = wx.Font(pointSize = fontsize, family = wx.FONTFAMILY_DEFAULT, 
00720                          style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL)
00721 
00722         return fn
00723        
00724        
00725     def getTextExtent(self, textDict):
00726         """!Estimates bounding rectangle of text"""
00727         #fontsize = str(fontsize if fontsize >= 4 else 4)
00728         dc = wx.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
00729        
00730         fn = self.makePSFont(textDict)
00731 
00732         try:
00733             dc.SetFont(fn)
00734             w,h,lh = dc.GetMultiLineTextExtent(textDict['text'])
00735             return (w,h)
00736         except:
00737             return (0,0)
00738     
00739     def getInitMap(self):
00740         """!Create default map frame when no map is selected, needed for coordinates in map units"""
00741         instrFile = grass.tempfile()
00742         instrFileFd = open(instrFile, mode = 'w')
00743         instrFileFd.write(self.InstructionFile())
00744         instrFileFd.flush()
00745         instrFileFd.close()
00746         
00747         page = self.instruction.FindInstructionByType('page')
00748         mapInitRect = GetMapBounds(instrFile, portrait = (page['Orientation'] == 'Portrait'))
00749         grass.try_remove(instrFile)
00750         
00751         region = grass.region()
00752         units = UnitConversion(self)
00753         realWidth = units.convert(value = abs(region['w'] - region['e']), fromUnit = 'meter', toUnit = 'inch')
00754         scale = mapInitRect.Get()[2]/realWidth  
00755         
00756         initMap = self.instruction.FindInstructionByType('initMap')
00757         if initMap:
00758             id = initMap.id 
00759         else:
00760             id = None
00761 
00762         
00763         if not id:
00764             id = wx.NewId()
00765             initMap = InitMap(id)
00766             self.instruction.AddInstruction(initMap)
00767         self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
00768 
00769     def OnDelete(self, event):
00770         if self.canvas.dragId != -1 and self.currentPage == 0:
00771             if self.instruction[self.canvas.dragId].type == 'map':
00772                 self.deleteObject(self.canvas.dragId)
00773                 self.getInitMap()
00774                 self.canvas.RecalculateEN()
00775             else:
00776                 self.deleteObject(self.canvas.dragId)   
00777     
00778     def deleteObject(self, id):
00779         """!Deletes object, his id and redraws"""
00780         #delete from canvas
00781         self.canvas.pdcObj.RemoveId(id)
00782         if id == self.canvas.dragId:
00783             self.canvas.pdcTmp.RemoveAll()
00784             self.canvas.dragId = -1
00785         self.canvas.Refresh()
00786         
00787         # delete from instructions
00788         del self.instruction[id]
00789 
00790     def DialogDataChanged(self, id):
00791         ids = id
00792         if type(id) == int:
00793             ids = [id]
00794         for id in ids:
00795             itype = self.instruction[id].type
00796             
00797             if itype in ('scalebar', 'mapinfo'):
00798                 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
00799                 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
00800                                  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
00801                 self.canvas.RedrawSelectBox(id)
00802                 
00803             if itype == 'text':
00804                 
00805                 if self.instruction[id]['rotate']:
00806                     rot = float(self.instruction[id]['rotate']) 
00807                 else:
00808                     rot = 0
00809 
00810                 extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
00811                 rect = wx.Rect2D(self.instruction[id]['where'][0], self.instruction[id]['where'][1], 0, 0)
00812                 self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
00813                 
00814                 #computes text coordinates according to reference point, not precisely
00815                 if self.instruction[id]['ref'].split()[0] == 'lower':
00816                     self.instruction[id]['coords'][1] -= extent[1]
00817                 elif self.instruction[id]['ref'].split()[0] == 'center':
00818                     self.instruction[id]['coords'][1] -= extent[1]/2
00819                 if self.instruction[id]['ref'].split()[1] == 'right':
00820                     self.instruction[id]['coords'][0] -= extent[0] * cos(rot/180*pi)
00821                     self.instruction[id]['coords'][1] += extent[0] * sin(rot/180*pi)
00822                 elif self.instruction[id]['ref'].split()[1] == 'center':
00823                     self.instruction[id]['coords'][0] -= extent[0]/2 * cos(rot/180*pi)
00824                     self.instruction[id]['coords'][1] += extent[0]/2 * sin(rot/180*pi)
00825                     
00826                 self.instruction[id]['coords'][0] += self.instruction[id]['xoffset']
00827                 self.instruction[id]['coords'][1] -= self.instruction[id]['yoffset']
00828                 coords = self.instruction[id]['coords']
00829                 self.instruction[id]['rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
00830                 self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
00831                                         textDict = self.instruction[id].GetInstruction(),
00832                                         coords = coords, bounds = bounds)
00833                 self.canvas.RedrawSelectBox(id)
00834                 
00835             if itype in ('map', 'vector', 'raster'):
00836                 
00837                 if itype == 'raster':#set resolution
00838                     resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
00839                     resol = grass.parse_key_val(resol, val_type = float)
00840                     RunCommand('g.region', nsres = resol['nsres'], ewres = resol['ewres'])
00841                     # change current raster in raster legend
00842                     
00843                 if 'rasterLegend' in self.openDialogs:
00844                     self.openDialogs['rasterLegend'].updateDialog()
00845                 id = self.instruction.FindInstructionByType('map').id
00846                 
00847                 #check resolution
00848                 if itype == 'raster':
00849                     SetResolution(dpi = self.instruction[id]['resolution'], 
00850                                   width = self.instruction[id]['rect'].width,
00851                                   height = self.instruction[id]['rect'].height)   
00852                 rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'],
00853                                                                 canvasToPaper = False)
00854                 self.canvas.RecalculateEN()
00855                 self.canvas.UpdateMapLabel()
00856                 
00857                 self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
00858                                  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
00859                 # redraw select box  
00860                 self.canvas.RedrawSelectBox(id)
00861                 self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
00862                 # redraw to get map to the bottom layer
00863                 #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
00864                 
00865             if itype == 'rasterLegend':
00866                 if self.instruction[id]['rLegend']:
00867                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
00868                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
00869                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
00870                     self.canvas.RedrawSelectBox(id)
00871                 else:
00872                     self.deleteObject(id)
00873                     
00874             if itype == 'vectorLegend':
00875                 if not self.instruction.FindInstructionByType('vector'):
00876                     self.deleteObject(id)
00877                 elif self.instruction[id]['vLegend']:
00878                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
00879                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
00880                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
00881                     self.canvas.RedrawSelectBox(id)
00882 
00883                 else:
00884                     self.deleteObject(id)
00885                 
00886     def OnPageChanged(self, event):
00887         """!Flatnotebook page has changed"""
00888         self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
00889         
00890         
00891     def OnPageChanging(self, event):
00892         """!Flatnotebook page is changing"""
00893         if self.currentPage == 0 and self.mouse['use'] == 'addMap':
00894             event.Veto()
00895 
00896     def OnHelp(self, event):
00897         """!Show help"""
00898         if self.parent and self.parent.GetName() == 'LayerManager':
00899             log = self.parent.GetLogWindow()
00900             log.RunCmd(['g.manual',
00901                         'entry=wxGUI.PsMap'])
00902         else:
00903             RunCommand('g.manual',
00904                        quiet = True,
00905                        entry = 'wxGUI.PsMap')
00906         
00907     def OnAbout(self, event):
00908         """!Display About window"""
00909         info = wx.AboutDialogInfo()
00910         
00911         info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00912         info.SetName(_('wxGUI Cartographic Composer'))
00913         info.SetWebSite('http://grass.osgeo.org')
00914         info.SetDescription(_('(C) 2011 by the GRASS Development Team\n\n') + 
00915                             '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
00916                                                       '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
00917         
00918         wx.AboutBox(info)
00919 
00920     def OnCloseWindow(self, event):
00921         """!Close window"""
00922         try:
00923             os.remove(self.imgName)
00924         except OSError:
00925             pass
00926         grass.set_raise_on_error(False)
00927         self.Destroy()
00928 
00929 
00930 
00931 class PsMapBufferedWindow(wx.Window):
00932     """!A buffered window class.
00933     
00934     @param parent parent window
00935     @param kwargs other wx.Window parameters
00936     """
00937     def __init__(self, parent, id =  wx.ID_ANY,
00938                  style = wx.NO_FULL_REPAINT_ON_RESIZE,
00939                  **kwargs):
00940         wx.Window.__init__(self, parent, id = id, style = style)
00941         self.parent = parent
00942     
00943         self.FitInside()
00944         
00945         # store an off screen empty bitmap for saving to file
00946         self._buffer = None
00947         # indicates whether or not a resize event has taken place
00948         self.resize = False 
00949         
00950         self.mouse = kwargs['mouse']
00951         self.cursors = kwargs['cursors']
00952         self.preview = kwargs['preview']
00953         self.pen = kwargs['pen']
00954         self.brush = kwargs['brush']
00955         
00956         if kwargs.has_key('instruction'):
00957             self.instruction = kwargs['instruction']
00958         if kwargs.has_key('openDialogs'):
00959             self.openDialogs = kwargs['openDialogs']
00960         if kwargs.has_key('pageId'):
00961             self.pageId = kwargs['pageId']
00962         if kwargs.has_key('objectId'):
00963             self.objectId = kwargs['objectId']
00964         
00965         
00966         #labels
00967         self.itemLabels = { 'map': ['MAP FRAME'],
00968                             'rasterLegend': ['RASTER LEGEND'],
00969                             'vectorLegend': ['VECTOR LEGEND'],
00970                             'mapinfo': ['MAP INFO'],
00971                             'scalebar': ['SCALE BAR']}
00972         
00973         # define PseudoDC
00974         self.pdc = wx.PseudoDC()
00975         self.pdcObj = wx.PseudoDC()
00976         self.pdcPaper = wx.PseudoDC()
00977         self.pdcTmp = wx.PseudoDC()
00978         self.pdcImage = wx.PseudoDC()
00979         dc = wx.ClientDC(self)
00980         self.font = dc.GetFont()
00981         
00982         self.SetClientSize((700,510))#?
00983         self._buffer = wx.EmptyBitmap(*self.GetClientSize())
00984         
00985         self.idBoxTmp = wx.NewId()
00986         self.idZoomBoxTmp = wx.NewId()
00987         self.idResizeBoxTmp = wx.NewId()
00988         
00989         
00990 
00991         self.dragId = -1
00992         
00993         if self.preview:
00994             self.image = None
00995             self.imageId = 2000
00996             self.imgName = self.parent.imgName
00997             
00998             
00999             
01000         self.currScale = None
01001         
01002         self.Clear()
01003         
01004         self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
01005         
01006         self.Bind(wx.EVT_PAINT, self.OnPaint)
01007         self.Bind(wx.EVT_SIZE,  self.OnSize)
01008         self.Bind(wx.EVT_IDLE,  self.OnIdle)
01009         self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
01010 
01011 
01012     def Clear(self):
01013         """!Clear canvas and set paper
01014         """
01015         bg = wx.LIGHT_GREY_BRUSH
01016         self.pdcPaper.BeginDrawing()
01017         self.pdcPaper.SetBackground(bg)
01018         self.pdcPaper.Clear()
01019         self.pdcPaper.EndDrawing()
01020         
01021         self.pdcObj.RemoveAll()
01022         self.pdcTmp.RemoveAll()
01023         
01024 
01025 
01026         if not self.preview:
01027             self.SetPage()
01028 
01029     
01030     def CanvasPaperCoordinates(self, rect, canvasToPaper = True):
01031         """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
01032         
01033         units = UnitConversion(self)
01034         
01035         fromU = 'pixel'
01036         toU = 'inch'
01037         pRect = self.pdcPaper.GetIdBounds(self.pageId)
01038         pRectx, pRecty = pRect.x, pRect.y 
01039         scale = 1/self.currScale
01040         if not canvasToPaper: # paper -> canvas
01041             fromU = 'inch'
01042             toU = 'pixel'
01043             scale = self.currScale
01044             pRectx = units.convert(value =  - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
01045             pRecty = units.convert(value =  - pRect.y, fromUnit = 'pixel', toUnit = 'inch' ) /scale 
01046         Width = units.convert(value = rect.width, fromUnit = fromU, toUnit = toU) * scale
01047         Height = units.convert(value = rect.height, fromUnit = fromU, toUnit = toU) * scale
01048         X = units.convert(value = (rect.x - pRectx), fromUnit = fromU, toUnit = toU) * scale
01049         Y = units.convert(value = (rect.y - pRecty), fromUnit = fromU, toUnit = toU) * scale
01050 
01051         return wx.Rect2D(X, Y, Width, Height)
01052 
01053     
01054     
01055     def SetPage(self):
01056         """!Sets and changes page, redraws paper"""
01057         
01058         page = self.instruction[self.pageId]
01059         if not page:
01060             page = PageSetup(id = self.pageId)
01061             self.instruction.AddInstruction(page)
01062         
01063         ppi = wx.ClientDC(self).GetPPI()
01064         cW, cH = self.GetClientSize()
01065         pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
01066 
01067         if self.currScale is None:
01068             self.currScale = min(cW/pW, cH/pH)
01069         pW = pW * self.currScale
01070         pH = pH * self.currScale
01071         
01072         x = cW/2 - pW/2
01073         y = cH/2 - pH/2
01074         self.DrawPaper(wx.Rect(x, y, pW, pH))
01075 
01076 
01077     def modifyRectangle(self, r):
01078         """! Recalculates rectangle not to have negative size"""
01079         if r.GetWidth() < 0:
01080             r.SetX(r.GetX() + r.GetWidth())
01081         if r.GetHeight() < 0:
01082             r.SetY(r.GetY() + r.GetHeight())
01083         r.SetWidth(abs(r.GetWidth()))
01084         r.SetHeight(abs(r.GetHeight()))
01085         return r 
01086     
01087     def RecalculateEN(self):
01088         """!Recalculate east and north for texts (eps, points) after their or map's movement"""
01089         try:
01090             mapId = self.instruction.FindInstructionByType('map').id
01091         except AttributeError:
01092             mapId = self.instruction.FindInstructionByType('initMap').id
01093             
01094         texts = self.instruction.FindInstructionByType('text', list = True)
01095         for text in texts:
01096             e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
01097                                        y = self.instruction[text.id]['where'][1], paperToMap = True)
01098             self.instruction[text.id]['east'], self.instruction[text.id]['north'] = e, n
01099             
01100     def OnPaint(self, event):
01101         """!Draw pseudo DC to buffer
01102         """
01103         if not self._buffer:
01104             return
01105         dc = wx.BufferedPaintDC(self, self._buffer)
01106         # use PrepareDC to set position correctly
01107         self.PrepareDC(dc)
01108         
01109         dc.SetBackground(wx.LIGHT_GREY_BRUSH)
01110         dc.Clear()
01111         
01112         # draw paper
01113         if not self.preview:
01114             self.pdcPaper.DrawToDC(dc)
01115         # draw to the DC using the calculated clipping rect
01116 
01117         rgn = self.GetUpdateRegion()
01118         
01119         if not self.preview:
01120             self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
01121         else: 
01122             self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
01123         self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
01124         
01125     def OnMouse(self, event):
01126 
01127         if event.GetWheelRotation():
01128             zoom = event.GetWheelRotation()
01129             use = self.mouse['use']
01130             self.mouse['begin'] = event.GetPosition()
01131             if zoom > 0:
01132                 self.mouse['use'] = 'zoomin'
01133             else:
01134                 self.mouse['use'] = 'zoomout'
01135                 
01136             zoomFactor, view = self.ComputeZoom(wx.Rect(0,0,0,0))
01137             self.Zoom(zoomFactor, view)
01138             self.mouse['use'] = use
01139             
01140         if event.Moving():
01141             if self.mouse['use'] in ('pointer', 'resize'):
01142                 pos = event.GetPosition()
01143                 foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
01144                 if foundResize and foundResize[0] == self.idResizeBoxTmp:
01145                     self.SetCursor(self.cursors["sizenwse"])
01146                     self.parent.SetStatusText(_('Click and drag to resize object'), 0)
01147                 else:
01148                     self.parent.SetStatusText('', 0)
01149                     self.SetCursor(self.cursors["default"])
01150                     
01151         elif event.LeftDown():
01152             self.mouse['begin'] = event.GetPosition()
01153             self.begin = self.mouse['begin']
01154             if self.mouse['use'] in ('pan', 'zoomin', 'zoomout', 'addMap'):
01155                 pass
01156             
01157             #select
01158             if self.mouse['use'] == 'pointer':
01159                 found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
01160                 foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
01161 
01162                 if foundResize and foundResize[0] == self.idResizeBoxTmp:
01163                     self.mouse['use'] = 'resize'
01164                     
01165                     # when resizing, proportions match region
01166                     if self.instruction[self.dragId].type == 'map':
01167                         self.constraint = False
01168                         self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
01169                         if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
01170                             self.constraint = True
01171                             self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
01172                     
01173                 elif found:
01174                     self.dragId = found[0]  
01175                     self.RedrawSelectBox(self.dragId)
01176                     if self.instruction[self.dragId].type != 'map':
01177                         self.pdcTmp.RemoveId(self.idResizeBoxTmp)
01178                         self.Refresh()
01179                         
01180                 else:
01181                     self.dragId = -1
01182                     self.pdcTmp.RemoveId(self.idBoxTmp)
01183                     self.pdcTmp.RemoveId(self.idResizeBoxTmp)
01184                     self.Refresh()           
01185                     
01186                     
01187         elif event.Dragging() and event.LeftIsDown():
01188             #draw box when zooming, creating map 
01189             if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap'):
01190                 self.mouse['end'] = event.GetPosition()
01191                 r = wx.Rect(self.mouse['begin'][0], self.mouse['begin'][1],
01192                             self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
01193                 r = self.modifyRectangle(r)
01194                 self.Draw(pen = self.pen['box'], brush = self.brush['box'], pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
01195                           pdctype = 'rect', bb = r)
01196                 
01197             # panning                
01198             if self.mouse["use"] == 'pan':
01199                 self.mouse['end'] = event.GetPosition()
01200                 view = self.mouse['begin'][0] - self.mouse['end'][0], self.mouse['begin'][1] - self.mouse['end'][1]
01201                 zoomFactor = 1
01202                 self.Zoom(zoomFactor, view)
01203                 self.mouse['begin'] = event.GetPosition()
01204                 
01205             #move object
01206             if self.mouse['use'] == 'pointer' and self.dragId != -1:
01207                 
01208                 self.mouse['end'] = event.GetPosition()
01209                 dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
01210                 self.pdcObj.TranslateId(self.dragId, dx, dy)
01211                 self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
01212                 self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
01213                 if self.instruction[self.dragId].type == 'text': 
01214                     self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
01215                         self.instruction[self.dragId]['coords'][1] + dy
01216                 self.begin = event.GetPosition()
01217                 self.Refresh()
01218                 
01219             # resize object
01220             if self.mouse['use'] == 'resize':
01221                 type = self.instruction[self.dragId].type
01222                 pos = event.GetPosition()
01223                 x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
01224                 width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
01225                 diffX = pos[0] - self.mouse['begin'][0]
01226                 diffY = pos[1] - self.mouse['begin'][1]
01227                 # match given region
01228                 if self.constraint:
01229                     if width > height:
01230                         newWidth = width + diffX
01231                         newHeight = height + diffX * (float(height) / width)
01232                     else:
01233                         newWidth = width + diffY * (float(width) / height)
01234                         newHeight = height + diffY
01235                 else:
01236                     newWidth = width + diffX
01237                     newHeight = height + diffY
01238                     
01239                 if newWidth < 10 or newHeight < 10:
01240                     return
01241                 
01242                 bounds = wx.Rect(x, y, newWidth, newHeight)    
01243                 self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj, drawid = self.dragId,
01244                           pdctype = 'rectText', bb = bounds)
01245                 self.RedrawSelectBox(self.dragId)
01246                 
01247         elif event.LeftUp():
01248             # zoom in, zoom out
01249             if self.mouse['use'] in ('zoomin','zoomout'):
01250                 zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
01251                 self.pdcTmp.RemoveId(self.idZoomBoxTmp)
01252                 self.Refresh()
01253                 zoomFactor, view = self.ComputeZoom(zoomR)
01254                 self.Zoom(zoomFactor, view)
01255 
01256                 
01257             # draw map frame    
01258             if self.mouse['use'] == 'addMap':
01259                 rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
01260                 # too small rectangle, it's usually some mistake
01261                 if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
01262                     self.pdcTmp.RemoveId(self.idZoomBoxTmp)
01263                     self.Refresh()
01264                     return
01265                 rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)                
01266                 
01267                 dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction, 
01268                                 rect = rectPaper)
01269                 self.openDialogs['map'] = dlg
01270                 self.openDialogs['map'].Show()
01271                 
01272                 
01273                 self.mouse['use'] = self.parent.mouseOld
01274 
01275                 self.SetCursor(self.parent.cursorOld)
01276                 self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
01277                 self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
01278                 self.parent.toolbar.action['id'] = self.parent.actionOld
01279                 
01280 
01281 
01282             # resize resizable objects (only map sofar)
01283             if self.mouse['use'] == 'resize':
01284                 mapId = self.instruction.FindInstructionByType('map').id
01285                 
01286                 if self.dragId == mapId:
01287                     # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
01288                     newRectCanvas = self.pdcObj.GetIdBounds(mapId)
01289                     newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
01290                     self.instruction[mapId]['rect'] = newRectPaper
01291                     
01292                     if self.instruction[mapId]['scaleType'] in (0, 1, 2):
01293                         if self.instruction[mapId]['scaleType'] == 0:
01294                             
01295                             scale, foo, rect = AutoAdjust(self, scaleType = 0,
01296                                                           map = self.instruction[mapId]['map'],
01297                                                           mapType = self.instruction[mapId]['mapType'], 
01298                                                           rect = self.instruction[mapId]['rect'])
01299                             
01300                         elif self.instruction[mapId]['scaleType'] == 1:
01301                             scale, foo, rect = AutoAdjust(self, scaleType = 1,
01302                                                           region = self.instruction[mapId]['region'],
01303                                                           rect = self.instruction[mapId]['rect'])
01304                         else:
01305                             scale, foo, rect = AutoAdjust(self, scaleType = 2,
01306                                                           rect = self.instruction[mapId]['rect'])
01307                         self.instruction[mapId]['rect'] = rect
01308                         self.instruction[mapId]['scale'] = scale
01309                         
01310                         rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
01311                         self.Draw(pen = self.pen['map'], brush = self.brush['map'],
01312                                   pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
01313                         
01314                     elif self.instruction[mapId]['scaleType'] == 3:
01315                         ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
01316                     #check resolution
01317                     SetResolution(dpi = self.instruction[mapId]['resolution'],
01318                                   width = self.instruction[mapId]['rect'].width,
01319                                   height = self.instruction[mapId]['rect'].height)
01320                     
01321                     self.RedrawSelectBox(mapId)
01322                     self.Zoom(zoomFactor = 1, view = (0, 0))
01323                 self.mouse['use'] = 'pointer'
01324                 
01325             # recalculate the position of objects after dragging    
01326             if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
01327                 if self.mouse['begin'] != event.GetPosition(): #for double click
01328                     
01329                     self.RecalculatePosition(ids = [self.dragId])
01330                     if self.instruction[self.dragId].type in self.openDialogs:
01331                         self.openDialogs[self.instruction[self.dragId].type].updateDialog()
01332 
01333         # double click launches dialogs
01334         elif event.LeftDClick():
01335             if self.mouse['use'] == 'pointer' and self.dragId != -1:
01336                 itemCall = {    'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
01337                                 'scalebar': self.parent.OnAddScalebar,
01338                                 'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,  
01339                                 'map': self.parent.OnAddMap}
01340                 itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
01341                             'scalebar': dict(event = None),
01342                             'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
01343                             'map': dict(event = None, notebook = True)}
01344                 type = self.instruction[self.dragId].type
01345                 itemCall[type](**itemArg[type])
01346 
01347                 
01348                 
01349                 
01350     def RecalculatePosition(self, ids):
01351         for id in ids:
01352             itype = self.instruction[id].type
01353             if itype == 'map':
01354                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
01355                                                                            canvasToPaper = True)
01356                 self.RecalculateEN()
01357                 
01358             elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend'):
01359                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
01360                                                                            canvasToPaper = True)
01361                 self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
01362                                                                             canvasToPaper = True)[:2]            
01363             elif  itype == 'scalebar':
01364                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
01365                                                                            canvasToPaper = True)
01366 
01367                 
01368                 self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
01369                 
01370             elif  itype == 'text':
01371                 x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
01372                     self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
01373                 extent = self.parent.getTextExtent(textDict = self.instruction[id])
01374                 if self.instruction[id]['rotate'] is not None:
01375                     rot = float(self.instruction[id]['rotate'])/180*pi 
01376                 else:
01377                     rot = 0
01378 
01379                 if self.instruction[id]['ref'].split()[0] == 'lower':
01380                     y += extent[1]
01381                 elif self.instruction[id]['ref'].split()[0] == 'center':
01382                     y += extent[1]/2
01383                 if self.instruction[id]['ref'].split()[1] == 'right':
01384                     x += extent[0] * cos(rot)
01385                     y -= extent[0] * sin(rot)
01386                 elif self.instruction[id]['ref'].split()[1] == 'center':
01387                     x += extent[0]/2 * cos(rot)
01388                     y -= extent[0]/2 * sin(rot)
01389                 
01390                 self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = wx.Rect2D(x, y, 0, 0),
01391                                                                             canvasToPaper = True)[:2]
01392                 self.RecalculateEN()
01393         
01394     def ComputeZoom(self, rect):
01395         """!Computes zoom factor and scroll view"""
01396         zoomFactor = 1
01397         cW, cH = self.GetClientSize()
01398         cW = float(cW)
01399         if rect.IsEmpty(): # clicked on canvas
01400             zoomFactor = 1.5
01401             if self.mouse['use'] == 'zoomout':
01402                 zoomFactor = 1./zoomFactor
01403             x,y = self.mouse['begin']
01404             xView = x - x/zoomFactor#x - cW/(zoomFactor * 2)
01405             yView = y - y/zoomFactor#y - cH/(zoomFactor * 2)
01406 
01407         else:   #dragging    
01408             rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
01409             try:
01410                 zoomFactor = 1/max(rW/cW, rH/cH)
01411             except ZeroDivisionError:
01412                 zoomFactor = 1
01413             # when zooming to full extent, in some cases, there was zoom 1.01..., which causes problem
01414             if abs(zoomFactor - 1) > 0.01:
01415                 zoomFactor = zoomFactor 
01416             else:
01417                 zoomFactor = 1.
01418 
01419 
01420             if self.mouse['use'] == 'zoomout':
01421                 zoomFactor = min(rW/cW, rH/cH)
01422             try:
01423                 if rW/rH > cW/cH:
01424                     yView = rect.GetY() - (rW*(cH/cW) - rH)/2
01425                     xView = rect.GetX()
01426                     
01427                     if self.mouse['use'] == 'zoomout':
01428                         x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
01429                         xView, yView = -x, -y
01430                 else:
01431                     xView = rect.GetX() - (rH*(cW/cH) - rW)/2
01432                     yView = rect.GetY()
01433                     if self.mouse['use'] == 'zoomout':
01434                         x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
01435                         xView, yView = -x, -y
01436             except ZeroDivisionError:
01437                 xView, yView = rect.GetX(), rect.GetY()
01438                 
01439         return zoomFactor, (int(xView), int(yView))
01440     
01441     
01442     def Zoom(self, zoomFactor, view):
01443         """! Zoom to specified region, scroll view, redraw"""
01444         if not self.currScale:
01445             return
01446         self.currScale = self.currScale*zoomFactor
01447         
01448         if self.currScale > 10 or self.currScale < 0.1:
01449             self.currScale = self.currScale/zoomFactor
01450             return 
01451         if not self.preview:
01452             # redraw paper
01453             pRect = self.pdcPaper.GetIdBounds(self.pageId)
01454             pRect.OffsetXY(-view[0], -view[1])
01455             pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
01456             self.DrawPaper(pRect)
01457             
01458             #redraw objects
01459             for id in self.objectId:
01460                 oRect = self.CanvasPaperCoordinates(
01461                     rect = self.instruction[id]['rect'], canvasToPaper = False)
01462                 
01463                 type = self.instruction[id].type
01464                 if type == 'text':
01465                     coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
01466                     self.instruction[id]['coords'] = coords = [(int(coord) - view[i]) * zoomFactor
01467                                                                for i, coord in enumerate(coords)]
01468                     self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
01469                                      coords = coords, bounds = oRect )
01470                     extent = self.parent.getTextExtent(textDict = self.instruction[id])
01471                     if self.instruction[id]['rotate']:
01472                         rot = float(self.instruction[id]['rotate']) 
01473                     else:
01474                         rot = 0
01475 
01476                     self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
01477                     self.pdcObj.SetIdBounds(id, bounds)
01478                 else:
01479                     self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
01480                               drawid = id, pdctype = 'rectText', bb = oRect)
01481             #redraw tmp objects
01482             if self.dragId != -1:
01483                 self.RedrawSelectBox(self.dragId)
01484                 
01485         #redraw preview
01486         else: # preview mode    
01487             imageRect = self.pdcImage.GetIdBounds(self.imageId)
01488             imageRect.OffsetXY(-view[0], -view[1])
01489             imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
01490             self.DrawImage(imageRect)
01491         
01492     def ZoomAll(self):
01493         """! Zoom to full extent"""  
01494         if not self.preview:
01495             bounds = self.pdcPaper.GetIdBounds(self.pageId)
01496         else:
01497             bounds = self.pdcImage.GetIdBounds(self.imageId)
01498         zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
01499         zoomFactor, view = self.ComputeZoom(zoomP)
01500         self.Zoom(zoomFactor, view)
01501         
01502     def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0)): 
01503         """! Draw object"""    
01504         if drawid is None:
01505             drawid = wx.NewId()
01506         bb = bb.Get()
01507         pdc.BeginDrawing()
01508         pdc.RemoveId(drawid)
01509         pdc.SetId(drawid)
01510         pdc.SetPen(pen)
01511         pdc.SetBrush(brush)
01512         if pdctype in ('rect', 'rectText'):
01513             pdc.DrawRectangle(*bb)
01514         if pdctype == 'rectText':
01515             dc = wx.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
01516             font = self.font
01517             size = 10
01518             font.SetPointSize(size)
01519             font.SetStyle(wx.ITALIC)
01520             dc.SetFont(font)
01521             pdc.SetFont(font)
01522             text = '\n'.join(self.itemLabels[self.instruction[drawid].type])
01523             w,h,lh = dc.GetMultiLineTextExtent(text)
01524             textExtent = (w,h)
01525             textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
01526             r = map(int, bb)
01527             while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
01528                 size -= 2
01529                 font.SetPointSize(size)
01530                 dc.SetFont(font)
01531                 pdc.SetFont(font)
01532                 textExtent = dc.GetTextExtent(text)
01533                 textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
01534             pdc.SetTextForeground(wx.Color(100,100,100,200)) 
01535             pdc.SetBackgroundMode(wx.TRANSPARENT)
01536             pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
01537             
01538         pdc.SetIdBounds(drawid, bb)
01539         pdc.EndDrawing()
01540         self.Refresh()
01541 
01542         return drawid
01543     
01544     def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
01545         if textDict['rotate']:
01546             rot = float(textDict['rotate']) 
01547         else:
01548             rot = 0
01549         
01550         fontsize = textDict['fontsize'] * self.currScale
01551         if textDict['background'] != 'none':
01552             background = textDict['background'] 
01553         else:
01554             background = None
01555 
01556         pdc.RemoveId(drawId)
01557         pdc.SetId(drawId)
01558         pdc.BeginDrawing()
01559         
01560         # border is not redrawn when zoom changes, why?
01561 ##        if textDict['border'] != 'none' and not rot:
01562 ##            units = UnitConversion(self)
01563 ##            borderWidth = units.convert(value = textDict['width'],
01564 ##                                        fromUnit = 'point', toUnit = 'pixel' ) * self.currScale
01565 ##            pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth))
01566 ##            pdc.DrawRectangle(*bounds)
01567             
01568         if background:
01569             pdc.SetTextBackground(convertRGB(background))
01570             pdc.SetBackgroundMode(wx.SOLID)
01571         else:
01572             pdc.SetBackgroundMode(wx.TRANSPARENT)
01573         
01574         fn = self.parent.makePSFont(textDict)
01575         
01576         pdc.SetFont(fn)
01577         pdc.SetTextForeground(convertRGB(textDict['color']))        
01578         pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
01579         
01580         pdc.SetIdBounds(drawId, wx.Rect(*bounds))
01581         self.Refresh()
01582         pdc.EndDrawing()
01583         
01584     def DrawImage(self, rect):
01585         """!Draw preview image to pseudoDC"""
01586         self.pdcImage.ClearId(self.imageId)
01587         self.pdcImage.SetId(self.imageId)
01588         img = self.image
01589         
01590 
01591         if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
01592             img = img.Scale(rect.width, rect.height)
01593         bitmap = img.ConvertToBitmap()
01594         
01595         self.pdcImage.BeginDrawing()
01596         self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
01597         self.pdcImage.SetIdBounds(self.imageId, rect)
01598         self.pdcImage.EndDrawing()
01599         self.Refresh()
01600         
01601     def DrawPaper(self, rect):
01602         """!Draw paper and margins"""
01603         page = self.instruction[self.pageId]
01604         scale = page['Width'] / rect.GetWidth()
01605         w = (page['Width'] - page['Right'] - page['Left']) / scale
01606         h = (page['Height'] - page['Top'] - page['Bottom']) / scale
01607         x = page['Left'] / scale + rect.GetX()
01608         y = page['Top'] / scale + rect.GetY()
01609         
01610         self.pdcPaper.BeginDrawing()
01611         self.pdcPaper.RemoveId(self.pageId)
01612         self.pdcPaper.SetId(self.pageId)
01613         self.pdcPaper.SetPen(self.pen['paper'])
01614         self.pdcPaper.SetBrush(self.brush['paper'])
01615         self.pdcPaper.DrawRectangleRect(rect)
01616         
01617         self.pdcPaper.SetPen(self.pen['margins'])
01618         self.pdcPaper.SetBrush(self.brush['margins'])
01619         self.pdcPaper.DrawRectangle(x, y, w, h)
01620         
01621         self.pdcPaper.SetIdBounds(self.pageId, rect)
01622         self.pdcPaper.EndDrawing()
01623         self.Refresh()
01624 
01625         
01626     def ImageRect(self):
01627         """!Returns image centered in canvas, computes scale"""
01628         img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
01629         cW, cH = self.GetClientSize()
01630         iW, iH = img.GetWidth(), img.GetHeight()
01631 
01632         self.currScale = min(float(cW)/iW, float(cH)/iH)
01633         iW = iW * self.currScale
01634         iH = iH * self.currScale
01635         x = cW/2 - iW/2
01636         y = cH/2 - iH/2
01637         imageRect = wx.Rect(x, y, iW, iH)
01638 
01639         return imageRect 
01640     
01641     def RedrawSelectBox(self, id):
01642         """!Redraws select box when selected object changes its size"""
01643         if self.dragId == id:
01644             rect = [self.pdcObj.GetIdBounds(id).Inflate(3,3)]
01645             type = ['select']
01646             ids = [self.idBoxTmp]
01647             if self.instruction[id].type == 'map':
01648                 controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
01649                 rect.append(wx.Rect(controlP.x, controlP.y, 10,10))
01650                 type.append('resize')
01651                 ids.append(self.idResizeBoxTmp)
01652             for id, type, rect in zip(ids, type, rect):
01653                 self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcTmp,
01654                           drawid = id, pdctype = 'rect', bb = rect)
01655         
01656     def UpdateMapLabel(self):
01657         """!Updates map frame label"""
01658 
01659         vector = self.instruction.FindInstructionByType('vector')
01660         if vector:
01661             vectorId = vector.id 
01662         else:
01663             vectorId = None
01664 
01665         raster = self.instruction.FindInstructionByType('raster')
01666         if raster:
01667             rasterId = raster.id 
01668         else:
01669             rasterId = None
01670 
01671         rasterName = 'None'
01672         if rasterId:
01673             rasterName = self.instruction[rasterId]['raster'].split('@')[0]
01674             
01675         self.itemLabels['map'] = self.itemLabels['map'][0:1]
01676         self.itemLabels['map'].append("raster: " + rasterName)
01677         if vectorId: 
01678             for map in self.instruction[vectorId]['list']:
01679                 self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
01680             
01681     def OnSize(self, event):
01682         """!Init image size to match window size
01683         """
01684         # not zoom all when notebook page is changed
01685         if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
01686             self.ZoomAll()
01687         self.OnIdle(None)
01688         event.Skip()
01689         
01690     def OnIdle(self, event):
01691         """!Only re-render a image during idle time instead of
01692         multiple times during resizing.
01693         """ 
01694         
01695         width, height = self.GetClientSize()
01696         # Make new off screen bitmap: this bitmap will always have the
01697         # current drawing in it, so it can be used to save the image
01698         # to a file, or whatever.
01699         self._buffer = wx.EmptyBitmap(width, height)
01700         # re-render image on idle
01701         self.resize = True
01702         
01703     def ScaleRect(self, rect, scale):
01704         """! Scale rectangle"""
01705         return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
01706                        rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)   
01707     
01708 def main():
01709     app = wx.PySimpleApp()
01710     wx.InitAllImageHandlers()
01711     frame = PsMapFrame()
01712     frame.Show()
01713     
01714     app.MainLoop()
01715 
01716 if __name__ == "__main__":
01717     main()
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines