/[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 78 by bh, Mon Feb 4 19:37:16 2002 UTC revision 301 by bh, Mon Sep 2 15:59:11 2002 UTC
# Line 15  from math import hypot Line 15  from math import hypot
15    
16  from wxPython.wx import wxWindow,\  from wxPython.wx import wxWindow,\
17       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
18       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW
19    
20    
21  from wxPython import wx  from wxPython import wx
# Line 29  from Thuban.Model.layer import SHAPETYPE Line 29  from Thuban.Model.layer import SHAPETYPE
29       SHAPETYPE_POINT       SHAPETYPE_POINT
30  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
31       ALIGN_LEFT, ALIGN_RIGHT       ALIGN_LEFT, ALIGN_RIGHT
32    from Thuban.Lib.connector import Publisher
33    
34  from renderer import ScreenRenderer, PrinterRender  from renderer import ScreenRenderer, PrinterRender
35    
36  import labeldialog  import labeldialog
37    
38  from messages import SELECTED_SHAPE  from messages import SELECTED_SHAPE, VIEW_POSITION
39    
40    
41  #  #
# 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 167  class PanTool(Tool): Line 175  class PanTool(Tool):
175    
176      def MouseMove(self, event):      def MouseMove(self, event):
177          if self.dragging:          if self.dragging:
             x0, y0 = self.current  
178              Tool.MouseMove(self, event)              Tool.MouseMove(self, event)
179                sx, sy = self.start
180              x, y = self.current              x, y = self.current
181              width, height = self.view.GetSizeTuple()              width, height = self.view.GetSizeTuple()
182    
183                bitmapdc = wx.wxMemoryDC()
184                bitmapdc.SelectObject(self.view.bitmap)
185    
186              dc = self.view.drag_dc              dc = self.view.drag_dc
187              dc.Blit(0, 0, width, height, dc, x0 - x, y0 - y)              dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
188    
189      def MouseUp(self, event):      def MouseUp(self, event):
190          if self.dragging:          if self.dragging:
# Line 180  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 238  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  class MapCanvas(wxWindow):  
255    class MapCanvas(wxWindow, Publisher):
256    
257      """A widget that displays a map and offers some interaction"""      """A widget that displays a map and offers some interaction"""
258    
259      def __init__(self, parent, winid, interactor):      def __init__(self, parent, winid, interactor):
260          wxWindow.__init__(self, parent, winid)          wxWindow.__init__(self, parent, winid)
261          self.SetBackgroundColour(wxColour(255, 255, 255))          self.SetBackgroundColour(wxColour(255, 255, 255))
262    
263            # the map displayed in this canvas. Set with SetMap()
264          self.map = None          self.map = None
265    
266            # scale and offset describe the transformation from projected
267            # coordinates to window coordinates.
268          self.scale = 1.0          self.scale = 1.0
269          self.offset = (0, 0)          self.offset = (0, 0)
270    
271            # whether the user is currently dragging the mouse, i.e. moving
272            # the mouse while pressing a mouse button
273          self.dragging = 0          self.dragging = 0
274    
275            # the currently active tool
276          self.tool = None          self.tool = None
277    
278            # The current mouse position of the last OnMotion event or None
279            # if the mouse is outside the window.
280            self.current_position = None
281    
282            # If true, OnIdle will call do_redraw to do the actual
283            # redrawing. Set by OnPaint to avoid some unnecessary redraws.
284            # To force a redraw call full_redraw().
285          self.redraw_on_idle = 0          self.redraw_on_idle = 0
286    
287            # the bitmap serving as backing store
288            self.bitmap = None
289    
290            # the interactor
291            self.interactor = interactor
292            self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)
293    
294            # keep track of which layers/shapes are selected to make sure we
295            # only redraw when necessary
296            self.last_selected_layer = None
297            self.last_selected_shape = None
298    
299            # subscribe the WX events we're interested in
300          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
301          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
302          EVT_LEFT_UP(self, self.OnLeftUp)          EVT_LEFT_UP(self, self.OnLeftUp)
303          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
304            EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
305            wx.EVT_SIZE(self, self.OnSize)
306          wx.EVT_IDLE(self, self.OnIdle)          wx.EVT_IDLE(self, self.OnIdle)
307          self.interactor = interactor  
308          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)      def __del__(self):
309            wxWindow.__del__(self)
310            Publisher.__del__(self)
311    
312      def OnPaint(self, event):      def OnPaint(self, event):
313          dc = wxPaintDC(self)          dc = wxPaintDC(self)
# Line 269  class MapCanvas(wxWindow): Line 317  class MapCanvas(wxWindow):
317          else:          else:
318              # 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
319              # the screen.              # the screen.
320                
321              # XXX it's probably possible to get rid of this. The              # XXX it's probably possible to get rid of this. The
322              # background color of the window is already white and the              # background color of the window is already white and the
323              # only thing we may have to do is to call self.Refresh()              # only thing we may have to do is to call self.Refresh()
324              # with a true argument in the right places.              # with a true argument in the right places.
325              dc.BeginDrawing()              dc.BeginDrawing()
326              dc.Clear()                          dc.Clear()
327              dc.EndDrawing()              dc.EndDrawing()
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 window size.
333          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
         bitmap = wx.wxEmptyBitmap(width, height)  
         dc = wx.wxMemoryDC()  
         dc.SelectObject(bitmap)  
         dc.BeginDrawing()  
