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.Color(86, 122, 17), width = 2),
96 'rasterLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
97 'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
98 'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
99 'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
100 'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
101 'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
102 'point': wx.Pen(colour = wx.Color(100, 100, 100), width = 2),
103 'line': wx.Pen(colour = wx.Color(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.Color(151, 214, 90)),
112 'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
113 'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
114 'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
115 'scalebar': wx.Brush(wx.Color(200, 200, 200)),
116 'image': wx.Brush(wx.Color(255, 200, 50)),
117 'northArrow': wx.Brush(wx.Color(255, 255, 255)),
118 'point': wx.Brush(wx.Color(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'}
1127 dc = wx.ClientDC(self)
1130 self.SetClientSize((700,510))
1131 self.
_buffer = wx.EmptyBitmap(*self.GetClientSize())
1156 self.Bind(wx.EVT_ERASE_BACKGROUND,
lambda x:
None)
1158 self.Bind(wx.EVT_PAINT, self.
OnPaint)
1159 self.Bind(wx.EVT_SIZE, self.OnSize)
1160 self.Bind(wx.EVT_IDLE, self.OnIdle)
1166 """!Clear canvas and set paper
1168 bg = wx.LIGHT_GREY_BRUSH
1169 self.pdcPaper.BeginDrawing()
1170 self.pdcPaper.SetBackground(bg)
1171 self.pdcPaper.Clear()
1172 self.pdcPaper.EndDrawing()
1174 self.pdcObj.RemoveAll()
1175 self.pdcTmp.RemoveAll()
1184 """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
1186 units = UnitConversion(self)
1190 pRect = self.pdcPaper.GetIdBounds(self.
pageId)
1191 pRectx, pRecty = pRect.x, pRect.y
1193 if not canvasToPaper:
1197 pRectx = units.convert(value = - pRect.x, fromUnit =
'pixel', toUnit =
'inch' ) /scale
1198 pRecty = units.convert(value = - pRect.y, fromUnit =
'pixel', toUnit =
'inch' ) /scale
1199 Width = units.convert(value = rect.GetWidth(), fromUnit = fromU, toUnit = toU) * scale
1200 Height = units.convert(value = rect.GetHeight(), fromUnit = fromU, toUnit = toU) * scale
1201 X = units.convert(value = (rect.GetX() - pRectx), fromUnit = fromU, toUnit = toU) * scale
1202 Y = units.convert(value = (rect.GetY() - pRecty), fromUnit = fromU, toUnit = toU) * scale
1204 return Rect2D(X, Y, Width, Height)
1209 """!Sets and changes page, redraws paper"""
1213 page = PageSetup(id = self.
pageId)
1214 self.instruction.AddInstruction(page)
1216 ppi = wx.ClientDC(self).GetPPI()
1217 cW, cH = self.GetClientSize()
1218 pW, pH = page[
'Width']*ppi[0], page[
'Height']*ppi[1]
1227 self.DrawPaper(wx.Rect(x, y, pW, pH))
1231 """! Recalculates rectangle not to have negative size"""
1232 if r.GetWidth() < 0:
1233 r.SetX(r.GetX() + r.GetWidth())
1234 if r.GetHeight() < 0:
1235 r.SetY(r.GetY() + r.GetHeight())
1236 r.SetWidth(abs(r.GetWidth()))
1237 r.SetHeight(abs(r.GetHeight()))
1241 """!Recalculate east and north for texts (eps, points) after their or map's movement"""
1243 mapId = self.instruction.FindInstructionByType(
'map').id
1244 except AttributeError:
1245 mapId = self.instruction.FindInstructionByType(
'initMap').id
1247 for itemType
in (
'text',
'image',
'northArrow',
'point',
'line',
'rectangle'):
1248 items = self.instruction.FindInstructionByType(itemType, list =
True)
1251 if itemType
in (
'line',
'rectangle'):
1252 if itemType ==
'line':
1254 y = instr[
'where'][0][1], paperToMap =
True)
1256 y = instr[
'where'][1][1], paperToMap =
True)
1259 y = instr[
'rect'].GetTop(), paperToMap =
True)
1261 y = instr[
'rect'].GetBottom(), paperToMap =
True)
1263 instr[
'north1'] = n1
1265 instr[
'north2'] = n2
1268 y = instr[
'where'][1], paperToMap =
True)
1269 instr[
'east'], instr[
'north'] = e, n
1272 """!Draw pseudo DC to buffer
1276 dc = wx.BufferedPaintDC(self, self.
_buffer)
1280 dc.SetBackground(wx.LIGHT_GREY_BRUSH)
1285 self.pdcPaper.DrawToDC(dc)
1288 rgn = self.GetUpdateRegion()
1291 self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
1293 self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
1294 self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
1297 """!Mouse motion and button click notifier
1300 if event.GetWheelRotation() != 0:
1304 elif event.LeftDown():
1308 elif event.LeftUp():
1312 elif event.Dragging():
1316 elif event.ButtonDClick():
1320 elif event.MiddleDown():
1323 elif event.Moving():
1327 """!Mouse wheel scrolled.
1330 if UserSettings.Get(group =
'display',
1331 key =
'mouseWheelZoom',
1332 subkey =
'selection') == 2:
1336 zoom = event.GetWheelRotation()
1337 oldUse = self.
mouse[
'use']
1338 self.
mouse[
'begin'] = event.GetPosition()
1340 if UserSettings.Get(group =
'display',
1341 key =
'scrollDirection',
1342 subkey =
'selection'):
1346 self.
mouse[
'use'] =
'zoomin'
1348 self.
mouse[
'use'] =
'zoomout'
1350 zoomFactor, view = self.
ComputeZoom(wx.Rect(0, 0, 0, 0))
1351 self.
Zoom(zoomFactor, view)
1352 self.
mouse[
'use'] = oldUse
1355 """!Mouse cursor moving.
1357 Change cursor when moving over resize marker.
1362 if self.
mouse[
'use']
in (
'pointer',
'resize'):
1363 pos = event.GetPosition()
1364 foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
1366 self.SetCursor(self.
cursors[
"sizenwse"])
1367 self.parent.SetStatusText(_(
'Click and drag to resize object'), 0)
1371 self.parent.SetStatusText(
'', 0)
1372 self.SetCursor(self.
cursors[
"default"])
1376 """!Left mouse button pressed.
1378 Select objects, redraw, prepare for moving/resizing.
1380 self.
mouse[
'begin'] = event.GetPosition()
1384 if self.
mouse[
'use'] ==
'pointer':
1385 found = self.pdcObj.FindObjects(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1])
1386 foundResize = self.pdcTmp.FindObjects(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1])
1389 self.
mouse[
'use'] =
'resize'
1404 self.RedrawSelectBox(self.
dragId)
1410 self.pdcTmp.RemoveId(id)
1415 self.pdcTmp.RemoveId(self.
idBoxTmp)
1418 self.pdcTmp.RemoveId(id)
1422 """!Left mouse button released.
1424 Recalculate zooming/resizing/moving and redraw.
1427 if self.
mouse[
'use']
in (
'zoomin',
'zoomout'):
1432 self.
Zoom(zoomFactor, view)
1435 if self.
mouse[
'use'] ==
'addMap':
1438 if rectTmp.GetWidth() < 20
or rectTmp.GetHeight() < 20:
1444 dlg = MapDialog(parent = self.
parent, id = [
None,
None,
None], settings = self.
instruction,
1449 self.
mouse[
'use'] = self.parent.mouseOld
1451 self.SetCursor(self.parent.cursorOld)
1452 self.parent.toolbar.ToggleTool(self.parent.actionOld,
True)
1453 self.parent.toolbar.ToggleTool(self.parent.toolbar.action[
'id'],
False)
1454 self.parent.toolbar.action[
'id'] = self.parent.actionOld
1458 if self.
mouse[
'use'] ==
'resize':
1459 mapObj = self.instruction.FindInstructionByType(
'map')
1461 mapObj = self.instruction.FindInstructionByType(
'initMap')
1466 newRectCanvas = self.pdcObj.GetIdBounds(mapId)
1470 if self.
instruction[mapId][
'scaleType']
in (0, 1, 2):
1473 scale, foo, rect =
AutoAdjust(self, scaleType = 0,
1479 scale, foo, rect =
AutoAdjust(self, scaleType = 1,
1483 scale, foo, rect =
AutoAdjust(self, scaleType = 2,
1489 self.
Draw(pen = self.
pen[
'map'], brush = self.
brush[
'map'],
1490 pdc = self.
pdcObj, drawid = mapId, pdctype =
'rectText', bb = rectCanvas)
1499 self.RedrawSelectBox(mapId)
1500 self.
Zoom(zoomFactor = 1, view = (0, 0))
1510 self.
mouse[
'use'] =
'pointer'
1513 if self.
mouse[
'use']
in (
'pointer',
'resize')
and self.
dragId != -1:
1514 if self.
mouse[
'begin'] != event.GetPosition():
1520 elif self.
mouse[
'use']
in (
'addPoint',
'addLine',
'addRectangle'):
1522 canvasToPaper =
True)[:2]
1524 diffX = event.GetX() - self.
mouse[
'begin'][0]
1525 diffY = event.GetY() - self.
mouse[
'begin'][1]
1527 if self.
mouse[
'use'] ==
'addPoint':
1528 self.parent.AddPoint(coordinates = endCoordinates)
1529 elif self.
mouse[
'use']
in (
'addLine',
'addRectangle'):
1531 if sqrt(diffX * diffX + diffY * diffY) < 5:
1537 self.
mouse[
'begin'][1], 0, 0),
1538 canvasToPaper =
True)[:2]
1539 if self.
mouse[
'use'] ==
'addLine':
1540 self.parent.AddLine(coordinates = [beginCoordinates, endCoordinates])
1542 self.parent.AddRectangle(coordinates = [beginCoordinates, endCoordinates])
1547 """!Open object dialog for editing."""
1548 if self.
mouse[
'use'] ==
'pointer' and self.
dragId != -1:
1549 itemCall = {
'text':self.parent.OnAddText,
1550 'mapinfo': self.parent.OnAddMapinfo,
1551 'scalebar': self.parent.OnAddScalebar,
1552 'image': self.parent.OnAddImage,
1553 'northArrow' : self.parent.OnAddNorthArrow,
1554 'point': self.parent.AddPoint,
1555 'line': self.parent.AddLine,
1556 'rectangle': self.parent.AddRectangle,
1557 'rasterLegend': self.parent.OnAddLegend,
1558 'vectorLegend': self.parent.OnAddLegend,
1559 'map': self.parent.OnAddMap}
1561 itemArg = {
'text': dict(event =
None, id = self.
dragId),
1562 'mapinfo': dict(event =
None),
1563 'scalebar': dict(event =
None),
1564 'image': dict(event =
None, id = self.
dragId),
1565 'northArrow': dict(event =
None, id = self.
dragId),
1566 'point': dict(id = self.
dragId),
1567 'line': dict(id = self.
dragId),
1568 'rectangle': dict(id = self.
dragId),
1569 'rasterLegend': dict(event =
None),
1570 'vectorLegend': dict(event =
None, page = 1),
1571 'map': dict(event =
None, notebook =
True)}
1574 itemCall[type](**itemArg[type])
1577 """!Process panning/resizing/drawing/moving."""
1578 if event.MiddleIsDown():
1580 self.
mouse[
'end'] = event.GetPosition()
1581 self.
Pan(begin = self.
mouse[
'begin'], end = self.
mouse[
'end'])
1582 self.
mouse[
'begin'] = event.GetPosition()
1584 elif event.LeftIsDown():
1586 if self.
mouse[
'use']
in (
'zoomin',
'zoomout',
'addMap',
'addLine',
'addRectangle'):
1587 self.
mouse[
'end'] = event.GetPosition()
1588 r = wx.Rect(self.
mouse[
'begin'][0], self.
mouse[
'begin'][1],
1592 if self.
mouse[
'use']
in (
'addLine',
'addRectangle'):
1593 if self.
mouse[
'use'] ==
'addLine':
1595 lineCoords = (self.
mouse[
'begin'], self.
mouse[
'end'])
1599 if r[2] < 2
or r[3] < 2:
1603 self.
Draw(pen = self.
pen[
'line'], brush = self.
brush[
'line'],
1605 pdctype = pdcType, bb = r, lineCoords = lineCoords)
1608 self.
Draw(pen = self.
pen[
'box'], brush = self.
brush[
'box'],
1610 pdctype =
'rect', bb = r)
1613 if self.
mouse[
"use"] ==
'pan':
1614 self.
mouse[
'end'] = event.GetPosition()
1615 self.
Pan(begin = self.
mouse[
'begin'], end = self.
mouse[
'end'])
1616 self.
mouse[
'begin'] = event.GetPosition()
1619 if self.
mouse[
'use'] ==
'pointer' and self.
dragId != -1:
1620 self.
mouse[
'end'] = event.GetPosition()
1622 self.pdcObj.TranslateId(self.
dragId, dx, dy)
1623 self.pdcTmp.TranslateId(self.
idBoxTmp, dx, dy)
1626 self.pdcTmp.TranslateId(id, dx, dy)
1630 self.
begin = event.GetPosition()
1634 if self.
mouse[
'use'] ==
'resize':
1635 pos = event.GetPosition()
1636 diffX = pos[0] - self.
mouse[
'begin'][0]
1637 diffY = pos[1] - self.
mouse[
'begin'][1]
1639 x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
1640 width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
1644 newWidth = width + diffX
1645 newHeight = height + diffX * (float(height) / width)
1647 newWidth = width + diffY * (float(width) / height)
1648 newHeight = height + diffY
1650 newWidth = width + diffX
1651 newHeight = height + diffY
1653 if newWidth < 10
or newHeight < 10:
1656 bounds = wx.Rect(x, y, newWidth, newHeight)
1658 pdctype =
'rectText', bb = bounds)
1663 rect.SetWidth(rect.GetWidth() + diffX)
1664 rect.SetHeight(rect.GetHeight() + diffY)
1666 if rect.GetWidth() < 5
or rect.GetHeight() < 5:
1670 fcolor = instr[
'fcolor'], width = instr[
'width'], bb = rect)
1674 points = instr[
'where']
1681 canvasToPaper =
False)[:2]
1682 bounds = wx.RectPP(pCanvas, pos)
1684 width = instr[
'width'], bb = bounds, lineCoords = (pos, pCanvas))
1688 canvasToPaper =
True)[:2]
1690 self.RedrawSelectBox(self.
dragId)
1693 """!Middle mouse button pressed."""
1694 self.
mouse[
'begin'] = event.GetPosition()
1697 """!Move canvas while dragging.
1699 @param begin x,y coordinates of first point
1700 @param end x,y coordinates of second point
1702 view = begin[0] - end[0], begin[1] - end[1]
1704 self.
Zoom(zoomFactor, view)
1709 if itype
in (
'map',
'rectangle'):
1711 canvasToPaper =
True)
1714 elif itype
in (
'mapinfo' ,
'rasterLegend',
'vectorLegend',
'image',
'northArrow'):
1716 canvasToPaper =
True)
1718 canvasToPaper =
True)[:2]
1719 if itype
in (
'image',
'northArrow'):
1722 elif itype ==
'point':
1723 rect = self.pdcObj.GetIdBounds(id)
1725 canvasToPaper =
True)
1726 rect.OffsetXY(rect.GetWidth()/2, rect.GetHeight()/2)
1728 canvasToPaper =
True)[:2]
1731 elif itype ==
'line':
1732 rect = self.pdcObj.GetIdBounds(id)
1735 xDiff = newRect[0] - oldRect[0]
1736 yDiff = newRect[1] - oldRect[1]
1739 point1 = wx.Point2D(xDiff, yDiff) + self.
instruction[id][
'where'][0]
1740 point2 = wx.Point2D(xDiff, yDiff) + self.
instruction[id][
'where'][1]
1745 elif itype ==
'scalebar':
1747 canvasToPaper =
True)
1752 elif itype ==
'text':
1755 extent = self.parent.getTextExtent(textDict = self.
instruction[id])
1757 rot = float(self.
instruction[id][
'rotate'])/180*pi
1766 x += extent[0] * cos(rot)
1767 y -= extent[0] * sin(rot)
1769 x += extent[0]/2 * cos(rot)
1770 y -= extent[0]/2 * sin(rot)
1773 canvasToPaper =
True)[:2]
1777 """!Computes zoom factor and scroll view"""
1779 cW, cH = self.GetClientSize()
1783 if self.
mouse[
'use'] ==
'zoomout':
1784 zoomFactor = 1./zoomFactor
1785 x,y = self.
mouse[
'begin']
1786 xView = x - x/zoomFactor
1787 yView = y - y/zoomFactor
1790 rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
1792 zoomFactor = 1/
max(rW/cW, rH/cH)
1793 except ZeroDivisionError:
1796 if abs(zoomFactor - 1) > 0.01:
1797 zoomFactor = zoomFactor
1802 if self.
mouse[
'use'] ==
'zoomout':
1803 zoomFactor =
min(rW/cW, rH/cH)
1806 yView = rect.GetY() - (rW*(cH/cW) - rH)/2
1809 if self.
mouse[
'use'] ==
'zoomout':
1810 x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
1811 xView, yView = -x, -y
1813 xView = rect.GetX() - (rH*(cW/cH) - rW)/2
1815 if self.
mouse[
'use'] ==
'zoomout':
1816 x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
1817 xView, yView = -x, -y
1818 except ZeroDivisionError:
1819 xView, yView = rect.GetX(), rect.GetY()
1820 return zoomFactor, (
int(xView),
int(yView))
1824 """! Zoom to specified region, scroll view, redraw"""
1834 pRect = self.pdcPaper.GetIdBounds(self.
pageId)
1835 pRect.OffsetXY(-view[0], -view[1])
1836 pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
1837 self.DrawPaper(pRect)
1842 rect = self.
instruction[id][
'rect'], canvasToPaper =
False)
1847 self.
instruction[id][
'coords'] = coords = [(
int(coord) - view[i]) * zoomFactor
1848 for i, coord
in enumerate(coords)]
1849 extent = self.parent.getTextExtent(textDict = self.
instruction[id])
1854 self.
instruction[id][
'rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
1856 coords = coords, bounds = bounds )
1858 self.pdcObj.SetIdBounds(id, bounds)
1860 elif type ==
'northArrow':
1862 drawid = id, pdctype =
'bitmap', bb = oRect)
1864 elif type
in (
'point',
'line',
'rectangle'):
1867 width = fcolor = coords =
None
1869 if type
in (
'point',
'rectangle'):
1871 if type
in (
'line',
'rectangle'):
1873 if type
in (
'line'):
1874 point1, point2 = instr[
'where'][0], instr[
'where'][1]
1876 canvasToPaper =
False)[:2]
1878 canvasToPaper =
False)[:2]
1879 coords = (point1, point2)
1881 self.
DrawGraphics(drawid = id, shape = type, bb = oRect, lineCoords = coords,
1882 color = color, fcolor = fcolor, width = width)
1886 drawid = id, pdctype =
'rectText', bb = oRect)
1889 self.RedrawSelectBox(self.
dragId)
1893 imageRect = self.pdcImage.GetIdBounds(self.
imageId)
1894 imageRect.OffsetXY(-view[0], -view[1])
1895 imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
1896 self.DrawImage(imageRect)
1899 """! Zoom to full extent"""
1901 bounds = self.pdcPaper.GetIdBounds(self.
pageId)
1903 bounds = self.pdcImage.GetIdBounds(self.
imageId)
1904 zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
1906 self.
Zoom(zoomFactor, view)
1908 def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0), lineCoords =
None):
1909 """! Draw object with given pen and brush.
1912 @param pdctype 'bitmap'/'rectText'/'rect'/'point'/'line'
1913 @param bb bounding box
1914 @param lineCoords coordinates of line start, end points (wx.Point, wx.Point)
1920 pdc.RemoveId(drawid)
1925 if pdctype ==
'bitmap':
1929 self.
DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
1931 pdctype =
'rectText'
1933 if pdctype
in (
'rect',
'rectText'):
1934 pdc.DrawRectangle(*bb)
1936 if pdctype ==
'rectText':
1937 dc = wx.ClientDC(self)
1940 font.SetPointSize(size)
1941 font.SetStyle(wx.ITALIC)
1945 w,h,lh = dc.GetMultiLineTextExtent(text)
1947 textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
1949 while not wx.Rect(*r).ContainsRect(textRect)
and size >= 8:
1951 font.SetPointSize(size)
1954 textExtent = dc.GetTextExtent(text)
1955 textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
1956 pdc.SetTextForeground(wx.Color(100,100,100,200))
1957 pdc.SetBackgroundMode(wx.TRANSPARENT)
1958 pdc.DrawLabel(text = text, rect = textRect)
1960 elif pdctype ==
'point':
1961 pdc.DrawCircle(x = bb[0] + bb[2] / 2,
1962 y = bb[1] + bb[3] / 2,
1965 elif pdctype ==
'line':
1966 pdc.DrawLinePoint(lineCoords[0], lineCoords[1])
1968 pdc.SetIdBounds(drawid, bb)
1974 def DrawGraphics(self, drawid, shape, color, bb, width = None, fcolor = None, lineCoords = None):
1975 """!Draw point/line/rectangle with given color and width
1977 @param drawid id of drawn object
1978 @param shape drawn shape: 'point'/'line'/'rectangle'
1979 @param color pen outline color ('RRR:GGG:BBB')
1980 @param fcolor brush fill color, if meaningful ('RRR:GGG:BBB')
1981 @param width pen width
1982 @param bb bounding box
1983 @param lineCoords line coordinates (for line only)
1985 pdctype = {
'point' :
'point',
1987 'rectangle' :
'rect'}
1990 pen = wx.TRANSPARENT_PEN
1992 if width
is not None:
1993 units = UnitConversion(self)
1994 width =
int(units.convert(value = width, fromUnit =
'point', toUnit =
'pixel') * self.
currScale)
1997 pen = wx.Pen(colour =
convertRGB(color), width = width)
1998 pen.SetCap(wx.CAP_BUTT)
2000 brush = wx.TRANSPARENT_BRUSH
2001 if fcolor
and fcolor !=
'none':
2002 brush = wx.Brush(colour =
convertRGB(fcolor))
2004 self.
Draw(pen = pen, brush = brush, pdc = self.
pdcObj, pdctype = pdctype[shape],
2005 drawid = drawid, bb = bb, lineCoords = lineCoords)
2008 """!Draw bitmap using PIL"""
2009 pImg = PILImage.open(filePath)
2010 if sys.platform ==
'win32' and \
2011 'eps' in os.path.splitext(filePath)[1].lower():
2013 pImg.load = types.MethodType(loadPSForWindows, pImg)
2017 pImg = pImg.convert(
"RGBA")
2018 rot = pImg.rotate(rotation, expand = 1)
2019 new = PILImage.new(
'RGBA', rot.size, (255,) * 4)
2020 pImg = PILImage.composite(rot, new, rot)
2021 pImg = pImg.resize((
int(bbox[2]),
int(bbox[3])), resample = PILImage.BICUBIC)
2023 bitmap = img.ConvertToBitmap()
2024 mask = wx.Mask(bitmap, wx.WHITE)
2025 bitmap.SetMask(mask)
2026 pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask =
True)
2029 if textDict[
'rotate']:
2030 rot = float(textDict[
'rotate'])
2034 if textDict[
'background'] !=
'none':
2035 background = textDict[
'background']
2039 pdc.RemoveId(drawId)
2052 pdc.SetTextBackground(
convertRGB(background))
2053 pdc.SetBackgroundMode(wx.SOLID)
2055 pdc.SetBackgroundMode(wx.TRANSPARENT)
2057 fn = self.parent.makePSFont(textDict)
2060 pdc.SetTextForeground(
convertRGB(textDict[
'color']))
2062 pdc.DrawLabel(text=textDict[
'text'], rect=bounds)
2064 pdc.DrawRotatedText(textDict[
'text'], coords[0], coords[1], rot)
2066 pdc.SetIdBounds(drawId, wx.Rect(*bounds))
2071 """!Draw preview image to pseudoDC"""
2072 self.pdcImage.ClearId(self.imageId)
2073 self.pdcImage.SetId(self.imageId)
2077 if img.GetWidth() != rect.width
or img.GetHeight() != rect.height:
2078 img = img.Scale(rect.width, rect.height)
2079 bitmap = img.ConvertToBitmap()
2081 self.pdcImage.BeginDrawing()
2082 self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
2083 self.pdcImage.SetIdBounds(self.imageId, rect)
2084 self.pdcImage.EndDrawing()
2088 """!Draw paper and margins"""
2089 page = self.instruction[self.pageId]
2090 scale = page[
'Width'] / rect.GetWidth()
2091 w = (page[
'Width'] - page[
'Right'] - page[
'Left']) / scale
2092 h = (page[
'Height'] - page[
'Top'] - page[
'Bottom']) / scale
2093 x = page[
'Left'] / scale + rect.GetX()
2094 y = page[
'Top'] / scale + rect.GetY()
2096 self.pdcPaper.BeginDrawing()
2097 self.pdcPaper.RemoveId(self.pageId)
2098 self.pdcPaper.SetId(self.pageId)
2099 self.pdcPaper.SetPen(self.pen[
'paper'])
2100 self.pdcPaper.SetBrush(self.brush[
'paper'])
2101 self.pdcPaper.DrawRectangleRect(rect)
2103 self.pdcPaper.SetPen(self.pen[
'margins'])
2104 self.pdcPaper.SetBrush(self.brush[
'margins'])
2105 self.pdcPaper.DrawRectangle(x, y, w, h)
2107 self.pdcPaper.SetIdBounds(self.pageId, rect)
2108 self.pdcPaper.EndDrawing()
2113 """!Returns image centered in canvas, computes scale"""
2114 img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
2115 cW, cH = self.GetClientSize()
2116 iW, iH = img.GetWidth(), img.GetHeight()
2118 self.currScale =
min(float(cW)/iW, float(cH)/iH)
2119 iW = iW * self.currScale
2120 iH = iH * self.currScale
2123 imageRect = wx.Rect(x, y, iW, iH)
2128 """!Redraws select box when selected object changes its size"""
2129 if self.dragId == id:
2130 rect = self.pdcObj.GetIdBounds(id)
2131 if self.instruction[id].type !=
'line':
2132 rect = rect.Inflate(3,3)
2134 self.Draw(pen = self.pen[
'select'], brush = self.brush[
'select'], pdc = self.pdcTmp,
2135 drawid = self.idBoxTmp, pdctype =
'rect', bb = rect)
2138 if self.instruction[id].type
in (
'map',
'rectangle'):
2139 controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
2140 rect = wx.RectPS(controlP, self.resizeBoxSize)
2141 self.Draw(pen = self.pen[
'resize'], brush = self.brush[
'resize'], pdc = self.pdcTmp,
2142 drawid = self.idResizeBoxTmp, pdctype =
'rect', bb = rect)
2144 elif self.instruction[id].type ==
'line':
2145 p1Paper = self.instruction[id][
'where'][0]
2146 p2Paper = self.instruction[id][
'where'][1]
2147 p1Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p1Paper, (0, 0)), canvasToPaper =
False)[:2]
2148 p2Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p2Paper, (0, 0)), canvasToPaper =
False)[:2]
2150 box = wx.RectS(self.resizeBoxSize)
2151 rect.append(box.CenterIn(wx.RectPS(p1Canvas, wx.Size())))
2152 rect.append(box.CenterIn(wx.RectPS(p2Canvas, wx.Size())))
2153 for i, point
in enumerate((p1Canvas, p2Canvas)):
2154 self.Draw(pen = self.pen[
'resize'], brush = self.brush[
'resize'], pdc = self.pdcTmp,
2155 drawid = self.idLinePointsTmp[i], pdctype =
'rect', bb = rect[i])
2158 """!Updates map frame label"""
2160 vector = self.instruction.FindInstructionByType(
'vector')
2162 vectorId = vector.id
2166 raster = self.instruction.FindInstructionByType(
'raster')
2168 rasterId = raster.id
2174 rasterName = self.instruction[rasterId][
'raster'].
split(
'@')[0]
2176 mapId = self.instruction.FindInstructionByType(
'map').id
2177 self.itemLabels[mapId] = []
2178 self.itemLabels[mapId].append(self.itemLabelsDict[
'map'])
2179 self.itemLabels[mapId].append(
"raster: " + rasterName)
2181 for map
in self.instruction[vectorId][
'list']:
2182 self.itemLabels[mapId].append(
'vector: ' + map[0].
split(
'@')[0])
2185 self.itemLabels[id] = []
2186 self.itemLabels[id].append(self.itemLabelsDict[itype])
2187 if itype ==
'image':
2188 file = os.path.basename(self.instruction[id][
'epsfile'])
2189 self.itemLabels[id].append(file)
2192 """!Init image size to match window size
2195 if self.preview
and self.parent.currentPage == 1
or not self.preview
and self.parent.currentPage == 0:
2201 """!Only re-render a image during idle time instead of
2202 multiple times during resizing.
2205 width, height = self.GetClientSize()
2209 self._buffer = wx.EmptyBitmap(width, height)
2214 """! Scale rectangle"""
2215 return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
2216 rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)
2221 gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"),
'locale'), unicode =
True)
2223 app = wx.PySimpleApp()
2224 wx.InitAllImageHandlers()
2230 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.