GRASS Programmer's Manual  6.4.3(2013)-r
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
psmap/frame.py
Go to the documentation of this file.
1 """!
2 @package psmap.frame
3 
4 @brief GUI for ps.map
5 
6 Classes:
7  - frame::PsMapFrame
8  - frame::PsMapBufferedWindow
9 
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.
13 
14 @author Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
15 @author Martin Landa <landa.martin gmail.com> (mentor)
16 """
17 
18 import os
19 import sys
20 import textwrap
21 import Queue
22 from math import sin, cos, pi, sqrt
23 
24 if __name__ == "__main__":
25  sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
26 from core import globalvar
27 import wx
28 
29 try:
30  import wx.lib.agw.flatnotebook as fnb
31 except ImportError:
32  import wx.lib.flatnotebook as fnb
33 
34 import grass.script as grass
35 
36 from gui_core.menu import Menu
37 from gui_core.goutput import CmdThread, EVT_CMD_DONE
38 from psmap.toolbars import PsMapToolbar
39 from core.gcmd import RunCommand, GError, GMessage
40 from core.settings import UserSettings
41 from gui_core.forms import GUI
42 from gui_core.dialogs import HyperlinkDialog
43 from psmap.menudata import PsMapData
44 
45 from psmap.dialogs import *
46 from psmap.instructions import *
47 from psmap.utils import *
48 
49 class PsMapFrame(wx.Frame):
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
53 
54  @param parent parent window
55  @param id window id
56  @param title window title
57 
58  @param kwargs wx.Frames' arguments
59  """
60  self.parent = parent
61 
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))
64  #menubar
65  self.menubar = Menu(parent = self, data = PsMapData())
66  self.SetMenuBar(self.menubar)
67  #toolbar
68 
69  self.toolbar = PsMapToolbar(parent = self)
70  self.SetToolBar(self.toolbar)
71 
72  self.actionOld = self.toolbar.action['id']
73  self.iconsize = (16, 16)
74  #satusbar
75  self.statusbar = self.CreateStatusBar(number = 1)
76 
77  # mouse attributes -- position on the screen, begin and end of
78  # dragging, and type of drawing
79  self.mouse = {
80  'begin': [0, 0], # screen coordinates
81  'end' : [0, 0],
82  'use' : "pointer",
83  }
84  # available cursors
85  self.cursors = {
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)
90  }
91  # pen and brush
92  self.pen = {
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)
107  }
108  self.brush = {
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
123  }
124 
125 
126  # list of objects to draw
127  self.objectId = []
128 
129  # instructions
130  self.instruction = Instruction(parent = self, objectsToDraw = self.objectId)
131  # open dialogs
132  self.openDialogs = dict()
133 
134  self.pageId = wx.NewId()
135  #current page of flatnotebook
136  self.currentPage = 0
137  #canvas for draft mode
138  self.canvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, pen = self.pen,
139  brush = self.brush, cursors = self.cursors,
140  instruction = self.instruction, openDialogs = self.openDialogs,
141  pageId = self.pageId, objectId = self.objectId,
142  preview = False)
143 
144  self.canvas.SetCursor(self.cursors["default"])
145  self.getInitMap()
146 
147 
148  # image path
149  env = grass.gisenv()
150  self.imgName = grass.tempfile()
151 
152  #canvas for preview
153  self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
154  pen = self.pen, brush = self.brush, preview = True)
155 
156  # set WIND_OVERRIDE
157  grass.use_temp_region()
158 
159  # create queues
160  self.requestQ = Queue.Queue()
161  self.resultQ = Queue.Queue()
162  # thread
163  self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
164 
165  self._layout()
166  self.SetMinSize(wx.Size(750, 600))
167 
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)
171  self.Bind(EVT_CMD_DONE, self.OnCmdDone)
172 
173  if not havePILImage:
174  wx.CallAfter(self._showErrMsg)
175 
176  def _showErrMsg(self):
177  """!Show error message (missing preview)
178  """
179  GError(parent = self,
180  message = _("Python Imaging Library is not available.\n"
181  "'Preview' functionality won't work."),
182  showTraceback = False)
183 
184  def _layout(self):
185  """!Do layout
186  """
187  mainSizer = wx.BoxSizer(wx.VERTICAL)
188  if globalvar.hasAgw:
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)
192  else:
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)
196  #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
197  self.book.AddPage(self.canvas, "Draft mode")
198  self.book.AddPage(self.previewCanvas, "Preview")
199  self.book.SetSelection(0)
200 
201  mainSizer.Add(self.book,1, wx.EXPAND)
202 
203  self.SetSizer(mainSizer)
204  mainSizer.Fit(self)
205 
206 
207  def InstructionFile(self):
208  """!Creates mapping instructions"""
209 
210  return str(self.instruction)
211 
212  def OnPSFile(self, event):
213  """!Generate PostScript"""
214  filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
215  if filename:
216  self.PSFile(filename)
217 
218  def OnPsMapDialog(self, event):
219  """!Launch ps.map dialog
220  """
221  GUI(parent = self).ParseCommand(cmd = ['ps.map'])
222 
223  def OnPDFFile(self, event):
224  """!Generate PDF from PS with ps2pdf if available"""
225  if not sys.platform == 'win32':
226  try:
227  p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
228  p.stderr.close()
229 
230  except OSError:
231  GMessage(parent = self,
232  message = _("Program ps2pdf is not available. Please install it first to create PDF."))
233  return
234 
235  filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
236  if filename:
237  self.PSFile(filename, pdf = True)
238 
239  def OnPreview(self, event):
240  """!Run ps.map and show result"""
241  self.PSFile()
242 
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')
247  instrFileFd.write(self.InstructionFile())
248  instrFileFd.flush()
249  instrFileFd.close()
250 
251  temp = False
252  regOld = grass.region()
253 
254  if pdf:
255  pdfname = filename
256  else:
257  pdfname = None
258  #preview or pdf
259  if not filename or (filename and pdf):
260  temp = True
261  filename = grass.tempfile()
262  if not pdf: # lower resolution for preview
263  if self.instruction.FindInstructionByType('map'):
264  mapId = self.instruction.FindInstructionByType('map').id
265  SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
266  height = self.instruction[mapId]['rect'][3])
267 
268  cmd = ['ps.map', '--overwrite']
269  if os.path.splitext(filename)[1] == '.eps':
270  cmd.append('-e')
271  if self.instruction[self.pageId]['Orientation'] == 'Landscape':
272  cmd.append('-r')
273  cmd.append('input=%s' % instrFile)
274  cmd.append('output=%s' % filename)
275  if pdf:
276  self.SetStatusText(_('Generating PDF...'), 0)
277  elif not temp:
278  self.SetStatusText(_('Generating PostScript...'), 0)
279  else:
280  self.SetStatusText(_('Generating preview...'), 0)
281 
282  self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
283  'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
284 
285  def OnCmdDone(self, event):
286  """!ps.map process finished"""
287 
288  if event.returncode != 0:
289  GMessage(parent = self,
290  message = _("Ps.map exited with return code %s") % event.returncode)
291 
292  grass.try_remove(event.userData['instrFile'])
293  if event.userData['temp']:
294  grass.try_remove(event.userData['filename'])
295  return
296 
297  if event.userData['pdfname']:
298  if sys.platform == 'win32':
299  command = ['gswin32c',
300  '-P-', '-dSAFER',
301  '-dCompatibilityLevel=1.4',
302  '-q', '-P-',
303  '-dNOPAUSE', '-dBATCH',
304  '-sDEVICE=pdfwrite',
305  '-dPDFSETTINGS=/prepress', '-r1200',
306  '-sstdout=%stderr',
307  '-sOutputFile=%s' % event.userData['pdfname'],
308  '-P-', '-dSAFER',
309  '-dCompatibilityLevel=1.4',
310  '-c', '.setpdfwrite', '-f',
311  event.userData['filename']]
312  else:
313  command = ['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200',
314  event.userData['filename'], event.userData['pdfname']]
315  try:
316  proc = grass.Popen(command)
317  ret = proc.wait()
318  if ret > 0:
319  GMessage(parent = self,
320  message = _("%(prg)s exited with return code %(code)s") % {'prg': command[0],
321  'code': ret})
322  else:
323  self.SetStatusText(_('PDF generated'), 0)
324  except OSError, e:
325  GError(parent = self,
326  message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
327 
328  elif not event.userData['temp']:
329  self.SetStatusText(_('PostScript file generated'), 0)
330 
331  # show preview only when user doesn't want to create ps or pdf
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'])
334 
335  busy = wx.BusyInfo(message = _("Generating preview, wait please"), parent = self)
336  wx.Yield()
337  try:
338  im = PILImage.open(event.userData['filename'])
339  if self.instruction[self.pageId]['Orientation'] == 'Landscape':
340  im = im.rotate(270)
341 
342  # hack for Windows, change method for loading EPS
343  if sys.platform == 'win32':
344  import types
345  im.load = types.MethodType(loadPSForWindows, im)
346  im.save(self.imgName, format = 'PNG')
347  except IOError, e:
348  del busy
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."))
353  dlg.ShowModal()
354  dlg.Destroy()
355  return
356 
357 
358  rect = self.previewCanvas.ImageRect()
359  self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
360  self.previewCanvas.DrawImage(rect = rect)
361 
362  del busy
363  self.SetStatusText(_('Preview generated'), 0)
364  self.book.SetSelection(1)
365  self.currentPage = 1
366 
367  grass.try_remove(event.userData['instrFile'])
368  if event.userData['temp']:
369  grass.try_remove(event.userData['filename'])
370 
371  self.delayedCall = wx.CallLater(4000, lambda: self.SetStatusText("", 0))
372 
373  def getFile(self, wildcard):
374  suffix = []
375  for filter in wildcard.split('|')[1::2]:
376  s = filter.strip('*').split('.')[1]
377  if s:
378  s = '.' + s
379  suffix.append(s)
380  raster = self.instruction.FindInstructionByType('raster')
381  if raster:
382  rasterId = raster.id
383  else:
384  rasterId = None
385 
386 
387  if rasterId and self.instruction[rasterId]['raster']:
388  mapName = self.instruction[rasterId]['raster'].split('@')[0] + suffix[0]
389  else:
390  mapName = ''
391 
392  filename = ''
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
403 
404  dlg.Destroy()
405  return filename
406 
407  def OnInstructionFile(self, event):
408  filename = self.getFile(wildcard = "*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")
409  if filename:
410  instrFile = open(filename, "w")
411  instrFile.write(self.InstructionFile())
412  instrFile.close()
413 
414  def OnLoadFile(self, event):
415  """!Load file and read instructions"""
416  #find file
417  filename = ''
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()
423  dlg.Destroy()
424  if not filename:
425  return
426  # load instructions
427  readObjectId = []
428  readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
429  ok = readInstruction.Read(filename)
430  if not ok:
431  GMessage(_("Failed to read file %s.") % filename)
432  else:
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
438  self.canvas.Clear()
439  self.canvas.SetPage()
440  #self.canvas.ZoomAll()
441 
442  self.DialogDataChanged(self.objectId)
443 
444  def OnPageSetup(self, event = None):
445  """!Specify paper size, margins and orientation"""
446  id = self.instruction.FindInstructionByType('page').id
447  dlg = PageSetupDialog(self, id = id, settings = self.instruction)
448  dlg.CenterOnScreen()
449  val = dlg.ShowModal()
450  if val == wx.ID_OK:
451  self.canvas.SetPage()
452  self.getInitMap()
453  self.canvas.RecalculatePosition(ids = self.objectId)
454  dlg.Destroy()
455 
456  def OnPointer(self, event):
457  self.toolbar.OnTool(event)
458  self.mouse["use"] = "pointer"
459  self.canvas.SetCursor(self.cursors["default"])
460  self.previewCanvas.SetCursor(self.cursors["default"])
461 
462  def OnPan(self, event):
463  self.toolbar.OnTool(event)
464  self.mouse["use"] = "pan"
465  self.canvas.SetCursor(self.cursors["hand"])
466  self.previewCanvas.SetCursor(self.cursors["hand"])
467 
468  def OnZoomIn(self, event):
469  self.toolbar.OnTool(event)
470  self.mouse["use"] = "zoomin"
471  self.canvas.SetCursor(self.cursors["cross"])
472  self.previewCanvas.SetCursor(self.cursors["cross"])
473 
474  def OnZoomOut(self, event):
475  self.toolbar.OnTool(event)
476  self.mouse["use"] = "zoomout"
477  self.canvas.SetCursor(self.cursors["cross"])
478  self.previewCanvas.SetCursor(self.cursors["cross"])
479 
480  def OnZoomAll(self, event):
481  self.mouseOld = self.mouse['use']
482  if self.currentPage == 0:
483  self.cursorOld = self.canvas.GetCursor()
484  else:
485  self.cursorOld = self.previewCanvas.GetCursor()
486  self.previewCanvas.GetCursor()
487  self.mouse["use"] = "zoomin"
488  if self.currentPage == 0:
489  self.canvas.ZoomAll()
490  else:
491  self.previewCanvas.ZoomAll()
492  self.mouse["use"] = self.mouseOld
493  if self.currentPage == 0:
494  self.canvas.SetCursor(self.cursorOld)
495  else:
496  self.previewCanvas.SetCursor(self.cursorOld)
497 
498 
499  def OnAddMap(self, event, notebook = False):
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']
504  self.mouseOld = self.mouse['use']
505  self.cursorOld = self.canvas.GetCursor()
506  self.toolbar.OnTool(event)
507 
508  if self.instruction.FindInstructionByType('map'):
509  mapId = self.instruction.FindInstructionByType('map').id
510  else: mapId = None
511  id = [mapId, None, None]
512 
513  if notebook:
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
520  id[1] = rasterId
521  id[2] = vectorId
522 
523 
524  if mapId: # map exists
525 
526  self.toolbar.ToggleTool(self.actionOld, True)
527  self.toolbar.ToggleTool(self.toolbar.action['id'], False)
528  self.toolbar.action['id'] = self.actionOld
529  try:
530  self.canvas.SetCursor(self.cursorOld)
531  except AttributeError:
532  pass
533 
534 ## dlg = MapDialog(parent = self, id = id, settings = self.instruction,
535 ## notebook = notebook)
536 ## dlg.ShowModal()
537  if notebook:
538  #check map, raster, vector and save, destroy them
539  if 'map' in self.openDialogs:
540  self.openDialogs['map'].OnOK(event = None)
541  if 'raster' in self.openDialogs:
542  self.openDialogs['raster'].OnOK(event = None)
543  if 'vector' in self.openDialogs:
544  self.openDialogs['vector'].OnOK(event = None)
545 
546  if 'mapNotebook' not in self.openDialogs:
547  dlg = MapDialog(parent = self, id = id, settings = self.instruction,
548  notebook = notebook)
549  self.openDialogs['mapNotebook'] = dlg
550  self.openDialogs['mapNotebook'].Show()
551  else:
552  if 'mapNotebook' in self.openDialogs:
553  self.openDialogs['mapNotebook'].notebook.ChangeSelection(0)
554  else:
555  if 'map' not in self.openDialogs:
556  dlg = MapDialog(parent = self, id = id, settings = self.instruction,
557  notebook = notebook)
558  self.openDialogs['map'] = dlg
559  self.openDialogs['map'].Show()
560 
561 
562  else: # sofar no map
563  self.mouse["use"] = "addMap"
564  self.canvas.SetCursor(self.cursors["cross"])
565  if self.currentPage == 1:
566  self.book.SetSelection(0)
567  self.currentPage = 0
568 
569  def OnAddRaster(self, event):
570  """!Add raster map"""
571  if self.instruction.FindInstructionByType('raster'):
572  id = self.instruction.FindInstructionByType('raster').id
573  else: id = None
574  if self.instruction.FindInstructionByType('map'):
575  mapId = self.instruction.FindInstructionByType('map').id
576  else: mapId = None
577 
578  if not id:
579  if not mapId:
580  GMessage(message = _("Please, create map frame first."))
581  return
582 
583 ## dlg = RasterDialog(self, id = id, settings = self.instruction)
584 ## dlg.ShowModal()
585  if 'mapNotebook' in self.openDialogs:
586  self.openDialogs['mapNotebook'].notebook.ChangeSelection(1)
587  else:
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()
592 
593  def OnAddVect(self, event):
594  """!Add vector map"""
595  if self.instruction.FindInstructionByType('vector'):
596  id = self.instruction.FindInstructionByType('vector').id
597  else: id = None
598  if self.instruction.FindInstructionByType('map'):
599  mapId = self.instruction.FindInstructionByType('map').id
600  else: mapId = None
601  if not id:
602  if not mapId:
603  GMessage(message = _("Please, create map frame first."))
604  return
605 
606 ## dlg = MainVectorDialog(self, id = id, settings = self.instruction)
607 ## dlg.ShowModal()
608  if 'mapNotebook' in self.openDialogs:
609  self.openDialogs['mapNotebook'].notebook.ChangeSelection(2)
610  else:
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()
615 
616  def OnAddScalebar(self, event):
617  """!Add scalebar"""
618  if projInfo()['proj'] == 'll':
619  GMessage(message = _("Scalebar is not appropriate for this projection"))
620  return
621  if self.instruction.FindInstructionByType('scalebar'):
622  id = self.instruction.FindInstructionByType('scalebar').id
623  else: id = None
624 
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()
629 
630  def OnAddLegend(self, event, page = 0):
631  """!Add raster or vector legend"""
632  if self.instruction.FindInstructionByType('rasterLegend'):
633  idR = self.instruction.FindInstructionByType('rasterLegend').id
634  else: idR = None
635  if self.instruction.FindInstructionByType('vectorLegend'):
636  idV = self.instruction.FindInstructionByType('vectorLegend').id
637  else: idV = None
638 
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()
645 
646  def OnAddMapinfo(self, event):
647  if self.instruction.FindInstructionByType('mapinfo'):
648  id = self.instruction.FindInstructionByType('mapinfo').id
649  else: id = None
650 
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()
655 
656  def OnAddImage(self, event, id = None):
657  """!Show dialog for image adding and editing"""
658  position = None
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
665  if position:
666  dlg.SetPosition(position)
667  dlg.Show()
668 
669  def OnAddNorthArrow(self, event, id = None):
670  """!Show dialog for north arrow adding and editing"""
671  if self.instruction.FindInstructionByType('northArrow'):
672  id = self.instruction.FindInstructionByType('northArrow').id
673  else: id = None
674 
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()
679 
680  def OnAddText(self, event, id = None):
681  """!Show dialog for text adding and editing"""
682  position = None
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
689  if position:
690  dlg.SetPosition(position)
691  dlg.Show()
692 
693  def OnAddPoint(self, event):
694  """!Add point action selected"""
695  self.mouse["use"] = "addPoint"
696  self.canvas.SetCursor(self.cursors["cross"])
697 
698  def AddPoint(self, id = None, coordinates = None):
699  """!Add point and open property dialog.
700 
701  @param id id point id (None if creating new point)
702  @param coordinates coordinates of new point
703  """
704  position = None
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
712  if position:
713  dlg.SetPosition(position)
714  if coordinates:
715  dlg.OnApply(event = None)
716  dlg.Show()
717 
718  def OnAddLine(self, event):
719  """!Add line action selected"""
720  self.mouse["use"] = "addLine"
721  self.canvas.SetCursor(self.cursors["cross"])
722 
723  def AddLine(self, id = None, coordinates = None):
724  """!Add line and open property dialog.
725 
726  @param id id line id (None if creating new line)
727  @param coordinates coordinates of new line
728  """
729  position = None
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
737  if position:
738  dlg.SetPosition(position)
739  if coordinates:
740  dlg.OnApply(event = None)
741  dlg.Show()
742 
743  def OnAddRectangle(self, event):
744  """!Add rectangle action selected"""
745  self.mouse["use"] = "addRectangle"
746  self.canvas.SetCursor(self.cursors["cross"])
747 
748  def AddRectangle(self, id = None, coordinates = None):
749  """!Add rectangle and open property dialog.
750 
751  @param id id rectangle id (None if creating new rectangle)
752  @param coordinates coordinates of new rectangle
753  """
754  position = None
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
762  if position:
763  dlg.SetPosition(position)
764  if coordinates:
765  dlg.OnApply(event = None)
766  dlg.Show()
767 
768  def getModifiedTextBounds(self, x, y, textExtent, rotation):
769  """!computes bounding box of rotated text, not very precisely"""
770  w, h = textExtent
771  rotation = float(rotation)/180*pi
772  H = float(w) * sin(rotation)
773  W = float(w) * cos(rotation)
774  X, Y = x, y
775  if pi/2 < rotation <= 3*pi/2:
776  X = x + W
777  if 0 < rotation < pi:
778  Y = y - H
779  if rotation == 0:
780  return wx.Rect(x,y, *textExtent)
781  else:
782  return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h)
783 
784  def makePSFont(self, textDict):
785  """!creates a wx.Font object from selected postscript font. To be
786  used for estimating bounding rectangle of text"""
787 
788  fontsize = textDict['fontsize'] * self.canvas.currScale
789  fontface = textDict['font'].split('-')[0]
790  try:
791  fontstyle = textDict['font'].split('-')[1]
792  except IndexError:
793  fontstyle = ''
794 
795  if fontface == "Times":
796  family = wx.FONTFAMILY_ROMAN
797  face = "times"
798  elif fontface == "Helvetica":
799  family = wx.FONTFAMILY_SWISS
800  face = 'helvetica'
801  elif fontface == "Courier":
802  family = wx.FONTFAMILY_TELETYPE
803  face = 'courier'
804  else:
805  family = wx.FONTFAMILY_DEFAULT
806  face = ''
807 
808  style = wx.FONTSTYLE_NORMAL
809  weight = wx.FONTWEIGHT_NORMAL
810 
811  if 'Oblique' in fontstyle:
812  style = wx.FONTSTYLE_SLANT
813 
814  if 'Italic' in fontstyle:
815  style = wx.FONTSTYLE_ITALIC
816 
817  if 'Bold' in fontstyle:
818  weight = wx.FONTWEIGHT_BOLD
819 
820  try:
821  fn = wx.Font(pointSize = fontsize, family = family, style = style,
822  weight = weight, face = face)
823  except:
824  fn = wx.Font(pointSize = fontsize, family = wx.FONTFAMILY_DEFAULT,
825  style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL)
826 
827  return fn
828 
829 
830  def getTextExtent(self, textDict):
831  """!Estimates bounding rectangle of text"""
832  #fontsize = str(fontsize if fontsize >= 4 else 4)
833  dc = wx.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
834 
835  fn = self.makePSFont(textDict)
836 
837  try:
838  dc.SetFont(fn)
839  w,h,lh = dc.GetMultiLineTextExtent(textDict['text'])
840  return (w,h)
841  except:
842  return (0,0)
843 
844  def getInitMap(self):
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())
849  instrFileFd.flush()
850  instrFileFd.close()
851 
852  page = self.instruction.FindInstructionByType('page')
853  mapInitRect = GetMapBounds(instrFile, portrait = (page['Orientation'] == 'Portrait'))
854  grass.try_remove(instrFile)
855 
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
860 
861  initMap = self.instruction.FindInstructionByType('initMap')
862  if initMap:
863  id = initMap.id
864  else:
865  id = None
866 
867 
868  if not id:
869  id = wx.NewId()
870  initMap = InitMap(id)
871  self.instruction.AddInstruction(initMap)
872  self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
873 
874  def OnDelete(self, event):
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)
878  self.getInitMap()
879  self.canvas.RecalculateEN()
880  else:
881  self.deleteObject(self.canvas.dragId)
882 
883  def deleteObject(self, id):
884  """!Deletes object, his id and redraws"""
885  #delete from canvas
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()
891 
892  # delete from instructions
893  del self.instruction[id]
894 
895  def DialogDataChanged(self, id):
896  ids = id
897  if type(id) == int:
898  ids = [id]
899  for id in ids:
900  itype = self.instruction[id].type
901 
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)
914 
915  if itype in ('point', 'line', 'rectangle'):
916  drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
917  # coords only for line
918  coords = None
919  if itype == 'line':
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)
925 
926  # fill color is not in line
927  fcolor = None
928  if 'fcolor' in self.instruction[id].GetInstruction():
929  fcolor = self.instruction[id]['fcolor']
930  # width is not in point
931  width = None
932  if 'width' in self.instruction[id].GetInstruction():
933  width = self.instruction[id]['width']
934 
935  self.canvas.DrawGraphics(drawid = id, color = self.instruction[id]['color'], shape = itype,
936  fcolor = fcolor, width = width, bb = drawRectangle, lineCoords = coords)
937 
938  self.canvas.RedrawSelectBox(id)
939 
940  if itype == 'text':
941 
942  if self.instruction[id]['rotate']:
943  rot = float(self.instruction[id]['rotate'])
944  else:
945  rot = 0
946 
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])
950 
951  #computes text coordinates according to reference point, not precisely
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)
962 
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)
971 
972  if itype in ('map', 'vector', 'raster'):
973 
974  if itype == 'raster':#set resolution
975  info = grass.raster_info(self.instruction[id]['raster'])
976  RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
977  # change current raster in raster legend
978 
979  if 'rasterLegend' in self.openDialogs:
980  self.openDialogs['rasterLegend'].updateDialog()
981  id = self.instruction.FindInstructionByType('map').id
982 
983  #check resolution
984  if itype == 'raster':
985  SetResolution(dpi = self.instruction[id]['resolution'],
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()
992 
993  self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
994  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
995  # redraw select box
996  self.canvas.RedrawSelectBox(id)
997  self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
998  # redraw to get map to the bottom layer
999  #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
1000 
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)
1008  else:
1009  self.deleteObject(id)
1010 
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)
1020 
1021  else:
1022  self.deleteObject(id)
1023 
1024  def OnPageChanged(self, event):
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."))
1029  else:
1030  self.SetStatusText('')
1031 
1032 
1033 
1034  def OnPageChanging(self, event):
1035  """!Flatnotebook page is changing"""
1036  if self.currentPage == 0 and self.mouse['use'] == 'addMap':
1037  event.Veto()
1038 
1039  def OnHelp(self, event):
1040  """!Show help"""
1041  if self.parent and self.parent.GetName() == 'LayerManager':
1042  log = self.parent.GetLogWindow()
1043  log.RunCmd(['g.manual',
1044  'entry=wxGUI.PsMap'])
1045  else:
1046  RunCommand('g.manual',
1047  quiet = True,
1048  entry = 'wxGUI.PsMap')
1049 
1050  def OnAbout(self, event):
1051  """!Display About window"""
1052  info = wx.AboutDialogInfo()
1053 
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)))
1060 
1061  wx.AboutBox(info)
1062 
1063  def OnCloseWindow(self, event):
1064  """!Close window"""
1065  try:
1066  os.remove(self.imgName)
1067  except OSError:
1068  pass
1069  grass.set_raise_on_error(False)
1070  if hasattr(self, 'delayedCall') and self.delayedCall.IsRunning():
1071  self.delayedCall.Stop()
1072  self.Destroy()
1073 
1074 
1075 
1076 class PsMapBufferedWindow(wx.Window):
1077  """!A buffered window class.
1078 
1079  @param parent parent window
1080  @param kwargs other wx.Window parameters
1081  """
1082  def __init__(self, parent, id = wx.ID_ANY,
1083  style = wx.NO_FULL_REPAINT_ON_RESIZE,
1084  **kwargs):
1085  wx.Window.__init__(self, parent, id = id, style = style)
1086  self.parent = parent
1087 
1088  self.FitInside()
1089 
1090  # store an off screen empty bitmap for saving to file
1091  self._buffer = None
1092  # indicates whether or not a resize event has taken place
1093  self.resize = False
1094 
1095  self.mouse = kwargs['mouse']
1096  self.cursors = kwargs['cursors']
1097  self.preview = kwargs['preview']
1098  self.pen = kwargs['pen']
1099  self.brush = kwargs['brush']
1100 
1101  if kwargs.has_key('instruction'):
1102  self.instruction = kwargs['instruction']
1103  if kwargs.has_key('openDialogs'):
1104  self.openDialogs = kwargs['openDialogs']
1105  if kwargs.has_key('pageId'):
1106  self.pageId = kwargs['pageId']
1107  if kwargs.has_key('objectId'):
1108  self.objectId = kwargs['objectId']
1109 
1110 
1111  #labels
1112  self.itemLabelsDict = { 'map': 'MAP FRAME',
1113  'rasterLegend': 'RASTER LEGEND',
1114  'vectorLegend': 'VECTOR LEGEND',
1115  'mapinfo': 'MAP INFO',
1116  'scalebar': 'SCALE BAR',
1117  'image': 'IMAGE',
1118  'northArrow': 'NORTH ARROW'}
1119  self.itemLabels = {}
1120 
1121  # define PseudoDC
1122  self.pdc = wx.PseudoDC()
1123  self.pdcObj = wx.PseudoDC()
1124  self.pdcPaper = wx.PseudoDC()
1125  self.pdcTmp = wx.PseudoDC()
1126  self.pdcImage = wx.PseudoDC()
1127  dc = wx.ClientDC(self)
1128  self.font = dc.GetFont()
1129 
1130  self.SetClientSize((700,510))#?
1131  self._buffer = wx.EmptyBitmap(*self.GetClientSize())
1132 
1133  self.idBoxTmp = wx.NewId()
1134  self.idZoomBoxTmp = wx.NewId()
1135  self.idResizeBoxTmp = wx.NewId()
1136  self.idLinePointsTmp = (wx.NewId(), wx.NewId()) # ids of marks for moving line vertices
1137 
1138  self.resizeBoxSize = wx.Size(8, 8)
1139  self.showResizeHelp = False # helper for correctly working statusbar
1140 
1141 
1142 
1143  self.dragId = -1
1144 
1145  if self.preview:
1146  self.image = None
1147  self.imageId = 2000
1148  self.imgName = self.parent.imgName
1149 
1150 
1151 
1152  self.currScale = None
1153 
1154  self.Clear()
1155 
1156  self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
1157 
1158  self.Bind(wx.EVT_PAINT, self.OnPaint)
1159  self.Bind(wx.EVT_SIZE, self.OnSize)
1160  self.Bind(wx.EVT_IDLE, self.OnIdle)
1161  # self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
1162  self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
1163 
1164 
1165  def Clear(self):
1166  """!Clear canvas and set paper
1167  """
1168  bg = wx.LIGHT_GREY_BRUSH
1169  self.pdcPaper.BeginDrawing()
1170  self.pdcPaper.SetBackground(bg)
1171  self.pdcPaper.Clear()
1172  self.pdcPaper.EndDrawing()
1173 
1174  self.pdcObj.RemoveAll()
1175  self.pdcTmp.RemoveAll()
1176 
1177 
1178 
1179  if not self.preview:
1180  self.SetPage()
1181 
1182 
1183  def CanvasPaperCoordinates(self, rect, canvasToPaper = True):
1184  """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
1185 
1186  units = UnitConversion(self)
1187 
1188  fromU = 'pixel'
1189  toU = 'inch'
1190  pRect = self.pdcPaper.GetIdBounds(self.pageId)
1191  pRectx, pRecty = pRect.x, pRect.y
1192  scale = 1/self.currScale
1193  if not canvasToPaper: # paper -> canvas
1194  fromU = 'inch'
1195  toU = 'pixel'
1196  scale = self.currScale
1197  pRectx = units.convert(value = - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
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
1203 
1204  return Rect2D(X, Y, Width, Height)
1205 
1206 
1207 
1208  def SetPage(self):
1209  """!Sets and changes page, redraws paper"""
1210 
1211  page = self.instruction[self.pageId]
1212  if not page:
1213  page = PageSetup(id = self.pageId)
1214  self.instruction.AddInstruction(page)
1215 
1216  ppi = wx.ClientDC(self).GetPPI()
1217  cW, cH = self.GetClientSize()
1218  pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
1219 
1220  if self.currScale is None:
1221  self.currScale = min(cW/pW, cH/pH)
1222  pW = pW * self.currScale
1223  pH = pH * self.currScale
1224 
1225  x = cW/2 - pW/2
1226  y = cH/2 - pH/2
1227  self.DrawPaper(wx.Rect(x, y, pW, pH))
1228 
1229 
1230  def modifyRectangle(self, r):
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()))
1238  return r
1239 
1240  def RecalculateEN(self):
1241  """!Recalculate east and north for texts (eps, points) after their or map's movement"""
1242  try:
1243  mapId = self.instruction.FindInstructionByType('map').id
1244  except AttributeError:
1245  mapId = self.instruction.FindInstructionByType('initMap').id
1246 
1247  for itemType in ('text', 'image', 'northArrow', 'point', 'line', 'rectangle'):
1248  items = self.instruction.FindInstructionByType(itemType, list = True)
1249  for item in items:
1250  instr = self.instruction[item.id]
1251  if itemType in ('line', 'rectangle'):
1252  if itemType == 'line':
1253  e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0][0],
1254  y = instr['where'][0][1], paperToMap = True)
1255  e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][1][0],
1256  y = instr['where'][1][1], paperToMap = True)
1257  else:
1258  e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetLeft(),
1259  y = instr['rect'].GetTop(), paperToMap = True)
1260  e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetRight(),
1261  y = instr['rect'].GetBottom(), paperToMap = True)
1262  instr['east1'] = e1
1263  instr['north1'] = n1
1264  instr['east2'] = e2
1265  instr['north2'] = n2
1266  else:
1267  e, n = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0],
1268  y = instr['where'][1], paperToMap = True)
1269  instr['east'], instr['north'] = e, n
1270 
1271  def OnPaint(self, event):
1272  """!Draw pseudo DC to buffer
1273  """
1274  if not self._buffer:
1275  return
1276  dc = wx.BufferedPaintDC(self, self._buffer)
1277  # use PrepareDC to set position correctly
1278  self.PrepareDC(dc)
1279 
1280  dc.SetBackground(wx.LIGHT_GREY_BRUSH)
1281  dc.Clear()
1282 
1283  # draw paper
1284  if not self.preview:
1285  self.pdcPaper.DrawToDC(dc)
1286  # draw to the DC using the calculated clipping rect
1287 
1288  rgn = self.GetUpdateRegion()
1289 
1290  if not self.preview:
1291  self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
1292  else:
1293  self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
1294  self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
1295 
1296  def MouseActions(self, event):
1297  """!Mouse motion and button click notifier
1298  """
1299  # zoom with mouse wheel
1300  if event.GetWheelRotation() != 0:
1301  self.OnMouseWheel(event)
1302 
1303  # left mouse button pressed
1304  elif event.LeftDown():
1305  self.OnLeftDown(event)
1306 
1307  # left mouse button released
1308  elif event.LeftUp():
1309  self.OnLeftUp(event)
1310 
1311  # dragging
1312  elif event.Dragging():
1313  self.OnDragging(event)
1314 
1315  # double click
1316  elif event.ButtonDClick():
1317  self.OnButtonDClick(event)
1318 
1319  # middle mouse button pressed
1320  elif event.MiddleDown():
1321  self.OnMiddleDown(event)
1322 
1323  elif event.Moving():
1324  self.OnMouseMoving(event)
1325 
1326  def OnMouseWheel(self, event):
1327  """!Mouse wheel scrolled.
1328 
1329  Changes zoom."""
1330  if UserSettings.Get(group = 'display',
1331  key = 'mouseWheelZoom',
1332  subkey = 'selection') == 2:
1333  event.Skip()
1334  return
1335 
1336  zoom = event.GetWheelRotation()
1337  oldUse = self.mouse['use']
1338  self.mouse['begin'] = event.GetPosition()
1339 
1340  if UserSettings.Get(group = 'display',
1341  key = 'scrollDirection',
1342  subkey = 'selection'):
1343  zoom *= -1
1344 
1345  if zoom > 0:
1346  self.mouse['use'] = 'zoomin'
1347  else:
1348  self.mouse['use'] = 'zoomout'
1349 
1350  zoomFactor, view = self.ComputeZoom(wx.Rect(0, 0, 0, 0))
1351  self.Zoom(zoomFactor, view)
1352  self.mouse['use'] = oldUse
1353 
1354  def OnMouseMoving(self, event):
1355  """!Mouse cursor moving.
1356 
1357  Change cursor when moving over resize marker.
1358  """
1359  if self.preview:
1360  return
1361 
1362  if self.mouse['use'] in ('pointer', 'resize'):
1363  pos = event.GetPosition()
1364  foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
1365  if foundResize and foundResize[0] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
1366  self.SetCursor(self.cursors["sizenwse"])
1367  self.parent.SetStatusText(_('Click and drag to resize object'), 0)
1368  self.showResizeHelp = True
1369  else:
1370  if self.showResizeHelp:
1371  self.parent.SetStatusText('', 0)
1372  self.SetCursor(self.cursors["default"])
1373  self.showResizeHelp = False
1374 
1375  def OnLeftDown(self, event):
1376  """!Left mouse button pressed.
1377 
1378  Select objects, redraw, prepare for moving/resizing.
1379  """
1380  self.mouse['begin'] = event.GetPosition()
1381  self.begin = self.mouse['begin']
1382 
1383  # select
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])
1387 
1388  if foundResize and foundResize[0] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
1389  self.mouse['use'] = 'resize'
1390 
1391  # when resizing, proportions match region
1392  if self.instruction[self.dragId].type == 'map':
1393  self.constraint = False
1394  self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
1395  if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
1396  self.constraint = True
1397  self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
1398 
1399  if self.instruction[self.dragId].type == 'line':
1400  self.currentLinePoint = self.idLinePointsTmp.index(foundResize[0])
1401 
1402  elif found:
1403  self.dragId = found[0]
1404  self.RedrawSelectBox(self.dragId)
1405  if self.instruction[self.dragId].type not in ('map', 'rectangle'):
1406  self.pdcTmp.RemoveId(self.idResizeBoxTmp)
1407  self.Refresh()
1408  if self.instruction[self.dragId].type != 'line':
1409  for id in self.idLinePointsTmp:
1410  self.pdcTmp.RemoveId(id)
1411  self.Refresh()
1412 
1413  else:
1414  self.dragId = -1
1415  self.pdcTmp.RemoveId(self.idBoxTmp)
1416  self.pdcTmp.RemoveId(self.idResizeBoxTmp)
1417  for id in self.idLinePointsTmp:
1418  self.pdcTmp.RemoveId(id)
1419  self.Refresh()
1420 
1421  def OnLeftUp(self, event):
1422  """!Left mouse button released.
1423 
1424  Recalculate zooming/resizing/moving and redraw.
1425  """
1426  # zoom in, zoom out
1427  if self.mouse['use'] in ('zoomin','zoomout'):
1428  zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
1429  self.pdcTmp.RemoveId(self.idZoomBoxTmp)
1430  self.Refresh()
1431  zoomFactor, view = self.ComputeZoom(zoomR)
1432  self.Zoom(zoomFactor, view)
1433 
1434  # draw map frame
1435  if self.mouse['use'] == 'addMap':
1436  rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
1437  # too small rectangle, it's usually some mistake
1438  if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
1439  self.pdcTmp.RemoveId(self.idZoomBoxTmp)
1440  self.Refresh()
1441  return
1442  rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)
1443 
1444  dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction,
1445  rect = rectPaper)
1446  self.openDialogs['map'] = dlg
1447  self.openDialogs['map'].Show()
1448 
1449  self.mouse['use'] = self.parent.mouseOld
1450 
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
1455  return
1456 
1457  # resize resizable objects (map, line, rectangle)
1458  if self.mouse['use'] == 'resize':
1459  mapObj = self.instruction.FindInstructionByType('map')
1460  if not mapObj:
1461  mapObj = self.instruction.FindInstructionByType('initMap')
1462  mapId = mapObj.id
1463 
1464  if self.dragId == mapId:
1465  # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
1466  newRectCanvas = self.pdcObj.GetIdBounds(mapId)
1467  newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
1468  self.instruction[mapId]['rect'] = newRectPaper
1469 
1470  if self.instruction[mapId]['scaleType'] in (0, 1, 2):
1471  if self.instruction[mapId]['scaleType'] == 0:
1472 
1473  scale, foo, rect = AutoAdjust(self, scaleType = 0,
1474  map = self.instruction[mapId]['map'],
1475  mapType = self.instruction[mapId]['mapType'],
1476  rect = self.instruction[mapId]['rect'])
1477 
1478  elif self.instruction[mapId]['scaleType'] == 1:
1479  scale, foo, rect = AutoAdjust(self, scaleType = 1,
1480  region = self.instruction[mapId]['region'],
1481  rect = self.instruction[mapId]['rect'])
1482  else:
1483  scale, foo, rect = AutoAdjust(self, scaleType = 2,
1484  rect = self.instruction[mapId]['rect'])
1485  self.instruction[mapId]['rect'] = rect
1486  self.instruction[mapId]['scale'] = scale
1487 
1488  rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
1489  self.Draw(pen = self.pen['map'], brush = self.brush['map'],
1490  pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
1491 
1492  elif self.instruction[mapId]['scaleType'] == 3:
1493  ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
1494  #check resolution
1495  SetResolution(dpi = self.instruction[mapId]['resolution'],
1496  width = self.instruction[mapId]['rect'].width,
1497  height = self.instruction[mapId]['rect'].height)
1498 
1499  self.RedrawSelectBox(mapId)
1500  self.Zoom(zoomFactor = 1, view = (0, 0))
1501 
1502  elif self.instruction[self.dragId].type == 'line':
1503  points = self.instruction[self.dragId]['where']
1504  self.instruction[self.dragId]['rect'] = Rect2DPP(points[0], points[1])
1505  self.RecalculatePosition(ids = [self.dragId])
1506 
1507  elif self.instruction[self.dragId].type == 'rectangle':
1508  self.RecalculatePosition(ids = [self.dragId])
1509 
1510  self.mouse['use'] = 'pointer'
1511 
1512  # recalculate the position of objects after dragging
1513  if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
1514  if self.mouse['begin'] != event.GetPosition(): #for double click
1515 
1516  self.RecalculatePosition(ids = [self.dragId])
1517  if self.instruction[self.dragId].type in self.openDialogs:
1518  self.openDialogs[self.instruction[self.dragId].type].updateDialog()
1519 
1520  elif self.mouse['use'] in ('addPoint', 'addLine', 'addRectangle'):
1521  endCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(event.GetX(), event.GetY(), 0, 0),
1522  canvasToPaper = True)[:2]
1523 
1524  diffX = event.GetX() - self.mouse['begin'][0]
1525  diffY = event.GetY() - self.mouse['begin'][1]
1526 
1527  if self.mouse['use'] == 'addPoint':
1528  self.parent.AddPoint(coordinates = endCoordinates)
1529  elif self.mouse['use'] in ('addLine', 'addRectangle'):
1530  # not too small lines/rectangles
1531  if sqrt(diffX * diffX + diffY * diffY) < 5:
1532  self.pdcTmp.RemoveId(self.idZoomBoxTmp)
1533  self.Refresh()
1534  return
1535 
1536  beginCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(self.mouse['begin'][0],
1537  self.mouse['begin'][1], 0, 0),
1538  canvasToPaper = True)[:2]
1539  if self.mouse['use'] == 'addLine':
1540  self.parent.AddLine(coordinates = [beginCoordinates, endCoordinates])
1541  else:
1542  self.parent.AddRectangle(coordinates = [beginCoordinates, endCoordinates])
1543  self.pdcTmp.RemoveId(self.idZoomBoxTmp)
1544  self.Refresh()
1545 
1546  def OnButtonDClick(self, event):
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}
1560 
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)}
1572 
1573  type = self.instruction[self.dragId].type
1574  itemCall[type](**itemArg[type])
1575 
1576  def OnDragging(self, event):
1577  """!Process panning/resizing/drawing/moving."""
1578  if event.MiddleIsDown():
1579  # panning
1580  self.mouse['end'] = event.GetPosition()
1581  self.Pan(begin = self.mouse['begin'], end = self.mouse['end'])
1582  self.mouse['begin'] = event.GetPosition()
1583 
1584  elif event.LeftIsDown():
1585  # draw box when zooming, creating map
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],
1589  self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
1590  r = self.modifyRectangle(r)
1591 
1592  if self.mouse['use'] in ('addLine', 'addRectangle'):
1593  if self.mouse['use'] == 'addLine':
1594  pdcType = 'line'
1595  lineCoords = (self.mouse['begin'], self.mouse['end'])
1596  else:
1597  pdcType = 'rect'
1598  lineCoords = None
1599  if r[2] < 2 or r[3] < 2:
1600  # to avoid strange behavoiur
1601  return
1602 
1603  self.Draw(pen = self.pen['line'], brush = self.brush['line'],
1604  pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
1605  pdctype = pdcType, bb = r, lineCoords = lineCoords)
1606 
1607  else:
1608  self.Draw(pen = self.pen['box'], brush = self.brush['box'],
1609  pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
1610  pdctype = 'rect', bb = r)
1611 
1612  # panning
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()
1617 
1618  # move object
1619  if self.mouse['use'] == 'pointer' and self.dragId != -1:
1620  self.mouse['end'] = event.GetPosition()
1621  dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
1622  self.pdcObj.TranslateId(self.dragId, dx, dy)
1623  self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
1624  self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
1625  for id in self.idLinePointsTmp:
1626  self.pdcTmp.TranslateId(id, dx, dy)
1627  if self.instruction[self.dragId].type == 'text':
1628  self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
1629  self.instruction[self.dragId]['coords'][1] + dy
1630  self.begin = event.GetPosition()
1631  self.Refresh()
1632 
1633  # resize object
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]
1638  if self.instruction[self.dragId].type == 'map':
1639  x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
1640  width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
1641  # match given region
1642  if self.constraint:
1643  if width > height:
1644  newWidth = width + diffX
1645  newHeight = height + diffX * (float(height) / width)
1646  else:
1647  newWidth = width + diffY * (float(width) / height)
1648  newHeight = height + diffY
1649  else:
1650  newWidth = width + diffX
1651  newHeight = height + diffY
1652 
1653  if newWidth < 10 or newHeight < 10:
1654  return
1655 
1656  bounds = wx.Rect(x, y, newWidth, newHeight)
1657  self.Draw(pen = self.pen['map'], brush = self.brush['map'], pdc = self.pdcObj, drawid = self.dragId,
1658  pdctype = 'rectText', bb = bounds)
1659 
1660  elif self.instruction[self.dragId].type == 'rectangle':
1661  instr = self.instruction[self.dragId]
1662  rect = self.CanvasPaperCoordinates(rect = instr['rect'], canvasToPaper = False)
1663  rect.SetWidth(rect.GetWidth() + diffX)
1664  rect.SetHeight(rect.GetHeight() + diffY)
1665 
1666  if rect.GetWidth() < 5 or rect.GetHeight() < 5:
1667  return
1668 
1669  self.DrawGraphics(drawid = self.dragId, shape = 'rectangle', color = instr['color'],
1670  fcolor = instr['fcolor'], width = instr['width'], bb = rect)
1671 
1672  elif self.instruction[self.dragId].type == 'line':
1673  instr = self.instruction[self.dragId]
1674  points = instr['where']
1675  # moving point
1676  if self.currentLinePoint == 0:
1677  pPaper = points[1]
1678  else:
1679  pPaper = points[0]
1680  pCanvas = self.CanvasPaperCoordinates(rect = Rect2DPS(pPaper, (0, 0)),
1681  canvasToPaper = False)[:2]
1682  bounds = wx.RectPP(pCanvas, pos)
1683  self.DrawGraphics(drawid = self.dragId, shape = 'line', color = instr['color'],
1684  width = instr['width'], bb = bounds, lineCoords = (pos, pCanvas))
1685 
1686  # update paper coordinates
1687  points[self.currentLinePoint] = self.CanvasPaperCoordinates(rect = wx.RectPS(pos, (0, 0)),
1688  canvasToPaper = True)[:2]
1689 
1690  self.RedrawSelectBox(self.dragId)
1691 
1692  def OnMiddleDown(self, event):
1693  """!Middle mouse button pressed."""
1694  self.mouse['begin'] = event.GetPosition()
1695 
1696  def Pan(self, begin, end):
1697  """!Move canvas while dragging.
1698 
1699  @param begin x,y coordinates of first point
1700  @param end x,y coordinates of second point
1701  """
1702  view = begin[0] - end[0], begin[1] - end[1]
1703  zoomFactor = 1
1704  self.Zoom(zoomFactor, view)
1705 
1706  def RecalculatePosition(self, ids):
1707  for id in ids:
1708  itype = self.instruction[id].type
1709  if itype in ('map', 'rectangle'):
1710  self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
1711  canvasToPaper = True)
1712  self.RecalculateEN()
1713 
1714  elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
1715  self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
1716  canvasToPaper = True)
1717  self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
1718  canvasToPaper = True)[:2]
1719  if itype in ('image', 'northArrow'):
1720  self.RecalculateEN()
1721 
1722  elif itype == 'point':
1723  rect = self.pdcObj.GetIdBounds(id)
1724  self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = rect,
1725  canvasToPaper = True)
1726  rect.OffsetXY(rect.GetWidth()/2, rect.GetHeight()/2)
1727  self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = rect,
1728  canvasToPaper = True)[:2]
1729  self.RecalculateEN()
1730 
1731  elif itype == 'line':
1732  rect = self.pdcObj.GetIdBounds(id)
1733  oldRect = self.instruction[id]['rect']
1734  newRect = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = True)
1735  xDiff = newRect[0] - oldRect[0]
1736  yDiff = newRect[1] - oldRect[1]
1737  self.instruction[id]['rect'] = newRect
1738 
1739  point1 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][0]
1740  point2 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][1]
1741  self.instruction[id]['where'] = [point1, point2]
1742 
1743  self.RecalculateEN()
1744 
1745  elif itype == 'scalebar':
1746  self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
1747  canvasToPaper = True)
1748 
1749 
1750  self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
1751 
1752  elif itype == 'text':
1753  x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
1754  self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
1755  extent = self.parent.getTextExtent(textDict = self.instruction[id])
1756  if self.instruction[id]['rotate'] is not None:
1757  rot = float(self.instruction[id]['rotate'])/180*pi
1758  else:
1759  rot = 0
1760 
1761  if self.instruction[id]['ref'].split()[0] == 'lower':
1762  y += extent[1]
1763  elif self.instruction[id]['ref'].split()[0] == 'center':
1764  y += extent[1]/2
1765  if self.instruction[id]['ref'].split()[1] == 'right':
1766  x += extent[0] * cos(rot)
1767  y -= extent[0] * sin(rot)
1768  elif self.instruction[id]['ref'].split()[1] == 'center':
1769  x += extent[0]/2 * cos(rot)
1770  y -= extent[0]/2 * sin(rot)
1771 
1772  self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = Rect2D(x, y, 0, 0),
1773  canvasToPaper = True)[:2]
1774  self.RecalculateEN()
1775 
1776  def ComputeZoom(self, rect):
1777  """!Computes zoom factor and scroll view"""
1778  zoomFactor = 1
1779  cW, cH = self.GetClientSize()
1780  cW = float(cW)
1781  if rect.IsEmpty(): # clicked on canvas
1782  zoomFactor = 1.5
1783  if self.mouse['use'] == 'zoomout':
1784  zoomFactor = 1./zoomFactor
1785  x,y = self.mouse['begin']
1786  xView = x - x/zoomFactor#x - cW/(zoomFactor * 2)
1787  yView = y - y/zoomFactor#y - cH/(zoomFactor * 2)
1788 
1789  else: #dragging
1790  rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
1791  try:
1792  zoomFactor = 1/max(rW/cW, rH/cH)
1793  except ZeroDivisionError:
1794  zoomFactor = 1
1795  # when zooming to full extent, in some cases, there was zoom 1.01..., which causes problem
1796  if abs(zoomFactor - 1) > 0.01:
1797  zoomFactor = zoomFactor
1798  else:
1799  zoomFactor = 1.
1800 
1801 
1802  if self.mouse['use'] == 'zoomout':
1803  zoomFactor = min(rW/cW, rH/cH)
1804  try:
1805  if rW/rH > cW/cH:
1806  yView = rect.GetY() - (rW*(cH/cW) - rH)/2
1807  xView = rect.GetX()
1808 
1809  if self.mouse['use'] == 'zoomout':
1810  x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
1811  xView, yView = -x, -y
1812  else:
1813  xView = rect.GetX() - (rH*(cW/cH) - rW)/2
1814  yView = rect.GetY()
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))
1821 
1822 
1823  def Zoom(self, zoomFactor, view):
1824  """! Zoom to specified region, scroll view, redraw"""
1825  if not self.currScale:
1826  return
1827  self.currScale = self.currScale*zoomFactor
1828 
1829  if self.currScale > 10 or self.currScale < 0.1:
1830  self.currScale = self.currScale/zoomFactor
1831  return
1832  if not self.preview:
1833  # redraw paper
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)
1838 
1839  #redraw objects
1840  for id in self.objectId:
1841  oRect = self.CanvasPaperCoordinates(
1842  rect = self.instruction[id]['rect'], canvasToPaper = False)
1843 
1844  type = self.instruction[id].type
1845  if type == 'text':
1846  coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
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])
1850  if self.instruction[id]['rotate']:
1851  rot = float(self.instruction[id]['rotate'])
1852  else:
1853  rot = 0
1854  self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
1855  self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
1856  coords = coords, bounds = bounds )
1857 
1858  self.pdcObj.SetIdBounds(id, bounds)
1859 
1860  elif type == 'northArrow':
1861  self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
1862  drawid = id, pdctype = 'bitmap', bb = oRect)
1863 
1864  elif type in ('point', 'line', 'rectangle'):
1865  instr = self.instruction[id]
1866  color = self.instruction[id]['color']
1867  width = fcolor = coords = None
1868 
1869  if type in ('point', 'rectangle'):
1870  fcolor = self.instruction[id]['fcolor']
1871  if type in ('line', 'rectangle'):
1872  width = self.instruction[id]['width']
1873  if type in ('line'):
1874  point1, point2 = instr['where'][0], instr['where'][1]
1875  point1 = self.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)),
1876  canvasToPaper = False)[:2]
1877  point2 = self.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)),
1878  canvasToPaper = False)[:2]
1879  coords = (point1, point2)
1880 
1881  self.DrawGraphics(drawid = id, shape = type, bb = oRect, lineCoords = coords,
1882  color = color, fcolor = fcolor, width = width)
1883 
1884  else:
1885  self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
1886  drawid = id, pdctype = 'rectText', bb = oRect)
1887  #redraw tmp objects
1888  if self.dragId != -1:
1889  self.RedrawSelectBox(self.dragId)
1890 
1891  #redraw preview
1892  else: # preview mode
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)
1897 
1898  def ZoomAll(self):
1899  """! Zoom to full extent"""
1900  if not self.preview:
1901  bounds = self.pdcPaper.GetIdBounds(self.pageId)
1902  else:
1903  bounds = self.pdcImage.GetIdBounds(self.imageId)
1904  zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
1905  zoomFactor, view = self.ComputeZoom(zoomP)
1906  self.Zoom(zoomFactor, view)
1907 
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.
1910 
1911  @param pdc PseudoDC
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)
1915  """
1916  if drawid is None:
1917  drawid = wx.NewId()
1918  bb = bb.Get()
1919  pdc.BeginDrawing()
1920  pdc.RemoveId(drawid)
1921  pdc.SetId(drawid)
1922  pdc.SetPen(pen)
1923  pdc.SetBrush(brush)
1924 
1925  if pdctype == 'bitmap':
1926  if havePILImage:
1927  file = self.instruction[drawid]['epsfile']
1928  rotation = self.instruction[drawid]['rotate']
1929  self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
1930  else: # draw only rectangle with label
1931  pdctype = 'rectText'
1932 
1933  if pdctype in ('rect', 'rectText'):
1934  pdc.DrawRectangle(*bb)
1935 
1936  if pdctype == 'rectText':
1937  dc = wx.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
1938  font = self.font
1939  size = 10
1940  font.SetPointSize(size)
1941  font.SetStyle(wx.ITALIC)
1942  dc.SetFont(font)
1943  pdc.SetFont(font)
1944  text = '\n'.join(self.itemLabels[drawid])
1945  w,h,lh = dc.GetMultiLineTextExtent(text)
1946  textExtent = (w,h)
1947  textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
1948  r = map(int, bb)
1949  while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
1950  size -= 2
1951  font.SetPointSize(size)
1952  dc.SetFont(font)
1953  pdc.SetFont(font)
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)
1959 
1960  elif pdctype == 'point':
1961  pdc.DrawCircle(x = bb[0] + bb[2] / 2,
1962  y = bb[1] + bb[3] / 2,
1963  radius = bb[2] / 2)
1964 
1965  elif pdctype == 'line':
1966  pdc.DrawLinePoint(lineCoords[0], lineCoords[1])
1967 
1968  pdc.SetIdBounds(drawid, bb)
1969  pdc.EndDrawing()
1970  self.Refresh()
1971 
1972  return drawid
1973 
1974  def DrawGraphics(self, drawid, shape, color, bb, width = None, fcolor = None, lineCoords = None):
1975  """!Draw point/line/rectangle with given color and width
1976 
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)
1984  """
1985  pdctype = {'point' : 'point',
1986  'line' : 'line',
1987  'rectangle' : 'rect'}
1988 
1989  if color == 'none':
1990  pen = wx.TRANSPARENT_PEN
1991  else:
1992  if width is not None:
1993  units = UnitConversion(self)
1994  width = int(units.convert(value = width, fromUnit = 'point', toUnit = 'pixel') * self.currScale)
1995  else:
1996  width = 2
1997  pen = wx.Pen(colour = convertRGB(color), width = width)
1998  pen.SetCap(wx.CAP_BUTT) # this is how ps.map draws
1999 
2000  brush = wx.TRANSPARENT_BRUSH
2001  if fcolor and fcolor != 'none':
2002  brush = wx.Brush(colour = convertRGB(fcolor))
2003 
2004  self.Draw(pen = pen, brush = brush, pdc = self.pdcObj, pdctype = pdctype[shape],
2005  drawid = drawid, bb = bb, lineCoords = lineCoords)
2006 
2007  def DrawBitmap(self, pdc, filePath, rotation, bbox):
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():
2012  import types
2013  pImg.load = types.MethodType(loadPSForWindows, pImg)
2014 
2015  if rotation:
2016  # get rid of black background
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)
2022  img = PilImageToWxImage(pImg)
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)
2027 
2028  def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
2029  if textDict['rotate']:
2030  rot = float(textDict['rotate'])
2031  else:
2032  rot = 0
2033 
2034  if textDict['background'] != 'none':
2035  background = textDict['background']
2036  else:
2037  background = None
2038 
2039  pdc.RemoveId(drawId)
2040  pdc.SetId(drawId)
2041  pdc.BeginDrawing()
2042 
2043  # border is not redrawn when zoom changes, why?
2044 ## if textDict['border'] != 'none' and not rot:
2045 ## units = UnitConversion(self)
2046 ## borderWidth = units.convert(value = textDict['width'],
2047 ## fromUnit = 'point', toUnit = 'pixel' ) * self.currScale
2048 ## pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth))
2049 ## pdc.DrawRectangle(*bounds)
2050 
2051  if background:
2052  pdc.SetTextBackground(convertRGB(background))
2053  pdc.SetBackgroundMode(wx.SOLID)
2054  else:
2055  pdc.SetBackgroundMode(wx.TRANSPARENT)
2056 
2057  fn = self.parent.makePSFont(textDict)
2058 
2059  pdc.SetFont(fn)
2060  pdc.SetTextForeground(convertRGB(textDict['color']))
2061  if rot == 0:
2062  pdc.DrawLabel(text=textDict['text'], rect=bounds)
2063  else:
2064  pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
2065 
2066  pdc.SetIdBounds(drawId, wx.Rect(*bounds))
2067  self.Refresh()
2068  pdc.EndDrawing()
2069 
2070  def DrawImage(self, rect):
2071  """!Draw preview image to pseudoDC"""
2072  self.pdcImage.ClearId(self.imageId)
2073  self.pdcImage.SetId(self.imageId)
2074  img = self.image
2075 
2076 
2077  if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
2078  img = img.Scale(rect.width, rect.height)
2079  bitmap = img.ConvertToBitmap()
2080 
2081  self.pdcImage.BeginDrawing()
2082  self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
2083  self.pdcImage.SetIdBounds(self.imageId, rect)
2084  self.pdcImage.EndDrawing()
2085  self.Refresh()
2086 
2087  def DrawPaper(self, rect):
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()
2095 
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)
2102 
2103  self.pdcPaper.SetPen(self.pen['margins'])
2104  self.pdcPaper.SetBrush(self.brush['margins'])
2105  self.pdcPaper.DrawRectangle(x, y, w, h)
2106 
2107  self.pdcPaper.SetIdBounds(self.pageId, rect)
2108  self.pdcPaper.EndDrawing()
2109  self.Refresh()
2110 
2111 
2112  def ImageRect(self):
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()
2117 
2118  self.currScale = min(float(cW)/iW, float(cH)/iH)
2119  iW = iW * self.currScale
2120  iH = iH * self.currScale
2121  x = cW/2 - iW/2
2122  y = cH/2 - iH/2
2123  imageRect = wx.Rect(x, y, iW, iH)
2124 
2125  return imageRect
2126 
2127  def RedrawSelectBox(self, id):
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)
2133  # draw select box around object
2134  self.Draw(pen = self.pen['select'], brush = self.brush['select'], pdc = self.pdcTmp,
2135  drawid = self.idBoxTmp, pdctype = 'rect', bb = rect)
2136 
2137  # draw small marks signalizing resizing
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)
2143 
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]
2149  rect = []
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])
2156 
2157  def UpdateMapLabel(self):
2158  """!Updates map frame label"""
2159 
2160  vector = self.instruction.FindInstructionByType('vector')
2161  if vector:
2162  vectorId = vector.id
2163  else:
2164  vectorId = None
2165 
2166  raster = self.instruction.FindInstructionByType('raster')
2167  if raster:
2168  rasterId = raster.id
2169  else:
2170  rasterId = None
2171 
2172  rasterName = 'None'
2173  if rasterId:
2174  rasterName = self.instruction[rasterId]['raster'].split('@')[0]
2175 
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)
2180  if vectorId:
2181  for map in self.instruction[vectorId]['list']:
2182  self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
2183 
2184  def UpdateLabel(self, itype, id):
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)
2190 
2191  def OnSize(self, event):
2192  """!Init image size to match window size
2193  """
2194  # not zoom all when notebook page is changed
2195  if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
2196  self.ZoomAll()
2197  self.OnIdle(None)
2198  event.Skip()
2199 
2200  def OnIdle(self, event):
2201  """!Only re-render a image during idle time instead of
2202  multiple times during resizing.
2203  """
2204 
2205  width, height = self.GetClientSize()
2206  # Make new off screen bitmap: this bitmap will always have the
2207  # current drawing in it, so it can be used to save the image
2208  # to a file, or whatever.
2209  self._buffer = wx.EmptyBitmap(width, height)
2210  # re-render image on idle
2211  self.resize = True
2212 
2213  def ScaleRect(self, rect, scale):
2214  """! Scale rectangle"""
2215  return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
2216  rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)
2217 
2218 
2219 def main():
2220  import gettext
2221  gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
2222 
2223  app = wx.PySimpleApp()
2224  wx.InitAllImageHandlers()
2225  frame = PsMapFrame()
2226  frame.Show()
2227 
2228  app.MainLoop()
2229 
2230 if __name__ == "__main__":
2231  main()
def convertRGB
Converts wx.Colour(r,g,b,a) to string &#39;r:g:b&#39; or named color, or named color/r:g:b string to wx...
Definition: psmap/utils.py:136
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.
Definition: psmap/frame.py:680
def projInfo
Return region projection and map units information, taken from render.py.
Definition: psmap/utils.py:309
def DrawPaper
Draw paper and margins.
wxGUI command interface
def OnPSFile
Generate PostScript.
Definition: psmap/frame.py:212
def MouseActions
Mouse motion and button click notifier.
def OnPageChanging
Flatnotebook page is changing.
int
Definition: y.tab.c:1344
def PaperMapCoordinates
Converts paper (inch) coordinates &lt;-&gt; map coordinates.
Definition: psmap/utils.py:159
def OnCloseWindow
Close window.
#define min(x, y)
Definition: draw2.c:68
def __init__
Main window of ps.map GUI.
Definition: psmap/frame.py:51
def InstructionFile
Creates mapping instructions.
Definition: psmap/frame.py:207
def OnPsMapDialog
Launch ps.map dialog.
Definition: psmap/frame.py:218
def SetResolution
If resolution is too high, lower it.
Definition: psmap/utils.py:259
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&#39;s movement. ...
#define max(x, y)
Definition: draw2.c:69
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) ...
Definition: psmap/utils.py:196
def getInitMap
Create default map frame when no map is selected, needed for coordinates in map units.
Definition: psmap/frame.py:844
def Draw
Draw object with given pen and brush.
def PSFile
Create temporary instructions file and run ps.map with output = filename.
Definition: psmap/frame.py:243
def OnMouseMoving
Mouse cursor moving.
def AddPoint
Add point and open property dialog.
Definition: psmap/frame.py:698
Various dialogs used in wxGUI.
def OnPreview
Run ps.map and show result.
Definition: psmap/frame.py:239
Menu classes for wxGUI.
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def OnAddScalebar
Add scalebar.
Definition: psmap/frame.py:616
def OnAddMapinfo
Definition: psmap/frame.py:646
def DrawImage
Draw preview image to pseudoDC.
def OnAddLegend
Add raster or vector legend.
Definition: psmap/frame.py:630
def OnAddNorthArrow
Show dialog for north arrow adding and editing.
Definition: psmap/frame.py:669
def UpdateLabel
def OnCmdDone
ps.map process finished
Definition: psmap/frame.py:285
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.
Definition: psmap/utils.py:272
def OnDelete
Definition: psmap/frame.py:874
def deleteObject
Deletes object, his id and redraws.
Definition: psmap/frame.py:883
def OnAddRectangle
Add rectangle action selected.
Definition: psmap/frame.py:743
def DrawBitmap
Draw bitmap using PIL.
def OnMouseWheel
Mouse wheel scrolled.
def OnAddLine
Add line action selected.
Definition: psmap/frame.py:718
def ComputeZoom
Computes zoom factor and scroll view.
def AddRectangle
Add rectangle and open property dialog.
Definition: psmap/frame.py:748
utilities for wxpsmap (classes, functions)
A buffered window class.
def updateDialog
Update legend coordinates after moving.
def OnHelp
Show help.
Map feature objects.
def Pan
Move canvas while dragging.
def OnAddRaster
Add raster map.
Definition: psmap/frame.py:569
def OnDragging
Process panning/resizing/drawing/moving.
def PilImageToWxImage
Convert PIL image to wx.Image.
Definition: psmap/utils.py:360
def OnAddImage
Show dialog for image adding and editing.
Definition: psmap/frame.py:656
def SetPage
Sets and changes page, redraws paper.
def OnAddPoint
Add point action selected.
Definition: psmap/frame.py:693
def OnAddVect
Add vector map.
Definition: psmap/frame.py:593
def OnPageChanged
Flatnotebook page has changed.
def makePSFont
creates a wx.Font object from selected postscript font.
Definition: psmap/frame.py:784
def _showErrMsg
Show error message (missing preview)
Definition: psmap/frame.py:176
def _layout
Do layout.
Definition: psmap/frame.py:184
def OnLoadFile
Load file and read instructions.
Definition: psmap/frame.py:414
def GetMapBounds
Run ps.map -b to get information about map bounding box.
Definition: psmap/utils.py:331
def Zoom
Zoom to specified region, scroll view, redraw.
def OnPageSetup
Specify paper size, margins and orientation.
Definition: psmap/frame.py:444
def getTextExtent
Estimates bounding rectangle of text.
Definition: psmap/frame.py:830
wxPsMap toolbars classes
def getModifiedTextBounds
computes bounding box of rotated text, not very precisely
Definition: psmap/frame.py:768
def AddLine
Add line and open property dialog.
Definition: psmap/frame.py:723
def DialogDataChanged
Definition: psmap/frame.py:895
Default GUI settings.
def ZoomAll
Zoom to full extent.
def OnButtonDClick
Open object dialog for editing.
def OnAddMap
Add or edit map frame.
Definition: psmap/frame.py:499
def OnApply
parent.font[&#39;colorLabel&#39;] = wx.StaticText(parent, id = wx.ID_ANY, label = _(&quot;Color:&quot;)) 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.
Definition: psmap/frame.py:223
dialogs for wxPsMap
Command output widgets.
def OnIdle
Only re-render a image during idle time instead of multiple times during resizing.
def RunCommand
Run GRASS command.
Definition: gcmd.py:633
def CanvasPaperCoordinates
Converts canvas (pixel) -&gt; paper (inch) coordinates and size and vice versa.