334    
335          # clear the background          # If self.bitmap's still there, reuse it. Otherwise redraw it
336          dc.SetBrush(wx.wxWHITE_BRUSH)          if self.bitmap is not None:
337          dc.SetPen(wx.wxTRANSPARENT_PEN)              bitmap = self.bitmap
         dc.DrawRectangle(0, 0, width, height)  
   
         if 1: #self.interactor.selected_map is self.map:  
             selected_layer = self.interactor.selected_layer  
             selected_shape = self.interactor.selected_shape  
338          else:          else:
339              selected_layer = None              bitmap = wx.wxEmptyBitmap(width, height)
340              selected_shape = None              dc = wx.wxMemoryDC()
341                dc.SelectObject(bitmap)
342                dc.BeginDrawing()
343    
344          # draw the map into the bitmap              # clear the background
345          renderer = ScreenRenderer(dc, self.scale, self.offset)              dc.SetBrush(wx.wxWHITE_BRUSH)
346          renderer.RenderMap(self.map, selected_layer, selected_shape)              dc.SetPen(wx.wxTRANSPARENT_PEN)
347                dc.DrawRectangle(0, 0, width, height)
348    
349                if 1: #self.interactor.selected_map is self.map:
350                    selected_layer = self.interactor.selected_layer
351                    selected_shape = self.interactor.selected_shape
352                else:
353                    selected_layer = None
354                    selected_shape = None
355    
356          dc.EndDrawing()              # draw the map into the bitmap
357                renderer = ScreenRenderer(dc, self.scale, self.offset)
358    
359                # Pass the entire bitmap as update region to the renderer.
360                # We're redrawing the whole bitmap, after all.
361                renderer.RenderMap(self.map, (0, 0, width, height),
362                                   selected_layer, selected_shape)
363    
364                dc.EndDrawing()
365                dc.SelectObject(wx.wxNullBitmap)
366                self.bitmap = bitmap
367    
368          # blit the bitmap to the screen          # blit the bitmap to the screen
369            dc = wx.wxMemoryDC()
370            dc.SelectObject(bitmap)
371          clientdc = wxClientDC(self)          clientdc = wxClientDC(self)
372          clientdc.BeginDrawing()          clientdc.BeginDrawing()
373          clientdc.Blit(0, 0, width, height, dc, 0, 0)          clientdc.Blit(0, 0, width, height, dc, 0, 0)
# Line 316  class MapCanvas(wxWindow): Line 378  class MapCanvas(wxWindow):
378          printout = MapPrintout(self.map)          printout = MapPrintout(self.map)
379          printer.Print(self, printout, wx.true)          printer.Print(self, printout, wx.true)
380          printout.Destroy()          printout.Destroy()
381            
382      def SetMap(self, map):      def SetMap(self, map):
383          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,
384                             LAYER_VISIBILITY_CHANGED)                             LAYER_VISIBILITY_CHANGED)
385          if self.map is not None:          if self.map is not None:
386              for channel in redraw_channels:              for channel in redraw_channels:
387                  self.map.Unsubscribe(channel, self.redraw)                  self.map.Unsubscribe(channel, self.full_redraw)
388              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,
389                                   self.projection_changed)                                   self.projection_changed)
390          self.map = map          self.map = map
391          if self.map is not None:          if self.map is not None:
392              for channel in redraw_channels:              for channel in redraw_channels:
393                  self.map.Subscribe(channel, self.redraw)                  self.map.Subscribe(channel, self.full_redraw)
394              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)
395          self.FitMapToWindow()          self.FitMapToWindow()
396          # force a redraw. If map is not empty, it's already been called          # force a redraw. If map is not empty, it's already been called
397          # by FitMapToWindow but if map is empty it hasn't been called          # by FitMapToWindow but if map is empty it hasn't been called
398          # yet so we have to explicitly call it.          # yet so we have to explicitly call it.
399          self.redraw()          self.full_redraw()
400    
401      def Map(self):      def Map(self):
402            """Return the map displayed by this canvas"""
403          return self.map          return self.map
404    
405      def redraw(self, *args):      def redraw(self, *args):
406          self.Refresh(0)          self.Refresh(0)
407    
408        def full_redraw(self, *args):
409            self.bitmap = None
410            self.redraw()
411    
412      def projection_changed(self, *args):      def projection_changed(self, *args):
413          self.FitMapToWindow()          self.FitMapToWindow()
414          self.redraw()          self.full_redraw()
415    
416      def set_view_transform(self, scale, offset):      def set_view_transform(self, scale, offset):
417          self.scale = scale          self.scale = scale
418          self.offset = offset          self.offset = offset
419          self.redraw()          self.full_redraw()
420    
421      def proj_to_win(self, x, y):      def proj_to_win(self, x, y):
422          """\          """\
# Line 366  class MapCanvas(wxWindow): Line 433  class MapCanvas(wxWindow):
433          return ((x - offx) / self.scale, (offy - y) / self.scale)          return ((x - offx) / self.scale, (offy - y) / self.scale)
434    
435      def FitRectToWindow(self, rect):      def FitRectToWindow(self, rect):
436            """Fit the rectangular region given by rect into the window.
437            
438            Set scale so that rect (in projected coordinates) just fits into
439            the window and center it.
440            """
441          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
442          llx, lly, urx, ury = rect          llx, lly, urx, ury = rect
443          if llx == urx or lly == ury:          if llx == urx or lly == ury:
# Line 379  class MapCanvas(wxWindow): Line 451  class MapCanvas(wxWindow):
451          self.set_view_transform(scale, (offx, offy))          self.set_view_transform(scale, (offx, offy))
452    
453      def FitMapToWindow(self):      def FitMapToWindow(self):
454          """\          """Fit the map to the window
455          Set the scale and offset so that the map is centered in the          
456          window          Set the scale so that the map fits exactly into the window and
457            center it in the window.
458          """          """
459          bbox = self.map.ProjectedBoundingBox()          bbox = self.map.ProjectedBoundingBox()
460          if bbox is not None:          if bbox is not None:
# Line 407  class MapCanvas(wxWindow): Line 480  class MapCanvas(wxWindow):
480          self.set_view_transform(scale, offset)          self.set_view_transform(scale, offset)
481    
482      def ZoomOutToRect(self, rect):      def ZoomOutToRect(self, rect):
483          # rect is given in window coordinates          """Zoom out to fit the currently visible region into rect.
484    
485            The rect parameter is given in window coordinates
486            """
487          # determine the bbox of the displayed region in projected          # determine the bbox of the displayed region in projected
488          # coordinates          # coordinates
489          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
# Line 425  class MapCanvas(wxWindow): Line 500  class MapCanvas(wxWindow):
500          self.set_view_transform(scale, (offx, offy))          self.set_view_transform(scale, (offx, offy))
501    
502      def Translate(self, dx, dy):      def Translate(self, dx, dy):
503            """Move the map by dx, dy pixels"""
504          offx, offy = self.offset          offx, offy = self.offset
505          self.set_view_transform(self.scale, (offx + dx, offy + dy))          self.set_view_transform(self.scale, (offx + dx, offy + dy))
506    
507      def ZoomInTool(self):      def ZoomInTool(self):
508            """Start the zoom in tool"""
509          self.tool = ZoomInTool(self)          self.tool = ZoomInTool(self)
510    
511      def ZoomOutTool(self):      def ZoomOutTool(self):
512            """Start the zoom out tool"""
513          self.tool = ZoomOutTool(self)          self.tool = ZoomOutTool(self)
514    
515      def PanTool(self):      def PanTool(self):
516            """Start the pan tool"""
517          self.tool = PanTool(self)          self.tool = PanTool(self)
518    
519      def IdentifyTool(self):      def IdentifyTool(self):
520            """Start the identify tool"""
521          self.tool = IdentifyTool(self)          self.tool = IdentifyTool(self)
522    
523      def LabelTool(self):      def LabelTool(self):
524            """Start the label tool"""
525          self.tool = LabelTool(self)          self.tool = LabelTool(self)
526    
527      def CurrentTool(self):      def CurrentTool(self):
528            """Return the name of the current tool or None if no tool is active"""
529          return self.tool and self.tool.Name() or None          return self.tool and self.tool.Name() or None
530    
531        def CurrentPosition(self):
532            """Return current position of the mouse in projected coordinates.
533    
534            The result is a 2-tuple of floats with the coordinates. If the
535            mouse is not in the window, the result is None.
536            """
537            if self.current_position is not None:
538                x, y = self.current_position
539                return self.win_to_proj(x, y)
540            else:
541                return None
542    
543        def set_current_position(self, event):
544            """Set the current position from event
545    
546            Should be called by all events that contain mouse positions
547            especially EVT_MOTION. The event paramete may be None to
548            indicate the the pointer left the window.
549            """
550            if event is not None:
551                self.current_position = (event.m_x, event.m_y)
552            else:
553                self.current_position = None
554            self.issue(VIEW_POSITION)
555    
556      def OnLeftDown(self, event):      def OnLeftDown(self, event):
557            self.set_current_position(event)
558          if self.tool is not None:          if self.tool is not None:
559              self.drag_dc = wxClientDC(self)              self.drag_dc = wxClientDC(self)
560              self.drag_dc.SetLogicalFunction(wxINVERT)              self.drag_dc.SetLogicalFunction(wxINVERT)
# Line 455  class MapCanvas(wxWindow): Line 563  class MapCanvas(wxWindow):
563              self.tool.MouseDown(event)              self.tool.MouseDown(event)
564              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
565              self.dragging = 1              self.dragging = 1
566            
567      def OnLeftUp(self, event):      def OnLeftUp(self, event):
568          self.ReleaseMouse()          self.set_current_position(event)
569          if self.dragging:          if self.dragging:
570                self.ReleaseMouse()
571              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
572              self.tool.MouseUp(event)              self.tool.MouseUp(event)
573              self.drag_dc = None              self.drag_dc = None
574          self.dragging = 0          self.dragging = 0
575    
576      def OnMotion(self, event):      def OnMotion(self, event):
577            self.set_current_position(event)
578          if self.dragging:          if self.dragging:
579              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
580              self.tool.MouseMove(event)              self.tool.MouseMove(event)
581              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
582    
583        def OnLeaveWindow(self, event):
584            self.set_current_position(None)
585    
586      def OnIdle(self, event):      def OnIdle(self, event):
587          if self.redraw_on_idle:          if self.redraw_on_idle:
588              self.do_redraw()              self.do_redraw()
589          self.redraw_on_idle = 0          self.redraw_on_idle = 0
590    
591        def OnSize(self, event):
592            # the window's size has changed. We have to get a new bitmap. If
593            # we want to be clever we could try to get by without throwing
594            # everything away. E.g. when the window gets smaller, we could
595            # either keep the bitmap or create the new one from the old one.
596            # Even when the window becomes larger some parts of the bitmap
597            # could be reused.
598            self.full_redraw()
599    
600      def shape_selected(self, layer, shape):      def shape_selected(self, layer, shape):
601          self.redraw()          """Redraw the map.
602    
603            Receiver for the SELECTED_SHAPE messages. Try to redraw only
604            when necessary.
605            """
606            # A redraw is necessary when the display has to change, which
607            # means that either the status changes from having no selection
608            # to having a selection shape or vice versa, or when the fact
609            # whether there is a selection at all doesn't change, when the
610            # shape which is selected has changed (which means that layer or
611            # shapeid changes).
612            if ((shape is not None or self.last_selected_shape is not None)
613                and (shape != self.last_selected_shape
614                     or layer != self.last_selected_layer)):
615                self.full_redraw()
616    
617            # remember the selection so we can compare when it changes again.
618            self.last_selected_layer = layer
619            self.last_selected_shape = shape
620    
621        def unprojected_rect_around_point(self, x, y, dist):
622            """return a rect dist pixels around (x, y) in unprojected corrdinates
623    
624      def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):          The return value is a tuple (minx, miny, maxx, maxy) suitable a
625            parameter to a layer's ShapesInRegion method.
626            """
627            map_proj = self.map.projection
628            if map_proj is not None:
629                inverse = map_proj.Inverse
630            else:
631                inverse = None
632    
633            xs = []
634            ys = []
635            for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
636                px, py = self.win_to_proj(x + dist * dx, y + dist * dy)
637                if inverse:
638                    px, py = inverse(px, py)
639                xs.append(px)
640                ys.append(py)
641            return (min(xs), min(ys), max(xs), max(ys))
642    
643        def find_shape_at(self, px, py, select_labels = 0, searched_layer = None):
644          """Determine the shape at point px, py in window coords          """Determine the shape at point px, py in window coords
645    
646          Return the shape and the corresponding layer as a tuple (layer,          Return the shape and the corresponding layer as a tuple (layer,
# Line 488  class MapCanvas(wxWindow): Line 650  class MapCanvas(wxWindow):
650          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
651          as the shape and None as the layer.          as the shape and None as the layer.
652    
653          If the optional parameter selected_layer is true (default), only          If the optional parameter searched_layer is given (or not None
654          search in the currently selected layer.          which it defaults to), only search in that layer.
655          """          """
656          map_proj = self.map.projection          map_proj = self.map.projection
657          if map_proj is not None:          if map_proj is not None:
# Line 502  class MapCanvas(wxWindow): Line 664  class MapCanvas(wxWindow):
664    
665          if select_labels:          if select_labels:
666              labels = self.map.LabelLayer().Labels()              labels = self.map.LabelLayer().Labels()
667                
668              if labels:              if labels:
669                  dc = wxClientDC(self)                  dc = wxClientDC(self)
670                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
# Line 534  class MapCanvas(wxWindow): Line 696  class MapCanvas(wxWindow):
696                      if x <= px < x + width and y <= py <= y + height:                      if x <= px < x + width and y <= py <= y + height:
697                          return None, i                          return None, i
698    
699          if selected_layer:          if searched_layer:
700              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 = []  
701          else:          else:
702              layers = self.map.Layers()              layers = self.map.Layers()
703    
# Line 554  class MapCanvas(wxWindow): Line 710  class MapCanvas(wxWindow):
710    
711              filled = layer.fill is not None              filled = layer.fill is not None
712              stroked = layer.stroke is not None              stroked = layer.stroke is not None
713                    
714              layer_proj = layer.projection              layer_proj = layer.projection
715              if layer_proj is not None:              if layer_proj is not None:
716                  inverse = layer_proj.Inverse                  inverse = layer_proj.Inverse
717              else:              else:
718                  inverse = None                  inverse = None
719                    
720              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
721    
722              select_shape = -1              select_shape = -1
723    
724                # Determine the ids of the shapes that overlap a tiny area
725                # around the point. For layers containing points we have to
726                # choose a larger size of the box we're testing agains so
727                # that we take the size of the markers into account
728                # FIXME: Once the markers are more flexible this part has to
729                # become more flexible too, of course
730                if shapetype == SHAPETYPE_POINT:
731                    box = self.unprojected_rect_around_point(px, py, 5)
732                else:
733                    box = self.unprojected_rect_around_point(px, py, 1)
734                shape_ids = layer.ShapesInRegion(box)
735                shape_ids.reverse()
736    
737              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
738                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
739                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
740                                                      i,                                                      i,
741                                                      filled, stroked,                                                      filled, stroked,
# Line 576  class MapCanvas(wxWindow): Line 746  class MapCanvas(wxWindow):
746                          select_shape = i                          select_shape = i
747                          break                          break
748              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
749                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
750                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
751                                                      i, 0, 1,                                                      i, 0, 1,
752                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
# Line 586  class MapCanvas(wxWindow): Line 756  class MapCanvas(wxWindow):
756                          select_shape = i                          select_shape = i
757                          break                          break
758              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
759                  for i in range(layer.NumShapes() - 1, -1, -1):                  for i in shape_ids:
760                      shape = layer.Shape(i)                      shape = layer.Shape(i)
761                      x, y = shape.Points()[0]                      x, y = shape.Points()[0]
762                      if inverse:                      if inverse:
# Line 603  class MapCanvas(wxWindow): Line 773  class MapCanvas(wxWindow):
773                  return layer, select_shape                  return layer, select_shape
774          return None, None          return None, None
775    
776      def SelectShapeAt(self, x, y):      def SelectShapeAt(self, x, y, layer = None):
777          layer, shape = self.find_shape_at(x, y, selected_layer = 0)          """\
778            Select and return the shape and its layer at window position (x, y)
779    
780            If layer is given, only search in that layer. If no layer is
781            given, search through all layers.
782    
783            Return a tuple (layer, shapeid). If no shape is found, return
784            (None, None).
785            """
786            layer, shape = result = self.find_shape_at(x, y, searched_layer=layer)
787          # 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
788          # to deselect the currently selected layer, so we simply select          # to deselect the currently selected layer, so we simply select
789          # the already selected layer again.          # the already selected layer again.
790          if layer is None:          if layer is None:
791              layer = self.interactor.SelectedLayer()              layer = self.interactor.SelectedLayer()
792          self.interactor.SelectLayerAndShape(layer, shape)          self.interactor.SelectLayerAndShape(layer, shape)
793            return result
794    
795      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):
796            """Add or remove a label at window position x, y.
797    
798            If there's a label at the given position, remove it. Otherwise
799            determine the shape at the position, run the label dialog and
800            unless the user cancels the dialog, add a laber.
801            """
802          ox = x; oy = y          ox = x; oy = y
803          label_layer = self.map.LabelLayer()          label_layer = self.map.LabelLayer()
804          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.78  
changed lines
  Added in v.301

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26