/[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 176 by bh, Wed May 15 13:38:49 2002 UTC revision 303 by bh, Mon Sep 2 16:47:53 2002 UTC
# 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 140  class ZoomInTool(RectTool): Line 144  class ZoomInTool(RectTool):
144  class ZoomOutTool(RectTool):  class ZoomOutTool(RectTool):
145    
146      """The Zoom-Out Tool"""      """The Zoom-Out Tool"""
147        
148      def Name(self):      def Name(self):
149          return "ZoomOutTool"          return "ZoomOutTool"
150    
# 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                  self.view.ZoomFactor(0.5, center = (cy, cy))                  # 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))
163              else:              else:
164                  # A drag. Zoom out to the rectangle                  # A drag. Zoom out to the rectangle
165                  self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),                  self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
# Line 184  class PanTool(Tool): Line 192  class PanTool(Tool):
192              sx, sy = self.start              sx, sy = self.start
193              cx, cy = self.current              cx, cy = self.current
194              self.view.Translate(cx - sx, cy - sy)              self.view.Translate(cx - sx, cy - sy)
195            
196  class IdentifyTool(Tool):  class IdentifyTool(Tool):
197    
198      """The "Identify" Tool"""      """The "Identify" Tool"""
199        
200      def Name(self):      def Name(self):
201          return "IdentifyTool"          return "IdentifyTool"
202    
# Line 242  class MapPrintout(wx.wxPrintout): Line 250  class MapPrintout(wx.wxPrintout):
250          renderer = PrinterRender(dc, scale, (offx, offy), resolution = resx)          renderer = PrinterRender(dc, scale, (offx, offy), resolution = resx)
251          renderer.RenderMap(self.map)          renderer.RenderMap(self.map)
252          return wx.true          return wx.true
253            
254    
255  class MapCanvas(wxWindow, Publisher):  class MapCanvas(wxWindow, Publisher):
256    
# 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.
313                
314              # XXX it's probably possible to get rid of this. The              # XXX it's probably possible to get rid of this. The
315              # background color of the window is already white and the              # background color of the window is already white and the
316              # only thing we may have to do is to call self.Refresh()              # only thing we may have to do is to call self.Refresh()
317              # with a true argument in the right places.              # with a true argument in the right places.
318              dc.BeginDrawing()              dc.BeginDrawing()
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 383  class MapCanvas(wxWindow, Publisher): Line 371  class MapCanvas(wxWindow, Publisher):
371          printout = MapPrintout(self.map)          printout = MapPrintout(self.map)
372          printer.Print(self, printout, wx.true)          printer.Print(self, printout, wx.true)
373          printout.Destroy()          printout.Destroy()
374            
375      def SetMap(self, map):      def SetMap(self, map):
376          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,
377                             LAYER_VISIBILITY_CHANGED)                             LAYER_VISIBILITY_CHANGED)
# 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 ZoomInTool(self):      def ZoomInTool(self):
501            """Start the zoom in tool"""
502          self.tool = ZoomInTool(self)          self.tool = ZoomInTool(self)
503    
504      def ZoomOutTool(self):      def ZoomOutTool(self):
505            """Start the zoom out tool"""
506          self.tool = ZoomOutTool(self)          self.tool = ZoomOutTool(self)
507    
508      def PanTool(self):      def PanTool(self):
509            """Start the pan tool"""
510          self.tool = PanTool(self)          self.tool = PanTool(self)
511    
512      def IdentifyTool(self):      def IdentifyTool(self):
513            """Start the identify tool"""
514          self.tool = IdentifyTool(self)          self.tool = IdentifyTool(self)
515    
516      def LabelTool(self):      def LabelTool(self):
517            """Start the label tool"""
518          self.tool = LabelTool(self)          self.tool = LabelTool(self)
519    
520      def CurrentTool(self):      def CurrentTool(self):
521            """Return the name of the current tool or None if no tool is active"""
522          return self.tool and self.tool.Name() or None          return self.tool and self.tool.Name() or None
523    
524      def CurrentPosition(self):      def CurrentPosition(self):
# Line 552  class MapCanvas(wxWindow, Publisher): Line 556  class MapCanvas(wxWindow, Publisher):
556              self.tool.MouseDown(event)              self.tool.MouseDown(event)
557              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
558              self.dragging = 1              self.dragging = 1
559            
560      def OnLeftUp(self, event):      def OnLeftUp(self, event):
         self.ReleaseMouse()  
