/[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 2454 - (hide annotations)
Mon Dec 13 18:26:11 2004 UTC (20 years, 2 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 15742 byte(s)
* Thuban/UI/view.py (MapPrintout.draw_on_dc): The region for the
renderer has to be at the same position as the mapregion

* Thuban/UI/renderer.py (ExportRenderer.RenderMap): self.region
has to be moved by (self.shiftx, self.shifty) too.

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 bh 2454 region = (mapregion[0], mapregion[1],
98 bh 1866 (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 2072 if (self.Map() is not None
190     and (self.bitmap is None
191     or self.render_iter is not None
192     or (self.HasSelectedShapes()
193     and self.selection_bitmap is None))):
194 bh 1866 event.RequestMore(self._do_redraw())
195 bh 125
196 bh 1866 def _do_redraw(self):
197     """Redraw a bit and return whether this method has to be called again.
198 bh 6
199 bh 1866 Called by OnIdle to handle the actual redraw. Redraw is
200     incremental for both the bitmap with the normal layers and the
201     bitmap with the selection.
202     """
203     finished = False
204     if self.render_iter is not None:
205 bh 1552 try:
206 bh 1866 if self.render_iter.next():
207     # Redraw if the last preview redraw was some time
208     # ago and the user is not currently dragging the
209     # mouse because redrawing would interfere with what
210     # the current tool is drawing on the window.
211     if not self.dragging \
212     and time.time() - self.render_last_preview > 0.5:
213     client_dc = wxClientDC(self)
214     client_dc.BeginDrawing()
215     client_dc.DrawBitmap(self.bitmap, 0, 0)
216     client_dc.EndDrawing()
217     self.render_last_preview = time.time()
218     else:
219     self.render_iter = None
220     # Redraw if not dragging because redrawing would
221     # interfere with what the current tool is drawing on
222     # the window.
223     if not self.dragging:
224     self.redraw()
225     finished = True
226     except StopIteration:
227     finished = True
228     self.render_iter = None
229 bh 1552 except:
230 bh 1866 finished = True
231     self.render_iter = None
232     traceback.print_exc()
233     else:
234     self.render_iter = self._render_iterator()
235     self.render_last_preview = time.time()
236     return not finished
237 jonathan 1344
238 bh 1866 def _render_iterator(self):
239 bh 1552 width, height = self.GetSizeTuple()
240     dc = wx.wxMemoryDC()
241 bh 6
242 bh 1866 render_start = time.time()
243 bh 57
244 bh 1866 if self.bitmap is None:
245     self.bitmap = wx.wxEmptyBitmap(width, height)
246     dc.SelectObject(self.bitmap)
247     dc.BeginDrawing()
248 bh 149
249 bh 1866 dc.SetBackground(self.backgroundColor)
250     dc.Clear()
251 bh 125
252 bh 1866 # draw the map into the bitmap
253     renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
254     (0, 0, width, height))
255     for cont in renderer.RenderMapIncrementally():
256     yield True
257 jonathan 1344
258 bh 1866 dc.EndDrawing()
259     dc.SelectObject(wx.wxNullBitmap)
260 bh 125
261 bh 1866 if self.HasSelectedShapes() and self.selection_bitmap is None:
262     bitmap = wx.wxEmptyBitmap(width, height)
263     dc.SelectObject(bitmap)
264     dc.BeginDrawing()
265     dc.SetBackground(wx.wxWHITE_BRUSH)
266     dc.Clear()
267 bh 6
268 bh 1866 renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
269     (0, 0, width, height))
270     layer = self.SelectedLayer()
271     shapes = self.selection.SelectedShapes()
272     for cont in renderer.draw_selection_incrementally(layer, shapes):
273     yield True
274    
275     dc.EndDrawing()
276     dc.SelectObject(wx.wxNullBitmap)
277    
278     bitmap.SetMask(wx.wxMaskColour(bitmap, wx.wxWHITE))
279     self.selection_bitmap = bitmap
280    
281     yield False
282    
283 frank 910 def Export(self):
284 jonathan 967
285 frank 910 if hasattr(self, "export_path"):
286     export_path = self.export_path
287     else:
288     export_path="."
289     dlg = wxFileDialog(self, _("Export Map"), export_path, "",
290     "Enhanced Metafile (*.wmf)|*.wmf",
291     wxSAVE|wxOVERWRITE_PROMPT)
292     if dlg.ShowModal() == wxID_OK:
293     self.export_path = os.path.dirname(dlg.GetPath())
294     dc = wxMetaFileDC(dlg.GetPath())
295    
296 bh 1454 scale, offset, mapregion = output_transform(self.scale,
297     self.offset,
298     self.GetSizeTuple(),
299     dc.GetSizeTuple())
300 frank 910
301     selected_layer = self.selection.SelectedLayer()
302     selected_shapes = self.selection.SelectedShapes()
303    
304 bh 2066 width, height = self.GetSizeTuple()
305 bh 1866 renderer = ExportRenderer(dc, self.Map(), scale, offset,
306     region = (0, 0,
307     (width/self.scale)*scale,
308     (height/self.scale)*scale),
309     destination_region = mapregion)
310 bh 2066 renderer.RenderMap(selected_layer, selected_shapes)
311 frank 910
312     dc.EndDrawing()
313     dc.Close()
314     dlg.Destroy()
315    
316 bh 6 def Print(self):
317     printer = wx.wxPrinter()
318 frank 910 width, height = self.GetSizeTuple()
319     selected_layer = self.selection.SelectedLayer()
320     selected_shapes = self.selection.SelectedShapes()
321    
322 jonathan 1385 printout = MapPrintout(self, self.Map(), (0, 0, width, height),
323 frank 910 selected_layer, selected_shapes)
324 jan 1035 printer.Print(self, printout, True)
325 bh 6 printout.Destroy()
326 bh 246
327 bh 6 def redraw(self, *args):
328 jonathan 1344 self.Refresh(False)
329 bh 6
330 bh 125 def full_redraw(self, *args):
331     self.bitmap = None
332 bh 1866 self.selection_bitmap = None
333     self.render_iter = None
334 bh 125 self.redraw()
335    
336 bh 1866 def redraw_selection(self, *args):
337     self.selection_bitmap = None
338     self.render_iter = None
339     self.redraw()
340    
341 jonathan 1385 def map_projection_changed(self, map, old_proj):
342     ViewPort.map_projection_changed(self, map, old_proj)
343 bh 125 self.full_redraw()
344 bh 6
345 jonathan 1221 def layer_projection_changed(self, *args):
346 jonathan 1385 ViewPort.layer_projection_changed(self, args)
347 jonathan 1221 self.full_redraw()
348    
349 bh 6 def set_view_transform(self, scale, offset):
350 jonathan 1385 ViewPort.set_view_transform(self, scale, offset)
351 bh 125 self.full_redraw()
352 bh 6
353 jonathan 1385 def GetPortSizeTuple(self):
354     return self.GetSizeTuple()
355 jonathan 967
356 bh 6 def OnLeftDown(self, event):
357 jonathan 1385 self.MouseLeftDown(event)
358 bh 6 if self.tool is not None:
359     self.drag_dc = wxClientDC(self)
360     self.drag_dc.SetLogicalFunction(wxINVERT)
361     self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH)
362     self.tool.Show(self.drag_dc)
363 bh 1460 self.CaptureMouse()
364 bh 6 self.dragging = 1
365 bh 246
366 bh 6 def OnLeftUp(self, event):
367 bh 1652 """Handle EVT_LEFT_UP
368    
369     Release the mouse if it was captured, if a tool is active call
370     its Hide method and call self.MouseLeftUp.
371     """
372     # It's important that ReleaseMouse is called before MouseLeftUp.
373     # MouseLeftUp may pop up modal dialogs which leads to an
374     # effectively frozen X session because the user can only
375     # interact with the dialog but the mouse is still grabbed by the
376     # canvas.
377 bh 6 if self.dragging:
378 bh 1652 if self.HasCapture():
379     self.ReleaseMouse()
380 bh 404 try:
381     self.tool.Hide(self.drag_dc)
382     finally:
383     self.drag_dc = None
384     self.dragging = 0
385 bh 1652 self.MouseLeftUp(event)
386 bh 6
387     def OnMotion(self, event):
388     if self.dragging:
389     self.tool.Hide(self.drag_dc)
390 jonathan 1385
391     self.MouseMove(event)
392    
393     if self.dragging:
394 bh 6 self.tool.Show(self.drag_dc)
395    
396 bh 122 def OnLeaveWindow(self, event):
397     self.set_current_position(None)
398    
399 bh 125 def OnSize(self, event):
400     # the window's size has changed. We have to get a new bitmap. If
401     # we want to be clever we could try to get by without throwing
402     # everything away. E.g. when the window gets smaller, we could
403     # either keep the bitmap or create the new one from the old one.
404     # Even when the window becomes larger some parts of the bitmap
405     # could be reused.
406     self.full_redraw()
407    
408 bh 6 def shape_selected(self, layer, shape):
409 bh 535 """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
410     # The selection object takes care that it only issues
411     # SHAPES_SELECTED messages when the set of selected shapes has
412 bh 1866 # actually changed, so we can do a full redraw of the
413     # selection_bitmap unconditionally.
414 jonathan 1385 ViewPort.shape_selected(self, layer, shape)
415 bh 1866 self.redraw_selection()
416 bh 6
417 jonathan 1385 def GetTextExtent(self, text):
418     dc = wxClientDC(self)
419     font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
420     dc.SetFont(font)
421     return dc.GetTextExtent(text)
422 bh 159
423 jonathan 1385 def LabelShapeAt(self, x, y, text=None):
424 bh 295 """Add or remove a label at window position x, y.
425 bh 1454
426 bh 295 If there's a label at the given position, remove it. Otherwise
427     determine the shape at the position, run the label dialog and
428 jonathan 1385 unless the user cancels the dialog, add a label.
429 bh 295 """
430 bh 6 label_layer = self.map.LabelLayer()
431     layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
432     if layer is None and shape_index is not None:
433 jonathan 1385 ViewPort.LabelShapeAt(self, x, y)
434 bh 6 elif layer is not None:
435 bh 1219 text = labeldialog.run_label_dialog(self,
436     layer.ShapeStore().Table(),
437     shape_index)
438 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