/[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 2700 by dpinte, Mon Sep 18 14:27:02 2006 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # opyright (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, \  import wx
      wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\  
      EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \  
      wxPlatform, wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \  
      wxOVERWRITE_PROMPT, wxID_OK  
24    
25  # Export related stuff  # Export related stuff
26  if wxPlatform == '__WXMSW__':  if wx.Platform == '__WXMSW__':
27      from wxPython.wx import wxMetaFileDC      from wx import MetaFileDC
28    
29  from wxPython import wx  from Thuban import _
30    
31  from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \  from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \
32       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED
# Line 48  class CanvasPanTool(PanTool): Line 48  class CanvasPanTool(PanTool):
48              x, y = self.current              x, y = self.current
49              width, height = self.view.GetSizeTuple()              width, height = self.view.GetSizeTuple()
50    
51              bitmapdc = wx.wxMemoryDC()              bitmapdc = wx.MemoryDC()
52              bitmapdc.SelectObject(self.view.bitmap)              bitmapdc.SelectObject(self.view.PreviewBitmap())
53    
54              dc = self.view.drag_dc              dc = self.view.drag_dc
55              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
56    
57  class MapPrintout(wx.wxPrintout):  class MapPrintout(wx.Printout):
58    
59      """      """
60      wxPrintout class for printing Thuban maps      wxPrintout class for printing Thuban maps
61      """      """
62    
63      def __init__(self, canvas, map, region, selected_layer, selected_shapes):      def __init__(self, canvas, map, region, selected_layer, selected_shapes):
64          wx.wxPrintout.__init__(self)          wx.Printout.__init__(self)
65          self.canvas = canvas          self.canvas = canvas
66          self.map = map          self.map = map
67          self.region = region          self.region = region
# Line 85  class MapPrintout(wx.wxPrintout): Line 85  class MapPrintout(wx.wxPrintout):
85                                                      self.canvas.GetSizeTuple(),                                                      self.canvas.GetSizeTuple(),
86                                                      self.GetPageSizePixels())                                                      self.GetPageSizePixels())
87          resx, resy = self.GetPPIPrinter()          resx, resy = self.GetPPIPrinter()
         renderer = PrinterRenderer(dc, scale, offset, resolution = resy)  
         x, y, width, height = self.region  
88          canvas_scale = self.canvas.scale          canvas_scale = self.canvas.scale
89          renderer.RenderMap(self.map,          x, y, width, height = self.region
90                             (0,0,          renderer = PrinterRenderer(dc, self.map, scale, offset,
91                                  (width/canvas_scale)*scale,                                     region = (mapregion[0], mapregion[1],
92                                  (height/canvas_scale)*scale),                                               (width/canvas_scale)*scale,
93                                  mapregion,                                               (height/canvas_scale)*scale),
94                             self.selected_layer, self.selected_shapes)                                     resolution = resy,
95                                       destination_region = mapregion)
96            renderer.RenderMap(self.selected_layer, self.selected_shapes)
97          return True          return True
98    
99  class MapCanvas(wxWindow, ViewPort):  
100    class MapCanvas(wx.Window, ViewPort):
101    
102      """A widget that displays a map and offers some interaction"""      """A widget that displays a map and offers some interaction"""
103    
104      def __init__(self, parent, winid):      def __init__(self, parent, winid):
105          wxWindow.__init__(self, parent, winid)          wx.Window.__init__(self, parent, winid)
106          ViewPort.__init__(self)          ViewPort.__init__(self)
107    
108          self.SetBackgroundColour(wxColour(255, 255, 255))          self.SetBackgroundColour(wx.Colour(255, 255, 255))
109    
110          # the bitmap serving as backing store          # the bitmap serving as backing store
111          self.bitmap = None          self.bitmap = None
112            # the monochrome bitmap with the selection if any
113            self.selection_bitmap = None
114    
115          self.backgroundColor = wx.wxWHITE_BRUSH          self.backgroundColor = wx.WHITE_BRUSH
116    
117          # Set to true if there ever is an error during redraw. There          # The rendering iterator object. Used when rendering
118          # should never be errors, but unfortunately bugs happen.          # incrementally
119          self.error_on_redraw = 0          self.render_iter = None
120    
121          # subscribe the WX events we're interested in          # subscribe the WX events we're interested in
122          EVT_PAINT(self, self.OnPaint)          self.Bind(wx.EVT_PAINT, self.OnPaint)
123          EVT_LEFT_DOWN(self, self.OnLeftDown)          self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
124          EVT_LEFT_UP(self, self.OnLeftUp)          self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
125          EVT_MOTION(self, self.OnMotion)          self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
126          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)          self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
127          wx.EVT_SIZE(self, self.OnSize)          self.Bind(wx.EVT_MOTION, self.OnMotion)
128          wx.EVT_IDLE(self, self.OnIdle)          self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
129            self.Bind(wx.EVT_SIZE, self.OnSize)
130            self.Bind(wx.EVT_IDLE, self.OnIdle)
131    
132      def __del__(self):      def __del__(self):
133          wxWindow.__del__(self)          wx.Window.__del__(self)
134          ViewPort.__del__(self)          ViewPort.__del__(self)
135    
136        def PreviewBitmap(self):
137            return self.bitmap
138    
139      def PanTool(self):      def PanTool(self):
140          """Start the canvas pan tool"""          """Start the canvas pan tool"""
141          self.SelectTool(CanvasPanTool(self))          self.SelectTool(CanvasPanTool(self))
142            
143      def SetMap(self, map):      def SetMap(self, map):
144          redraw_channels = (MAP_LAYERS_CHANGED, LAYER_CHANGED,          redraw_channels = (MAP_LAYERS_CHANGED, LAYER_CHANGED,
145                             LAYER_VISIBILITY_CHANGED)                             LAYER_VISIBILITY_CHANGED)
# Line 151  class MapCanvas(wxWindow, ViewPort): Line 159  class MapCanvas(wxWindow, ViewPort):
159          self.full_redraw()          self.full_redraw()
160    
161      def OnPaint(self, event):      def OnPaint(self, event):
162          dc = wxPaintDC(self)          dc = wx.PaintDC(self)
   
