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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1552 by bh, Wed Aug 6 17:21:32 2003 UTC revision 2599 by russell, Wed Apr 13 16:08:33 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Frank Koormann <[email protected]>  # Frank Koormann <[email protected]>
# Line 10  Line 10 
10  Classes for display of a map and interaction with it  Classes for display of a map and interaction with it
11  """  """
12    
13  __version__ = "$Revision$"  from __future__ import generators
14    
15  from Thuban import _  __version__ = "$Revision$"
16    # $Source$
17    # $Id$
18    
19  import os.path  import os.path
20    import time
21    import traceback
22    
23  from wxPython.wx import wxWindow, \  from wxPython.wx import wxWindow, \
24       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
25       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \
26       wxPlatform, wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \       wxPlatform, wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \
27         EVT_MIDDLE_DOWN, EVT_MIDDLE_UP, \
28       wxOVERWRITE_PROMPT, wxID_OK       wxOVERWRITE_PROMPT, wxID_OK
29    
30  # Export related stuff  # Export related stuff
# Line 28  if wxPlatform == '__WXMSW__': Line 33  if wxPlatform == '__WXMSW__':
33    
34  from wxPython import wx  from wxPython import wx
35    
36    from Thuban import _
37    
38  from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \  from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \
39       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED
40    
# Line 49  class CanvasPanTool(PanTool): Line 56  class CanvasPanTool(PanTool):
56              width, height = self.view.GetSizeTuple()              width, height = self.view.GetSizeTuple()
57    
58              bitmapdc = wx.wxMemoryDC()              bitmapdc = wx.wxMemoryDC()
59              bitmapdc.SelectObject(self.view.bitmap)              bitmapdc.SelectObject(self.view.PreviewBitmap())
60    
61              dc = self.view.drag_dc              dc = self.view.drag_dc
62              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
# Line 85  class MapPrintout(wx.wxPrintout): Line 92  class MapPrintout(wx.wxPrintout):
92                                                      self.canvas.GetSizeTuple(),                                                      self.canvas.GetSizeTuple(),
93                                                      self.GetPageSizePixels())                                                      self.GetPageSizePixels())
94          resx, resy = self.GetPPIPrinter()          resx, resy = self.GetPPIPrinter()
         renderer = PrinterRenderer(dc, scale, offset, resolution = resy)  
         x, y, width, height = self.region  
95          canvas_scale = self.canvas.scale          canvas_scale = self.canvas.scale
96          renderer.RenderMap(self.map,          x, y, width, height = self.region
97                             (0,0,          renderer = PrinterRenderer(dc, self.map, scale, offset,
98                                  (width/canvas_scale)*scale,                                     region = (mapregion[0], mapregion[1],
99                                  (height/canvas_scale)*scale),                                               (width/canvas_scale)*scale,
100                                  mapregion,                                               (height/canvas_scale)*scale),
101                             self.selected_layer, self.selected_shapes)                                     resolution = resy,
102                                       destination_region = mapregion)
103            renderer.RenderMap(self.selected_layer, self.selected_shapes)
104          return True          return True
105    
106    
107  class MapCanvas(wxWindow, ViewPort):  class MapCanvas(wxWindow, ViewPort):
108    
109      """A widget that displays a map and offers some interaction"""      """A widget that displays a map and offers some interaction"""
# Line 108  class MapCanvas(wxWindow, ViewPort): Line 116  class MapCanvas(wxWindow, ViewPort):
116    
117          # the bitmap serving as backing store          # the bitmap serving as backing store
118          self.bitmap = None          self.bitmap = None
119            # the monochrome bitmap with the selection if any
120            self.selection_bitmap = None
121    
122          self.backgroundColor = wx.wxWHITE_BRUSH          self.backgroundColor = wx.wxWHITE_BRUSH
123    
124          # Set to true if there ever is an error during redraw. There          # The rendering iterator object. Used when rendering
125          # should never be errors, but unfortunately bugs happen.          # incrementally
126          self.error_on_redraw = 0          self.render_iter = None
127    
128          # subscribe the WX events we're interested in          # subscribe the WX events we're interested in
129          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
130          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
131          EVT_LEFT_UP(self, self.OnLeftUp)          EVT_LEFT_UP(self, self.OnLeftUp)
132            EVT_MIDDLE_DOWN(self, self.OnMiddleDown)
133            EVT_MIDDLE_UP(self, self.OnMiddleUp)
134          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
135          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
136          wx.EVT_SIZE(self, self.OnSize)          wx.EVT_SIZE(self, self.OnSize)
# Line 128  class MapCanvas(wxWindow, ViewPort): Line 140  class MapCanvas(wxWindow, ViewPort):
140          wxWindow.__del__(self)          wxWindow.__del__(self)
141          ViewPort.__del__(self)          ViewPort.__del__(self)
142    
143        def PreviewBitmap(self):
144            return self.bitmap
145    
146      def PanTool(self):      def PanTool(self):
147          """Start the canvas pan tool"""          """Start the canvas pan tool"""
148          self.SelectTool(CanvasPanTool(self))          self.SelectTool(CanvasPanTool(self))
# Line 152  class MapCanvas(wxWindow, ViewPort): Line 167  class MapCanvas(wxWindow, ViewPort):
167    
168      def OnPaint(self, event):      def OnPaint(self, event):
169          dc = wxPaintDC(self)          dc = wxPaintDC(self)
   
