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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1454 - (show annotations)
Fri Jul 18 14:41:04 2003 UTC (21 years, 7 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 12500 byte(s)
* test/test_export.py Remove unused imports. The OutputTransform
function is now in viewport.py and is called output_transform
(TestScalebar.test_output_transform)
(TestScalebar.test_OutputTransform): Renamed to
test_output_transform and updated to use output_transform instead
of OutputTransform

* Thuban/UI/view.py (OutputTransform): Moved to viewport.py and
renamed.
(MapCanvas.Export, MapPrintout.draw_on_dc): OutputTransform was
renamed to output_transform

* Thuban/UI/viewport.py (OutputTransform, output_transform):
Rename to output_transform

1 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 # Frank Koormann <[email protected]>
5 #
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 from Thuban import _
16
17 import sys
18 import os.path
19
20 from math import hypot
21
22 from wxPython.wx import wxWindow, \
23 wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
24 EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \
25 wxBITMAP_TYPE_XPM, wxCursor, wxPlatform, \
26 wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \
27 wxOVERWRITE_PROMPT, wxID_OK
28
29 # Export related stuff
30 if wxPlatform == '__WXMSW__':
31 from wxPython.wx import wxMetaFileDC
32
33 from wxPython import wx
34
35 from wxproj import point_in_polygon_shape, shape_centroid
36
37 from Thuban.Model.messages import \
38 MAP_PROJECTION_CHANGED, MAP_LAYERS_CHANGED, \
39 LAYER_PROJECTION_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED
40
41 from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer
42
43 import labeldialog
44
45 from viewport import ViewPort, PanTool, output_transform
46
47 class CanvasPanTool(PanTool):
48
49 """The Canvas Pan Tool"""
50
51 def MouseMove(self, event):
52 if self.dragging:
53 PanTool.MouseMove(self, event)
54 sx, sy = self.start
55 x, y = self.current
56 width, height = self.view.GetSizeTuple()
57
58 bitmapdc = wx.wxMemoryDC()
59 bitmapdc.SelectObject(self.view.bitmap)
60
61 dc = self.view.drag_dc
62 dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
63
64 class MapPrintout(wx.wxPrintout):
65
66 """
67 wxPrintout class for printing Thuban maps
68 """
69
70 def __init__(self, canvas, map, region, selected_layer, selected_shapes):
71 wx.wxPrintout.__init__(self)
72 self.canvas = canvas
73 self.map = map
74 self.region = region
75 self.selected_layer = selected_layer
76 self.selected_shapes = selected_shapes
77
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 scale, offset, mapregion = output_transform(self.canvas.scale,
91 self.canvas.offset,
92 self.canvas.GetSizeTuple(),
93 self.GetPageSizePixels())
94 resx, resy = self.GetPPIPrinter()
95 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 return True
105
106 class MapCanvas(wxWindow, ViewPort):
107
108 """A widget that displays a map and offers some interaction"""
109
110 def __init__(self, parent, winid):
111 wxWindow.__init__(self, parent, winid)
112 ViewPort.__init__(self)
113
114 self.SetBackgroundColour(wxColour(255, 255, 255))
115
116 # the bitmap serving as backing store
117 self.bitmap = None
118
119 self.backgroundColor = wx.wxWHITE_BRUSH
120
121 # subscribe the WX events we're interested in
122 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 EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
127 wx.EVT_SIZE(self, self.OnSize)
128 wx.EVT_IDLE(self, self.OnIdle)
129
130 def __del__(self):
131 wxWindow.__del__(self)
132 ViewPort.__del__(self)
133
134 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
145 ViewPort.SetMap(self, map)
146
147 if self.Map() is not None:
148 for channel in redraw_channels:
149 self.Map().Subscribe(channel, self.full_redraw)
150
151 # 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
156 def OnPaint(self, event):
157 dc = wxPaintDC(self)
158
159 if self.Map() is not None and self.Map().HasLayers():
160 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 else:
165 # blit the bitmap to the screen
166 dc.BeginDrawing()
167 dc.DrawBitmap(self.bitmap, 0, 0)
168 dc.EndDrawing()
169 else:
170 # If we've got no map or if the map is empty, simply clear
171 # the screen.
172
173 # 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
182 def OnIdle(self, event):
183 # render the screen if necessary
184
185 if self.bitmap != -1:
186 return
187
188 wxBeginBusyCursor()
189 try:
190 width, height = self.GetSizeTuple()
191
192 bitmap = wx.wxEmptyBitmap(width, height)
193 dc = wx.wxMemoryDC()
194 dc.SelectObject(bitmap)
195 dc.BeginDrawing()
196
197 dc.SetBackground(self.backgroundColor)
198 dc.Clear()
199
200 selected_layer = self.selection.SelectedLayer()
201 selected_shapes = self.selection.SelectedShapes()
202
203 # draw the map into the bitmap
204 renderer = ScreenRenderer(dc, self.scale, self.offset)
205
206 # Pass the entire bitmap as update region to the renderer.
207 # We're redrawing the whole bitmap, after all.
208 renderer.RenderMap(self.Map(), (0, 0, width, height),
209 selected_layer, selected_shapes)
210
211 dc.EndDrawing()
212 dc.SelectObject(wx.wxNullBitmap)
213
214 self.bitmap = bitmap
215 finally:
216 wxEndBusyCursor()
217 pass
218
219 # This causes a paint event that then draws the bitmap
220 self.redraw()
221
222 def Export(self):
223
224 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 = output_transform(self.scale,
236 self.offset,
237 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 renderer.RenderMap(self.Map(),
249 (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 def Print(self):
259 printer = wx.wxPrinter()
260 width, height = self.GetSizeTuple()
261 selected_layer = self.selection.SelectedLayer()
262 selected_shapes = self.selection.SelectedShapes()
263
264 printout = MapPrintout(self, self.Map(), (0, 0, width, height),
265 selected_layer, selected_shapes)
266 printer.Print(self, printout, True)
267 printout.Destroy()
268
269 def redraw(self, *args):
270 self.Refresh(False)
271
272 def full_redraw(self, *args):
273 self.bitmap = None
274 self.redraw()
275
276 def map_projection_changed(self, map, old_proj):
277 ViewPort.map_projection_changed(self, map, old_proj)
278 self.full_redraw()
279
280 def layer_projection_changed(self, *args):
281 ViewPort.layer_projection_changed(self, args)
282 self.full_redraw()
283
284 def set_view_transform(self, scale, offset):
285 ViewPort.set_view_transform(self, scale, offset)
286 self.full_redraw()
287
288 def GetPortSizeTuple(self):
289 return self.GetSizeTuple()
290
291 def OnLeftDown(self, event):
292 self.MouseLeftDown(event)
293 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
300 def OnLeftUp(self, event):
301 self.MouseLeftUp(event)
302 if self.dragging:
303 self.ReleaseMouse()
304 try:
305 self.tool.Hide(self.drag_dc)
306 finally:
307 self.drag_dc = None
308 self.dragging = 0
309
310 def OnMotion(self, event):
311 if self.dragging:
312 self.tool.Hide(self.drag_dc)
313
314 self.MouseMove(event)
315
316 if self.dragging:
317 self.tool.Show(self.drag_dc)
318
319 def OnLeaveWindow(self, event):
320 self.set_current_position(None)
321
322 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 def shape_selected(self, layer, shape):
332 """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 ViewPort.shape_selected(self, layer, shape)
340 self.full_redraw()
341
342 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
348 def LabelShapeAt(self, x, y, text=None):
349 """Add or remove a label at window position x, y.
350
351 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 unless the user cancels the dialog, add a label.
354 """
355 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 ViewPort.LabelShapeAt(self, x, y)
359 elif layer is not None:
360 text = labeldialog.run_label_dialog(self,
361 layer.ShapeStore().Table(),
362 shape_index)
363 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