163          if self.Map() is not None and self.Map().HasLayers():          if self.Map() is not None and self.Map().HasLayers():
164              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  
165                  dc.BeginDrawing()                  dc.BeginDrawing()
166                  dc.DrawBitmap(self.bitmap, 0, 0)                  dc.DrawBitmap(self.bitmap, 0, 0)
167                    if self.selection_bitmap is not None:
168                        dc.DrawBitmap(self.selection_bitmap, 0, 0, True)
169                  dc.EndDrawing()                  dc.EndDrawing()
170          else:          else:
171              # 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 182  class MapCanvas(wxWindow, ViewPort):
182    
183      def OnIdle(self, event):      def OnIdle(self, event):
184          """Idle handler. Redraw the bitmap if necessary"""          """Idle handler. Redraw the bitmap if necessary"""
185            if (self.Map() is not None
186                and (self.bitmap is None
187                     or self.render_iter is not None
188                     or (self.HasSelectedShapes()
189                         and self.selection_bitmap is None))):
190                event.RequestMore(self._do_redraw())
191    
192          if self.bitmap != -1:      def _do_redraw(self):
193              return          """Redraw a bit and return whether this method has to be called again.
         if self.error_on_redraw:  
             return  
194    
195          wxBeginBusyCursor()          Called by OnIdle to handle the actual redraw. Redraw is
196          try:          incremental for both the bitmap with the normal layers and the
197            bitmap with the selection.
198            """
199            finished = False
200            if self.render_iter is not None:
201              try:              try:
202                  self._do_redraw()                  if self.render_iter.next():
203                        # Redraw if the last preview redraw was some time
204                        # ago and the user is not currently dragging the
205                        # mouse because redrawing would interfere with what
206                        # the current tool is drawing on the window.
207                        if not self.dragging \
208                               and time.time() - self.render_last_preview > 0.5:
209                            client_dc = wx.ClientDC(self)
210                            client_dc.BeginDrawing()
211                            client_dc.DrawBitmap(self.bitmap, 0, 0)
212                            client_dc.EndDrawing()
213                            self.render_last_preview = time.time()
214                    else:
215                        self.render_iter = None
216                        # Redraw if not dragging because redrawing would
217                        # interfere with what the current tool is drawing on
218                        # the window.
219                        if not self.dragging:
220                            self.redraw()
221                        finished = True
222                except StopIteration:
223                    finished = True
224                    self.render_iter = None
225              except:              except:
226                  self.error_on_redraw = True                  finished = True
227                  raise                  self.render_iter = None
228          finally:                  traceback.print_exc()
229              wxEndBusyCursor()          else:
230                self.render_iter = self._render_iterator()
231                self.render_last_preview = time.time()
232            return not finished
233    
234      def _do_redraw(self):      def _render_iterator(self):
         """Called by OnIdle to do the actual redraw.  
         """  
235          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
236            dc = wx.MemoryDC()
237    
238          bitmap = wx.wxEmptyBitmap(width, height)          render_start = time.time()
         dc = wx.wxMemoryDC()  
         dc.SelectObject(bitmap)  
         dc.BeginDrawing()  
