/[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 125 by bh, Thu May 2 18:55:33 2002 UTC revision 246 by bh, Mon Jul 29 13:38:04 2002 UTC
# Line 140  class ZoomInTool(RectTool): Line 140  class ZoomInTool(RectTool):
140  class ZoomOutTool(RectTool):  class ZoomOutTool(RectTool):
141    
142      """The Zoom-Out Tool"""      """The Zoom-Out Tool"""
143        
144      def Name(self):      def Name(self):
145          return "ZoomOutTool"          return "ZoomOutTool"
146    
# Line 151  class ZoomOutTool(RectTool): Line 151  class ZoomOutTool(RectTool):
151              cx, cy = self.current              cx, cy = self.current
152              if sx == cx and sy == cy:              if sx == cx and sy == cy:
153                  # Just a mouse click. Simply zoom out by a factor of two                  # Just a mouse click. Simply zoom out by a factor of two
154                  self.view.ZoomFactor(0.5, center = (cy, cy))                  self.view.ZoomFactor(0.5, center = (cx, cy))
155              else:              else:
156                  # A drag. Zoom out to the rectangle                  # A drag. Zoom out to the rectangle
157                  self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),                  self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
# Line 167  class PanTool(Tool): Line 167  class PanTool(Tool):
167    
168      def MouseMove(self, event):      def MouseMove(self, event):
169          if self.dragging:          if self.dragging:
             x0, y0 = self.current  
170              Tool.MouseMove(self, event)              Tool.MouseMove(self, event)
171                sx, sy = self.start
172              x, y = self.current              x, y = self.current
173              width, height = self.view.GetSizeTuple()              width, height = self.view.GetSizeTuple()
174    
175                bitmapdc = wx.wxMemoryDC()
176                bitmapdc.SelectObject(self.view.bitmap)
177    
178              dc = self.view.drag_dc              dc = self.view.drag_dc
179              dc.Blit(0, 0, width, height, dc, x0 - x, y0 - y)              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
180    
181      def MouseUp(self, event):      def MouseUp(self, event):
182          if self.dragging:          if self.dragging:
# Line 180  class PanTool(Tool): Line 184  class PanTool(Tool):
184              sx, sy = self.start              sx, sy = self.start
185              cx, cy = self.current              cx, cy = self.current
186              self.view.Translate(cx - sx, cy - sy)              self.view.Translate(cx - sx, cy - sy)
187            
188  class IdentifyTool(Tool):  class IdentifyTool(Tool):
189    
190      """The "Identify" Tool"""      """The "Identify" Tool"""
191        
192      def Name(self):      def Name(self):
193          return "IdentifyTool"          return "IdentifyTool"
194    
# Line 238  class MapPrintout(wx.wxPrintout): Line 242  class MapPrintout(wx.wxPrintout):
242          renderer = PrinterRender(dc, scale, (offx, offy), resolution = resx)          renderer = PrinterRender(dc, scale, (offx, offy), resolution = resx)
243          renderer.RenderMap(self.map)          renderer.RenderMap(self.map)
244          return wx.true          return wx.true
245            
246    
247  class MapCanvas(wxWindow, Publisher):  class MapCanvas(wxWindow, Publisher):
248    
# Line 267  class MapCanvas(wxWindow, Publisher): Line 271  class MapCanvas(wxWindow, Publisher):
271          # if the mouse is outside the window.          # if the mouse is outside the window.
272          self.current_position = None          self.current_position = None
273    
   
