/[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 246 by bh, Mon Jul 29 13:38:04 2002 UTC revision 404 by bh, Fri Feb 14 17:40:26 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 129  class ZoomInTool(RectTool): Line 129  class ZoomInTool(RectTool):
129              Tool.MouseUp(self, event)              Tool.MouseUp(self, event)
130              sx, sy = self.start              sx, sy = self.start
131              cx, cy = self.current              cx, cy = self.current
132              if sx == cx and sy == cy:              if sx == cx or sy == cy:
133                  # Just a mouse click. Simply zoom in by a factor of two                  # Just a mouse click or a degenerate rectangle. Simply
134                    # zoom in by a factor of two
135                    # FIXME: For a click this is the desired behavior but should we
136                    # really do this for degenrate rectagles as well or
137                    # should we ignore them?
138                  self.view.ZoomFactor(2, center = (cx, cy))                  self.view.ZoomFactor(2, center = (cx, cy))
139              else:              else:
140                  # A drag. Zoom in to the rectangle                  # A drag. Zoom in to the rectangle
# Line 149  class ZoomOutTool(RectTool): Line 153  class ZoomOutTool(RectTool):
153              Tool.MouseUp(self, event)              Tool.MouseUp(self, event)
154              sx, sy = self.start              sx, sy = self.start
155              cx, cy = self.current              cx, cy = self.current
156              if sx == cx and sy == cy:              if sx == cx or sy == cy:
157                  # Just a mouse click. Simply zoom out by a factor of two                  # Just a mouse click or a degenerate rectangle. Simply
158                    # zoom out by a factor of two.
159                    # FIXME: For a click this is the desired behavior but should we
160                    # really do this for degenrate rectagles as well or
161                    # should we ignore them?
162                  self.view.ZoomFactor(0.5, center = (cx, cy))                  self.view.ZoomFactor(0.5, center = (cx, cy))
163              else:              else:
164                  # A drag. Zoom out to the rectangle                  # A drag. Zoom out to the rectangle
# Line 271  class MapCanvas(wxWindow, Publisher): Line 279  class MapCanvas(wxWindow, Publisher):
279          # if the mouse is outside the window.          # if the mouse is outside the window.
280          self.current_position = None          self.current_position = None
281    
         # If true, OnIdle will call do_redraw to do the actual  
         # redrawing. Set by OnPaint to avoid some unnecessary redraws.  
         # To force a redraw call full_redraw().  
         self.redraw_on_idle = 0  
   
         # The region to update when idle  
         self.update_region = wx.wxRegion()  
   
282          # the bitmap serving as backing store          # the bitmap serving as backing store
283          self.bitmap = None          self.bitmap = None
284    
# Line 298  class MapCanvas(wxWindow, Publisher): Line 298  class MapCanvas(wxWindow, Publisher):
298          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
299          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
300          wx.EVT_SIZE(self, self.OnSize)          wx.EVT_SIZE(self, self.OnSize)
         wx.EVT_IDLE(self, self.OnIdle)  
301    
302      def __del__(self):      def __del__(self):
303          wxWindow.__del__(self)          wxWindow.__del__(self)
# Line 307  class MapCanvas(wxWindow, Publisher): Line 306  class MapCanvas(wxWindow, Publisher):
306      def OnPaint(self, event):      def OnPaint(self, event):
307          dc = wxPaintDC(self)          dc = wxPaintDC(self)
308          if self.map is not None and self.map.HasLayers():          if self.map is not None and self.map.HasLayers():
309              # We have a non-empty map. Redraw it in idle time              self.do_redraw()
             self.redraw_on_idle = 1  
             # update the region that has to be redrawn  
             self.update_region.UnionRegion(self.GetUpdateRegion())  
310          else:          else:
311              # 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
312              # the screen.              # the screen.
# Line 323  class MapCanvas(wxWindow, Publisher): Line 319  class MapCanvas(wxWindow, Publisher):
319              dc.Clear()              dc.Clear()
320              dc.EndDrawing()              dc.EndDrawing()
321    
             # clear the region  
             self.update_region = wx.wxRegion()  
   
322      def do_redraw(self):      def do_redraw(self):
323          # This should only be called if we have a non-empty map.          # This should only be called if we have a non-empty map.
324    
         # get the update region and reset it. We're not actually using  
         # it anymore, though.  
         update_box = self.update_region.GetBox()  
         self.update_region = wx.wxRegion()  
   
325          # Get the window size.          # Get the window size.
326          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
327    
# Line 361  class MapCanvas(wxWindow, Publisher): Line 349  class MapCanvas(wxWindow, Publisher):
349              # draw the map into the bitmap              # draw the map into the bitmap
350              renderer = ScreenRenderer(dc, self.scale, self.offset)              renderer = ScreenRenderer(dc, self.scale, self.offset)
351    
352              # Pass the entire bitmap as update_region to the renderer.              # Pass the entire bitmap as update region to the renderer.
353              # We're redrawing the whole bitmap, after all.              # We're redrawing the whole bitmap, after all.
354              renderer.RenderMap(self.map, (0, 0, width, height),              renderer.RenderMap(self.map, (0, 0, width, height),
355                                 selected_layer, selected_shape)                                 selected_layer, selected_shape)
# Line 404  class MapCanvas(wxWindow, Publisher): Line 392  class MapCanvas(wxWindow, Publisher):
392          self.full_redraw()          self.full_redraw()
393    
394      def Map(self):      def Map(self):
395            """Return the map displayed by this canvas"""
396          return self.map          return self.map
397    
398      def redraw(self, *args):      def redraw(self, *args):
# Line 437  class MapCanvas(wxWindow, Publisher): Line 426  class MapCanvas(wxWindow, Publisher):
426          return ((x - offx) / self.scale, (offy - y) / self.scale)          return ((x - offx) / self.scale, (offy - y) / self.scale)
427    
428      def FitRectToWindow(self, rect):      def FitRectToWindow(self, rect):
429            """Fit the rectangular region given by rect into the window.
430            
431            Set scale so that rect (in projected coordinates) just fits into
432            the window and center it.
433            """
434          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
435          llx, lly, urx, ury = rect          llx, lly, urx, ury = rect
436          if llx == urx or lly == ury:          if llx == urx or lly == ury:
# Line 450  class MapCanvas(wxWindow, Publisher): Line 444  class MapCanvas(wxWindow, Publisher):
444          self.set_view_transform(scale, (offx, offy))          self.set_view_transform(scale, (offx, offy))
445    
446      def FitMapToWindow(self):      def FitMapToWindow(self):
447          """\          """Fit the map to the window
448          Set the scale and offset so that the map is centered in the          
449          window          Set the scale so that the map fits exactly into the window and
450            center it in the window.
451          """          """
452          bbox = self.map.ProjectedBoundingBox()          bbox = self.map.ProjectedBoundingBox()
453          if bbox is not None:          if bbox is not None:
# Line 478  class MapCanvas(wxWindow, Publisher): Line 473  class MapCanvas(wxWindow, Publisher):
473          self.set_view_transform(scale, offset)          self.set_view_transform(scale, offset)
474    
475      def ZoomOutToRect(self, rect):      def ZoomOutToRect(self, rect):
476          # rect is given in window coordinates          """Zoom out to fit the currently visible region into rect.
477    
478            The rect parameter is given in window coordinates
479            """
480          # determine the bbox of the displayed region in projected          # determine the bbox of the displayed region in projected
481          # coordinates          # coordinates
482          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
# Line 496  class MapCanvas(wxWindow, Publisher): Line 493  class MapCanvas(wxWindow, Publisher):
493          self.set_view_transform(scale, (offx, offy))          self.set_view_transform(scale, (offx, offy))
494    
495      def Translate(self, dx, dy):      def Translate(self, dx, dy):
496            """Move the map by dx, dy pixels"""
497          offx, offy = self.offset          offx, offy = self.offset
498          self.set_view_transform(self.scale, (offx + dx, offy + dy))          self.set_view_transform(self.scale, (offx + dx, offy + dy))
499    
500        def SelectTool(self, tool):
501            """Make tool the active tool.
502    
503            The parameter should be an instance of Tool or None to indicate
504            that no tool is active.
505            """
506            self.tool = tool
507    
508      def ZoomInTool(self):      def ZoomInTool(self):
509          self.tool = ZoomInTool(self)          """Start the zoom in tool"""
510            self.SelectTool(ZoomInTool(self))
511    
512      def ZoomOutTool(self):      def ZoomOutTool(self):
513          self.tool = ZoomOutTool(self)          """Start the zoom out tool"""
514            self.SelectTool(ZoomOutTool(self))
515    
516      def PanTool(self):      def PanTool(self):
517          self.tool = PanTool(self)          """Start the pan tool"""
518            self.SelectTool(PanTool(self))
519    
520      def IdentifyTool(self):      def IdentifyTool(self):
521          self.tool = IdentifyTool(self)          """Start the identify tool"""
522            self.SelectTool(IdentifyTool(self))
523    
524      def LabelTool(self):      def LabelTool(self):
525          self.tool = LabelTool(self)          """Start the label tool"""
526            self.SelectTool(LabelTool(self))
527    
528      def CurrentTool(self):      def CurrentTool(self):
529            """Return the name of the current tool or None if no tool is active"""
530          return self.tool and self.tool.Name() or None          return self.tool and self.tool.Name() or None
531    
532      def CurrentPosition(self):      def CurrentPosition(self):
# Line 554  class MapCanvas(wxWindow, Publisher): Line 566  class MapCanvas(wxWindow, Publisher):
566              self.dragging = 1              self.dragging = 1
567    
568      def OnLeftUp(self, event):      def OnLeftUp(self, event):
         self.ReleaseMouse()  
569          self.set_current_position(event)          self.set_current_position(event)
570          if self.dragging:          if self.dragging:
571              self.tool.Hide(self.drag_dc)              self.ReleaseMouse()
572              self.tool.MouseUp(event)              try:
573              self.drag_dc = None                  self.tool.Hide(self.drag_dc)
574          self.dragging = 0                  self.tool.MouseUp(event)
575                finally:
576                    self.drag_dc = None
577                    self.dragging = 0
578    
579      def OnMotion(self, event):      def OnMotion(self, event):
580          self.set_current_position(event)          self.set_current_position(event)
# Line 572  class MapCanvas(wxWindow, Publisher): Line 586  class MapCanvas(wxWindow, Publisher):
586      def OnLeaveWindow(self, event):      def OnLeaveWindow(self, event):
587          self.set_current_position(None)          self.set_current_position(None)
588    
     def OnIdle(self, event):  
         if self.redraw_on_idle:  
             self.do_redraw()  
         self.redraw_on_idle = 0  
   
589      def OnSize(self, event):      def OnSize(self, event):
590          # the window's size has changed. We have to get a new bitmap. If          # the window's size has changed. We have to get a new bitmap. If
591          # we want to be clever we could try to get by without throwing          # we want to be clever we could try to get by without throwing
# Line 607  class MapCanvas(wxWindow, Publisher): Line 616  class MapCanvas(wxWindow, Publisher):
616          self.last_selected_layer = layer          self.last_selected_layer = layer
617          self.last_selected_shape = shape          self.last_selected_shape = shape
618    
619      def unprojected_rect_around_point(self, x, y):      def unprojected_rect_around_point(self, x, y, dist):
620          """return a rect a few pixels around (x, y) in unprojected corrdinates          """return a rect dist pixels around (x, y) in unprojected corrdinates
621    
622          The return value is a tuple (minx, miny, maxx, maxy) suitable a          The return value is a tuple (minx, miny, maxx, maxy) suitable a
623          parameter to a layer's ShapesInRegion method.          parameter to a layer's ShapesInRegion method.
# Line 622  class MapCanvas(wxWindow, Publisher): Line 631  class MapCanvas(wxWindow, Publisher):
631          xs = []          xs = []
632          ys = []          ys = []
633          for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):          for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
634              px, py = self.win_to_proj(x + dx, y + dy)              px, py = self.win_to_proj(x + dist * dx, y + dist * dy)
635              if inverse:              if inverse:
636                  px, py = inverse(px, py)                  px, py = inverse(px, py)
637              xs.append(px)              xs.append(px)
# Line 651  class MapCanvas(wxWindow, Publisher): Line 660  class MapCanvas(wxWindow, Publisher):
660          scale = self.scale          scale = self.scale
661          offx, offy = self.offset          offx, offy = self.offset
662    
         box = self.unprojected_rect_around_point(px, py)  
   
663          if select_labels:          if select_labels:
664              labels = self.map.LabelLayer().Labels()              labels = self.map.LabelLayer().Labels()
665    
# Line 712  class MapCanvas(wxWindow, Publisher): Line 719  class MapCanvas(wxWindow, Publisher):
719    
720              select_shape = -1              select_shape = -1
721    
722                # Determine the ids of the shapes that overlap a tiny area
723                # around the point. For layers containing points we have to
724                # choose a larger size of the box we're testing agains so
725                # that we take the size of the markers into account
726                # FIXME: Once the markers are more flexible this part has to
727                # become more flexible too, of course
728                if shapetype == SHAPETYPE_POINT:
729                    box = self.unprojected_rect_around_point(px, py, 5)
730                else:
731                    box = self.unprojected_rect_around_point(px, py, 1)
732              shape_ids = layer.ShapesInRegion(box)              shape_ids = layer.ShapesInRegion(box)
733              shape_ids.reverse()              shape_ids.reverse()
734    
# Line 774  class MapCanvas(wxWindow, Publisher): Line 791  class MapCanvas(wxWindow, Publisher):
791          return result          return result
792    
793      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):
794            """Add or remove a label at window position x, y.
795    
796            If there's a label at the given position, remove it. Otherwise
797            determine the shape at the position, run the label dialog and
798            unless the user cancels the dialog, add a laber.
799            """
800          ox = x; oy = y          ox = x; oy = y
801          label_layer = self.map.LabelLayer()          label_layer = self.map.LabelLayer()
802          layer, shape_index = self.find_shape_at(x, y, select_labels = 1)          layer, shape_index = self.find_shape_at(x, y, select_labels = 1)

Legend:
Removed from v.246  
changed lines
  Added in v.404

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26