/[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 1652 - (hide annotations)
Mon Aug 25 15:59:58 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 13218 byte(s)
(MapCanvas.OnLeftUp): Release the the mouse
before calling MouseLeftUp. MouseLeftUp may pop up modal dialogs
which leads to an effectively frozen X session because the user
can only interact with the dialog but the mouse is still grabbed
by the canvas.
Also, call the tool's Hide method before MouseLeftUp because
MouseLeftUp may change the tool's coordinates.

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