561          self.set_current_position(event)          self.set_current_position(event)
562          if self.dragging:          if self.dragging:
563                self.ReleaseMouse()
564              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
565              self.tool.MouseUp(event)              self.tool.MouseUp(event)
566              self.drag_dc = None              self.drag_dc = None
# Line 572  class MapCanvas(wxWindow, Publisher): Line 576  class MapCanvas(wxWindow, Publisher):
576      def OnLeaveWindow(self, event):      def OnLeaveWindow(self, event):
577          self.set_current_position(None)          self.set_current_position(None)
578    
     def OnIdle(self, event):  
         if self.redraw_on_idle:  
             self.do_redraw()  
         self.redraw_on_idle = 0  
   
579      def OnSize(self, event):      def OnSize(self, event):
580          # 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
581          # 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 606  class MapCanvas(wxWindow, Publisher):
606          self.last_selected_layer = layer          self.last_selected_layer = layer
607          self.last_selected_shape = shape          self.last_selected_shape = shape
608    
609      def unprojected_rect_around_point(self, x, y):      def unprojected_rect_around_point(self, x, y, dist):
610          """return a rect a few pixels around (x, y) in unprojected corrdinates          """return a rect dist pixels around (x, y) in unprojected corrdinates
611    
612          The return value is a tuple (minx, miny, maxx, maxy) suitable a          The return value is a tuple (minx, miny, maxx, maxy) suitable a
613          parameter to a layer's ShapesInRegion method.          parameter to a layer's ShapesInRegion method.
# Line 622  class MapCanvas(wxWindow, Publisher): Line 621  class MapCanvas(wxWindow, Publisher):
621          xs = []          xs = []
622          ys = []          ys = []
623          for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):          for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
624              px, py = self.win_to_proj(x + dx, y + dy)              px, py = self.win_to_proj(x + dist * dx, y + dist * dy)
625              if inverse:              if inverse:
626                  px, py = inverse(px, py)                  px, py = inverse(px, py)
627              xs.append(px)              xs.append(px)
628              ys.append(py)              ys.append(py)
629          return (min(xs), min(ys), max(xs), max(ys))          return (min(xs), min(ys), max(xs), max(ys))
630    
631      def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):      def find_shape_at(self, px, py, select_labels = 0, searched_layer = None):
632          """Determine the shape at point px, py in window coords          """Determine the shape at point px, py in window coords
633    
634          Return the shape and the corresponding layer as a tuple (layer,          Return the shape and the corresponding layer as a tuple (layer,
# Line 639  class MapCanvas(wxWindow, Publisher): Line 638  class MapCanvas(wxWindow, Publisher):
638          search through the labels. If a label is found return it's index          search through the labels. If a label is found return it's index
639          as the shape and None as the layer.          as the shape and None as the layer.
640    
641          If the optional parameter selected_layer is true (default), only          If the optional parameter searched_layer is given (or not None
642          search in the currently selected layer.          which it defaults to), only search in that layer.
643          """          """
644          map_proj = self.map.projection          map_proj = self.map.projection
645          if map_proj is not None:          if map_proj is not None:
# Line 651  class MapCanvas(wxWindow, Publisher): Line 650  class MapCanvas(wxWindow, Publisher):
650          scale = self.scale          scale = self.scale
651          offx, offy = self.offset          offx, offy = self.offset
652    
         box = self.unprojected_rect_around_point(px, py)  
   
653          if select_labels:          if select_labels:
654              labels = self.map.LabelLayer().Labels()              labels = self.map.LabelLayer().Labels()
655                
656              if labels:              if labels:
657                  dc = wxClientDC(self)                  dc = wxClientDC(self)
658                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
# Line 687  class MapCanvas(wxWindow, Publisher): Line 684  class MapCanvas(wxWindow, Publisher):
684                      if x <= px < x + width and y <= py <= y + height:                      if x <= px < x + width and y <= py <= y + height:
685                          return None, i                          return None, i
686    
687          if selected_layer:          if searched_layer:
688              layer = self.interactor.SelectedLayer()              layers = [searched_layer]
             if layer is not None:  
                 layers = [layer]  
             else:  
                 # no layer selected. Use an empty list to effectively  
                 # ignore all layers.  
                 layers = []  
689          else:          else:
690              layers = self.map.Layers()              layers = self.map.Layers()
691    
# Line 707  class MapCanvas(wxWindow, Publisher): Line 698  class MapCanvas(wxWindow, Publisher):
698    
699              filled = layer.fill is not None              filled = layer.fill is not None
700              stroked = layer.stroke is not None              stroked = layer.stroke is not None
701                    
702              layer_proj = layer.projection              layer_proj = layer.projection
703              if layer_proj is not None:              if layer_proj is not None:
704                  inverse = layer_proj.Inverse                  inverse = layer_proj.Inverse
705              else:              else:
706                  inverse = None                  inverse = None
707                    
708              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
709    
710              select_shape = -1              select_shape = -1
711    
712                # Determine the ids of the shapes that overlap a tiny area
713                # around the point. For layers containing points we have to
714                # choose a larger size of the box we're testing agains so
715                # that we take the size of the markers into account
716                # FIXME: Once the markers are more flexible this part has to
717                # become more flexible too, of course
718                if shapetype == SHAPETYPE_POINT:
719                    box = self.unprojected_rect_around_point(px, py, 5)
720                else:
721                    box = self.unprojected_rect_around_point(px, py, 1)
722              shape_ids = layer.ShapesInRegion(box)              shape_ids = layer.ShapesInRegion(box)
723              shape_ids.reverse()              shape_ids.reverse()
724    
# Line 760  class MapCanvas(wxWindow, Publisher): Line 761  class MapCanvas(wxWindow, Publisher):
761                  return layer, select_shape                  return layer, select_shape
762          return None, None          return None, None
763    
764      def SelectShapeAt(self, x, y):      def SelectShapeAt(self, x, y, layer = None):
765          layer, shape = self.find_shape_at(x, y, selected_layer = 0)          """\
766            Select and return the shape and its layer at window position (x, y)
767    
768            If layer is given, only search in that layer. If no layer is
769            given, search through all layers.
770    
771            Return a tuple (layer, shapeid). If no shape is found, return
772            (None, None).
773            """
774            layer, shape = result = self.find_shape_at(x, y, searched_layer=layer)
775          # If layer is None, then shape will also be None. We don't want          # If layer is None, then shape will also be None. We don't want
776          # to deselect the currently selected layer, so we simply select          # to deselect the currently selected layer, so we simply select
777          # the already selected layer again.          # the already selected layer again.
778          if layer is None:          if layer is None:
779              layer = self.interactor.SelectedLayer()              layer = self.interactor.SelectedLayer()
780          self.interactor.SelectLayerAndShape(layer, shape)          self.interactor.SelectLayerAndShape(layer, shape)
781            return result
782    
783      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):
784            """Add or remove a label at window position x, y.
785    
786            If there's a label at the given position, remove it. Otherwise
787            determine the shape at the position, run the label dialog and
788            unless the user cancels the dialog, add a laber.
789            """
790          ox = x; oy = y          ox = x; oy = y
791          label_layer = self.map.LabelLayer()          label_layer = self.map.LabelLayer()
792          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.176  
changed lines
  Added in v.303

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26