/[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 1385 - (hide annotations)
Thu Jul 10 14:52:39 2003 UTC (21 years, 8 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 13679 byte(s)
Stripped out all non-wx functionality. Fixes RTTbug #1992.

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 jonathan 799 import sys
18 frank 910 import os.path
19 jonathan 799
20 bh 6 from math import hypot
21    
22 jonathan 1285 from wxPython.wx import wxWindow, \
23 bh 6 wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
24 jonathan 822 EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \
25 jonathan 1385 wxBITMAP_TYPE_XPM, wxCursor, wxPlatform, \
26     wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \
27     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     from wxproj import point_in_polygon_shape, shape_centroid
36    
37 jonathan 1385 from Thuban.Model.messages import \
38     MAP_PROJECTION_CHANGED, MAP_LAYERS_CHANGED, \
39     LAYER_PROJECTION_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED
40 bh 6
41 frank 910 from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer
42 bh 6
43     import labeldialog
44    
45 jonathan 1385 from viewport import ViewPort, PanTool
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     bitmapdc.SelectObject(self.view.bitmap)
60    
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 frank 910 scale, offset, mapregion = OutputTransform(self.canvas.scale,
91     self.canvas.offset,
92     self.canvas.GetSizeTuple(),
93     self.GetPageSizePixels())
94 bh 6 resx, resy = self.GetPPIPrinter()
95 frank 910 renderer = PrinterRenderer(dc, scale, offset, resolution = resy)
96     x, y, width, height = self.region
97     canvas_scale = self.canvas.scale
98     renderer.RenderMap(self.map,
99     (0,0,
100     (width/canvas_scale)*scale,
101     (height/canvas_scale)*scale),
102     mapregion,
103     self.selected_layer, self.selected_shapes)
104 jan 1035 return True
105 bh 6
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    
119 jonathan 1344 self.backgroundColor = wx.wxWHITE_BRUSH
120    
121 bh 125 # subscribe the WX events we're interested in
122 bh 6 EVT_PAINT(self, self.OnPaint)
123     EVT_LEFT_DOWN(self, self.OnLeftDown)
124     EVT_LEFT_UP(self, self.OnLeftUp)
125     EVT_MOTION(self, self.OnMotion)
126 bh 122 EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
127 bh 125 wx.EVT_SIZE(self, self.OnSize)
128 jonathan 1344 wx.EVT_IDLE(self, self.OnIdle)
129 bh 6
130 bh 122 def __del__(self):
131     wxWindow.__del__(self)
132 jonathan 1385 ViewPort.__del__(self)
133 bh 122
134 jonathan 1385 def PanTool(self):
135     """Start the canvas pan tool"""
136     self.SelectTool(CanvasPanTool(self))
137    
138     def SetMap(self, map):
139     redraw_channels = (MAP_LAYERS_CHANGED, LAYER_CHANGED,
140     LAYER_VISIBILITY_CHANGED)
141     if self.Map() is not None:
142     for channel in redraw_channels:
143     self.Map().Unsubscribe(channel, self.full_redraw)
144 bh 535
145 jonathan 1385 ViewPort.SetMap(self, map)
146 bh 535
147 jonathan 1385 if self.Map() is not None:
148     for channel in redraw_channels:
149     self.Map().Subscribe(channel, self.full_redraw)
150 bh 535
151 jonathan 1385 # force a redraw. If map is not empty, it's already been called
152     # by FitMapToWindow but if map is empty it hasn't been called
153     # yet so we have to explicitly call it.
154     self.full_redraw()
155 bh 535
156 bh 6 def OnPaint(self, event):
157     dc = wxPaintDC(self)
158 jonathan 1285
159 jonathan 1385 if self.Map() is not None and self.Map().HasLayers():
160 jonathan 1344 if self.bitmap in (None, -1):
161     # set the flag that we should redraw the
162     # bitmap in idle time
163     self.bitmap = -1
164 jonathan 1385 else:
165     # blit the bitmap to the screen
166     dc.BeginDrawing()
167     dc.DrawBitmap(self.bitmap, 0, 0)
168     dc.EndDrawing()
169 jonathan 1344 else:
170     # If we've got no map or if the map is empty, simply clear
171     # the screen.
172 jonathan 799
173 jonathan 1344 # XXX it's probably possible to get rid of this. The
174     # background color of the window is already white and the
175     # only thing we may have to do is to call self.Refresh()
176     # with a true argument in the right places.
177     dc.BeginDrawing()
178     dc.SetBackground(self.backgroundColor)
179     dc.Clear()
180     dc.EndDrawing()
181 bh 246
182 jonathan 1344 def OnIdle(self, event):
183     # render the screen if necessary
184 bh 125
185 jonathan 1344 if self.bitmap != -1:
186     return
187 bh 6
188 jonathan 1344 wxBeginBusyCursor()
189     try:
190     width, height = self.GetSizeTuple()
191    
192 bh 125 bitmap = wx.wxEmptyBitmap(width, height)
193     dc = wx.wxMemoryDC()
194     dc.SelectObject(bitmap)
195     dc.BeginDrawing()
196 bh 57
197 jonathan 1344 dc.SetBackground(self.backgroundColor)
198 jonathan 799 dc.Clear()
199 bh 6
200 bh 535 selected_layer = self.selection.SelectedLayer()
201     selected_shapes = self.selection.SelectedShapes()
202 bh 57
203 bh 125 # draw the map into the bitmap
204     renderer = ScreenRenderer(dc, self.scale, self.offset)
205 bh 149
206 bh 296 # Pass the entire bitmap as update region to the renderer.
207 bh 149 # We're redrawing the whole bitmap, after all.
208 jonathan 1385 renderer.RenderMap(self.Map(), (0, 0, width, height),
209 bh 535 selected_layer, selected_shapes)
210 bh 125
211     dc.EndDrawing()
212     dc.SelectObject(wx.wxNullBitmap)
213 jonathan 1344
214 bh 125 self.bitmap = bitmap
215 jonathan 1344 finally:
216     wxEndBusyCursor()
217     pass
218 bh 125
219 jonathan 1344 # This causes a paint event that then draws the bitmap
220     self.redraw()
221 bh 6
222 frank 910 def Export(self):
223 jonathan 967
224 frank 910 if hasattr(self, "export_path"):
225     export_path = self.export_path
226     else:
227     export_path="."
228     dlg = wxFileDialog(self, _("Export Map"), export_path, "",
229     "Enhanced Metafile (*.wmf)|*.wmf",
230     wxSAVE|wxOVERWRITE_PROMPT)
231     if dlg.ShowModal() == wxID_OK:
232     self.export_path = os.path.dirname(dlg.GetPath())
233     dc = wxMetaFileDC(dlg.GetPath())
234    
235     scale, offset, mapregion = OutputTransform(self.scale,
236 frank 926 self.offset,
237 frank 910 self.GetSizeTuple(),
238     dc.GetSizeTuple())
239    
240     selected_layer = self.selection.SelectedLayer()
241     selected_shapes = self.selection.SelectedShapes()
242    
243     renderer = ExportRenderer(dc, scale, offset)
244    
245     # Pass the entire bitmap as update region to the renderer.
246     # We're redrawing the whole bitmap, after all.
247     width, height = self.GetSizeTuple()
248 jonathan 1385 renderer.RenderMap(self.Map(),
249 frank 910 (0,0,
250     (width/self.scale)*scale,
251     (height/self.scale)*scale),
252     mapregion,
253     selected_layer, selected_shapes)
254     dc.EndDrawing()
255     dc.Close()
256     dlg.Destroy()
257    
258 bh 6 def Print(self):
259     printer = wx.wxPrinter()
260 frank 910 width, height = self.GetSizeTuple()
261     selected_layer = self.selection.SelectedLayer()
262     selected_shapes = self.selection.SelectedShapes()
263    
264 jonathan 1385 printout = MapPrintout(self, self.Map(), (0, 0, width, height),
265 frank 910 selected_layer, selected_shapes)
266 jan 1035 printer.Print(self, printout, True)
267 bh 6 printout.Destroy()
268 bh 246
269 bh 6 def redraw(self, *args):
270 jonathan 1344 self.Refresh(False)
271 bh 6
272 bh 125 def full_redraw(self, *args):
273     self.bitmap = None
274     self.redraw()
275    
276 jonathan 1385 def map_projection_changed(self, map, old_proj):
277     ViewPort.map_projection_changed(self, map, old_proj)
278 bh 125 self.full_redraw()
279 bh 6
280 jonathan 1221 def layer_projection_changed(self, *args):
281 jonathan 1385 ViewPort.layer_projection_changed(self, args)
282 jonathan 1221 self.full_redraw()
283    
284 bh 6 def set_view_transform(self, scale, offset):
285 jonathan 1385 ViewPort.set_view_transform(self, scale, offset)
286 bh 125 self.full_redraw()
287 bh 6
288 jonathan 1385 def GetPortSizeTuple(self):
289     return self.GetSizeTuple()
290 jonathan 967
291 bh 6 def OnLeftDown(self, event):
292 jonathan 1385 self.MouseLeftDown(event)
293 bh 6 if self.tool is not None:
294     self.drag_dc = wxClientDC(self)
295     self.drag_dc.SetLogicalFunction(wxINVERT)
296     self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH)
297     self.tool.Show(self.drag_dc)
298     self.dragging = 1
299 bh 246
300 bh 6 def OnLeftUp(self, event):
301 jonathan 1385 self.MouseLeftUp(event)
302 bh 6 if self.dragging:
303 bh 261 self.ReleaseMouse()
304 bh 404 try:
305     self.tool.Hide(self.drag_dc)
306     finally:
307     self.drag_dc = None
308     self.dragging = 0
309 bh 6
310     def OnMotion(self, event):
311     if self.dragging:
312     self.tool.Hide(self.drag_dc)
313 jonathan 1385
314     self.MouseMove(event)
315    
316     if self.dragging:
317 bh 6 self.tool.Show(self.drag_dc)
318    
319 bh 122 def OnLeaveWindow(self, event):
320     self.set_current_position(None)
321    
322 bh 125 def OnSize(self, event):
323     # the window's size has changed. We have to get a new bitmap. If
324     # we want to be clever we could try to get by without throwing
325     # everything away. E.g. when the window gets smaller, we could
326     # either keep the bitmap or create the new one from the old one.
327     # Even when the window becomes larger some parts of the bitmap
328     # could be reused.
329     self.full_redraw()
330    
331 bh 6 def shape_selected(self, layer, shape):
332 bh 535 """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
333     # The selection object takes care that it only issues
334     # SHAPES_SELECTED messages when the set of selected shapes has
335     # actually changed, so we can do a full redraw unconditionally.
336     # FIXME: We should perhaps try to limit the redraw to the are
337     # actually covered by the shapes before and after the selection
338     # change.
339 jonathan 1385 ViewPort.shape_selected(self, layer, shape)
340 bh 535 self.full_redraw()
341 bh 6
342 jonathan 1385 def GetTextExtent(self, text):
343     dc = wxClientDC(self)
344     font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
345     dc.SetFont(font)
346     return dc.GetTextExtent(text)
347 bh 159
348 jonathan 1385 def LabelShapeAt(self, x, y, text=None):
349 bh 295 """Add or remove a label at window position x, y.
350 jonathan 1385
351 bh 295 If there's a label at the given position, remove it. Otherwise
352     determine the shape at the position, run the label dialog and
353 jonathan 1385 unless the user cancels the dialog, add a label.
354 bh 295 """
355 bh 6 label_layer = self.map.LabelLayer()
356     layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
357     if layer is None and shape_index is not None:
358 jonathan 1385 ViewPort.LabelShapeAt(self, x, y)
359 bh 6 elif layer is not None:
360 bh 1219 text = labeldialog.run_label_dialog(self,
361     layer.ShapeStore().Table(),
362     shape_index)
363 jonathan 1385 ViewPort.LabelShapeAt(self, x, y, text)
364    
365 frank 910 def OutputTransform(canvas_scale, canvas_offset, canvas_size, device_extend):
366     """Calculate dimensions to transform canvas content to output device."""
367     width, height = device_extend
368    
369     # Only 80 % of the with are available for the map
370     width = width * 0.8
371    
372     # Define the distance of the map from DC border
373     distance = 20
374    
375     if height < width:
376     # landscape
377     map_height = height - 2*distance
378     map_width = map_height
379     else:
380     # portrait, recalibrate width (usually the legend width is too
381     # small
382     width = width * 0.9
383     map_height = width - 2*distance
384     map_width = map_height
385    
386     mapregion = (distance, distance,
387     distance+map_width, distance+map_height)
388    
389     canvas_width, canvas_height = canvas_size
390    
391     scalex = map_width / (canvas_width/canvas_scale)
392     scaley = map_height / (canvas_height/canvas_scale)
393     scale = min(scalex, scaley)
394     canvas_offx, canvas_offy = canvas_offset
395     offx = scale*canvas_offx/canvas_scale
396     offy = scale*canvas_offy/canvas_scale
397    
398     return scale, (offx, offy), mapregion

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26