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__":