170          if self.Map() is not None and self.Map().HasLayers():          if self.Map() is not None and self.Map().HasLayers():
171              if self.bitmap in (None, -1):              if self.bitmap is not None:
                 # set the flag that we should redraw the  
                 # bitmap in idle time  
                 self.bitmap = -1  
             else:  
                 # blit the bitmap to the screen  
172                  dc.BeginDrawing()                  dc.BeginDrawing()
173                  dc.DrawBitmap(self.bitmap, 0, 0)                  dc.DrawBitmap(self.bitmap, 0, 0)
174                    if self.selection_bitmap is not None:
175                        dc.DrawBitmap(self.selection_bitmap, 0, 0, True)
176                  dc.EndDrawing()                  dc.EndDrawing()
177          else:          else:
178              # If we've got no map or if the map is empty, simply clear              # If we've got no map or if the map is empty, simply clear
# Line 178  class MapCanvas(wxWindow, ViewPort): Line 189  class MapCanvas(wxWindow, ViewPort):
189    
190      def OnIdle(self, event):      def OnIdle(self, event):
191          """Idle handler. Redraw the bitmap if necessary"""          """Idle handler. Redraw the bitmap if necessary"""
192            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                event.RequestMore(self._do_redraw())
198    
199          if self.bitmap != -1:      def _do_redraw(self):
200              return          """Redraw a bit and return whether this method has to be called again.
         if self.error_on_redraw:  
             return  
201    
202          wxBeginBusyCursor()          Called by OnIdle to handle the actual redraw. Redraw is
203          try:          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              try:              try:
209                  self._do_redraw()                  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              except:              except:
233                  self.error_on_redraw = True                  finished = True
234                  raise                  self.render_iter = None
235          finally:                  traceback.print_exc()
236              wxEndBusyCursor()          else:
237                self.render_iter = self._render_iterator()
238                self.render_last_preview = time.time()
239            return not finished
240    
241      def _do_redraw(self):      def _render_iterator(self):
         """Called by OnIdle to do the actual redraw.  
         """  
242          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
   
         bitmap = wx.wxEmptyBitmap(width, height)  
243          dc = wx.wxMemoryDC()          dc = wx.wxMemoryDC()
         dc.SelectObject(bitmap)  
         dc.BeginDrawing()  
244    
245          dc.SetBackground(self.backgroundColor)          render_start = time.time()
         dc.Clear()  
246    
247          selected_layer = self.selection.SelectedLayer()          if self.bitmap is None:
248          selected_shapes = self.selection.SelectedShapes()              self.bitmap = wx.wxEmptyBitmap(width, height)
249                dc.SelectObject(self.bitmap)
250                dc.BeginDrawing()
251    
252                dc.SetBackground(self.backgroundColor)
253                dc.Clear()
254    
255          # draw the map into the bitmap              # draw the map into the bitmap
256          renderer = ScreenRenderer(dc, self.scale, self.offset)              renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
257                                          (0, 0, width, height))
258                for cont in renderer.RenderMapIncrementally():
259                    yield True
260    
261          # Pass the entire bitmap as update region to the renderer.              dc.EndDrawing()
262          # We're redrawing the whole bitmap, after all.              dc.SelectObject(wx.wxNullBitmap)
         renderer.RenderMap(self.Map(), (0, 0, width, height),  
                            selected_layer, selected_shapes)  
263    
264          dc.EndDrawing()          if self.HasSelectedShapes() and self.selection_bitmap is None:
265          dc.SelectObject(wx.wxNullBitmap)              bitmap = wx.wxEmptyBitmap(width, height)
266                dc.SelectObject(bitmap)
267                dc.BeginDrawing()
268                dc.SetBackground(wx.wxWHITE_BRUSH)
269                dc.Clear()
270    
271          self.bitmap = bitmap              renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
272          # This causes a paint event that then draws the bitmap                                        (0, 0, width, height))
273          self.redraw()              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      def Export(self):      def Export(self):
287    
# Line 246  class MapCanvas(wxWindow, ViewPort): Line 304  class MapCanvas(wxWindow, ViewPort):
304              selected_layer = self.selection.SelectedLayer()              selected_layer = self.selection.SelectedLayer()
305              selected_shapes = self.selection.SelectedShapes()              selected_shapes = self.selection.SelectedShapes()
306    
             renderer = ExportRenderer(dc, scale, offset)  
   
             # Pass the entire bitmap as update region to the renderer.  
             # We're redrawing the whole bitmap, after all.  
307              width, height = self.GetSizeTuple()              width, height = self.GetSizeTuple()
308              renderer.RenderMap(self.Map(),              renderer = ExportRenderer(dc, self.Map(), scale, offset,
309                                  (0,0,                                        region = (0, 0,
310                                      (width/self.scale)*scale,                                                  (width/self.scale)*scale,
311                                      (height/self.scale)*scale),                                                  (height/self.scale)*scale),
312                                  mapregion,                                        destination_region = mapregion)
313                                  selected_layer, selected_shapes)              renderer.RenderMap(selected_layer, selected_shapes)
314    
315              dc.EndDrawing()              dc.EndDrawing()
316              dc.Close()              dc.Close()
317          dlg.Destroy()          dlg.Destroy()
# Line 277  class MapCanvas(wxWindow, ViewPort): Line 332  class MapCanvas(wxWindow, ViewPort):
332    
333      def full_redraw(self, *args):      def full_redraw(self, *args):
334          self.bitmap = None          self.bitmap = None
335            self.selection_bitmap = None
336            self.render_iter = None
337            self.redraw()
338    
339        def redraw_selection(self, *args):
340            self.selection_bitmap = None
341            self.render_iter = None
342          self.redraw()          self.redraw()
343    
344      def map_projection_changed(self, map, old_proj):      def map_projection_changed(self, map, old_proj):
# Line 294  class MapCanvas(wxWindow, ViewPort): Line 356  class MapCanvas(wxWindow, ViewPort):
356      def GetPortSizeTuple(self):      def GetPortSizeTuple(self):
357          return self.GetSizeTuple()          return self.GetSizeTuple()
358    
359        def OnMiddleDown(self, event):
360            self.remembertool = self.tool
361            if self.Map() is not None and self.Map().HasLayers():
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      def OnLeftDown(self, event):      def OnLeftDown(self, event):
371          self.MouseLeftDown(event)          self.MouseLeftDown(event)
372          if self.tool is not None:          if self.tool is not None:
# Line 305  class MapCanvas(wxWindow, ViewPort): Line 378  class MapCanvas(wxWindow, ViewPort):
378              self.dragging = 1              self.dragging = 1
379    
380      def OnLeftUp(self, event):      def OnLeftUp(self, event):
381          self.MouseLeftUp(event)          """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          if self.dragging:          if self.dragging:
392              self.ReleaseMouse()              if self.HasCapture():
393                    self.ReleaseMouse()
394              try:              try:
395                  self.tool.Hide(self.drag_dc)                  self.tool.Hide(self.drag_dc)
396              finally:              finally:
397                  self.drag_dc = None                  self.drag_dc = None
398                  self.dragging = 0                  self.dragging = 0
399            self.MouseLeftUp(event)
400    
401      def OnMotion(self, event):      def OnMotion(self, event):
402          if self.dragging:          if self.dragging:
# Line 339  class MapCanvas(wxWindow, ViewPort): Line 423  class MapCanvas(wxWindow, ViewPort):
423          """Receiver for the SHAPES_SELECTED messages. Redraw the map."""          """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
424          # The selection object takes care that it only issues          # The selection object takes care that it only issues
425          # SHAPES_SELECTED messages when the set of selected shapes has          # SHAPES_SELECTED messages when the set of selected shapes has
426          # actually changed, so we can do a full redraw unconditionally.          # actually changed, so we can do a full redraw of the
427          # FIXME: We should perhaps try to limit the redraw to the are          # selection_bitmap unconditionally.
         # actually covered by the shapes before and after the selection  
         # change.  
428          ViewPort.shape_selected(self, layer, shape)          ViewPort.shape_selected(self, layer, shape)
429          self.full_redraw()          self.redraw_selection()
430    
431      def GetTextExtent(self, text):      def GetTextExtent(self, text):
432          dc = wxClientDC(self)          dc = wxClientDC(self)

Legend:
Removed from v.1552  
changed lines
  Added in v.2599

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26