274          # If true, OnIdle will call do_redraw to do the actual          # If true, OnIdle will call do_redraw to do the actual
275          # redrawing. Set by OnPaint to avoid some unnecessary redraws.          # redrawing. Set by OnPaint to avoid some unnecessary redraws.
276          # To force a redraw call full_redraw().          # To force a redraw call full_redraw().
277          self.redraw_on_idle = 0          self.redraw_on_idle = 0
278    
279            # The region to update when idle
280            self.update_region = wx.wxRegion()
281    
282          # the bitmap serving as backing store          # the bitmap serving as backing store
283          self.bitmap = None          self.bitmap = None
284    
# Line 280  class MapCanvas(wxWindow, Publisher): Line 286  class MapCanvas(wxWindow, Publisher):
286          self.interactor = interactor          self.interactor = interactor
287          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)
288    
289            # keep track of which layers/shapes are selected to make sure we
290            # only redraw when necessary
291            self.last_selected_layer = None
292            self.last_selected_shape = None
293    
294          # subscribe the WX events we're interested in          # subscribe the WX events we're interested in
295          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
296          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
# Line 298  class MapCanvas(wxWindow, Publisher): Line 309  class MapCanvas(wxWindow, Publisher):
309          if self.map is not None and self.map.HasLayers():          if self.map is not None and self.map.HasLayers():
310              # We have a non-empty map. Redraw it in idle time              # We have a non-empty map. Redraw it in idle time
311              self.redraw_on_idle = 1              self.redraw_on_idle = 1
312                # update the region that has to be redrawn
313                self.update_region.UnionRegion(self.GetUpdateRegion())
314          else:          else:
315              # 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
316              # the screen.              # the screen.
317                
318              # XXX it's probably possible to get rid of this. The              # XXX it's probably possible to get rid of this. The
319              # background color of the window is already white and the              # background color of the window is already white and the
320              # only thing we may have to do is to call self.Refresh()              # only thing we may have to do is to call self.Refresh()
321              # with a true argument in the right places.              # with a true argument in the right places.
322              dc.BeginDrawing()              dc.BeginDrawing()
323              dc.Clear()                          dc.Clear()
324              dc.EndDrawing()              dc.EndDrawing()
325    
326                # clear the region
327                self.update_region = wx.wxRegion()
328    
329      def do_redraw(self):      def do_redraw(self):
330          # This should only be called if we have a non-empty map. We draw          # This should only be called if we have a non-empty map.
331          # it into a memory DC and then blit it to the screen.  
332            # get the update region and reset it. We're not actually using
333            # it anymore, though.
334            update_box = self.update_region.GetBox()
335            self.update_region = wx.wxRegion()
336    
337            # Get the window size.
338          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
339    
340          # If self.bitmap's still there, reuse it. Otherwise redraw it          # If self.bitmap's still there, reuse it. Otherwise redraw it
# Line 339  class MapCanvas(wxWindow, Publisher): Line 360  class MapCanvas(wxWindow, Publisher):
360    
361              # draw the map into the bitmap              # draw the map into the bitmap
362              renderer = ScreenRenderer(dc, self.scale, self.offset)              renderer = ScreenRenderer(dc, self.scale, self.offset)
363              renderer.RenderMap(self.map, selected_layer, selected_shape)  
364                # Pass the entire bitmap as update_region to the renderer.
365                # We're redrawing the whole bitmap, after all.
366                renderer.RenderMap(self.map, (0, 0, width, height),
367                                   selected_layer, selected_shape)
368    
369              dc.EndDrawing()              dc.EndDrawing()
370              dc.SelectObject(wx.wxNullBitmap)              dc.SelectObject(wx.wxNullBitmap)
# Line 358  class MapCanvas(wxWindow, Publisher): Line 383  class MapCanvas(wxWindow, Publisher):
383          printout = MapPrintout(self.map)          printout = MapPrintout(self.map)
384          printer.Print(self, printout, wx.true)          printer.Print(self, printout, wx.true)
385          printout.Destroy()          printout.Destroy()
386            
387      def SetMap(self, map):      def SetMap(self, map):
388          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,
389                             LAYER_VISIBILITY_CHANGED)                             LAYER_VISIBILITY_CHANGED)
# Line 527  class MapCanvas(wxWindow, Publisher): Line 552  class MapCanvas(wxWindow, Publisher):
552              self.tool.MouseDown(event)              self.tool.MouseDown(event)
553              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
554              self.dragging = 1              self.dragging = 1
555            
556      def OnLeftUp(self, event):      def OnLeftUp(self, event):
557          self.ReleaseMouse()          self.ReleaseMouse()
558          self.set_current_position(event)          self.set_current_position(event)
# Line 562  class MapCanvas(wxWindow, Publisher): Line 587  class MapCanvas(wxWindow, Publisher):
587          self.full_redraw()          self.full_redraw()
588    
589      def shape_selected(self, layer, shape):      def shape_selected(self, layer, shape):
590          self.full_redraw()          """Redraw the map.
591    
592            Receiver for the SELECTED_SHAPE messages. Try to redraw only
593            when necessary.
594            """
595            # A redraw is necessary when the display has to change, which
596            # means that either the status changes from having no selection
597            # to having a selection shape or vice versa, or when the fact
598            # whether there is a selection at all doesn't change, when the
599            # shape which is selected has changed (which means that layer or
600            # shapeid changes).
601            if ((shape is not None or self.last_selected_shape is not None)
602                and (shape != self.last_selected_shape
603                     or layer != self.last_selected_layer)):
604                self.full_redraw()
605    
606            # remember the selection so we can compare when it changes again.
607            self.last_selected_layer = layer
608            self.last_selected_shape = shape
609    
610      def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):      def unprojected_rect_around_point(self, x, y):
611            """return a rect a few pixels around (x, y) in unprojected corrdinates
612    
613            The return value is a tuple (minx, miny, maxx, maxy) suitable a
614            parameter to a layer's ShapesInRegion method.
615            """
616            map_proj = self.map.projection
617            if map_proj is not None:
618                inverse = map_proj.Inverse
619            else:
620                inverse = None
621    
622            xs = []
623            ys = []
624            for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
625                px, py = self.win_to_proj(x + dx, y + dy)
626                if inverse:
627                    px, py = inverse(px, py)
628                xs.append(px)
629                ys.append(py)
630            return (min(xs), min(ys), max(xs), max(ys))
631    
632        def find_shape_at(self, px, py, select_labels = 0, searched_layer = None):
633          """Determine the shape at point px, py in window coords          """Determine the shape at point px, py in window coords
634    
635          Return the shape and the corresponding layer as a tuple (layer,          Return the shape and the corresponding layer as a tuple (layer,
# Line 574  class MapCanvas(wxWindow, Publisher): Line 639  class MapCanvas(wxWindow, Publisher):
639          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
640          as the shape and None as the layer.          as the shape and None as the layer.
641    
642          If the optional parameter selected_layer is true (default), only          If the optional parameter searched_layer is given (or not None
643          search in the currently selected layer.          which it defaults to), only search in that layer.
644          """          """
645          map_proj = self.map.projection          map_proj = self.map.projection
646          if map_proj is not None:          if map_proj is not None:
# Line 586  class MapCanvas(wxWindow, Publisher): Line 651  class MapCanvas(wxWindow, Publisher):
651          scale = self.scale          scale = self.scale
652          offx, offy = self.offset          offx, offy = self.offset
653    
654            box = self.unprojected_rect_around_point(px, py)
655    
656          if select_labels:          if select_labels:
657              labels = self.map.LabelLayer().Labels()              labels = self.map.LabelLayer().Labels()
658                
659              if labels:              if labels:
660                  dc = wxClientDC(self)                  dc = wxClientDC(self)
661                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
# Line 620  class MapCanvas(wxWindow, Publisher): Line 687  class MapCanvas(wxWindow, Publisher):
687                      if x <= px < x + width and y <= py <= y + height:                      if x <= px < x + width and y <= py <= y + height:
688                          return None, i                          return None, i
689    
690          if selected_layer:          if searched_layer:
691              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 = []  
692          else:          else:
693              layers = self.map.Layers()              layers = self.map.Layers()
694    
# Line 640  class MapCanvas(wxWindow, Publisher): Line 701  class MapCanvas(wxWindow, Publisher):
701    
702              filled = layer.fill is not None              filled = layer.fill is not None
703              stroked = layer.stroke is not None              stroked = layer.stroke is not None
704                    
705              layer_proj = layer.projection              layer_proj = layer.projection
706              if layer_proj is not None:              if layer_proj is not None:
707                  inverse = layer_proj.Inverse                  inverse = layer_proj.Inverse
708              else:              else:
709                  inverse = None                  inverse = None
710                    
711              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
712    
713              select_shape = -1              select_shape = -1
714    
715                shape_ids = layer.ShapesInRegion(box)
716                shape_ids.reverse()
717    
718              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
719                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
720                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
721                                                      i,                                                      i,
722                                                      filled, stroked,                                                      filled, stroked,
# Line 662  class MapCanvas(wxWindow, Publisher): Line 727  class MapCanvas(wxWindow, Publisher):
727                          select_shape = i                          select_shape = i
728                          break                          break
729              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
730                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
731                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
732                                                      i, 0, 1,                                                      i, 0, 1,
733                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
# Line 672  class MapCanvas(wxWindow, Publisher): Line 737  class MapCanvas(wxWindow, Publisher):
737                          select_shape = i                          select_shape = i
738                          break                          break
739              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
740                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
741                      shape = layer.Shape(i)                      shape = layer.Shape(i)
742                      x, y = shape.Points()[0]                      x, y = shape.Points()[0]
743                      if inverse:                      if inverse:
# Line 689  class MapCanvas(wxWindow, Publisher): Line 754  class MapCanvas(wxWindow, Publisher):
754                  return layer, select_shape                  return layer, select_shape
755          return None, None          return None, None
756    
757      def SelectShapeAt(self, x, y):      def SelectShapeAt(self, x, y, layer = None):
758          layer, shape = self.find_shape_at(x, y, selected_layer = 0)          """\
759            Select and return the shape and its layer at window position (x, y)
760    
761            If layer is given, only search in that layer. If no layer is
762            given, search through all layers.
763    
764            Return a tuple (layer, shapeid). If no shape is found, return
765            (None, None).
766            """
767            layer, shape = result = self.find_shape_at(x, y, searched_layer=layer)
768          # 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
769          # to deselect the currently selected layer, so we simply select          # to deselect the currently selected layer, so we simply select
770          # the already selected layer again.          # the already selected layer again.
771          if layer is None:          if layer is None:
772              layer = self.interactor.SelectedLayer()              layer = self.interactor.SelectedLayer()
773          self.interactor.SelectLayerAndShape(layer, shape)          self.interactor.SelectLayerAndShape(layer, shape)
774            return result
775    
776      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):
777          ox = x; oy = y          ox = x; oy = y

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26