8 - frame::PsMapBufferedWindow
10 (C) 2011-2012 by Anna Kratochvilova, and the GRASS Development Team
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
14 @author Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
15 @author Martin Landa <landa.martin gmail.com> (mentor)
22 from math
import sin, cos, pi, sqrt
24 if __name__ ==
"__main__":
25 sys.path.append(os.path.join(os.getenv(
'GISBASE'),
'etc',
'gui',
'wxpython'))
26 from core
import globalvar
30 import wx.lib.agw.flatnotebook
as fnb
32 import wx.lib.flatnotebook
as fnb
39 from core.gcmd import RunCommand, GError, GMessage
41 from gui_core.forms
import GUI
43 from psmap.menudata
import PsMapData
50 def __init__(self, parent = None, id = wx.ID_ANY,
51 title = _(
"GRASS GIS Cartographic Composer (experimental prototype)"), **kwargs):
52 """!Main window of ps.map GUI
54 @param parent parent window
56 @param title window title
58 @param kwargs wx.Frames' arguments
62 wx.Frame.__init__(self, parent = parent, id = id, title = title, name =
"PsMap", **kwargs)
63 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
65 self.
menubar = Menu(parent = self, data = PsMapData())
69 self.
toolbar = PsMapToolbar(parent = self)
86 "default" : wx.StockCursor(wx.CURSOR_ARROW),
87 "cross" : wx.StockCursor(wx.CURSOR_CROSS),
88 "hand" : wx.StockCursor(wx.CURSOR_HAND),
89 "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
93 'paper': wx.Pen(colour =
"BLACK", width = 1),
94 'margins': wx.Pen(colour =
"GREY", width = 1),
95 'map': wx.Pen(colour = wx.Colour(86, 122, 17), width = 2),
96 'rasterLegend': wx.Pen(colour = wx.Colour(219, 216, 4), width = 2),
97 'vectorLegend': wx.Pen(colour = wx.Colour(219, 216, 4), width = 2),
98 'mapinfo': wx.Pen(colour = wx.Colour(5, 184, 249), width = 2),
99 'scalebar': wx.Pen(colour = wx.Colour(150, 150, 150), width = 2),
100 'image': wx.Pen(colour = wx.Colour(255, 150, 50), width = 2),
101 'northArrow': wx.Pen(colour = wx.Colour(200, 200, 200), width = 2),
102 'point': wx.Pen(colour = wx.Colour(100, 100, 100), width = 2),
103 'line': wx.Pen(colour = wx.Colour(0, 0, 0), width = 2),
104 'box': wx.Pen(colour =
'RED', width = 2, style = wx.SHORT_DASH),
105 'select': wx.Pen(colour =
'BLACK', width = 1, style = wx.SHORT_DASH),
106 'resize': wx.Pen(colour =
'BLACK', width = 1)
109 'paper': wx.WHITE_BRUSH,
110 'margins': wx.TRANSPARENT_BRUSH,
111 'map': wx.Brush(wx.Colour(151, 214, 90)),
112 'rasterLegend': wx.Brush(wx.Colour(250, 247, 112)),
113 'vectorLegend': wx.Brush(wx.Colour(250, 247, 112)),
114 'mapinfo': wx.Brush(wx.Colour(127, 222, 252)),
115 'scalebar': wx.Brush(wx.Colour(200, 200, 200)),
116 'image': wx.Brush(wx.Colour(255, 200, 50)),
117 'northArrow': wx.Brush(wx.Colour(255, 255, 255)),
118 'point': wx.Brush(wx.Colour(200, 200, 200)),
119 'line': wx.TRANSPARENT_BRUSH,
120 'box': wx.TRANSPARENT_BRUSH,
121 'select':wx.TRANSPARENT_BRUSH,
122 'resize': wx.BLACK_BRUSH
144 self.canvas.SetCursor(self.
cursors[
"default"])
154 pen = self.
pen, brush = self.
brush, preview =
True)
157 grass.use_temp_region()
166 self.SetMinSize(wx.Size(750, 600))
168 self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
169 self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
170 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
176 def _showErrMsg(self):
177 """!Show error message (missing preview)
179 GError(parent = self,
180 message = _(
"Python Imaging Library is not available.\n"
181 "'Preview' functionality won't work."),
182 showTraceback =
False)
187 mainSizer = wx.BoxSizer(wx.VERTICAL)
189 self.
book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
190 agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
191 fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
193 self.
book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
194 style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
195 fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
197 self.book.AddPage(self.
canvas,
"Draft mode")
199 self.book.SetSelection(0)
201 mainSizer.Add(self.
book,1, wx.EXPAND)
203 self.SetSizer(mainSizer)
208 """!Creates mapping instructions"""
213 """!Generate PostScript"""
214 filename = self.
getFile(wildcard =
"PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
219 """!Launch ps.map dialog
221 GUI(parent = self).ParseCommand(cmd = [
'ps.map'])
224 """!Generate PDF from PS with ps2pdf if available"""
225 if not sys.platform ==
'win32':
227 p = grass.Popen([
"ps2pdf"], stderr = grass.PIPE)
231 GMessage(parent = self,
232 message = _(
"Program ps2pdf is not available. Please install it first to create PDF."))
235 filename = self.
getFile(wildcard =
"PDF (*.pdf)|*.pdf")
237 self.
PSFile(filename, pdf =
True)
240 """!Run ps.map and show result"""
243 def PSFile(self, filename = None, pdf = False):
244 """!Create temporary instructions file and run ps.map with output = filename"""
245 instrFile = grass.tempfile()
246 instrFileFd = open(instrFile, mode =
'w')
252 regOld = grass.region()
259 if not filename
or (filename
and pdf):
261 filename = grass.tempfile()
263 if self.instruction.FindInstructionByType(
'map'):
264 mapId = self.instruction.FindInstructionByType(
'map').id
268 cmd = [
'ps.map',
'--overwrite']
269 if os.path.splitext(filename)[1] ==
'.eps':
273 cmd.append(
'input=%s' % instrFile)
274 cmd.append(
'output=%s' % filename)
276 self.SetStatusText(_(
'Generating PDF...'), 0)
278 self.SetStatusText(_(
'Generating PostScript...'), 0)
280 self.SetStatusText(_(
'Generating preview...'), 0)
282 self.cmdThread.RunCmd(cmd, userData = {
'instrFile' : instrFile,
'filename' : filename,
283 'pdfname' : pdfname,
'temp' : temp,
'regionOld' : regOld})
286 """!ps.map process finished"""
288 if event.returncode != 0:
289 GMessage(parent = self,
290 message = _(
"Ps.map exited with return code %s") % event.returncode)
292 grass.try_remove(event.userData[
'instrFile'])
293 if event.userData[
'temp']:
294 grass.try_remove(event.userData[
'filename'])
297 if event.userData[
'pdfname']:
298 if sys.platform ==
'win32':
299 command = [
'gswin32c',
301 '-dCompatibilityLevel=1.4',
303 '-dNOPAUSE',
'-dBATCH',
305 '-dPDFSETTINGS=/prepress',
'-r1200',
307 '-sOutputFile=%s' % event.userData[
'pdfname'],
309 '-dCompatibilityLevel=1.4',
310 '-c',
'.setpdfwrite',
'-f',
311 event.userData[
'filename']]
313 command = [
'ps2pdf',
'-dPDFSETTINGS=/prepress',
'-r1200',
314 event.userData[
'filename'], event.userData[
'pdfname']]
316 proc = grass.Popen(command)
319 GMessage(parent = self,
320 message = _(
"%(prg)s exited with return code %(code)s") % {
'prg': command[0],
323 self.SetStatusText(_(
'PDF generated'), 0)
325 GError(parent = self,
326 message = _(
"Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
328 elif not event.userData[
'temp']:
329 self.SetStatusText(_(
'PostScript file generated'), 0)
332 if havePILImage
and event.userData[
'temp']
and not event.userData[
'pdfname']:
333 RunCommand(
'g.region', cols = event.userData[
'regionOld'][
'cols'], rows = event.userData[
'regionOld'][
'rows'])
335 busy = wx.BusyInfo(message = _(
"Generating preview, wait please"), parent = self)
338 im = PILImage.open(event.userData[
'filename'])
343 if sys.platform ==
'win32':
345 im.load = types.MethodType(loadPSForWindows, im)
346 im.save(self.
imgName, format =
'PNG')
349 dlg = HyperlinkDialog(self, title=_(
"Preview not available"),
350 message=_(
"Preview is not available probably due to missing Ghostscript."),
351 hyperlink=
'http://trac.osgeo.org/grass/wiki/CompileOnWindows#Ghostscript',
352 hyperlinkLabel=_(
"Please follow instructions on GRASS Trac Wiki."))
358 rect = self.previewCanvas.ImageRect()
359 self.previewCanvas.image = wx.Image(self.
imgName, wx.BITMAP_TYPE_PNG)
360 self.previewCanvas.DrawImage(rect = rect)
363 self.SetStatusText(_(
'Preview generated'), 0)
364 self.book.SetSelection(1)
367 grass.try_remove(event.userData[
'instrFile'])
368 if event.userData[
'temp']:
369 grass.try_remove(event.userData[
'filename'])
371 self.
delayedCall = wx.CallLater(4000,
lambda: self.SetStatusText(
"", 0))
375 for filter
in wildcard.split(
'|')[1::2]:
376 s = filter.strip(
'*').
split(
'.')[1]
380 raster = self.instruction.FindInstructionByType(
'raster')
387 if rasterId
and self.
instruction[rasterId][
'raster']:
393 dlg = wx.FileDialog(self, message = _(
"Save file as"), defaultDir =
"",
394 defaultFile = mapName, wildcard = wildcard,
395 style = wx.CHANGE_DIR | wx.SAVE | wx.OVERWRITE_PROMPT)
396 if dlg.ShowModal() == wx.ID_OK:
397 filename = dlg.GetPath()
398 suffix = suffix[dlg.GetFilterIndex()]
399 if not os.path.splitext(filename)[1]:
400 filename = filename + suffix
401 elif os.path.splitext(filename)[1] != suffix
and suffix !=
'':
402 filename = os.path.splitext(filename)[0] + suffix
408 filename = self.
getFile(wildcard =
"*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")
410 instrFile = open(filename,
"w")
415 """!Load file and read instructions"""
418 dlg = wx.FileDialog(self, message =
"Find instructions file", defaultDir =
"",
419 defaultFile =
'', wildcard =
"All files (*.*)|*.*",
420 style = wx.CHANGE_DIR|wx.OPEN)
421 if dlg.ShowModal() == wx.ID_OK:
422 filename = dlg.GetPath()
428 readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
429 ok = readInstruction.Read(filename)
431 GMessage(_(
"Failed to read file %s.") % filename)
433 self.
instruction = self.canvas.instruction = readInstruction
434 self.
objectId = self.canvas.objectId = readObjectId
435 self.
pageId = self.canvas.pageId = self.instruction.FindInstructionByType(
'page').id
436 self.canvas.UpdateMapLabel()
437 self.canvas.dragId = -1
439 self.canvas.SetPage()
442 self.DialogDataChanged(self.
objectId)
445 """!Specify paper size, margins and orientation"""
446 id = self.instruction.FindInstructionByType(
'page').id
447 dlg = PageSetupDialog(self, id = id, settings = self.
instruction)
449 val = dlg.ShowModal()
451 self.canvas.SetPage()
453 self.canvas.RecalculatePosition(ids = self.
objectId)
457 self.toolbar.OnTool(event)
458 self.
mouse[
"use"] =
"pointer"
459 self.canvas.SetCursor(self.
cursors[
"default"])
460 self.previewCanvas.SetCursor(self.
cursors[
"default"])
463 self.toolbar.OnTool(event)
464 self.
mouse[
"use"] =
"pan"
465 self.canvas.SetCursor(self.
cursors[
"hand"])
466 self.previewCanvas.SetCursor(self.
cursors[
"hand"])
469 self.toolbar.OnTool(event)
470 self.
mouse[
"use"] =
"zoomin"
471 self.canvas.SetCursor(self.
cursors[
"cross"])
472 self.previewCanvas.SetCursor(self.
cursors[
"cross"])
475 self.toolbar.OnTool(event)
476 self.
mouse[
"use"] =
"zoomout"
477 self.canvas.SetCursor(self.
cursors[
"cross"])
478 self.previewCanvas.SetCursor(self.
cursors[
"cross"])
485 self.
cursorOld = self.previewCanvas.GetCursor()
486 self.previewCanvas.GetCursor()
487 self.
mouse[
"use"] =
"zoomin"
489 self.canvas.ZoomAll()
491 self.previewCanvas.ZoomAll()
496 self.previewCanvas.SetCursor(self.
cursorOld)
500 """!Add or edit map frame"""
501 if event
is not None:
502 if event.GetId() != self.toolbar.action[
'id']:
503 self.
actionOld = self.toolbar.action[
'id']
506 self.toolbar.OnTool(event)
508 if self.instruction.FindInstructionByType(
'map'):
509 mapId = self.instruction.FindInstructionByType(
'map').id
511 id = [mapId,
None,
None]
514 if self.instruction.FindInstructionByType(
'vector'):
515 vectorId = self.instruction.FindInstructionByType(
'vector').id
516 else: vectorId =
None
517 if self.instruction.FindInstructionByType(
'raster'):
518 rasterId = self.instruction.FindInstructionByType(
'raster').id
519 else: rasterId =
None
526 self.toolbar.ToggleTool(self.
actionOld,
True)
527 self.toolbar.ToggleTool(self.toolbar.action[
'id'],
False)
528 self.toolbar.action[
'id'] = self.
actionOld
531 except AttributeError:
547 dlg = MapDialog(parent = self, id = id, settings = self.instruction,
549 self.openDialogs[
'mapNotebook'] = dlg
550 self.openDialogs[
'mapNotebook'].Show()
552 if 'mapNotebook' in self.openDialogs:
553 self.openDialogs[
'mapNotebook'].notebook.ChangeSelection(0)
555 if 'map' not in self.openDialogs:
556 dlg = MapDialog(parent = self, id = id, settings = self.instruction,
558 self.openDialogs[
'map'] = dlg
559 self.openDialogs[
'map'].Show()
563 self.mouse[
"use"] =
"addMap"
564 self.canvas.SetCursor(self.cursors[
"cross"])
565 if self.currentPage == 1:
566 self.book.SetSelection(0)
570 """!Add raster map"""
571 if self.instruction.FindInstructionByType(
'raster'):
572 id = self.instruction.FindInstructionByType(
'raster').id
574 if self.instruction.FindInstructionByType(
'map'):
575 mapId = self.instruction.FindInstructionByType(
'map').id
580 GMessage(message = _(
"Please, create map frame first."))
585 if 'mapNotebook' in self.openDialogs:
586 self.openDialogs[
'mapNotebook'].notebook.ChangeSelection(1)
588 if 'raster' not in self.openDialogs:
589 dlg = RasterDialog(self, id = id, settings = self.instruction)
590 self.openDialogs[
'raster'] = dlg
591 self.openDialogs[
'raster'].Show()
594 """!Add vector map"""
595 if self.instruction.FindInstructionByType(
'vector'):
596 id = self.instruction.FindInstructionByType(
'vector').id
598 if self.instruction.FindInstructionByType(
'map'):
599 mapId = self.instruction.FindInstructionByType(
'map').id
603 GMessage(message = _(
"Please, create map frame first."))
608 if 'mapNotebook' in self.openDialogs:
609 self.openDialogs[
'mapNotebook'].notebook.ChangeSelection(2)
611 if 'vector' not in self.openDialogs:
612 dlg = MainVectorDialog(self, id = id, settings = self.instruction)
613 self.openDialogs[
'vector'] = dlg
614 self.openDialogs[
'vector'].Show()
619 GMessage(message = _(
"Scalebar is not appropriate for this projection"))
621 if self.instruction.FindInstructionByType(
'scalebar'):
622 id = self.instruction.FindInstructionByType(
'scalebar').id
625 if 'scalebar' not in self.openDialogs:
626 dlg = ScalebarDialog(self, id = id, settings = self.instruction)
627 self.openDialogs[
'scalebar'] = dlg
628 self.openDialogs[
'scalebar'].Show()
631 """!Add raster or vector legend"""
632 if self.instruction.FindInstructionByType(
'rasterLegend'):
633 idR = self.instruction.FindInstructionByType(
'rasterLegend').id
635 if self.instruction.FindInstructionByType(
'vectorLegend'):
636 idV = self.instruction.FindInstructionByType(
'vectorLegend').id
639 if 'rasterLegend' not in self.openDialogs:
640 dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
641 self.openDialogs[
'rasterLegend'] = dlg
642 self.openDialogs[
'vectorLegend'] = dlg
643 self.openDialogs[
'rasterLegend'].notebook.ChangeSelection(page)
644 self.openDialogs[
'rasterLegend'].Show()
647 if self.instruction.FindInstructionByType(
'mapinfo'):
648 id = self.instruction.FindInstructionByType(
'mapinfo').id
651 if 'mapinfo' not in self.openDialogs:
652 dlg = MapinfoDialog(self, id = id, settings = self.instruction)
653 self.openDialogs[
'mapinfo'] = dlg
654 self.openDialogs[
'mapinfo'].Show()
657 """!Show dialog for image adding and editing"""
659 if 'image' in self.openDialogs:
660 position = self.openDialogs[
'image'].GetPosition()
661 self.openDialogs[
'image'].
OnApply(event =
None)
662 self.openDialogs[
'image'].Destroy()
663 dlg = ImageDialog(self, id = id, settings = self.instruction)
664 self.openDialogs[
'image'] = dlg
666 dlg.SetPosition(position)
670 """!Show dialog for north arrow adding and editing"""
671 if self.instruction.FindInstructionByType(
'northArrow'):
672 id = self.instruction.FindInstructionByType(
'northArrow').id
675 if 'northArrow' not in self.openDialogs:
676 dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
677 self.openDialogs[
'northArrow'] = dlg
678 self.openDialogs[
'northArrow'].Show()
681 """!Show dialog for text adding and editing"""
683 if 'text' in self.openDialogs:
684 position = self.openDialogs[
'text'].GetPosition()
685 self.openDialogs[
'text'].
OnApply(event =
None)
686 self.openDialogs[
'text'].Destroy()
687 dlg = TextDialog(self, id = id, settings = self.instruction)
688 self.openDialogs[
'text'] = dlg
690 dlg.SetPosition(position)
694 """!Add point action selected"""
695 self.mouse[
"use"] =
"addPoint"
696 self.canvas.SetCursor(self.cursors[
"cross"])
699 """!Add point and open property dialog.
701 @param id id point id (None if creating new point)
702 @param coordinates coordinates of new point
705 if 'point' in self.openDialogs:
706 position = self.openDialogs[
'point'].GetPosition()
707 self.openDialogs[
'point'].
OnApply(event =
None)
708 self.openDialogs[
'point'].Destroy()
709 dlg = PointDialog(self, id = id, settings = self.instruction,
710 coordinates = coordinates)
711 self.openDialogs[
'point'] = dlg
713 dlg.SetPosition(position)
715 dlg.OnApply(event =
None)
719 """!Add line action selected"""
720 self.mouse[
"use"] =
"addLine"
721 self.canvas.SetCursor(self.cursors[
"cross"])
723 def AddLine(self, id = None, coordinates = None):
724 """!Add line and open property dialog.
726 @param id id line id (None if creating new line)
727 @param coordinates coordinates of new line
730 if 'line' in self.openDialogs:
731 position = self.openDialogs[
'line'].GetPosition()
732 self.openDialogs[
'line'].
OnApply(event =
None)
733 self.openDialogs[
'line'].Destroy()
734 dlg = RectangleDialog(self, id = id, settings = self.instruction,
735 type =
'line', coordinates = coordinates)
736 self.openDialogs[
'line'] = dlg
738 dlg.SetPosition(position)
740 dlg.OnApply(event =
None)
744 """!Add rectangle action selected"""
745 self.mouse[
"use"] =
"addRectangle"
746 self.canvas.SetCursor(self.cursors[
"cross"])
749 """!Add rectangle and open property dialog.
751 @param id id rectangle id (None if creating new rectangle)
752 @param coordinates coordinates of new rectangle
755 if 'rectangle' in self.openDialogs:
756 position = self.openDialogs[
'rectangle'].GetPosition()
757 self.openDialogs[
'rectangle'].
OnApply(event =
None)
758 self.openDialogs[
'rectangle'].Destroy()
759 dlg = RectangleDialog(self, id = id, settings = self.instruction,
760 type =
'rectangle', coordinates = coordinates)
761 self.openDialogs[
'rectangle'] = dlg
763 dlg.SetPosition(position)
765 dlg.OnApply(event =
None)
769 """!computes bounding box of rotated text, not very precisely"""
771 rotation = float(rotation)/180*pi
772 H = float(w) * sin(rotation)
773 W = float(w) * cos(rotation)
775 if pi/2 < rotation <= 3*pi/2:
777 if 0 < rotation < pi:
780 return wx.Rect(x,y, *textExtent)
782 return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h)
785 """!creates a wx.Font object from selected postscript font. To be
786 used for estimating bounding rectangle of text"""
788 fontsize = textDict[
'fontsize'] * self.canvas.currScale
789 fontface = textDict[
'font'].
split(
'-')[0]
791 fontstyle = textDict[
'font'].
split(
'-')[1]
795 if fontface ==
"Times":
796 family = wx.FONTFAMILY_ROMAN
798 elif fontface ==
"Helvetica":
799 family = wx.FONTFAMILY_SWISS
801 elif fontface ==
"Courier":
802 family = wx.FONTFAMILY_TELETYPE
805 family = wx.FONTFAMILY_DEFAULT
808 style = wx.FONTSTYLE_NORMAL
809 weight = wx.FONTWEIGHT_NORMAL
811 if 'Oblique' in fontstyle:
812 style = wx.FONTSTYLE_SLANT
814 if 'Italic' in fontstyle:
815 style = wx.FONTSTYLE_ITALIC
817 if 'Bold' in fontstyle:
818 weight = wx.FONTWEIGHT_BOLD
821 fn = wx.Font(pointSize = fontsize, family = family, style = style,
822 weight = weight, face = face)
824 fn = wx.Font(pointSize = fontsize, family = wx.FONTFAMILY_DEFAULT,
825 style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL)
831 """!Estimates bounding rectangle of text"""
833 dc = wx.ClientDC(self)
835 fn = self.makePSFont(textDict)
839 w,h,lh = dc.GetMultiLineTextExtent(textDict[
'text'])
845 """!Create default map frame when no map is selected, needed for coordinates in map units"""
846 instrFile = grass.tempfile()
847 instrFileFd = open(instrFile, mode =
'w')
848 instrFileFd.write(self.InstructionFile())
852 page = self.instruction.FindInstructionByType(
'page')
853 mapInitRect =
GetMapBounds(instrFile, portrait = (page[
'Orientation'] ==
'Portrait'))
854 grass.try_remove(instrFile)
856 region = grass.region()
857 units = UnitConversion(self)
858 realWidth = units.convert(value = abs(region[
'w'] - region[
'e']), fromUnit =
'meter', toUnit =
'inch')
859 scale = mapInitRect.Get()[2]/realWidth
861 initMap = self.instruction.FindInstructionByType(
'initMap')
870 initMap = InitMap(id)
871 self.instruction.AddInstruction(initMap)
872 self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
875 if self.canvas.dragId != -1
and self.currentPage == 0:
876 if self.instruction[self.canvas.dragId].type ==
'map':
877 self.deleteObject(self.canvas.dragId)
879 self.canvas.RecalculateEN()
881 self.deleteObject(self.canvas.dragId)
884 """!Deletes object, his id and redraws"""
886 self.canvas.pdcObj.RemoveId(id)
887 if id == self.canvas.dragId:
888 self.canvas.pdcTmp.RemoveAll()
889 self.canvas.dragId = -1
890 self.canvas.Refresh()
893 del self.instruction[id]
900 itype = self.instruction[id].type
902 if itype
in (
'scalebar',
'mapinfo',
'image'):
903 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'], canvasToPaper =
False)
904 self.canvas.UpdateLabel(itype = itype, id = id)
905 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
906 pdc = self.canvas.pdcObj, drawid = id, pdctype =
'rectText', bb = drawRectangle)
907 self.canvas.RedrawSelectBox(id)
908 if itype ==
'northArrow':
909 self.canvas.UpdateLabel(itype = itype, id = id)
910 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'], canvasToPaper =
False)
911 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
912 pdc = self.canvas.pdcObj, drawid = id, pdctype =
'bitmap', bb = drawRectangle)
913 self.canvas.RedrawSelectBox(id)
915 if itype
in (
'point',
'line',
'rectangle'):
916 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'], canvasToPaper =
False)
920 point1 = self.instruction[id][
'where'][0]
921 point2 = self.instruction[id][
'where'][1]
922 point1Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)), canvasToPaper =
False)[:2]
923 point2Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)), canvasToPaper =
False)[:2]
924 coords = (point1Coords, point2Coords)
928 if 'fcolor' in self.instruction[id].GetInstruction():
929 fcolor = self.instruction[id][
'fcolor']
932 if 'width' in self.instruction[id].GetInstruction():
933 width = self.instruction[id][
'width']
935 self.canvas.DrawGraphics(drawid = id, color = self.instruction[id][
'color'], shape = itype,
936 fcolor = fcolor, width = width, bb = drawRectangle, lineCoords = coords)
938 self.canvas.RedrawSelectBox(id)
942 if self.instruction[id][
'rotate']:
943 rot = float(self.instruction[id][
'rotate'])
947 extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
948 rect = Rect2DPS(self.instruction[id][
'where'], (0, 0))
949 self.instruction[id][
'coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper =
False)[:2])
952 if self.instruction[id][
'ref'].
split()[0] ==
'lower':
953 self.instruction[id][
'coords'][1] -= extent[1]
954 elif self.instruction[id][
'ref'].
split()[0] ==
'center':
955 self.instruction[id][
'coords'][1] -= extent[1]/2
956 if self.instruction[id][
'ref'].
split()[1] ==
'right':
957 self.instruction[id][
'coords'][0] -= extent[0] * cos(rot/180*pi)
958 self.instruction[id][
'coords'][1] += extent[0] * sin(rot/180*pi)
959 elif self.instruction[id][
'ref'].
split()[1] ==
'center':
960 self.instruction[id][
'coords'][0] -= extent[0]/2 * cos(rot/180*pi)
961 self.instruction[id][
'coords'][1] += extent[0]/2 * sin(rot/180*pi)
963 self.instruction[id][
'coords'][0] += self.instruction[id][
'xoffset']
964 self.instruction[id][
'coords'][1] -= self.instruction[id][
'yoffset']
965 coords = self.instruction[id][
'coords']
966 self.instruction[id][
'rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
967 self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
968 textDict = self.instruction[id].GetInstruction(),
969 coords = coords, bounds = bounds)
970 self.canvas.RedrawSelectBox(id)
972 if itype
in (
'map',
'vector',
'raster'):
974 if itype ==
'raster':
975 info = grass.raster_info(self.instruction[id][
'raster'])
976 RunCommand(
'g.region', nsres = info[
'nsres'], ewres = info[
'ewres'])
979 if 'rasterLegend' in self.openDialogs:
981 id = self.instruction.FindInstructionByType(
'map').id
984 if itype ==
'raster':
986 width = self.instruction[id][
'rect'].width,
987 height = self.instruction[id][
'rect'].height)
988 rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'],
989 canvasToPaper =
False)
990 self.canvas.RecalculateEN()
991 self.canvas.UpdateMapLabel()
993 self.canvas.Draw(pen = self.pen[
'map'], brush = self.brush[
'map'],
994 pdc = self.canvas.pdcObj, drawid = id, pdctype =
'rectText', bb = rectCanvas)
996 self.canvas.RedrawSelectBox(id)
997 self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
1001 if itype ==
'rasterLegend':
1002 if self.instruction[id][
'rLegend']:
1003 self.canvas.UpdateLabel(itype = itype, id = id)
1004 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'], canvasToPaper =
False)
1005 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
1006 pdc = self.canvas.pdcObj, drawid = id, pdctype =
'rectText', bb = drawRectangle)
1007 self.canvas.RedrawSelectBox(id)
1009 self.deleteObject(id)
1011 if itype ==
'vectorLegend':
1012 if not self.instruction.FindInstructionByType(
'vector'):
1013 self.deleteObject(id)
1014 elif self.instruction[id][
'vLegend']:
1015 self.canvas.UpdateLabel(itype = itype, id = id)
1016 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id][
'rect'], canvasToPaper =
False)
1017 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
1018 pdc = self.canvas.pdcObj, drawid = id, pdctype =
'rectText', bb = drawRectangle)
1019 self.canvas.RedrawSelectBox(id)
1022 self.deleteObject(id)
1025 """!Flatnotebook page has changed"""
1026 self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
1027 if self.currentPage == 1:
1028 self.SetStatusText(_(
"Press button with green triangle icon to generate preview."))
1030 self.SetStatusText(
'')
1035 """!Flatnotebook page is changing"""
1036 if self.currentPage == 0
and self.mouse[
'use'] ==
'addMap':
1041 if self.parent
and self.parent.GetName() ==
'LayerManager':
1042 log = self.parent.GetLogWindow()
1043 log.RunCmd([
'g.manual',
1044 'entry=wxGUI.PsMap'])
1048 entry =
'wxGUI.PsMap')
1051 """!Display About window"""
1052 info = wx.AboutDialogInfo()
1054 info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
1055 info.SetName(_(
'wxGUI Cartographic Composer'))
1056 info.SetWebSite(
'http://grass.osgeo.org')
1057 info.SetDescription(_(
'(C) 2011 by the GRASS Development Team\n\n') +
1058 '\n'.join(textwrap.wrap(_(
'This program is free software under the GNU General Public License'
1059 '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
1066 os.remove(self.imgName)
1069 grass.set_raise_on_error(
False)
1070 if hasattr(self,
'delayedCall')
and self.delayedCall.IsRunning():
1071 self.delayedCall.Stop()
1077 """!A buffered window class.
1079 @param parent parent window
1080 @param kwargs other wx.Window parameters
1082 def __init__(self, parent, id = wx.ID_ANY,
1083 style = wx.NO_FULL_REPAINT_ON_RESIZE,
1085 wx.Window.__init__(self, parent, id = id, style = style)
1101 if kwargs.has_key(
'instruction'):
1103 if kwargs.has_key(
'openDialogs'):
1105 if kwargs.has_key(
'pageId'):
1107 if kwargs.has_key(
'objectId'):
1113 'rasterLegend':
'RASTER LEGEND',
1114 'vectorLegend':
'VECTOR LEGEND',
1115 'mapinfo':
'MAP INFO',
1116 'scalebar':
'SCALE BAR',
1118 'northArrow':
'NORTH ARROW'}
1128 self.SetClientSize((700,510))
1129 self.
_buffer = wx.EmptyBitmap(*self.GetClientSize())
1154 self.Bind(wx.EVT_ERASE_BACKGROUND,
lambda x:
None)
1156 self.Bind(wx.EVT_PAINT, self.
OnPaint)
1157 self.Bind(wx.EVT_SIZE, self.OnSize)
1158 self.Bind(wx.EVT_IDLE, self.OnIdle)
1164 """!Clear canvas and set paper
1166 bg = wx.LIGHT_GREY_BRUSH
1167 self.pdcPaper.BeginDrawing()
1168 self.pdcPaper.SetBackground(bg)
1169 self.pdcPaper.Clear()
1170 self.pdcPaper.EndDrawing()
1172 self.pdcObj.RemoveAll()
1173 self.pdcTmp.RemoveAll()
1182 """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
1184 units = UnitConversion(self)
1188 pRect = self.pdcPaper.GetIdBounds(self.
pageId)
1189 pRectx, pRecty = pRect.x, pRect.y
1191 if not canvasToPaper:
1195 pRectx = units.convert(value = - pRect.x, fromUnit =
'pixel', toUnit =
'inch' ) /scale
1196 pRecty = units.convert(value = - pRect.y, fromUnit =
'pixel', toUnit =
'inch' ) /scale
1197 Width = units.convert(value = rect.GetWidth(), fromUnit = fromU, toUnit = toU) * scale
1198 Height = units.convert(value = rect.GetHeight(), fromUnit = fromU, toUnit = toU) * scale
1199 X = units.convert(value = (rect.GetX() - pRectx), fromUnit = fromU, toUnit = toU) * scale
1200 Y = units.convert(value = (rect.GetY() - pRecty), fromUnit = fromU, toUnit = toU) * scale
1202 return Rect2D(X, Y, Width, Height)
1207 """!Sets and changes page, redraws paper"""
1211 page = PageSetup(id = self.
pageId)
1212 self.instruction.AddInstruction(page)
1214 ppi = wx.ClientDC(self).GetPPI()
1215 cW, cH = self.GetClientSize()
1216 pW, pH = page[
'Width']*ppi[0], page[
'Height']*ppi[1]
1225 self.DrawPaper(wx.Rect(x, y, pW, pH))
1229 """! Recalculates rectangle not to have negative size"""
1230 if r.GetWidth() < 0:
1231 r.SetX(r.GetX() + r.GetWidth())
1232 if r.GetHeight() < 0:
1233 r.SetY(r.GetY() + r.GetHeight())
1234 r.SetWidth(abs(r.GetWidth()))
1235 r.SetHeight(abs(r.GetHeight()))
1239 """!Recalculate east and north for texts (eps, points) after their or map's movement"""
1241 mapId = self.instruction.FindInstructionByType(
'map').id
1242 except AttributeError:
1243 mapId = self.instruction.FindInstructionByType(
'initMap').id
1245 for itemType
in (
'text',
'image',
'northArrow',
'point',
'line',
'rectangle'):
1246 items = self.instruction.FindInstructionByType(itemType, list =
True)
1249 if itemType
in (
'line',
'rectangle'):
1250 if itemType ==
'line':
1252 y = instr[
'where'][0][1], paperToMap =
True)
1254 y = instr[
'where'][1][1], paperToMap =
True)
1257 y = instr[
'rect'].GetTop(), paperToMap =
True)
1259 y = instr[
'rect'].GetBottom(), paperToMap =
True)
1261 instr[
'north1'] = n1
1263 instr[
'north2'] = n2
1266 y = instr[
'where'][1], paperToMap =
True)
1267 instr[
'east'], instr[
'north'] = e, n
1270 """!Draw pseudo DC to buffer
1274 dc = wx.BufferedPaintDC(self, self.
_buffer)
1279 dc.SetBackground(wx.LIGHT_GREY_BRUSH)
1284 self.pdcPaper.DrawToDC(dc)
1287 rgn = self.GetUpdateRegion()
1290 self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
1292 self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
1293 self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
1296 """!Mouse motion and button click notifier
1299 if event.GetWheelRotation() != 0:
1303 elif event.LeftDown():
1307 elif event.LeftUp():
1311 elif event.Dragging():
1315 elif event.ButtonDClick():
1319 elif event.MiddleDown():
1322 elif event.Moving():
1326 """!Mouse wheel scrolled.
1329 if UserSettings.Get(group =
'display',
1330 key =
'mouseWheelZoom',
1331 subkey =
'selection') == 2:
1335 zoom = event.GetWheelRotation()
1336 oldUse = self.
mouse[
'use']
1337 self.
mouse[
'begin'] = event.GetPosition()
1339 if UserSettings.Get(group =
'display',
1340 key =
'scrollDirection',
1341 subkey =
'selection'):
1345 self.
mouse[
'use'] =
'zoomin'
1347 self.
mouse[
'use'] =
'zoomout'
1349 zoomFactor, view = self.
ComputeZoom(wx.Rect(0, 0, 0, 0))
1350 self.
Zoom(zoomFactor, view)
1351 self.
mouse[
'use'] = oldUse
1354 """!Mouse cursor moving.
1356 Change cursor when moving over resize marker.
1361 if self.
mouse[
'use']
in (
'pointer',
'resize'):
1362 pos = event.GetPosition()
1363 foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
1365 self.SetCursor(self.
cursors[
"sizenwse"])
1366 self.parent.SetStatusText(_(
'Click and drag to resize object'), 0)
1370 self.parent.SetStatusText(
'', 0)
1371 self.SetCursor(self.
cursors[
"default"])
1375 """!Left mouse button pressed.
1377 Select objects, redraw, prepare for moving/resizing.
1379 self.
mouse[
'begin'] = event.GetPosition()
1383 if self.
mouse[
'use'] ==
'pointer':
1384 found = self.pdcObj.FindObjects(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1])
1385 foundResize = self.pdcTmp.FindObjects(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1])
1388 self.
mouse[
'use'] =
'resize'
1403 self.RedrawSelectBox(self.
dragId)
1409 self.pdcTmp.RemoveId(id)
1414 self.pdcTmp.RemoveId(self.
idBoxTmp)
1417 self.pdcTmp.RemoveId(id)
1421 """!Left mouse button released.
1423 Recalculate zooming/resizing/moving and redraw.
1426 if self.
mouse[
'use']
in (
'zoomin',
'zoomout'):
1431 self.
Zoom(zoomFactor, view)
1434 if self.
mouse[
'use'] ==
'addMap':
1437 if rectTmp.GetWidth() < 20
or rectTmp.GetHeight() < 20:
1443 dlg = MapDialog(parent = self.
parent, id = [
None,
None,
None], settings = self.
instruction,
1448 self.
mouse[
'use'] = self.parent.mouseOld
1450 self.SetCursor(self.parent.cursorOld)
1451 self.parent.toolbar.ToggleTool(self.parent.actionOld,
True)
1452 self.parent.toolbar.ToggleTool(self.parent.toolbar.action[
'id'],
False)
1453 self.parent.toolbar.action[
'id'] = self.parent.actionOld
1457 if self.
mouse[
'use'] ==
'resize':
1458 mapObj = self.instruction.FindInstructionByType(
'map')
1460 mapObj = self.instruction.FindInstructionByType(
'initMap')
1465 newRectCanvas = self.pdcObj.GetIdBounds(mapId)
1469 if self.
instruction[mapId][
'scaleType']
in (0, 1, 2):
1472 scale, foo, rect =
AutoAdjust(self, scaleType = 0,
1478 scale, foo, rect =
AutoAdjust(self, scaleType = 1,
1482 scale, foo, rect =
AutoAdjust(self, scaleType = 2,
1488 self.
Draw(pen = self.
pen[
'map'], brush = self.
brush[
'map'],
1489 pdc = self.
pdcObj, drawid = mapId, pdctype =
'rectText', bb = rectCanvas)
1498 self.RedrawSelectBox(mapId)
1499 self.
Zoom(zoomFactor = 1, view = (0, 0))
1509 self.
mouse[
'use'] =
'pointer'
1512 if self.
mouse[
'use']
in (
'pointer',
'resize')
and self.
dragId != -1:
1513 if self.
mouse[
'begin'] != event.GetPosition():
1519 elif self.
mouse[
'use']
in (
'addPoint',
'addLine',
'addRectangle'):
1521 canvasToPaper =
True)[:2]
1523 diffX = event.GetX() - self.
mouse[
'begin'][0]
1524 diffY = event.GetY() - self.
mouse[
'begin'][1]
1526 if self.
mouse[
'use'] ==
'addPoint':
1527 self.parent.AddPoint(coordinates = endCoordinates)
1528 elif self.
mouse[
'use']
in (
'addLine',
'addRectangle'):
1530 if sqrt(diffX * diffX + diffY * diffY) < 5:
1536 self.
mouse[
'begin'][1], 0, 0),
1537 canvasToPaper =
True)[:2]
1538 if self.
mouse[
'use'] ==
'addLine':
1539 self.parent.AddLine(coordinates = [beginCoordinates, endCoordinates])
1541 self.parent.AddRectangle(coordinates = [beginCoordinates, endCoordinates])
1546 """!Open object dialog for editing."""
1547 if self.
mouse[
'use'] ==
'pointer' and self.
dragId != -1:
1548 itemCall = {
'text':self.parent.OnAddText,
1549 'mapinfo': self.parent.OnAddMapinfo,
1550 'scalebar': self.parent.OnAddScalebar,
1551 'image': self.parent.OnAddImage,
1552 'northArrow' : self.parent.OnAddNorthArrow,
1553 'point': self.parent.AddPoint,
1554 'line': self.parent.AddLine,
1555 'rectangle': self.parent.AddRectangle,
1556 'rasterLegend': self.parent.OnAddLegend,
1557 'vectorLegend': self.parent.OnAddLegend,
1558 'map': self.parent.OnAddMap}
1560 itemArg = {
'text': dict(event =
None, id = self.
dragId),
1561 'mapinfo': dict(event =
None),
1562 'scalebar': dict(event =
None),
1563 'image': dict(event =
None, id = self.
dragId),
1564 'northArrow': dict(event =
None, id = self.
dragId),
1565 'point': dict(id = self.
dragId),
1566 'line': dict(id = self.
dragId),
1567 'rectangle': dict(id = self.
dragId),
1568 'rasterLegend': dict(event =
None),
1569 'vectorLegend': dict(event =
None, page = 1),
1570 'map': dict(event =
None, notebook =
True)}
1573 itemCall[type](**itemArg[type])
1576 """!Process panning/resizing/drawing/moving."""
1577 if event.MiddleIsDown():
1579 self.
mouse[
'end'] = event.GetPosition()
1580 self.
Pan(begin = self.
mouse[
'begin'], end = self.
mouse[
'end'])
1581 self.
mouse[
'begin'] = event.GetPosition()
1583 elif event.LeftIsDown():
1585 if self.
mouse[
'use']
in (
'zoomin',
'zoomout',
'addMap',
'addLine',
'addRectangle'):
1586 self.
mouse[
'end'] = event.GetPosition()
1587 r = wx.Rect(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1],
1591 if self.
mouse[
'use']
in (
'addLine',
'addRectangle'):
1592 if self.
mouse[
'use'] ==
'addLine':
1594 lineCoords = (self.
mouse[
'begin'], self.
mouse[
'end'])
1598 if r[2] < 2
or r[3] < 2:
1602 self.
Draw(pen = self.
pen[
'line'], brush = self.
brush[
'line'],
1604 pdctype = pdcType, bb = r, lineCoords = lineCoords)
1607 self.
Draw(pen = self.
pen[
'box'], brush = self.
brush[
'box'],
1609 pdctype =
'rect', bb = r)
1612 if self.
mouse[
"use"] ==
'pan':
1613 self.
mouse[
'end'] = event.GetPosition()
1614 self.
Pan(begin = self.
mouse[
'begin'], end = self.
mouse[
'end'])
1615 self.
mouse[
'begin'] = event.GetPosition()
1618 if self.
mouse[
'use'] ==
'pointer' and self.
dragId != -1:
1619 self.
mouse[
'end'] = event.GetPosition()
1621 self.pdcObj.TranslateId(self.
dragId, dx, dy)
1622 self.pdcTmp.TranslateId(self.
idBoxTmp, dx, dy)
1625 self.pdcTmp.TranslateId(id, dx, dy)
1629 self.
begin = event.GetPosition()
1633 if self.
mouse[
'use'] ==
'resize':
1634 pos = event.GetPosition()
1635 diffX = pos[0] - self.
mouse[
'begin'][0]
1636 diffY = pos[1] - self.
mouse[
'begin'][1]
1638 x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
1639 width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
1643 newWidth = width + diffX
1644 newHeight = height + diffX * (float(height) / width)
1646 newWidth = width + diffY * (float(width) / height)
1647 newHeight = height + diffY
1649 newWidth = width + diffX
1650 newHeight = height + diffY
1652 if newWidth < 10
or newHeight < 10:
1655 bounds = wx.Rect(x, y, newWidth, newHeight)
1657 pdctype =
'rectText', bb = bounds)
1662 rect.SetWidth(rect.GetWidth() + diffX)
1663 rect.SetHeight(rect.GetHeight() + diffY)
1665 if rect.GetWidth() < 5
or rect.GetHeight() < 5:
1669 fcolor = instr[
'fcolor'], width = instr[
'width'], bb = rect)
1673 points = instr[
'where']
1680 canvasToPaper =
False)[:2]
1681 bounds = wx.RectPP(pCanvas, pos)
1683 width = instr[
'width'], bb = bounds, lineCoords = (pos, pCanvas))
1687 canvasToPaper =
True)[:2]
1689 self.RedrawSelectBox(self.
dragId)
1692 """!Middle mouse button pressed."""
1693 self.
mouse[
'begin'] = event.GetPosition()
1696 """!Move canvas while dragging.
1698 @param begin x,y coordinates of first point
1699 @param end x,y coordinates of second point
1701 view = begin[0] - end[0], begin[1] - end[1]
1703 self.
Zoom(zoomFactor, view)
1708 if itype
in (
'map',
'rectangle'):
1710 canvasToPaper =
True)
1713 elif itype
in (
'mapinfo' ,
'rasterLegend',
'vectorLegend',
'image',
'northArrow'):
1715 canvasToPaper =
True)
1717 canvasToPaper =
True)[:2]
1718 if itype
in (
'image',
'northArrow'):
1721 elif itype ==
'point':
1722 rect = self.pdcObj.GetIdBounds(id)
1724 canvasToPaper =
True)
1725 rect.OffsetXY(rect.GetWidth()/2, rect.GetHeight()/2)
1727 canvasToPaper =
True)[:2]
1730 elif itype ==
'line':
1731 rect = self.pdcObj.GetIdBounds(id)
1734 xDiff = newRect[0] - oldRect[0]
1735 yDiff = newRect[1] - oldRect[1]
1738 point1 = wx.Point2D(xDiff, yDiff) + self.
instruction[id][
'where'][0]
1739 point2 = wx.Point2D(xDiff, yDiff) + self.
instruction[id][
'where'][1]
1744 elif itype ==
'scalebar':
1746 canvasToPaper =
True)
1751 elif itype ==
'text':
1754 extent = self.parent.getTextExtent(textDict = self.
instruction[id])
1756 rot = float(self.
instruction[id][
'rotate'])/180*pi
1765 x += extent[0] * cos(rot)
1766 y -= extent[0] * sin(rot)
1768 x += extent[0]/2 * cos(rot)
1769 y -= extent[0]/2 * sin(rot)
1772 canvasToPaper =
True)[:2]
1776 """!Computes zoom factor and scroll view"""
1778 cW, cH = self.GetClientSize()
1782 if self.
mouse[
'use'] ==
'zoomout':
1783 zoomFactor = 1./zoomFactor
1784 x,y = self.
mouse[
'begin']
1785 xView = x - x/zoomFactor
1786 yView = y - y/zoomFactor
1789 rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
1791 zoomFactor = 1/
max(rW/cW, rH/cH)
1792 except ZeroDivisionError:
1795 if abs(zoomFactor - 1) > 0.01:
1796 zoomFactor = zoomFactor
1801 if self.
mouse[
'use'] ==
'zoomout':
1802 zoomFactor =
min(rW/cW, rH/cH)
1805 yView = rect.GetY() - (rW*(cH/cW) - rH)/2
1808 if self.
mouse[
'use'] ==
'zoomout':
1809 x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
1810 xView, yView = -x, -y
1812 xView = rect.GetX() - (rH*(cW/cH) - rW)/2
1814 if self.
mouse[
'use'] ==
'zoomout':
1815 x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
1816 xView, yView = -x, -y
1817 except ZeroDivisionError:
1818 xView, yView = rect.GetX(), rect.GetY()
1819 return zoomFactor, (int(xView), int(yView))
1823 """! Zoom to specified region, scroll view, redraw"""
1833 pRect = self.pdcPaper.GetIdBounds(self.
pageId)
1834 pRect.OffsetXY(-view[0], -view[1])
1835 pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
1836 self.DrawPaper(pRect)
1841 rect = self.
instruction[id][
'rect'], canvasToPaper =
False)
1846 self.
instruction[id][
'coords'] = coords = [(int(coord) - view[i]) * zoomFactor
1847 for i, coord
in enumerate(coords)]
1848 extent = self.parent.getTextExtent(textDict = self.
instruction[id])
1853 self.
instruction[id][
'rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
1855 coords = coords, bounds = bounds )
1857 self.pdcObj.SetIdBounds(id, bounds)
1859 elif type ==
'northArrow':
1861 drawid = id, pdctype =
'bitmap', bb = oRect)
1863 elif type
in (
'point',
'line',
'rectangle'):
1866 width = fcolor = coords =
None
1868 if type
in (
'point',
'rectangle'):
1870 if type
in (
'line',
'rectangle'):
1872 if type
in (
'line'):
1873 point1, point2 = instr[
'where'][0], instr[
'where'][1]
1875 canvasToPaper =
False)[:2]
1877 canvasToPaper =
False)[:2]
1878 coords = (point1, point2)
1880 self.
DrawGraphics(drawid = id, shape = type, bb = oRect, lineCoords = coords,
1881 color = color, fcolor = fcolor, width = width)
1885 drawid = id, pdctype =
'rectText', bb = oRect)
1888 self.RedrawSelectBox(self.
dragId)
1892 imageRect = self.pdcImage.GetIdBounds(self.
imageId)
1893 imageRect.OffsetXY(-view[0], -view[1])
1894 imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
1895 self.DrawImage(imageRect)
1898 """! Zoom to full extent"""
1900 bounds = self.pdcPaper.GetIdBounds(self.
pageId)
1902 bounds = self.pdcImage.GetIdBounds(self.
imageId)
1903 zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
1905 self.
Zoom(zoomFactor, view)
1907 def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0), lineCoords =
None):
1908 """! Draw object with given pen and brush.
1911 @param pdctype 'bitmap'/'rectText'/'rect'/'point'/'line'
1912 @param bb bounding box
1913 @param lineCoords coordinates of line start, end points (wx.Point, wx.Point)
1919 pdc.RemoveId(drawid)
1924 if pdctype ==
'bitmap':
1928 self.
DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
1930 pdctype =
'rectText'
1932 if pdctype
in (
'rect',
'rectText'):
1933 pdc.DrawRectangle(*bb)
1935 if pdctype ==
'rectText':
1936 dc = wx.ClientDC(self)
1939 font.SetPointSize(size)
1940 font.SetStyle(wx.ITALIC)
1944 w,h,lh = dc.GetMultiLineTextExtent(text)
1946 textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
1948 while not wx.Rect(*r).ContainsRect(textRect)
and size >= 8:
1950 font.SetPointSize(size)
1953 textExtent = dc.GetTextExtent(text)
1954 textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
1955 pdc.SetTextForeground(wx.Colour(100,100,100,200))
1956 pdc.SetBackgroundMode(wx.TRANSPARENT)
1957 pdc.DrawLabel(text = text, rect = textRect)
1959 elif pdctype ==
'point':
1960 pdc.DrawCircle(x = bb[0] + bb[2] / 2,
1961 y = bb[1] + bb[3] / 2,
1964 elif pdctype ==
'line':
1965 pdc.DrawLinePoint(lineCoords[0], lineCoords[1])
1967 pdc.SetIdBounds(drawid, bb)
1973 def DrawGraphics(self, drawid, shape, color, bb, width = None, fcolor = None, lineCoords = None):
1974 """!Draw point/line/rectangle with given color and width
1976 @param drawid id of drawn object
1977 @param shape drawn shape: 'point'/'line'/'rectangle'
1978 @param color pen outline color ('RRR:GGG:BBB')
1979 @param fcolor brush fill color, if meaningful ('RRR:GGG:BBB')
1980 @param width pen width
1981 @param bb bounding box
1982 @param lineCoords line coordinates (for line only)
1984 pdctype = {
'point' :
'point',
1986 'rectangle' :
'rect'}
1989 pen = wx.TRANSPARENT_PEN
1991 if width
is not None:
1992 units = UnitConversion(self)
1993 width = int(units.convert(value = width, fromUnit =
'point', toUnit =
'pixel') * self.
currScale)
1996 pen = wx.Pen(colour =
convertRGB(color), width = width)
1997 pen.SetCap(wx.CAP_BUTT)
1999 brush = wx.TRANSPARENT_BRUSH
2000 if fcolor
and fcolor !=
'none':
2001 brush = wx.Brush(colour =
convertRGB(fcolor))
2003 self.
Draw(pen = pen, brush = brush, pdc = self.
pdcObj, pdctype = pdctype[shape],
2004 drawid = drawid, bb = bb, lineCoords = lineCoords)
2007 """!Draw bitmap using PIL"""
2008 pImg = PILImage.open(filePath)
2009 if sys.platform ==
'win32' and \
2010 'eps' in os.path.splitext(filePath)[1].lower():
2012 pImg.load = types.MethodType(loadPSForWindows, pImg)
2016 pImg = pImg.convert(
"RGBA")
2017 rot = pImg.rotate(rotation, expand = 1)
2018 new = PILImage.new(
'RGBA', rot.size, (255,) * 4)
2019 pImg = PILImage.composite(rot, new, rot)
2020 pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
2022 bitmap = img.ConvertToBitmap()
2023 mask = wx.Mask(bitmap, wx.WHITE)
2024 bitmap.SetMask(mask)
2025 pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask =
True)
2028 if textDict[
'rotate']:
2029 rot = float(textDict[
'rotate'])
2033 if textDict[
'background'] !=
'none':
2034 background = textDict[
'background']
2038 pdc.RemoveId(drawId)
2051 pdc.SetTextBackground(
convertRGB(background))
2052 pdc.SetBackgroundMode(wx.SOLID)
2054 pdc.SetBackgroundMode(wx.TRANSPARENT)
2056 fn = self.parent.makePSFont(textDict)
2059 pdc.SetTextForeground(
convertRGB(textDict[
'color']))
2061 pdc.DrawLabel(text=textDict[
'text'], rect=bounds)
2063 pdc.DrawRotatedText(textDict[
'text'], coords[0], coords[1], rot)
2065 pdc.SetIdBounds(drawId, wx.Rect(*bounds))
2070 """!Draw preview image to pseudoDC"""
2071 self.pdcImage.ClearId(self.imageId)
2072 self.pdcImage.SetId(self.imageId)
2076 if img.GetWidth() != rect.width
or img.GetHeight() != rect.height:
2077 img = img.Scale(rect.width, rect.height)
2078 bitmap = img.ConvertToBitmap()
2080 self.pdcImage.BeginDrawing()
2081 self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
2082 self.pdcImage.SetIdBounds(self.imageId, rect)
2083 self.pdcImage.EndDrawing()
2087 """!Draw paper and margins"""
2088 page = self.instruction[self.pageId]
2089 scale = page[
'Width'] / rect.GetWidth()
2090 w = (page[
'Width'] - page[
'Right'] - page[
'Left']) / scale
2091 h = (page[
'Height'] - page[
'Top'] - page[
'Bottom']) / scale
2092 x = page[
'Left'] / scale + rect.GetX()
2093 y = page[
'Top'] / scale + rect.GetY()
2095 self.pdcPaper.BeginDrawing()
2096 self.pdcPaper.RemoveId(self.pageId)
2097 self.pdcPaper.SetId(self.pageId)
2098 self.pdcPaper.SetPen(self.pen[
'paper'])
2099 self.pdcPaper.SetBrush(self.brush[
'paper'])
2100 self.pdcPaper.DrawRectangleRect(rect)
2102 self.pdcPaper.SetPen(self.pen[
'margins'])
2103 self.pdcPaper.SetBrush(self.brush[
'margins'])
2104 self.pdcPaper.DrawRectangle(x, y, w, h)
2106 self.pdcPaper.SetIdBounds(self.pageId, rect)
2107 self.pdcPaper.EndDrawing()
2112 """!Returns image centered in canvas, computes scale"""
2113 img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
2114 cW, cH = self.GetClientSize()
2115 iW, iH = img.GetWidth(), img.GetHeight()
2117 self.currScale =
min(float(cW)/iW, float(cH)/iH)
2118 iW = iW * self.currScale
2119 iH = iH * self.currScale
2122 imageRect = wx.Rect(x, y, iW, iH)
2127 """!Redraws select box when selected object changes its size"""
2128 if self.dragId == id:
2129 rect = self.pdcObj.GetIdBounds(id)
2130 if self.instruction[id].type !=
'line':
2131 rect = rect.Inflate(3,3)
2133 self.Draw(pen = self.pen[
'select'], brush = self.brush[
'select'], pdc = self.pdcTmp,
2134 drawid = self.idBoxTmp, pdctype =
'rect', bb = rect)
2137 if self.instruction[id].type
in (
'map',
'rectangle'):
2138 controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
2139 rect = wx.RectPS(controlP, self.resizeBoxSize)
2140 self.Draw(pen = self.pen[
'resize'], brush = self.brush[
'resize'], pdc = self.pdcTmp,
2141 drawid = self.idResizeBoxTmp, pdctype =
'rect', bb = rect)
2143 elif self.instruction[id].type ==
'line':
2144 p1Paper = self.instruction[id][
'where'][0]
2145 p2Paper = self.instruction[id][
'where'][1]
2146 p1Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p1Paper, (0, 0)), canvasToPaper =
False)[:2]
2147 p2Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p2Paper, (0, 0)), canvasToPaper =
False)[:2]
2149 box = wx.RectS(self.resizeBoxSize)
2150 rect.append(box.CenterIn(wx.RectPS(p1Canvas, wx.Size())))
2151 rect.append(box.CenterIn(wx.RectPS(p2Canvas, wx.Size())))
2152 for i, point
in enumerate((p1Canvas, p2Canvas)):
2153 self.Draw(pen = self.pen[
'resize'], brush = self.brush[
'resize'], pdc = self.pdcTmp,
2154 drawid = self.idLinePointsTmp[i], pdctype =
'rect', bb = rect[i])
2157 """!Updates map frame label"""
2159 vector = self.instruction.FindInstructionByType(
'vector')
2161 vectorId = vector.id
2165 raster = self.instruction.FindInstructionByType(
'raster')
2167 rasterId = raster.id
2173 rasterName = self.instruction[rasterId][
'raster'].
split(
'@')[0]
2175 mapId = self.instruction.FindInstructionByType(
'map').id
2176 self.itemLabels[mapId] = []
2177 self.itemLabels[mapId].append(self.itemLabelsDict[
'map'])
2178 self.itemLabels[mapId].append(
"raster: " + rasterName)
2180 for map
in self.instruction[vectorId][
'list']:
2181 self.itemLabels[mapId].append(
'vector: ' + map[0].
split(
'@')[0])
2184 self.itemLabels[id] = []
2185 self.itemLabels[id].append(self.itemLabelsDict[itype])
2186 if itype ==
'image':
2187 file = os.path.basename(self.instruction[id][
'epsfile'])
2188 self.itemLabels[id].append(file)
2191 """!Init image size to match window size
2194 if self.preview
and self.parent.currentPage == 1
or not self.preview
and self.parent.currentPage == 0:
2200 """!Only re-render a image during idle time instead of
2201 multiple times during resizing.
2204 width, height = self.GetClientSize()
2208 self._buffer = wx.EmptyBitmap(width, height)
2213 """! Scale rectangle"""
2214 return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
2215 rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)
2220 gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"),
'locale'), unicode =
True)
2222 app = wx.PySimpleApp()
2223 wx.InitAllImageHandlers()
2229 if __name__ ==
"__main__":
def convertRGB
Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color, or named color/r:g:b string to wx...
def OnLeftDown
Left mouse button pressed.
def OnSize
Init image size to match window size.
def OnLeftUp
Left mouse button released.
def modifyRectangle
Recalculates rectangle not to have negative size.
def OnAddText
Show dialog for text adding and editing.
def projInfo
Return region projection and map units information, taken from render.py.
def DrawPaper
Draw paper and margins.
def OnPSFile
Generate PostScript.
def MouseActions
Mouse motion and button click notifier.
def OnPageChanging
Flatnotebook page is changing.
def PaperMapCoordinates
Converts paper (inch) coordinates <-> map coordinates.
def OnCloseWindow
Close window.
def __init__
Main window of ps.map GUI.
def InstructionFile
Creates mapping instructions.
def OnPsMapDialog
Launch ps.map dialog.
def SetResolution
If resolution is too high, lower it.
def UpdateMapLabel
Updates map frame label.
def ImageRect
Returns image centered in canvas, computes scale.
def OnOK
Apply changes, close dialog.
def OnAbout
Display About window.
def OnPaint
Draw pseudo DC to buffer.
def RecalculateEN
Recalculate east and north for texts (eps, points) after their or map's movement. ...
def ScaleRect
Scale rectangle.
def Clear
Clear canvas and set paper.
def AutoAdjust
Computes map scale, center and map frame rectangle to fit region (scale is not fixed) ...
def getInitMap
Create default map frame when no map is selected, needed for coordinates in map units.
def Draw
Draw object with given pen and brush.
def PSFile
Create temporary instructions file and run ps.map with output = filename.
def OnMouseMoving
Mouse cursor moving.
def AddPoint
Add point and open property dialog.
Various dialogs used in wxGUI.
def OnPreview
Run ps.map and show result.
def split
Platform spefic shlex.split.
def OnAddScalebar
Add scalebar.
def DrawImage
Draw preview image to pseudoDC.
def OnAddLegend
Add raster or vector legend.
def OnAddNorthArrow
Show dialog for north arrow adding and editing.
def OnCmdDone
ps.map process finished
def RedrawSelectBox
Redraws select box when selected object changes its size.
def ComputeSetRegion
Computes and sets region from current scale, map center coordinates and map rectangle.
def deleteObject
Deletes object, his id and redraws.
def OnAddRectangle
Add rectangle action selected.
def DrawBitmap
Draw bitmap using PIL.
def OnMouseWheel
Mouse wheel scrolled.
def OnAddLine
Add line action selected.
def ComputeZoom
Computes zoom factor and scroll view.
def AddRectangle
Add rectangle and open property dialog.
utilities for wxpsmap (classes, functions)
def updateDialog
Update legend coordinates after moving.
def Pan
Move canvas while dragging.
def OnAddRaster
Add raster map.
def OnDragging
Process panning/resizing/drawing/moving.
def PilImageToWxImage
Convert PIL image to wx.Image.
def OnAddImage
Show dialog for image adding and editing.
def SetPage
Sets and changes page, redraws paper.
def OnAddPoint
Add point action selected.
def OnAddVect
Add vector map.
def OnPageChanged
Flatnotebook page has changed.
def makePSFont
creates a wx.Font object from selected postscript font.
def _showErrMsg
Show error message (missing preview)
def OnLoadFile
Load file and read instructions.
def GetMapBounds
Run ps.map -b to get information about map bounding box.
def Zoom
Zoom to specified region, scroll view, redraw.
def OnPageSetup
Specify paper size, margins and orientation.
def getTextExtent
Estimates bounding rectangle of text.
def getModifiedTextBounds
computes bounding box of rotated text, not very precisely
def AddLine
Add line and open property dialog.
def ZoomAll
Zoom to full extent.
def OnButtonDClick
Open object dialog for editing.
def OnAddMap
Add or edit map frame.
def OnApply
parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Color:")) colorChoices...
def OnMiddleDown
Middle mouse button pressed.
def DrawGraphics
Draw point/line/rectangle with given color and width.
def OnPDFFile
Generate PDF from PS with ps2pdf if available.
def OnIdle
Only re-render a image during idle time instead of multiple times during resizing.
def RunCommand
Run GRASS command.
def CanvasPaperCoordinates
Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa.