/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/view.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/view.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2068 - (hide annotations)
Mon Feb 16 19:42:04 2004 UTC (21 years ago) by bh
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 15664 byte(s)
(MapCanvas.Export): Remove accidentally added
line

1 bh 2066 # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4 frank 910 # Frank Koormann <[email protected]>
5 bh 6 #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     """
10     Classes for display of a map and interaction with it
11     """
12    
13 bh 1866 from __future__ import generators
14    
15 bh 6 __version__ = "$Revision$"
16 bh 1866 # $Source$
17     # $Id$
18 bh 6
19 frank 910 import os.path
20 bh 1866 import time
21     import traceback
22 jonathan 799
23 jonathan 1285 from wxPython.wx import wxWindow, \
24 bh 6 wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
25 jonathan 822 EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \
26 bh 1456 wxPlatform, wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \
27 jonathan 1385 wxOVERWRITE_PROMPT, wxID_OK
28 bh 6
29 frank 910 # Export related stuff
30     if wxPlatform == '__WXMSW__':
31     from wxPython.wx import wxMetaFileDC
32 bh 6
33     from wxPython import wx
34    
35 bh 1866 from Thuban import _
36    
37 bh 1456 from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \
38     LAYER_VISIBILITY_CHANGED
39 bh 6
40 frank 910 from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer
41 bh 6
42     import labeldialog
43    
44 bh 1454 from viewport import ViewPort, PanTool, output_transform
45 bh 6
46 jonathan 1385 class CanvasPanTool(PanTool):
47 bh 6
48 jonathan 1385 """The Canvas Pan Tool"""
49 bh 6
50     def MouseMove(self, event):
51     if self.dragging:
52 jonathan 1385 PanTool.MouseMove(self, event)
53 bh 57 sx, sy = self.start
54 bh 6 x, y = self.current
55     width, height = self.view.GetSizeTuple()
56 bh 159
57     bitmapdc = wx.wxMemoryDC()
58 bh 1866 bitmapdc.SelectObject(self.view.PreviewBitmap())
59 bh 159
60 bh 6 dc = self.view.drag_dc
61 bh 159 dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
62 bh 6
63     class MapPrintout(wx.wxPrintout):
64    
65     """
66     wxPrintout class for printing Thuban maps
67     """
68    
69 frank 910 def __init__(self, canvas, map, region, selected_layer, selected_shapes):
70 bh 6 wx.wxPrintout.__init__(self)
71 frank 910 self.canvas = canvas
72 bh 6 self.map = map
73 frank 910 self.region = region
74     self.selected_layer = selected_layer
75     self.selected_shapes = selected_shapes
76 bh 6
77     def GetPageInfo(self):
78     return (1, 1, 1, 1)
79    
80     def HasPage(self, pagenum):
81     return pagenum == 1
82    
83     def OnPrintPage(self, pagenum):
84     if pagenum == 1:
85     self.draw_on_dc(self.GetDC())
86    
87     def draw_on_dc(self, dc):
88     width, height = self.GetPageSizePixels()
89 bh 1454 scale, offset, mapregion = output_transform(self.canvas.scale,
90     self.canvas.offset,
91     self.canvas.GetSizeTuple(),
92     self.GetPageSizePixels())
93 bh 6 resx, resy = self.GetPPIPrinter()
94 bh 1866 canvas_scale = self.canvas.scale
95 frank 910 x, y, width, height = self.region
96 bh 1866 renderer = PrinterRenderer(dc, self.map, scale, offset,
97     region = (0, 0,
98     (width/canvas_scale)*scale,
99     (height/canvas_scale)*scale),
100     resolution = resy,
101     destination_region = mapregion)
102     renderer.RenderMap(self.selected_layer, self.selected_shapes)
103 jan 1035 return True
104 bh 6
105 bh 1866
106 jonathan 1385 class MapCanvas(wxWindow, ViewPort):
107 bh 6
108     """A widget that displays a map and offers some interaction"""
109    
110 bh 535 def __init__(self, parent, winid):
111 bh 6 wxWindow.__init__(self, parent, winid)
112 jonathan 1385 ViewPort.__init__(self)
113    
114 bh 6 self.SetBackgroundColour(wxColour(255, 255, 255))
115 bh 125
116     # the bitmap serving as backing store
117     self.bitmap = None
118 bh 1866 # the monochrome bitmap with the selection if any
119     self.selection_bitmap = None
120 bh 125
121 jonathan 1344 self.backgroundColor = wx.wxWHITE_BRUSH
122    
123 bh 1866 # The rendering iterator object. Used when rendering
124     # incrementally
125     self.render_iter = None
126 bh 1552
127 bh 125 # subscribe the WX events we're interested in
128 bh 6 EVT_PAINT(self, self.OnPaint)
129     EVT_LEFT_DOWN(self, self.OnLeftDown)
130     EVT_LEFT_UP(self, self.OnLeftUp)
131     EVT_MOTION(self, self.OnMotion)
132 bh 122 EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
133 bh 125 wx.EVT_SIZE(self, self.OnSize)
134 jonathan 1344 wx.EVT_IDLE(self, self.OnIdle)
135 bh 6
136 bh 122 def __del__(self):
137     wxWindow.__del__(self)
138 jonathan 1385 ViewPort.__del__(self)
139 bh 122
140 bh 1866 def PreviewBitmap(self):
141     return self.bitmap
142    
143 jonathan 1385 def PanTool(self):
144     """Start the canvas pan tool"""
145     self.SelectTool(CanvasPanTool(self))
146    
147     def SetMap(self, map):
148     redraw_channels = (MAP_LAYERS_CHANGED, LAYER_CHANGED,
149     LAYER_VISIBILITY_CHANGED)
150     if self.Map() is not None:
151     for channel in redraw_channels:
152     self.Map().Unsubscribe(channel, self.full_redraw)
153 bh 535
154 jonathan 1385 ViewPort.SetMap(self, map)
155 bh 535
156 jonathan 1385 if self.Map() is not None:
157     for channel in redraw_channels:
158     self.Map().Subscribe(channel, self.full_redraw)
159 bh 535
160 jonathan 1385 # force a redraw. If map is not empty, it's already been called
161     # by FitMapToWindow but if map is empty it hasn't been called
162     # yet so we have to explicitly call it.
163     self.full_redraw()
164 bh 535
165 bh 6 def OnPaint(self, event):
166     dc = wxPaintDC(self)
167 jonathan 1385 if self.Map() is not None and self.Map().HasLayers():
168 bh 1866 if self.bitmap is not None:
169 jonathan 1385 dc.BeginDrawing()
170     dc.DrawBitmap(self.bitmap, 0, 0)
171 bh 1866 if self.selection_bitmap is not None:
172     dc.DrawBitmap(self.selection_bitmap, 0, 0, True)
173 jonathan 1385 dc.EndDrawing()
174 jonathan 1344 else:
175     # If we've got no map or if the map is empty, simply clear
176     # the screen.
177 jonathan 799
178 jonathan 1344 # XXX it's probably possible to get rid of this. The
179     # background color of the window is already white and the
180     # only thing we may have to do is to call self.Refresh()
181     # with a true argument in the right places.
182     dc.BeginDrawing()
183     dc.SetBackground(self.backgroundColor)
184     dc.Clear()
185     dc.EndDrawing()
186 bh 246
187 jonathan 1344 def OnIdle(self, event):
188 bh 1552 """Idle handler. Redraw the bitmap if necessary"""
189 bh 1866 if (self.bitmap is None
190     or self.render_iter is not None
191     or (self.HasSelectedShapes()
192     and self.selection_bitmap is None)):
193     event.RequestMore(self._do_redraw())
194 bh 125
195 bh 1866 def _do_redraw(self):
196     """Redraw a bit and return whether this method has to be called again.
197 bh 6
198 bh 1866 Called by OnIdle to handle the actual redraw. Redraw is
199     incremental for both the bitmap with the normal layers and the
200     bitmap with the selection.
201     """
202     finished = False
203     if self.render_iter is not None:
204 bh 1552 try:
205 bh 1866 if self.render_iter.next():
206     # Redraw if the last preview redraw was some time
207     # ago and the user is not currently dragging the
208     # mouse because redrawing would interfere with what
209     # the current tool is drawing on the window.
210     if not self.dragging \
211     and time.time() - self.render_last_preview > 0.5:
212     client_dc = wxClientDC(self)
213     client_dc.BeginDrawing()
214     client_dc.DrawBitmap(self.bitmap, 0, 0)
215     client_dc.EndDrawing()
216     self.render_last_preview = time.time()
217     else:
218     self.render_iter = None
219     # Redraw if not dragging because redrawing would
220     # interfere with what the current tool is drawing on
221     # the window.
222     if not self.dragging:
223     self.redraw()
224     finished = True
225     except StopIteration:
226     finished = True
227     self.render_iter = None
228 bh 1552 except:
229 bh 1866 finished = True
230     self.render_iter = None
231     traceback.print_exc()
232     else:
233     self.render_iter = self._render_iterator()
234     self.render_last_preview = time.time()
235     return not finished
236 jonathan 1344
237 bh 1866 def _render_iterator(self):
238 bh 1552 width, height = self.GetSizeTuple()
239     dc = wx.wxMemoryDC()
240 bh 6
241 bh 1866 render_start = time.time()
242 bh 57
243 bh 1866 if self.bitmap is None:
244     self.bitmap = wx.wxEmptyBitmap(width, height)
245     dc.SelectObject(self.bitmap)
246     dc.BeginDrawing()
247 bh 149
248 bh 1866 dc.SetBackground(self.backgroundColor)
249     dc.Clear()
250 bh 125
251 bh 1866 # draw the map into the bitmap
252     renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
253     (0, 0, width, height))
254     for cont in renderer.RenderMapIncrementally():
255     yield True
256 jonathan 1344
257 bh 1866 dc.EndDrawing()
258     dc.SelectObject(wx.wxNullBitmap)
259 bh 125
260 bh 1866 if self.HasSelectedShapes() and self.selection_bitmap is None:
261     bitmap = wx.wxEmptyBitmap(width, height)
262     dc.SelectObject(bitmap)
263     dc.BeginDrawing()
264     dc.SetBackground(wx.wxWHITE_BRUSH)
265     dc.Clear()
266 bh 6
267 bh 1866 renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
268     (0, 0, width, height))
269     layer = self.SelectedLayer()
270     shapes = self.selection.SelectedShapes()
271     for cont in renderer.draw_selection_incrementally(layer, shapes):
272     yield True
273    
274     dc.EndDrawing()
275     dc.SelectObject(wx.wxNullBitmap)
276    
277     bitmap.SetMask(wx.wxMaskColour(bitmap, wx.wxWHITE))
278     self.selection_bitmap = bitmap
279    
280     yield False
281    
282 frank 910 def Export(self):
283 jonathan 967
284 frank 910 if hasattr(self, "export_path"):
285     export_path = self.export_path
286     else:
287     export_path="."
288     dlg = wxFileDialog(self, _("Export Map"), export_path, "",
289     "Enhanced Metafile (*.wmf)|*.wmf",
290     wxSAVE|wxOVERWRITE_PROMPT)
291     if dlg.ShowModal() == wxID_OK:
292     self.export_path = os.path.dirname(dlg.GetPath())
293     dc = wxMetaFileDC(dlg.GetPath())
294    
295 bh 1454 scale, offset, mapregion = output_transform(self.scale,
296     self.offset,
297     self.GetSizeTuple(),
298     dc.GetSizeTuple())
299 frank 910
300     selected_layer = self.selection.SelectedLayer()
301     selected_shapes = self.selection.SelectedShapes()
302    
303 bh 2066 width, height = self.GetSizeTuple()
304 bh 1866 renderer = ExportRenderer(dc, self.Map(), scale, offset,
305     region = (0, 0,
306     (width/self.scale)*scale,
307     (height/self.scale)*scale),
308     destination_region = mapregion)
309 bh 2066 renderer.RenderMap(selected_layer, selected_shapes)
310 frank 910
311     dc.EndDrawing()
312     dc.Close()
313     dlg.Destroy()
314    
315 bh 6 def Print(self):
316     printer = wx.wxPrinter()
317 frank 910 width, height = self.GetSizeTuple()
318     selected_layer = self.selection.SelectedLayer()
319     selected_shapes = self.selection.SelectedShapes()
320    
321 jonathan 1385 printout = MapPrintout(self, self.Map(), (0, 0, width, height),
322 frank 910 selected_layer, selected_shapes)
323 jan 1035 printer.Print(self, printout, True)
324 bh 6 printout.Destroy()
325 bh 246
326 bh 6 def redraw(self, *args):
327 jonathan 1344 self.Refresh(False)
328 bh 6
329 bh 125 def full_redraw(self, *args):
330     self.bitmap = None
331 bh 1866 self.selection_bitmap = None
332     self.render_iter = None
333 bh 125 self.redraw()
334    
335 bh 1866 def redraw_selection(self, *args):
336     self.selection_bitmap = None
337     self.render_iter = None
338     self.redraw()
339    
340 jonathan 1385 def map_projection_changed(self, map, old_proj):
341     ViewPort.map_projection_changed(self, map, old_proj)
342 bh 125 self.full_redraw()
343 bh 6
344 jonathan 1221 def layer_projection_changed(self, *args):
345 jonathan 1385 ViewPort.layer_projection_changed(self, args)
346 jonathan 1221 self.full_redraw()
347    
348 bh 6 def set_view_transform(self, scale, offset):
349 jonathan 1385 ViewPort.set_view_transform(self, scale, offset)
350 bh 125 self.full_redraw()
351 bh 6
352 jonathan 1385 def GetPortSizeTuple(self):
353     return self.GetSizeTuple()
354 jonathan 967
355 bh 6 def OnLeftDown(self, event):
356 jonathan 1385 self.MouseLeftDown(event)
357 bh 6 if self.tool is not None:
358     self.drag_dc = wxClientDC(self)
359     self.drag_dc.SetLogicalFunction(wxINVERT)
360     self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH)
361     self.tool.Show(self.drag_dc)
362 bh 1460 self.CaptureMouse()
363 bh 6 self.dragging = 1
364 bh 246
365 bh 6 def OnLeftUp(self, event):
366 bh 1652 """Handle EVT_LEFT_UP
367    
368     Release the mouse if it was captured, if a tool is active call
369     its Hide method and call self.MouseLeftUp.
370     """
371     # It's important that ReleaseMouse is called before MouseLeftUp.
372     # MouseLeftUp may pop up modal dialogs which leads to an
373     # effectively frozen X session because the user can only
374     # interact with the dialog but the mouse is still grabbed by the
375     # canvas.
376 bh 6 if self.dragging:
377 bh 1652 if self.HasCapture():
378     self.ReleaseMouse()
379 bh 404 try:
380     self.tool.Hide(self.drag_dc)
381     finally:
382     self.drag_dc = None
383     self.dragging = 0
384 bh 1652 self.MouseLeftUp(event)
385 bh 6
386     def OnMotion(self, event):
387     if self.dragging:
388     self.tool.Hide(self.drag_dc)
389 jonathan 1385
390     self.MouseMove(event)
391    
392     if self.dragging:
393 bh 6 self.tool.Show(self.drag_dc)
394    
395 bh 122 def OnLeaveWindow(self, event):
396     self.set_current_position(None)
397    
398 bh 125 def OnSize(self, event):
399     # the window's size has changed. We have to get a new bitmap. If
400     # we want to be clever we could try to get by without throwing
401     # everything away. E.g. when the window gets smaller, we could
402     # either keep the bitmap or create the new one from the old one.
403     # Even when the window becomes larger some parts of the bitmap
404     # could be reused.
405     self.full_redraw()
406    
407 bh 6 def shape_selected(self, layer, shape):
408 bh 535 """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
409     # The selection object takes care that it only issues
410     # SHAPES_SELECTED messages when the set of selected shapes has
411 bh 1866 # actually changed, so we can do a full redraw of the
412     # selection_bitmap unconditionally.
413 jonathan 1385 ViewPort.shape_selected(self, layer, shape)
414 bh 1866 self.redraw_selection()
415 bh 6
416 jonathan 1385 def GetTextExtent(self, text):
417     dc = wxClientDC(self)
418     font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
419     dc.SetFont(font)
420     return dc.GetTextExtent(text)
421 bh 159
422 jonathan 1385 def LabelShapeAt(self, x, y, text=None):
423 bh 295 """Add or remove a label at window position x, y.
424 bh 1454
425 bh 295 If there's a label at the given position, remove it. Otherwise
426     determine the shape at the position, run the label dialog and
427 jonathan 1385 unless the user cancels the dialog, add a label.
428 bh 295 """
429 bh 6 label_layer = self.map.LabelLayer()
430     layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
431     if layer is None and shape_index is not None:
432 jonathan 1385 ViewPort.LabelShapeAt(self, x, y)
433 bh 6 elif layer is not None:
434 bh 1219 text = labeldialog.run_label_dialog(self,
435     layer.ShapeStore().Table(),
436     shape_index)
437 jonathan 1385 ViewPort.LabelShapeAt(self, x, y, text)

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26