239    
240          dc.SetBackground(self.backgroundColor)          if self.bitmap is None:
241          dc.Clear()              self.bitmap = wx.EmptyBitmap(width, height)
242                dc.SelectObject(self.bitmap)
243                dc.BeginDrawing()
244    
245          selected_layer = self.selection.SelectedLayer()              dc.SetBackground(self.backgroundColor)
246          selected_shapes = self.selection.SelectedShapes()              dc.Clear()
247    
248          # draw the map into the bitmap              # draw the map into the bitmap
249          renderer = ScreenRenderer(dc, self.scale, self.offset)              renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
250                                          (0, 0, width, height))
251                for cont in renderer.RenderMapIncrementally():
252                    yield True
253    
254          # Pass the entire bitmap as update region to the renderer.              dc.EndDrawing()
255          # We're redrawing the whole bitmap, after all.              dc.SelectObject(wx.NullBitmap)
         renderer.RenderMap(self.Map(), (0, 0, width, height),  
                            selected_layer, selected_shapes)  
256    
257          dc.EndDrawing()          if self.HasSelectedShapes() and self.selection_bitmap is None:
258          dc.SelectObject(wx.wxNullBitmap)              bitmap = wx.EmptyBitmap(width, height)
259                dc.SelectObject(bitmap)
260                dc.BeginDrawing()
261                dc.SetBackground(wx.WHITE_BRUSH)
262                dc.Clear()
263    
264          self.bitmap = bitmap              renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
265          # This causes a paint event that then draws the bitmap                                        (0, 0, width, height))
266          self.redraw()              layer = self.SelectedLayer()
267                shapes = self.selection.SelectedShapes()
268                for cont in renderer.draw_selection_incrementally(layer, shapes):
269                    yield True
270    
271                dc.EndDrawing()
272                dc.SelectObject(wx.NullBitmap)
273    
274                bitmap.SetMask(wx.Mask(bitmap, wx.WHITE))
275                self.selection_bitmap = bitmap
276    
277            yield False
278    
279      def Export(self):      def Export(self):
280    
# Line 231  class MapCanvas(wxWindow, ViewPort): Line 282  class MapCanvas(wxWindow, ViewPort):
282              export_path = self.export_path              export_path = self.export_path
283          else:          else:
284              export_path="."              export_path="."
285          dlg = wxFileDialog(self, _("Export Map"), export_path, "",          dlg = wx.FileDialog(self, _("Export Map"), export_path, "",
286                             "Enhanced Metafile (*.wmf)|*.wmf",                             "Enhanced Metafile (*.wmf)|*.wmf",
287                             wxSAVE|wxOVERWRITE_PROMPT)                             wx.SAVE|wx.OVERWRITE_PROMPT)
288          if dlg.ShowModal() == wxID_OK:          if dlg.ShowModal() == wx.ID_OK:
289              self.export_path = os.path.dirname(dlg.GetPath())              self.export_path = os.path.dirname(dlg.GetPath())
290              dc = wxMetaFileDC(dlg.GetPath())              dc = wx.MetaFileDC(dlg.GetPath())
291        
292              scale, offset, mapregion = output_transform(self.scale,              scale, offset, mapregion = output_transform(self.scale,
293                                                          self.offset,                                                          self.offset,
294                                                          self.GetSizeTuple(),                                                          self.GetSizeTuple(),
# Line 246  class MapCanvas(wxWindow, ViewPort): Line 297  class MapCanvas(wxWindow, ViewPort):
297              selected_layer = self.selection.SelectedLayer()              selected_layer = self.selection.SelectedLayer()
298              selected_shapes = self.selection.SelectedShapes()              selected_shapes = self.selection.SelectedShapes()
299    
             renderer = ExportRenderer(dc, scale, offset)  
   
             # Pass the entire bitmap as update region to the renderer.  
             # We're redrawing the whole bitmap, after all.  
300              width, height = self.GetSizeTuple()              width, height = self.GetSizeTuple()
301              renderer.RenderMap(self.Map(),              renderer = ExportRenderer(dc, self.Map(), scale, offset,
302                                  (0,0,                                        region = (0, 0,
303                                      (width/self.scale)*scale,                                                  (width/self.scale)*scale,
304                                      (height/self.scale)*scale),                                                  (height/self.scale)*scale),
305                                  mapregion,                                        destination_region = mapregion)
306                                  selected_layer, selected_shapes)              renderer.RenderMap(selected_layer, selected_shapes)
307    
308              dc.EndDrawing()              dc.EndDrawing()
309              dc.Close()              dc.Close()
310          dlg.Destroy()          dlg.Destroy()
311            
312      def Print(self):      def Print(self):
313          printer = wx.wxPrinter()          printer = wx.Printer()
314          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
315          selected_layer = self.selection.SelectedLayer()          selected_layer = self.selection.SelectedLayer()
316          selected_shapes = self.selection.SelectedShapes()          selected_shapes = self.selection.SelectedShapes()
317            
318          printout = MapPrintout(self, self.Map(), (0, 0, width, height),          printout = MapPrintout(self, self.Map(), (0, 0, width, height),
319                                 selected_layer, selected_shapes)                                 selected_layer, selected_shapes)
320          printer.Print(self, printout, True)          printer.Print(self, printout, True)
321          printout.Destroy()          printout.Destroy()
# Line 277  class MapCanvas(wxWindow, ViewPort): Line 325  class MapCanvas(wxWindow, ViewPort):
325    
326      def full_redraw(self, *args):      def full_redraw(self, *args):
327          self.bitmap = None          self.bitmap = None
328            self.selection_bitmap = None
329            self.render_iter = None
330            self.redraw()
331    
332        def redraw_selection(self, *args):
333            self.selection_bitmap = None
334            self.render_iter = None
335          self.redraw()          self.redraw()
336    
337      def map_projection_changed(self, map, old_proj):      def map_projection_changed(self, map, old_proj):
# Line 294  class MapCanvas(wxWindow, ViewPort): Line 349  class MapCanvas(wxWindow, ViewPort):
349      def GetPortSizeTuple(self):      def GetPortSizeTuple(self):
350          return self.GetSizeTuple()          return self.GetSizeTuple()
351    
352        def OnMiddleDown(self, event):
353            self.remembertool = self.tool
354            if self.Map() is not None and self.Map().HasLayers():
355                self.PanTool()
356                self.OnLeftDown(event)
357    
358        def OnMiddleUp(self, event):
359            self.OnLeftUp(event)
360            if self.remembertool:
361                self.SelectTool(self.remembertool)
362    
363      def OnLeftDown(self, event):      def OnLeftDown(self, event):
364          self.MouseLeftDown(event)          self.MouseLeftDown(event)
365          if self.tool is not None:          if self.tool is not None:
366              self.drag_dc = wxClientDC(self)              self.drag_dc = wx.ClientDC(self)
367              self.drag_dc.SetLogicalFunction(wxINVERT)              self.drag_dc.SetLogicalFunction(wx.INVERT)
368              self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH)              self.drag_dc.SetBrush(wx.TRANSPARENT_BRUSH)
369              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
370              self.CaptureMouse()              self.CaptureMouse()
371              self.dragging = 1              self.dragging = 1
372    
373      def OnLeftUp(self, event):      def OnLeftUp(self, event):
374          self.MouseLeftUp(event)          """Handle EVT_LEFT_UP
375    
376            Release the mouse if it was captured, if a tool is active call
377            its Hide method and call self.MouseLeftUp.
378            """
379            # It's important that ReleaseMouse is called before MouseLeftUp.
380            # MouseLeftUp may pop up modal dialogs which leads to an
381            # effectively frozen X session because the user can only
382            # interact with the dialog but the mouse is still grabbed by the
383            # canvas.
384          if self.dragging:          if self.dragging:
385              self.ReleaseMouse()              if self.HasCapture():
386                    self.ReleaseMouse()
387              try:              try:
388                  self.tool.Hide(self.drag_dc)                  self.tool.Hide(self.drag_dc)
389              finally:              finally:
390                  self.drag_dc = None                  self.drag_dc = None
391                  self.dragging = 0                  self.dragging = 0
392            self.MouseLeftUp(event)
393    
394      def OnMotion(self, event):      def OnMotion(self, event):
395          if self.dragging:          if self.dragging:
# Line 339  class MapCanvas(wxWindow, ViewPort): Line 416  class MapCanvas(wxWindow, ViewPort):
416          """Receiver for the SHAPES_SELECTED messages. Redraw the map."""          """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
417          # The selection object takes care that it only issues          # The selection object takes care that it only issues
418          # SHAPES_SELECTED messages when the set of selected shapes has          # SHAPES_SELECTED messages when the set of selected shapes has
419          # actually changed, so we can do a full redraw unconditionally.          # actually changed, so we can do a full redraw of the
420          # 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.  
421          ViewPort.shape_selected(self, layer, shape)          ViewPort.shape_selected(self, layer, shape)
422          self.full_redraw()          self.redraw_selection()
423    
424      def GetTextExtent(self, text):      def GetTextExtent(self, text):
425          dc = wxClientDC(self)          dc = wx.ClientDC(self)
426          font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)          font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
427          dc.SetFont(font)          dc.SetFont(font)
428          return dc.GetTextExtent(text)          return dc.GetTextExtent(text)
429    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26