GRASS Programmer's Manual
6.4.2(2012)
|
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()