/[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 2511 - (hide annotations)
Mon Dec 27 16:31:32 2004 UTC (20 years, 2 months ago) by russell
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 16169 byte(s)
The middle button now pans the map view.

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