psmap.py 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659
  1. """!
  2. @package psmap.py
  3. @brief GUI for ps.map
  4. Classes:
  5. - PsMapFrame
  6. - PsMapBufferedWindow
  7. (C) 2011 by Anna Kratochvilova, and the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. @author Anna Kratochvilova <anna.kratochvilova fsv.cvut.cz> (bachelor's project)
  11. @author Martin Landa <landa.martin gmail.com> (mentor)
  12. """
  13. import os
  14. import sys
  15. import textwrap
  16. import Queue
  17. try:
  18. import Image
  19. haveImage = True
  20. except ImportError:
  21. haveImage = False
  22. from math import sin, cos, pi
  23. import grass.script as grass
  24. if int(grass.version()['version'].split('.')[0]) > 6:
  25. sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython',
  26. 'gui_modules'))
  27. else:
  28. sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython',
  29. 'gui_modules'))
  30. import globalvar
  31. import menu
  32. from goutput import CmdThread, EVT_CMD_DONE
  33. from menudata import PsMapData
  34. from toolbars import PsMapToolbar
  35. from icon import Icons, MetaIcon, iconSet
  36. from gcmd import RunCommand, GError, GMessage
  37. from menuform import GUI
  38. from psmap_dialogs import *
  39. import wx
  40. try:
  41. import wx.lib.agw.flatnotebook as fnb
  42. except ImportError:
  43. import wx.lib.flatnotebook as fnb
  44. class PsMapFrame(wx.Frame):
  45. def __init__(self, parent = None, id = wx.ID_ANY,
  46. title = _("GRASS GIS Hardcopy Map Output Utility"), **kwargs):
  47. """!Main window of ps.map GUI
  48. @param parent parent window
  49. @param id window id
  50. @param title window title
  51. @param kwargs wx.Frames' arguments
  52. """
  53. self.parent = parent
  54. wx.Frame.__init__(self, parent = parent, id = id, title = title, name = "PsMap", **kwargs)
  55. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  56. #menubar
  57. self.menubar = menu.Menu(parent = self, data = PsMapData())
  58. self.SetMenuBar(self.menubar)
  59. #toolbar
  60. self.toolbar = PsMapToolbar(parent = self)
  61. self.SetToolBar(self.toolbar)
  62. self.actionOld = self.toolbar.action['id']
  63. self.iconsize = (16, 16)
  64. #satusbar
  65. self.statusbar = self.CreateStatusBar(number = 1)
  66. # mouse attributes -- position on the screen, begin and end of
  67. # dragging, and type of drawing
  68. self.mouse = {
  69. 'begin': [0, 0], # screen coordinates
  70. 'end' : [0, 0],
  71. 'use' : "pointer",
  72. }
  73. # available cursors
  74. self.cursors = {
  75. "default" : wx.StockCursor(wx.CURSOR_ARROW),
  76. "cross" : wx.StockCursor(wx.CURSOR_CROSS),
  77. "hand" : wx.StockCursor(wx.CURSOR_HAND),
  78. "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
  79. }
  80. # pen and brush
  81. self.pen = {
  82. 'paper': wx.Pen(colour = "BLACK", width = 1),
  83. 'margins': wx.Pen(colour = "GREY", width = 1),
  84. 'map': wx.Pen(colour = wx.Color(86, 122, 17), width = 2),
  85. 'rasterLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
  86. 'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
  87. 'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
  88. 'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
  89. 'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
  90. 'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
  91. 'resize': wx.Pen(colour = 'BLACK', width = 1)
  92. }
  93. self.brush = {
  94. 'paper': wx.WHITE_BRUSH,
  95. 'margins': wx.TRANSPARENT_BRUSH,
  96. 'map': wx.Brush(wx.Color(151, 214, 90)),
  97. 'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
  98. 'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
  99. 'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
  100. 'scalebar': wx.Brush(wx.Color(200, 200, 200)),
  101. 'box': wx.TRANSPARENT_BRUSH,
  102. 'select':wx.TRANSPARENT_BRUSH,
  103. 'resize': wx.BLACK_BRUSH
  104. }
  105. # list of objects to draw
  106. self.objectId = []
  107. # instructions
  108. self.instruction = Instruction(parent = self, objectsToDraw = self.objectId)
  109. # open dialogs
  110. self.openDialogs = dict()
  111. self.pageId = wx.NewId()
  112. #current page of flatnotebook
  113. self.currentPage = 0
  114. #canvas for draft mode
  115. self.canvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, pen = self.pen,
  116. brush = self.brush, cursors = self.cursors,
  117. instruction = self.instruction, openDialogs = self.openDialogs,
  118. pageId = self.pageId, objectId = self.objectId,
  119. preview = False)
  120. self.canvas.SetCursor(self.cursors["default"])
  121. self.getInitMap()
  122. # image path
  123. env = grass.gisenv()
  124. self.imgName = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], '.tmp', 'tmpImage.png')
  125. #canvas for preview
  126. self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
  127. pen = self.pen, brush = self.brush, preview = True)
  128. # set WIND_OVERRIDE
  129. grass.use_temp_region()
  130. # create queues
  131. self.requestQ = Queue.Queue()
  132. self.resultQ = Queue.Queue()
  133. # thread
  134. self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
  135. self._layout()
  136. self.SetMinSize(wx.Size(750, 600))
  137. self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
  138. self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
  139. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  140. self.Bind(EVT_CMD_DONE, self.OnCmdDone)
  141. if not haveImage:
  142. wx.CallAfter(self._showErrMsg)
  143. def _showErrMsg(self):
  144. """!Show error message (missing preview)
  145. """
  146. GError(parent = self,
  147. message = _("Python Imaging Library is not available.\n"
  148. "'Preview' functionality won't work."),
  149. showTraceback = False)
  150. def _layout(self):
  151. """!Do layout
  152. """
  153. mainSizer = wx.BoxSizer(wx.VERTICAL)
  154. if globalvar.hasAgw:
  155. self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
  156. agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
  157. fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
  158. else:
  159. self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
  160. style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
  161. fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
  162. #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
  163. self.book.AddPage(self.canvas, "Draft mode")
  164. self.book.AddPage(self.previewCanvas, "Preview")
  165. self.book.SetSelection(0)
  166. mainSizer.Add(self.book,1, wx.EXPAND)
  167. self.SetSizer(mainSizer)
  168. mainSizer.Fit(self)
  169. def InstructionFile(self):
  170. """!Creates mapping instructions"""
  171. return str(self.instruction)
  172. def OnPSFile(self, event):
  173. """!Generate PostScript"""
  174. filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
  175. if filename:
  176. self.PSFile(filename)
  177. def OnPsMapDialog(self, event):
  178. """!Launch ps.map dialog
  179. """
  180. GUI(parent = self).ParseCommand(cmd = ['ps.map'])
  181. def OnPDFFile(self, event):
  182. """!Generate PDF from PS with ps2pdf if available"""
  183. try:
  184. p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
  185. p.stderr.close()
  186. except OSError:
  187. GMessage(parent = self,
  188. message = _("Program ps2pdf is not available. Please install it first to create PDF."))
  189. return
  190. filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
  191. if filename:
  192. self.PSFile(filename, pdf = True)
  193. def OnPreview(self, event):
  194. """!Run ps.map and show result"""
  195. self.PSFile()
  196. def PSFile(self, filename = None, pdf = False):
  197. """!Create temporary instructions file and run ps.map with output = filename"""
  198. instrFile = grass.tempfile()
  199. instrFileFd = open(instrFile, mode = 'w')
  200. instrFileFd.write(self.InstructionFile())
  201. instrFileFd.flush()
  202. instrFileFd.close()
  203. temp = False
  204. regOld = grass.region()
  205. if pdf:
  206. pdfname = filename
  207. else:
  208. pdfname = None
  209. #preview or pdf
  210. if not filename or (filename and pdf):
  211. temp = True
  212. filename = grass.tempfile()
  213. if not pdf: # lower resolution for preview
  214. if self.instruction.FindInstructionByType('map'):
  215. mapId = self.instruction.FindInstructionByType('map').id
  216. SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
  217. height = self.instruction[mapId]['rect'][3])
  218. cmd = ['ps.map', '--overwrite']
  219. if os.path.splitext(filename)[1] == '.eps':
  220. cmd.append('-e')
  221. if self.instruction[self.pageId]['Orientation'] == 'Landscape':
  222. cmd.append('-r')
  223. cmd.append('input=%s' % instrFile)
  224. cmd.append('output=%s' % filename)
  225. if pdf:
  226. self.SetStatusText(_('Generating PDF...'), 0)
  227. elif not temp:
  228. self.SetStatusText(_('Generating PostScript...'), 0)
  229. else:
  230. self.SetStatusText(_('Generating preview...'), 0)
  231. self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
  232. 'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
  233. def OnCmdDone(self, event):
  234. """!ps.map process finished"""
  235. if event.returncode != 0:
  236. GMessage(parent = self,
  237. message = _("Ps.map exited with return code %s") % event.returncode)
  238. grass.try_remove(event.userData['instrFile'])
  239. if event.userData['temp']:
  240. grass.try_remove(event.userData['filename'])
  241. return
  242. if event.userData['pdfname']:
  243. try:
  244. proc = grass.Popen(['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200',
  245. event.userData['filename'], event.userData['pdfname']])
  246. ret = proc.wait()
  247. if ret > 0:
  248. GMessage(parent = self,
  249. message = _("ps2pdf exited with return code %s") % ret)
  250. except OSError, e:
  251. GError(parent = self,
  252. message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
  253. # show preview only when user doesn't want to create ps or pdf
  254. if haveImage and event.userData['temp'] and not event.userData['pdfname']:
  255. RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
  256. ## wx.BusyInfo does not display the message
  257. ## busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
  258. try:
  259. im = Image.open(event.userData['filename'])
  260. if self.instruction[self.pageId]['Orientation'] == 'Landscape':
  261. im = im.rotate(270)
  262. im.save(self.imgName, format = 'png')
  263. except IOError, e:
  264. GError(parent = self,
  265. message = _("Unable to generate preview. %s") % e)
  266. rect = self.previewCanvas.ImageRect()
  267. self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
  268. self.previewCanvas.DrawImage(rect = rect)
  269. ## busy.Destroy()
  270. self.SetStatusText(_('Preview generated'), 0)
  271. self.book.SetSelection(1)
  272. self.currentPage = 1
  273. grass.try_remove(event.userData['instrFile'])
  274. if event.userData['temp']:
  275. grass.try_remove(event.userData['filename'])
  276. def getFile(self, wildcard):
  277. suffix = []
  278. for filter in wildcard.split('|')[1::2]:
  279. s = filter.strip('*').split('.')[1]
  280. if s:
  281. s = '.' + s
  282. suffix.append(s)
  283. raster = self.instruction.FindInstructionByType('raster')
  284. if raster:
  285. rasterId = raster.id
  286. else:
  287. rasterId = None
  288. if rasterId and self.instruction[rasterId]['raster']:
  289. mapName = self.instruction[rasterId]['raster'].split('@')[0] + suffix[0]
  290. else:
  291. mapName = ''
  292. filename = ''
  293. dlg = wx.FileDialog(self, message = _("Save file as"), defaultDir = "",
  294. defaultFile = mapName, wildcard = wildcard,
  295. style = wx.CHANGE_DIR | wx.SAVE | wx.OVERWRITE_PROMPT)
  296. if dlg.ShowModal() == wx.ID_OK:
  297. filename = dlg.GetPath()
  298. suffix = suffix[dlg.GetFilterIndex()]
  299. if not os.path.splitext(filename)[1]:
  300. filename = filename + suffix
  301. elif os.path.splitext(filename)[1] != suffix and suffix != '':
  302. filename = os.path.splitext(filename)[0] + suffix
  303. dlg.Destroy()
  304. return filename
  305. def OnInstructionFile(self, event):
  306. filename = self.getFile(wildcard = "*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")
  307. if filename:
  308. instrFile = open(filename, "w")
  309. instrFile.write(self.InstructionFile())
  310. instrFile.close()
  311. def OnLoadFile(self, event):
  312. """!Load file and read instructions"""
  313. #find file
  314. filename = ''
  315. dlg = wx.FileDialog(self, message = "Find instructions file", defaultDir = "",
  316. defaultFile = '', wildcard = "All files (*.*)|*.*",
  317. style = wx.CHANGE_DIR|wx.OPEN)
  318. if dlg.ShowModal() == wx.ID_OK:
  319. filename = dlg.GetPath()
  320. dlg.Destroy()
  321. if not filename:
  322. return
  323. # load instructions
  324. #filename = '/home/anna/Desktop/reading.txt'
  325. readObjectId = []
  326. readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
  327. ok = readInstruction.Read(filename)
  328. if not ok:
  329. GMessage(_("Failed to read file %s.") % filename)
  330. else:
  331. self.instruction = self.canvas.instruction = readInstruction
  332. self.objectId = self.canvas.objectId = readObjectId
  333. self.pageId = self.canvas.pageId = self.instruction.FindInstructionByType('page').id
  334. self.canvas.UpdateMapLabel()
  335. self.canvas.dragId = -1
  336. self.canvas.Clear()
  337. #self.canvas.ZoomAll()
  338. self.DialogDataChanged(self.objectId)
  339. def OnPageSetup(self, event = None):
  340. """!Specify paper size, margins and orientation"""
  341. id = self.instruction.FindInstructionByType('page').id
  342. dlg = PageSetupDialog(self, id = id, settings = self.instruction)
  343. dlg.CenterOnScreen()
  344. val = dlg.ShowModal()
  345. if val == wx.ID_OK:
  346. self.canvas.SetPage()
  347. self.canvas.RecalculatePosition(ids = self.objectId)
  348. dlg.Destroy()
  349. def OnPointer(self, event):
  350. self.toolbar.OnTool(event)
  351. self.mouse["use"] = "pointer"
  352. self.canvas.SetCursor(self.cursors["default"])
  353. self.previewCanvas.SetCursor(self.cursors["default"])
  354. def OnPan(self, event):
  355. self.toolbar.OnTool(event)
  356. self.mouse["use"] = "pan"
  357. self.canvas.SetCursor(self.cursors["hand"])
  358. self.previewCanvas.SetCursor(self.cursors["hand"])
  359. def OnZoomIn(self, event):
  360. self.toolbar.OnTool(event)
  361. self.mouse["use"] = "zoomin"
  362. self.canvas.SetCursor(self.cursors["cross"])
  363. self.previewCanvas.SetCursor(self.cursors["cross"])
  364. def OnZoomOut(self, event):
  365. self.toolbar.OnTool(event)
  366. self.mouse["use"] = "zoomout"
  367. self.canvas.SetCursor(self.cursors["cross"])
  368. self.previewCanvas.SetCursor(self.cursors["cross"])
  369. def OnZoomAll(self, event):
  370. self.mouseOld = self.mouse['use']
  371. if self.currentPage == 0:
  372. self.cursorOld = self.canvas.GetCursor()
  373. else:
  374. self.previewCanvas.GetCursor()
  375. self.mouse["use"] = "zoomin"
  376. if self.currentPage == 0:
  377. self.canvas.ZoomAll()
  378. else:
  379. self.previewCanvas.ZoomAll()
  380. self.mouse["use"] = self.mouseOld
  381. if self.currentPage == 0:
  382. self.canvas.SetCursor(self.cursorOld)
  383. else:
  384. self.previewCanvas.SetCursor(self.cursorOld)
  385. def OnAddMap(self, event, notebook = False):
  386. """!Add or edit map frame"""
  387. if event is not None:
  388. if event.GetId() != self.toolbar.action['id']:
  389. self.actionOld = self.toolbar.action['id']
  390. self.mouseOld = self.mouse['use']
  391. self.cursorOld = self.canvas.GetCursor()
  392. self.toolbar.OnTool(event)
  393. if self.instruction.FindInstructionByType('map'):
  394. mapId = self.instruction.FindInstructionByType('map').id
  395. else: mapId = None
  396. id = [mapId, None, None]
  397. if notebook:
  398. if self.instruction.FindInstructionByType('vector'):
  399. vectorId = self.instruction.FindInstructionByType('vector').id
  400. else: vectorId = None
  401. if self.instruction.FindInstructionByType('raster'):
  402. rasterId = self.instruction.FindInstructionByType('raster').id
  403. else: rasterId = None
  404. id[1] = rasterId
  405. id[2] = vectorId
  406. if mapId: # map exists
  407. self.toolbar.ToggleTool(self.actionOld, True)
  408. self.toolbar.ToggleTool(self.toolbar.action['id'], False)
  409. self.toolbar.action['id'] = self.actionOld
  410. try:
  411. self.canvas.SetCursor(self.cursorOld)
  412. except AttributeError:
  413. pass
  414. ## dlg = MapDialog(parent = self, id = id, settings = self.instruction,
  415. ## notebook = notebook)
  416. ## dlg.ShowModal()
  417. if notebook:
  418. #check map, raster, vector and save, destroy them
  419. if 'map' in self.openDialogs:
  420. self.openDialogs['map'].OnOK(event = None)
  421. if 'raster' in self.openDialogs:
  422. self.openDialogs['raster'].OnOK(event = None)
  423. if 'vector' in self.openDialogs:
  424. self.openDialogs['vector'].OnOK(event = None)
  425. if 'mapNotebook' not in self.openDialogs:
  426. dlg = MapDialog(parent = self, id = id, settings = self.instruction,
  427. notebook = notebook)
  428. self.openDialogs['mapNotebook'] = dlg
  429. self.openDialogs['mapNotebook'].Show()
  430. else:
  431. if 'mapNotebook' in self.openDialogs:
  432. self.openDialogs['mapNotebook'].notebook.ChangeSelection(0)
  433. else:
  434. if 'map' not in self.openDialogs:
  435. dlg = MapDialog(parent = self, id = id, settings = self.instruction,
  436. notebook = notebook)
  437. self.openDialogs['map'] = dlg
  438. self.openDialogs['map'].Show()
  439. else: # sofar no map
  440. self.mouse["use"] = "addMap"
  441. self.canvas.SetCursor(self.cursors["cross"])
  442. if self.currentPage == 1:
  443. self.book.SetSelection(0)
  444. self.currentPage = 0
  445. def OnAddRaster(self, event):
  446. """!Add raster map"""
  447. if self.instruction.FindInstructionByType('raster'):
  448. id = self.instruction.FindInstructionByType('raster').id
  449. else: id = None
  450. if self.instruction.FindInstructionByType('map'):
  451. mapId = self.instruction.FindInstructionByType('map').id
  452. else: mapId = None
  453. if not id:
  454. if not mapId:
  455. GMessage(message = _("Please, create map frame first."))
  456. return
  457. ## dlg = RasterDialog(self, id = id, settings = self.instruction)
  458. ## dlg.ShowModal()
  459. if 'mapNotebook' in self.openDialogs:
  460. self.openDialogs['mapNotebook'].notebook.ChangeSelection(1)
  461. else:
  462. if 'raster' not in self.openDialogs:
  463. dlg = RasterDialog(self, id = id, settings = self.instruction)
  464. self.openDialogs['raster'] = dlg
  465. self.openDialogs['raster'].Show()
  466. def OnAddVect(self, event):
  467. """!Add vector map"""
  468. if self.instruction.FindInstructionByType('vector'):
  469. id = self.instruction.FindInstructionByType('vector').id
  470. else: id = None
  471. if self.instruction.FindInstructionByType('map'):
  472. mapId = self.instruction.FindInstructionByType('map').id
  473. else: mapId = None
  474. if not id:
  475. if not mapId:
  476. GMessage(message = _("Please, create map frame first."))
  477. return
  478. ## dlg = MainVectorDialog(self, id = id, settings = self.instruction)
  479. ## dlg.ShowModal()
  480. if 'mapNotebook' in self.openDialogs:
  481. self.openDialogs['mapNotebook'].notebook.ChangeSelection(2)
  482. else:
  483. if 'vector' not in self.openDialogs:
  484. dlg = MainVectorDialog(self, id = id, settings = self.instruction)
  485. self.openDialogs['vector'] = dlg
  486. self.openDialogs['vector'].Show()
  487. def OnDecoration(self, event):
  488. """!Decorations overlay menu
  489. """
  490. decmenu = wx.Menu()
  491. # legend
  492. AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addLegend"].GetLabel())
  493. AddLegend.SetBitmap(Icons['psMap']["addLegend"].GetBitmap(self.iconsize))
  494. decmenu.AppendItem(AddLegend)
  495. self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
  496. # mapinfo
  497. AddMapinfo = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addMapinfo"].GetLabel())
  498. AddMapinfo.SetBitmap(Icons['psMap']["addMapinfo"].GetBitmap(self.iconsize))
  499. decmenu.AppendItem(AddMapinfo)
  500. self.Bind(wx.EVT_MENU, self.OnAddMapinfo, AddMapinfo)
  501. # scalebar
  502. AddScalebar = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addScalebar"].GetLabel())
  503. AddScalebar.SetBitmap(Icons['psMap']["addScalebar"].GetBitmap(self.iconsize))
  504. decmenu.AppendItem(AddScalebar)
  505. self.Bind(wx.EVT_MENU, self.OnAddScalebar, AddScalebar)
  506. # text
  507. AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addText"].GetLabel())
  508. AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
  509. decmenu.AppendItem(AddText)
  510. self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
  511. # Popup the menu. If an item is selected then its handler
  512. # will be called before PopupMenu returns.
  513. self.PopupMenu(decmenu)
  514. decmenu.Destroy()
  515. def OnAddScalebar(self, event):
  516. """!Add scalebar"""
  517. if projInfo()['proj'] == 'll':
  518. GMessage(message = _("Scalebar is not appropriate for this projection"))
  519. return
  520. if self.instruction.FindInstructionByType('scalebar'):
  521. id = self.instruction.FindInstructionByType('scalebar').id
  522. else: id = None
  523. if 'scalebar' not in self.openDialogs:
  524. dlg = ScalebarDialog(self, id = id, settings = self.instruction)
  525. self.openDialogs['scalebar'] = dlg
  526. self.openDialogs['scalebar'].Show()
  527. def OnAddLegend(self, event, page = 0):
  528. """!Add raster or vector legend"""
  529. if self.instruction.FindInstructionByType('rasterLegend'):
  530. idR = self.instruction.FindInstructionByType('rasterLegend').id
  531. else: idR = None
  532. if self.instruction.FindInstructionByType('vectorLegend'):
  533. idV = self.instruction.FindInstructionByType('vectorLegend').id
  534. else: idV = None
  535. if 'rasterLegend' not in self.openDialogs:
  536. dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
  537. self.openDialogs['rasterLegend'] = dlg
  538. self.openDialogs['vectorLegend'] = dlg
  539. self.openDialogs['rasterLegend'].notebook.ChangeSelection(page)
  540. self.openDialogs['rasterLegend'].Show()
  541. def OnAddMapinfo(self, event):
  542. if self.instruction.FindInstructionByType('mapinfo'):
  543. id = self.instruction.FindInstructionByType('mapinfo').id
  544. else: id = None
  545. if 'mapinfo' not in self.openDialogs:
  546. dlg = MapinfoDialog(self, id = id, settings = self.instruction)
  547. self.openDialogs['mapinfo'] = dlg
  548. self.openDialogs['mapinfo'].Show()
  549. def OnAddText(self, event, id = None):
  550. """!Show dialog for text adding and editing"""
  551. position = None
  552. if 'text' in self.openDialogs:
  553. position = self.openDialogs['text'].GetPosition()
  554. self.openDialogs['text'].OnApply(event = None)
  555. self.openDialogs['text'].Destroy()
  556. dlg = TextDialog(self, id = id, settings = self.instruction)
  557. self.openDialogs['text'] = dlg
  558. if position:
  559. dlg.SetPosition(position)
  560. dlg.Show()
  561. def getModifiedTextBounds(self, x, y, textExtent, rotation):
  562. """!computes bounding box of rotated text, not very precisely"""
  563. w, h = textExtent
  564. rotation = float(rotation)/180*pi
  565. H = float(w) * sin(rotation)
  566. W = float(w) * cos(rotation)
  567. X, Y = x, y
  568. if pi/2 < rotation <= 3*pi/2:
  569. X = x + W
  570. if 0 < rotation < pi:
  571. Y = y - H
  572. if rotation == 0:
  573. return wx.Rect(x,y, *textExtent)
  574. else:
  575. return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h)
  576. def getTextExtent(self, textDict):
  577. fontsize = str(textDict['fontsize'] * self.canvas.currScale)
  578. #fontsize = str(fontsize if fontsize >= 4 else 4)
  579. dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
  580. dc.SetFont(wx.FontFromNativeInfoString(textDict['font'] + " " + fontsize))
  581. return dc.GetTextExtent(textDict['text'])
  582. def getInitMap(self):
  583. """!Create default map frame when no map is selected, needed for coordinates in map units"""
  584. instrFile = grass.tempfile()
  585. instrFileFd = open(instrFile, mode = 'w')
  586. instrFileFd.write(self.InstructionFile())
  587. instrFileFd.flush()
  588. instrFileFd.close()
  589. mapInitRect = GetMapBounds(instrFile)
  590. grass.try_remove(instrFile)
  591. region = grass.region()
  592. units = UnitConversion(self)
  593. realWidth = units.convert(value = abs(region['w'] - region['e']), fromUnit = 'meter', toUnit = 'inch')
  594. scale = mapInitRect.Get()[2]/realWidth
  595. initMap = self.instruction.FindInstructionByType('initMap')
  596. if initMap:
  597. id = initMap.id
  598. else:
  599. id = None
  600. if not id:
  601. id = wx.NewId()
  602. initMap = InitMap(id)
  603. self.instruction.AddInstruction(initMap)
  604. self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
  605. def OnDelete(self, event):
  606. if self.canvas.dragId != -1 and self.currentPage == 0:
  607. if self.instruction[self.canvas.dragId].type == 'map':
  608. self.deleteObject(self.canvas.dragId)
  609. self.getInitMap()
  610. self.canvas.RecalculateEN()
  611. else:
  612. self.deleteObject(self.canvas.dragId)
  613. def deleteObject(self, id):
  614. """!Deletes object, his id and redraws"""
  615. #delete from canvas
  616. self.canvas.pdcObj.RemoveId(id)
  617. if id == self.canvas.dragId:
  618. self.canvas.pdcTmp.RemoveAll()
  619. self.canvas.dragId = -1
  620. self.canvas.Refresh()
  621. # delete from instructions
  622. del self.instruction[id]
  623. def DialogDataChanged(self, id):
  624. ids = id
  625. if type(id) == int:
  626. ids = [id]
  627. for id in ids:
  628. itype = self.instruction[id].type
  629. if itype in ('scalebar', 'mapinfo'):
  630. drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
  631. self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
  632. pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
  633. self.canvas.RedrawSelectBox(id)
  634. if itype == 'text':
  635. if self.instruction[id]['rotate']:
  636. rot = float(self.instruction[id]['rotate'])
  637. else:
  638. rot = 0
  639. extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
  640. rect = wx.Rect2D(self.instruction[id]['where'][0], self.instruction[id]['where'][1], 0, 0)
  641. self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
  642. #computes text coordinates according to reference point, not precisely
  643. if self.instruction[id]['ref'].split()[0] == 'lower':
  644. self.instruction[id]['coords'][1] -= extent[1]
  645. elif self.instruction[id]['ref'].split()[0] == 'center':
  646. self.instruction[id]['coords'][1] -= extent[1]/2
  647. if self.instruction[id]['ref'].split()[1] == 'right':
  648. self.instruction[id]['coords'][0] -= extent[0] * cos(rot/180*pi)
  649. self.instruction[id]['coords'][1] += extent[0] * sin(rot/180*pi)
  650. elif self.instruction[id]['ref'].split()[1] == 'center':
  651. self.instruction[id]['coords'][0] -= extent[0]/2 * cos(rot/180*pi)
  652. self.instruction[id]['coords'][1] += extent[0]/2 * sin(rot/180*pi)
  653. self.instruction[id]['coords'][0] += self.instruction[id]['xoffset']
  654. self.instruction[id]['coords'][1] -= self.instruction[id]['yoffset']
  655. coords = self.instruction[id]['coords']
  656. self.instruction[id]['rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
  657. self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
  658. textDict = self.instruction[id].GetInstruction(),
  659. coords = coords, bounds = bounds)
  660. self.canvas.RedrawSelectBox(id)
  661. if itype in ('map', 'vector', 'raster'):
  662. if itype == 'raster':#set resolution
  663. resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
  664. resol = grass.parse_key_val(resol, val_type = float)
  665. RunCommand('g.region', nsres = resol['nsres'], ewres = resol['ewres'])
  666. # change current raster in raster legend
  667. if 'rasterLegend' in self.openDialogs:
  668. self.openDialogs['rasterLegend'].updateDialog()
  669. id = self.instruction.FindInstructionByType('map').id
  670. #check resolution
  671. if itype == 'raster':
  672. SetResolution(dpi = self.instruction[id]['resolution'],
  673. width = self.instruction[id]['rect'].width,
  674. height = self.instruction[id]['rect'].height)
  675. rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'],
  676. canvasToPaper = False)
  677. self.canvas.RecalculateEN()
  678. self.canvas.UpdateMapLabel()
  679. self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
  680. pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
  681. # redraw select box
  682. self.canvas.RedrawSelectBox(id)
  683. self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
  684. # redraw to get map to the bottom layer
  685. #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
  686. if itype == 'rasterLegend':
  687. if self.instruction[id]['rLegend']:
  688. drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
  689. self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
  690. pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
  691. self.canvas.RedrawSelectBox(id)
  692. else:
  693. self.deleteObject(id)
  694. if itype == 'vectorLegend':
  695. if not self.instruction.FindInstructionByType('vector'):
  696. self.deleteObject(id)
  697. elif self.instruction[id]['vLegend']:
  698. drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
  699. self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
  700. pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
  701. self.canvas.RedrawSelectBox(id)
  702. else:
  703. self.deleteObject(id)
  704. def OnPageChanged(self, event):
  705. """!Flatnotebook page has changed"""
  706. self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
  707. def OnPageChanging(self, event):
  708. """!Flatnotebook page is changing"""
  709. if self.currentPage == 0 and self.mouse['use'] == 'addMap':
  710. event.Veto()
  711. def OnHelp(self, event):
  712. """!Show help"""
  713. if self.parent and self.parent.GetName() == 'LayerManager':
  714. log = self.parent.GetLogWindow()
  715. log.RunCmd(['g.manual',
  716. 'entry=wxGUI.PsMap'])
  717. else:
  718. RunCommand('g.manual',
  719. quiet = True,
  720. entry = 'wxGUI.PsMap')
  721. def OnAbout(self, event):
  722. """!Display About window"""
  723. info = wx.AboutDialogInfo()
  724. info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  725. info.SetName(_('wxGUI Hardcopy Map Utility'))
  726. info.SetWebSite('http://grass.osgeo.org')
  727. info.SetDescription(_('(C) 2011 by the GRASS Development Team\n\n') +
  728. '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
  729. '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
  730. wx.AboutBox(info)
  731. def OnCloseWindow(self, event):
  732. """!Close window"""
  733. try:
  734. os.remove(self.imgName)
  735. except OSError:
  736. pass
  737. grass.set_raise_on_error(False)
  738. self.Destroy()
  739. class PsMapBufferedWindow(wx.Window):
  740. """!A buffered window class.
  741. @param parent parent window
  742. @param kwargs other wx.Window parameters
  743. """
  744. def __init__(self, parent, id = wx.ID_ANY,
  745. style = wx.NO_FULL_REPAINT_ON_RESIZE,
  746. **kwargs):
  747. wx.Window.__init__(self, parent, id = id, style = style)
  748. self.parent = parent
  749. self.FitInside()
  750. # store an off screen empty bitmap for saving to file
  751. self._buffer = None
  752. # indicates whether or not a resize event has taken place
  753. self.resize = False
  754. self.mouse = kwargs['mouse']
  755. self.cursors = kwargs['cursors']
  756. self.preview = kwargs['preview']
  757. self.pen = kwargs['pen']
  758. self.brush = kwargs['brush']
  759. if kwargs.has_key('instruction'):
  760. self.instruction = kwargs['instruction']
  761. if kwargs.has_key('openDialogs'):
  762. self.openDialogs = kwargs['openDialogs']
  763. if kwargs.has_key('pageId'):
  764. self.pageId = kwargs['pageId']
  765. if kwargs.has_key('objectId'):
  766. self.objectId = kwargs['objectId']
  767. #labels
  768. self.itemLabels = { 'map': ['MAP FRAME'],
  769. 'rasterLegend': ['RASTER LEGEND'],
  770. 'vectorLegend': ['VECTOR LEGEND'],
  771. 'mapinfo': ['MAP INFO'],
  772. 'scalebar': ['SCALE BAR']}
  773. # define PseudoDC
  774. self.pdc = wx.PseudoDC()
  775. self.pdcObj = wx.PseudoDC()
  776. self.pdcPaper = wx.PseudoDC()
  777. self.pdcTmp = wx.PseudoDC()
  778. self.pdcImage = wx.PseudoDC()
  779. dc = wx.PaintDC(self)
  780. self.font = dc.GetFont()
  781. self.SetClientSize((700,510))#?
  782. self._buffer = wx.EmptyBitmap(*self.GetClientSize())
  783. self.idBoxTmp = wx.NewId()
  784. self.idZoomBoxTmp = wx.NewId()
  785. self.idResizeBoxTmp = wx.NewId()
  786. self.dragId = -1
  787. if self.preview:
  788. self.image = None
  789. self.imageId = 2000
  790. self.imgName = self.parent.imgName
  791. self.currScale = None
  792. self.Clear()
  793. self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
  794. self.Bind(wx.EVT_PAINT, self.OnPaint)
  795. self.Bind(wx.EVT_SIZE, self.OnSize)
  796. self.Bind(wx.EVT_IDLE, self.OnIdle)
  797. self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
  798. def Clear(self):
  799. """!Clear canvas and set paper
  800. """
  801. bg = wx.LIGHT_GREY_BRUSH
  802. self.pdcPaper.BeginDrawing()
  803. self.pdcPaper.SetBackground(bg)
  804. self.pdcPaper.Clear()
  805. self.pdcPaper.EndDrawing()
  806. self.pdcObj.RemoveAll()
  807. self.pdcTmp.RemoveAll()
  808. if not self.preview:
  809. self.SetPage()
  810. def CanvasPaperCoordinates(self, rect, canvasToPaper = True):
  811. """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
  812. units = UnitConversion(self)
  813. fromU = 'pixel'
  814. toU = 'inch'
  815. pRect = self.pdcPaper.GetIdBounds(self.pageId)
  816. pRectx, pRecty = pRect.x, pRect.y
  817. scale = 1/self.currScale
  818. if not canvasToPaper: # paper -> canvas
  819. fromU = 'inch'
  820. toU = 'pixel'
  821. scale = self.currScale
  822. pRectx = units.convert(value = - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
  823. pRecty = units.convert(value = - pRect.y, fromUnit = 'pixel', toUnit = 'inch' ) /scale
  824. Width = units.convert(value = rect.width, fromUnit = fromU, toUnit = toU) * scale
  825. Height = units.convert(value = rect.height, fromUnit = fromU, toUnit = toU) * scale
  826. X = units.convert(value = (rect.x - pRectx), fromUnit = fromU, toUnit = toU) * scale
  827. Y = units.convert(value = (rect.y - pRecty), fromUnit = fromU, toUnit = toU) * scale
  828. return wx.Rect2D(X, Y, Width, Height)
  829. def SetPage(self):
  830. """!Sets and changes page, redraws paper"""
  831. page = self.instruction[self.pageId]
  832. if not page:
  833. page = PageSetup(id = self.pageId)
  834. self.instruction.AddInstruction(page)
  835. ppi = wx.PaintDC(self).GetPPI()
  836. cW, cH = self.GetClientSize()
  837. pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
  838. if self.currScale is None:
  839. self.currScale = min(cW/pW, cH/pH)
  840. pW = pW * self.currScale
  841. pH = pH * self.currScale
  842. x = cW/2 - pW/2
  843. y = cH/2 - pH/2
  844. self.DrawPaper(wx.Rect(x, y, pW, pH))
  845. def modifyRectangle(self, r):
  846. """! Recalculates rectangle not to have negative size"""
  847. if r.GetWidth() < 0:
  848. r.SetX(r.GetX() + r.GetWidth())
  849. if r.GetHeight() < 0:
  850. r.SetY(r.GetY() + r.GetHeight())
  851. r.SetWidth(abs(r.GetWidth()))
  852. r.SetHeight(abs(r.GetHeight()))
  853. return r
  854. def RecalculateEN(self):
  855. """!Recalculate east and north for texts (eps, points) after their or map's movement"""
  856. try:
  857. mapId = self.instruction.FindInstructionByType('map').id
  858. except AttributeError:
  859. mapId = self.instruction.FindInstructionByType('initMap').id
  860. texts = self.instruction.FindInstructionByType('text', list = True)
  861. for text in texts:
  862. e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
  863. y = self.instruction[text.id]['where'][1], paperToMap = True)
  864. self.instruction[text.id]['east'], self.instruction[text.id]['north'] = e, n
  865. def OnPaint(self, event):
  866. """!Draw pseudo DC to buffer
  867. """
  868. if not self._buffer:
  869. return
  870. dc = wx.BufferedPaintDC(self, self._buffer)
  871. # use PrepareDC to set position correctly
  872. self.PrepareDC(dc)
  873. dc.SetBackground(wx.LIGHT_GREY_BRUSH)
  874. dc.Clear()
  875. # draw paper
  876. if not self.preview:
  877. self.pdcPaper.DrawToDC(dc)
  878. # draw to the DC using the calculated clipping rect
  879. rgn = self.GetUpdateRegion()
  880. if not self.preview:
  881. self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
  882. else:
  883. self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
  884. self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
  885. def OnMouse(self, event):
  886. if event.GetWheelRotation():
  887. zoom = event.GetWheelRotation()
  888. use = self.mouse['use']
  889. self.mouse['begin'] = event.GetPosition()
  890. if zoom > 0:
  891. self.mouse['use'] = 'zoomin'
  892. else:
  893. self.mouse['use'] = 'zoomout'
  894. zoomFactor, view = self.ComputeZoom(wx.Rect(0,0,0,0))
  895. self.Zoom(zoomFactor, view)
  896. self.mouse['use'] = use
  897. if event.Moving():
  898. if self.mouse['use'] in ('pointer', 'resize'):
  899. pos = event.GetPosition()
  900. foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
  901. if foundResize and foundResize[0] == self.idResizeBoxTmp:
  902. self.SetCursor(self.cursors["sizenwse"])
  903. self.parent.SetStatusText(_('Click and drag to resize object'), 0)
  904. else:
  905. self.parent.SetStatusText(_(''), 0)
  906. self.SetCursor(self.cursors["default"])
  907. elif event.LeftDown():
  908. self.mouse['begin'] = event.GetPosition()
  909. self.begin = self.mouse['begin']
  910. if self.mouse['use'] in ('pan', 'zoomin', 'zoomout', 'addMap'):
  911. pass
  912. #select
  913. if self.mouse['use'] == 'pointer':
  914. found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
  915. foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
  916. if foundResize and foundResize[0] == self.idResizeBoxTmp:
  917. self.mouse['use'] = 'resize'
  918. # when resizing, proportions match region
  919. if self.instruction[self.dragId].type == 'map':
  920. self.constraint = False
  921. self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
  922. if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
  923. self.constraint = True
  924. self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
  925. elif found:
  926. self.dragId = found[0]
  927. self.RedrawSelectBox(self.dragId)
  928. if self.instruction[self.dragId].type != 'map':
  929. self.pdcTmp.RemoveId(self.idResizeBoxTmp)
  930. self.Refresh()
  931. else:
  932. self.dragId = -1
  933. self.pdcTmp.RemoveId(self.idBoxTmp)
  934. self.pdcTmp.RemoveId(self.idResizeBoxTmp)
  935. self.Refresh()
  936. elif event.Dragging() and event.LeftIsDown():
  937. #draw box when zooming, creating map
  938. if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap'):
  939. self.mouse['end'] = event.GetPosition()
  940. r = wx.Rect(self.mouse['begin'][0], self.mouse['begin'][1],
  941. self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
  942. r = self.modifyRectangle(r)
  943. self.Draw(pen = self.pen['box'], brush = self.brush['box'], pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
  944. pdctype = 'rect', bb = r)
  945. # panning
  946. if self.mouse["use"] == 'pan':
  947. self.mouse['end'] = event.GetPosition()
  948. view = self.mouse['begin'][0] - self.mouse['end'][0], self.mouse['begin'][1] - self.mouse['end'][1]
  949. zoomFactor = 1
  950. self.Zoom(zoomFactor, view)
  951. self.mouse['begin'] = event.GetPosition()
  952. #move object
  953. if self.mouse['use'] == 'pointer' and self.dragId != -1:
  954. self.mouse['end'] = event.GetPosition()
  955. dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
  956. self.pdcObj.TranslateId(self.dragId, dx, dy)
  957. self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
  958. self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
  959. if self.instruction[self.dragId].type == 'text':
  960. self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
  961. self.instruction[self.dragId]['coords'][1] + dy
  962. self.begin = event.GetPosition()
  963. self.Refresh()
  964. # resize object
  965. if self.mouse['use'] == 'resize':
  966. type = self.instruction[self.dragId].type
  967. pos = event.GetPosition()
  968. x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
  969. width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
  970. diffX = pos[0] - self.mouse['begin'][0]
  971. diffY = pos[1] - self.mouse['begin'][1]
  972. # match given region
  973. if self.constraint:
  974. if width > height:
  975. newWidth = width + diffX
  976. newHeight = height + diffX * (float(height) / width)
  977. else:
  978. newWidth = width + diffY * (float(width) / height)
  979. newHeight = height + diffY
  980. else:
  981. newWidth = width + diffX
  982. newHeight = height + diffY
  983. if newWidth < 10 or newHeight < 10:
  984. return
  985. bounds = wx.Rect(x, y, newWidth, newHeight)
  986. self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj, drawid = self.dragId,
  987. pdctype = 'rectText', bb = bounds)
  988. self.RedrawSelectBox(self.dragId)
  989. elif event.LeftUp():
  990. # zoom in, zoom out
  991. if self.mouse['use'] in ('zoomin','zoomout'):
  992. zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
  993. self.pdcTmp.RemoveId(self.idZoomBoxTmp)
  994. self.Refresh()
  995. zoomFactor, view = self.ComputeZoom(zoomR)
  996. self.Zoom(zoomFactor, view)
  997. # draw map frame
  998. if self.mouse['use'] == 'addMap':
  999. rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
  1000. # too small rectangle, it's usually some mistake
  1001. if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
  1002. self.pdcTmp.RemoveId(self.idZoomBoxTmp)
  1003. self.Refresh()
  1004. return
  1005. rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)
  1006. dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction,
  1007. rect = rectPaper)
  1008. self.openDialogs['map'] = dlg
  1009. self.openDialogs['map'].Show()
  1010. self.mouse['use'] = self.parent.mouseOld
  1011. self.SetCursor(self.parent.cursorOld)
  1012. self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
  1013. self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
  1014. self.parent.toolbar.action['id'] = self.parent.actionOld
  1015. # resize resizable objects (only map sofar)
  1016. if self.mouse['use'] == 'resize':
  1017. mapId = self.instruction.FindInstructionByType('map').id
  1018. if self.dragId == mapId:
  1019. # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
  1020. newRectCanvas = self.pdcObj.GetIdBounds(mapId)
  1021. newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
  1022. self.instruction[mapId]['rect'] = newRectPaper
  1023. if self.instruction[mapId]['scaleType'] in (0, 1, 2):
  1024. if self.instruction[mapId]['scaleType'] == 0:
  1025. scale, foo, rect = AutoAdjust(self, scaleType = 0,
  1026. map = self.instruction[mapId]['map'],
  1027. mapType = self.instruction[mapId]['mapType'],
  1028. rect = self.instruction[mapId]['rect'])
  1029. elif self.instruction[mapId]['scaleType'] == 1:
  1030. scale, foo, rect = AutoAdjust(self, scaleType = 1,
  1031. region = self.instruction[mapId]['region'],
  1032. rect = self.instruction[mapId]['rect'])
  1033. else:
  1034. scale, foo, rect = AutoAdjust(self, scaleType = 2,
  1035. rect = self.instruction[mapId]['rect'])
  1036. self.instruction[mapId]['rect'] = rect
  1037. self.instruction[mapId]['scale'] = scale
  1038. rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
  1039. self.Draw(pen = self.pen['map'], brush = self.brush['map'],
  1040. pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
  1041. elif self.instruction[mapId]['scaleType'] == 3:
  1042. ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
  1043. #check resolution
  1044. SetResolution(dpi = self.instruction[mapId]['resolution'],
  1045. width = self.instruction[mapId]['rect'].width,
  1046. height = self.instruction[mapId]['rect'].height)
  1047. self.RedrawSelectBox(mapId)
  1048. self.Zoom(zoomFactor = 1, view = (0, 0))
  1049. self.mouse['use'] = 'pointer'
  1050. # recalculate the position of objects after dragging
  1051. if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
  1052. if self.mouse['begin'] != event.GetPosition(): #for double click
  1053. self.RecalculatePosition(ids = [self.dragId])
  1054. if self.instruction[self.dragId].type in self.openDialogs:
  1055. self.openDialogs[self.instruction[self.dragId].type].updateDialog()
  1056. # double click launches dialogs
  1057. elif event.LeftDClick():
  1058. if self.mouse['use'] == 'pointer' and self.dragId != -1:
  1059. itemCall = { 'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
  1060. 'scalebar': self.parent.OnAddScalebar,
  1061. 'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,
  1062. 'map': self.parent.OnAddMap}
  1063. itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
  1064. 'scalebar': dict(event = None),
  1065. 'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
  1066. 'map': dict(event = None, notebook = True)}
  1067. type = self.instruction[self.dragId].type
  1068. itemCall[type](**itemArg[type])
  1069. def RecalculatePosition(self, ids):
  1070. for id in ids:
  1071. itype = self.instruction[id].type
  1072. if itype == 'map':
  1073. self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
  1074. canvasToPaper = True)
  1075. self.RecalculateEN()
  1076. elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend'):
  1077. self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
  1078. canvasToPaper = True)
  1079. self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
  1080. canvasToPaper = True)[:2]
  1081. elif itype == 'scalebar':
  1082. self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
  1083. canvasToPaper = True)
  1084. self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
  1085. elif itype == 'text':
  1086. x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
  1087. self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
  1088. extent = self.parent.getTextExtent(textDict = self.instruction[id])
  1089. if self.instruction[id]['rotate'] is not None:
  1090. rot = float(self.instruction[id]['rotate'])/180*pi
  1091. else:
  1092. rot = 0
  1093. if self.instruction[id]['ref'].split()[0] == 'lower':
  1094. y += extent[1]
  1095. elif self.instruction[id]['ref'].split()[0] == 'center':
  1096. y += extent[1]/2
  1097. if self.instruction[id]['ref'].split()[1] == 'right':
  1098. x += extent[0] * cos(rot)
  1099. y -= extent[0] * sin(rot)
  1100. elif self.instruction[id]['ref'].split()[1] == 'center':
  1101. x += extent[0]/2 * cos(rot)
  1102. y -= extent[0]/2 * sin(rot)
  1103. self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = wx.Rect2D(x, y, 0, 0),
  1104. canvasToPaper = True)[:2]
  1105. self.RecalculateEN()
  1106. def ComputeZoom(self, rect):
  1107. """!Computes zoom factor and scroll view"""
  1108. zoomFactor = 1
  1109. cW, cH = self.GetClientSize()
  1110. cW = float(cW)
  1111. if rect.IsEmpty(): # clicked on canvas
  1112. zoomFactor = 1.5
  1113. if self.mouse['use'] == 'zoomout':
  1114. zoomFactor = 1./zoomFactor
  1115. x,y = self.mouse['begin']
  1116. xView = x - x/zoomFactor#x - cW/(zoomFactor * 2)
  1117. yView = y - y/zoomFactor#y - cH/(zoomFactor * 2)
  1118. else: #dragging
  1119. rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
  1120. zoomFactor = 1/max(rW/cW, rH/cH)
  1121. # when zooming to full extent, in some cases, there was zoom 1.01..., which causes problem
  1122. if abs(zoomFactor - 1) > 0.01:
  1123. zoomFactor = zoomFactor
  1124. else:
  1125. zoomFactor = 1.
  1126. if self.mouse['use'] == 'zoomout':
  1127. zoomFactor = min(rW/cW, rH/cH)
  1128. if rW/rH > cW/cH:
  1129. yView = rect.GetY() - (rW*(cH/cW) - rH)/2
  1130. xView = rect.GetX()
  1131. if self.mouse['use'] == 'zoomout':
  1132. x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
  1133. xView, yView = -x, -y
  1134. else:
  1135. xView = rect.GetX() - (rH*(cW/cH) - rW)/2
  1136. yView = rect.GetY()
  1137. if self.mouse['use'] == 'zoomout':
  1138. x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
  1139. xView, yView = -x, -y
  1140. return zoomFactor, (int(xView), int(yView))
  1141. def Zoom(self, zoomFactor, view):
  1142. """! Zoom to specified region, scroll view, redraw"""
  1143. if not self.currScale:
  1144. return
  1145. self.currScale = self.currScale*zoomFactor
  1146. if self.currScale > 10 or self.currScale < 0.1:
  1147. self.currScale = self.currScale/zoomFactor
  1148. return
  1149. if not self.preview:
  1150. # redraw paper
  1151. pRect = self.pdcPaper.GetIdBounds(self.pageId)
  1152. pRect.OffsetXY(-view[0], -view[1])
  1153. pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
  1154. self.DrawPaper(pRect)
  1155. #redraw objects
  1156. for id in self.objectId:
  1157. oRect = self.CanvasPaperCoordinates(
  1158. rect = self.instruction[id]['rect'], canvasToPaper = False)
  1159. type = self.instruction[id].type
  1160. if type == 'text':
  1161. coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
  1162. self.instruction[id]['coords'] = coords = [(int(coord) - view[i]) * zoomFactor
  1163. for i, coord in enumerate(coords)]
  1164. self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
  1165. coords = coords, bounds = oRect )
  1166. extent = self.parent.getTextExtent(textDict = self.instruction[id])
  1167. if self.instruction[id]['rotate']:
  1168. rot = float(self.instruction[id]['rotate'])
  1169. else:
  1170. rot = 0
  1171. self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
  1172. self.pdcObj.SetIdBounds(id, bounds)
  1173. else:
  1174. self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
  1175. drawid = id, pdctype = 'rectText', bb = oRect)
  1176. #redraw tmp objects
  1177. if self.dragId != -1:
  1178. self.RedrawSelectBox(self.dragId)
  1179. #redraw preview
  1180. else: # preview mode
  1181. imageRect = self.pdcImage.GetIdBounds(self.imageId)
  1182. imageRect.OffsetXY(-view[0], -view[1])
  1183. imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
  1184. self.DrawImage(imageRect)
  1185. def ZoomAll(self):
  1186. """! Zoom to full extent"""
  1187. if not self.preview:
  1188. bounds = self.pdcPaper.GetIdBounds(self.pageId)
  1189. else:
  1190. bounds = self.pdcImage.GetIdBounds(self.imageId)
  1191. zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
  1192. zoomFactor, view = self.ComputeZoom(zoomP)
  1193. self.Zoom(zoomFactor, view)
  1194. def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0)):
  1195. """! Draw object"""
  1196. if drawid is None:
  1197. drawid = wx.NewId()
  1198. bb = bb.Get()
  1199. pdc.BeginDrawing()
  1200. pdc.RemoveId(drawid)
  1201. pdc.SetId(drawid)
  1202. pdc.SetPen(pen)
  1203. pdc.SetBrush(brush)
  1204. if pdctype in ('rect', 'rectText'):
  1205. pdc.DrawRectangle(*bb)
  1206. if pdctype == 'rectText':
  1207. dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
  1208. font = self.font
  1209. size = 10
  1210. font.SetPointSize(size)
  1211. font.SetStyle(wx.ITALIC)
  1212. dc.SetFont(font)
  1213. pdc.SetFont(font)
  1214. text = '\n'.join(self.itemLabels[self.instruction[drawid].type])
  1215. textExtent = dc.GetTextExtent(text)
  1216. textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
  1217. r = map(int, bb)
  1218. while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
  1219. size -= 2
  1220. font.SetPointSize(size)
  1221. dc.SetFont(font)
  1222. pdc.SetFont(font)
  1223. textExtent = dc.GetTextExtent(text)
  1224. textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
  1225. pdc.SetTextForeground(wx.Color(100,100,100,200))
  1226. pdc.SetBackgroundMode(wx.TRANSPARENT)
  1227. pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
  1228. pdc.SetIdBounds(drawid, bb)
  1229. pdc.EndDrawing()
  1230. self.Refresh()
  1231. return drawid
  1232. def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
  1233. if textDict['rotate']:
  1234. rot = float(textDict['rotate'])
  1235. else:
  1236. rot = 0
  1237. fontsize = str(textDict['fontsize'] * self.currScale)
  1238. if textDict['background'] != 'none':
  1239. background = textDict['background']
  1240. else:
  1241. background = None
  1242. pdc.RemoveId(drawId)
  1243. pdc.SetId(drawId)
  1244. pdc.BeginDrawing()
  1245. # doesn't work
  1246. if background:
  1247. pdc.SetBackground(wx.Brush(convertRGB(background)))
  1248. pdc.SetBackgroundMode(wx.SOLID)
  1249. else:
  1250. pdc.SetBackground(wx.TRANSPARENT_BRUSH)
  1251. pdc.SetBackgroundMode(wx.TRANSPARENT)
  1252. pdc.SetFont(wx.FontFromNativeInfoString(textDict['font'] + " " + fontsize))
  1253. pdc.SetTextForeground(convertRGB(textDict['color']))
  1254. pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
  1255. pdc.SetIdBounds(drawId, wx.Rect(*bounds))
  1256. self.Refresh()
  1257. pdc.EndDrawing()
  1258. def DrawImage(self, rect):
  1259. """!Draw preview image to pseudoDC"""
  1260. self.pdcImage.ClearId(self.imageId)
  1261. self.pdcImage.SetId(self.imageId)
  1262. img = self.image
  1263. if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
  1264. img = img.Scale(rect.width, rect.height)
  1265. bitmap = img.ConvertToBitmap()
  1266. self.pdcImage.BeginDrawing()
  1267. self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
  1268. self.pdcImage.SetIdBounds(self.imageId, rect)
  1269. self.pdcImage.EndDrawing()
  1270. self.Refresh()
  1271. def DrawPaper(self, rect):
  1272. """!Draw paper and margins"""
  1273. page = self.instruction[self.pageId]
  1274. scale = page['Width'] / rect.GetWidth()
  1275. w = (page['Width'] - page['Right'] - page['Left']) / scale
  1276. h = (page['Height'] - page['Top'] - page['Bottom']) / scale
  1277. x = page['Left'] / scale + rect.GetX()
  1278. y = page['Top'] / scale + rect.GetY()
  1279. self.pdcPaper.BeginDrawing()
  1280. self.pdcPaper.RemoveId(self.pageId)
  1281. self.pdcPaper.SetId(self.pageId)
  1282. self.pdcPaper.SetPen(self.pen['paper'])
  1283. self.pdcPaper.SetBrush(self.brush['paper'])
  1284. self.pdcPaper.DrawRectangleRect(rect)
  1285. self.pdcPaper.SetPen(self.pen['margins'])
  1286. self.pdcPaper.SetBrush(self.brush['margins'])
  1287. self.pdcPaper.DrawRectangle(x, y, w, h)
  1288. self.pdcPaper.SetIdBounds(self.pageId, rect)
  1289. self.pdcPaper.EndDrawing()
  1290. self.Refresh()
  1291. def ImageRect(self):
  1292. """!Returns image centered in canvas, computes scale"""
  1293. img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
  1294. cW, cH = self.GetClientSize()
  1295. iW, iH = img.GetWidth(), img.GetHeight()
  1296. self.currScale = min(float(cW)/iW, float(cH)/iH)
  1297. iW = iW * self.currScale
  1298. iH = iH * self.currScale
  1299. x = cW/2 - iW/2
  1300. y = cH/2 - iH/2
  1301. imageRect = wx.Rect(x, y, iW, iH)
  1302. return imageRect
  1303. def RedrawSelectBox(self, id):
  1304. """!Redraws select box when selected object changes its size"""
  1305. if self.dragId == id:
  1306. rect = [self.pdcObj.GetIdBounds(id).Inflate(3,3)]
  1307. type = ['select']
  1308. ids = [self.idBoxTmp]
  1309. if self.instruction[id].type == 'map':
  1310. controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
  1311. rect.append(wx.Rect(controlP.x, controlP.y, 10,10))
  1312. type.append('resize')
  1313. ids.append(self.idResizeBoxTmp)
  1314. for id, type, rect in zip(ids, type, rect):
  1315. self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcTmp,
  1316. drawid = id, pdctype = 'rect', bb = rect)
  1317. def UpdateMapLabel(self):
  1318. """!Updates map frame label"""
  1319. vector = self.instruction.FindInstructionByType('vector')
  1320. if vector:
  1321. vectorId = vector.id
  1322. else:
  1323. vectorId = None
  1324. raster = self.instruction.FindInstructionByType('raster')
  1325. if raster:
  1326. rasterId = raster.id
  1327. else:
  1328. rasterId = None
  1329. rasterName = 'None'
  1330. if rasterId:
  1331. rasterName = self.instruction[rasterId]['raster'].split('@')[0]
  1332. self.itemLabels['map'] = self.itemLabels['map'][0:1]
  1333. self.itemLabels['map'].append("raster: " + rasterName)
  1334. if vectorId:
  1335. for map in self.instruction[vectorId]['list']:
  1336. self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
  1337. def OnSize(self, event):
  1338. """!Init image size to match window size
  1339. """
  1340. # not zoom all when notebook page is changed
  1341. if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
  1342. self.ZoomAll()
  1343. self.OnIdle(None)
  1344. event.Skip()
  1345. def OnIdle(self, event):
  1346. """!Only re-render a image during idle time instead of
  1347. multiple times during resizing.
  1348. """
  1349. width, height = self.GetClientSize()
  1350. # Make new off screen bitmap: this bitmap will always have the
  1351. # current drawing in it, so it can be used to save the image
  1352. # to a file, or whatever.
  1353. self._buffer = wx.EmptyBitmap(width, height)
  1354. # re-render image on idle
  1355. self.resize = True
  1356. def ScaleRect(self, rect, scale):
  1357. """! Scale rectangle"""
  1358. return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
  1359. rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)
  1360. def main():
  1361. app = wx.PySimpleApp()
  1362. wx.InitAllImageHandlers()
  1363. frame = PsMapFrame()
  1364. frame.Show()
  1365. app.MainLoop()
  1366. if __name__ == "__main__":
  1367. main()