/[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 43 by bh, Fri Sep 7 11:55:51 2001 UTC revision 293 by bh, Fri Aug 30 10:18:50 2002 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# 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 127  class ZoomInTool(RectTool): Line 127  class ZoomInTool(RectTool):
127      def MouseUp(self, event):      def MouseUp(self, event):
128          if self.dragging:          if self.dragging:
129              Tool.MouseUp(self, event)              Tool.MouseUp(self, event)
130              self.view.FitRectToWindow(self.proj_rect())              sx, sy = self.start
131                cx, cy = self.current
132                if sx == cx or sy == cy:
133                    # 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))
139                else:
140                    # A drag. Zoom in to the rectangle
141                    self.view.FitRectToWindow(self.proj_rect())
142    
143    
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 142  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              self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),              if sx == cx or sy == cy:
157                                       max(sx, cx), max(sy, cy)))                  # 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))
163                else:
164                    # A drag. Zoom out to the rectangle
165                    self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
166                                             max(sx, cx), max(sy, cy)))
167    
168    
169  class PanTool(Tool):  class PanTool(Tool):
# Line 155  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 168  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 226  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 region to update when idle
288            self.update_region = wx.wxRegion()
289    
290            # the bitmap serving as backing store
291            self.bitmap = None
292    
293            # the interactor
294            self.interactor = interactor
295            self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)
296    
297            # keep track of which layers/shapes are selected to make sure we
298            # only redraw when necessary
299            self.last_selected_layer = None
300            self.last_selected_shape = None
301    
302            # subscribe the WX events we're interested in
303          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
304          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
305          EVT_LEFT_UP(self, self.OnLeftUp)          EVT_LEFT_UP(self, self.OnLeftUp)
306          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
307            EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
308            wx.EVT_SIZE(self, self.OnSize)
309          wx.EVT_IDLE(self, self.OnIdle)          wx.EVT_IDLE(self, self.OnIdle)
310          self.interactor = interactor  
311          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)      def __del__(self):
312            wxWindow.__del__(self)
313            Publisher.__del__(self)
314    
315      def OnPaint(self, event):      def OnPaint(self, event):
316          dc = wxPaintDC(self)          dc = wxPaintDC(self)
317          if self.map is None or not self.map.HasLayers():          if self.map is not None and self.map.HasLayers():
318              return              # We have a non-empty map. Redraw it in idle time
319          self.redraw_on_idle = 1              self.redraw_on_idle = 1
320                # update the region that has to be redrawn
321                self.update_region.UnionRegion(self.GetUpdateRegion())
322            else:
323                # If we've got no map or if the map is empty, simply clear
324                # the screen.
325    
326                # XXX it's probably possible to get rid of this. The
327                # background color of the window is already white and the
328                # only thing we may have to do is to call self.Refresh()
329                # with a true argument in the right places.
330                dc.BeginDrawing()
331                dc.Clear()
332                dc.EndDrawing()
333    
334                # clear the region
335                self.update_region = wx.wxRegion()
336    
337      def do_redraw(self):      def do_redraw(self):
338          width, height = self.GetSizeTuple()          # This should only be called if we have a non-empty map.
         bitmap = wx.wxEmptyBitmap(width, height)  
339    
340          dc = wx.wxMemoryDC()          # get the update region and reset it. We're not actually using
341          dc.SelectObject(bitmap)          # it anymore, though.
342            update_box = self.update_region.GetBox()
343            self.update_region = wx.wxRegion()
344    
345          dc.BeginDrawing()          # Get the window size.
346            width, height = self.GetSizeTuple()
347    
348          dc.SetBrush(wx.wxWHITE_BRUSH)          # If self.bitmap's still there, reuse it. Otherwise redraw it
349          dc.SetPen(wx.wxTRANSPARENT_PEN)          if self.bitmap is not None:
350          dc.DrawRectangle(0, 0, width, height)              bitmap = self.bitmap
   
         if 1: #self.interactor.selected_map is self.map:  
             selected_layer = self.interactor.selected_layer  
             selected_shape = self.interactor.selected_shape  
351          else:          else:
352              selected_layer = None              bitmap = wx.wxEmptyBitmap(width, height)
353              selected_shape = None              dc = wx.wxMemoryDC()
354                            dc.SelectObject(bitmap)
355          renderer = ScreenRenderer(dc, self.scale, self.offset)              dc.BeginDrawing()
356          renderer.RenderMap(self.map, selected_layer, selected_shape)  
357                # clear the background
358                dc.SetBrush(wx.wxWHITE_BRUSH)
359                dc.SetPen(wx.wxTRANSPARENT_PEN)
360                dc.DrawRectangle(0, 0, width, height)
361    
362                if 1: #self.interactor.selected_map is self.map:
363                    selected_layer = self.interactor.selected_layer
364                    selected_shape = self.interactor.selected_shape
365                else:
366                    selected_layer = None
367                    selected_shape = None
368    
369                # draw the map into the bitmap
370                renderer = ScreenRenderer(dc, self.scale, self.offset)
371    
372                # Pass the entire bitmap as update_region to the renderer.
373                # We're redrawing the whole bitmap, after all.
374                renderer.RenderMap(self.map, (0, 0, width, height),
375                                   selected_layer, selected_shape)
376    
377                dc.EndDrawing()
378                dc.SelectObject(wx.wxNullBitmap)
379                self.bitmap = bitmap
380    
381            # blit the bitmap to the screen
382            dc = wx.wxMemoryDC()
383            dc.SelectObject(bitmap)
384          clientdc = wxClientDC(self)          clientdc = wxClientDC(self)
385          clientdc.BeginDrawing()          clientdc.BeginDrawing()
386          clientdc.Blit(0, 0, width, height, dc, 0, 0)          clientdc.Blit(0, 0, width, height, dc, 0, 0)
387          clientdc.EndDrawing()          clientdc.EndDrawing()
388    
   
389      def Print(self):      def Print(self):
390          printer = wx.wxPrinter()          printer = wx.wxPrinter()
391          printout = MapPrintout(self.map)          printout = MapPrintout(self.map)
392          printer.Print(self, printout, wx.true)          printer.Print(self, printout, wx.true)
393          printout.Destroy()          printout.Destroy()
394            
395      def SetMap(self, map):      def SetMap(self, map):
396          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,          redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,
397                             LAYER_VISIBILITY_CHANGED)                             LAYER_VISIBILITY_CHANGED)
398          if self.map is not None:          if self.map is not None:
399              for channel in redraw_channels:              for channel in redraw_channels:
400                  self.map.Unsubscribe(channel, self.redraw)                  self.map.Unsubscribe(channel, self.full_redraw)
401              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,
402                                   self.projection_changed)                                   self.projection_changed)
403          self.map = map          self.map = map
404          if self.map is not None:          if self.map is not None:
405              for channel in redraw_channels:              for channel in redraw_channels:
406                  self.map.Subscribe(channel, self.redraw)                  self.map.Subscribe(channel, self.full_redraw)
407              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)
408          self.FitMapToWindow()          self.FitMapToWindow()
409            # force a redraw. If map is not empty, it's already been called
410            # by FitMapToWindow but if map is empty it hasn't been called
411            # yet so we have to explicitly call it.
412            self.full_redraw()
413    
414      def Map(self):      def Map(self):
415          return self.map          return self.map
# Line 311  class MapCanvas(wxWindow): Line 417  class MapCanvas(wxWindow):
417      def redraw(self, *args):      def redraw(self, *args):
418          self.Refresh(0)          self.Refresh(0)
419    
420        def full_redraw(self, *args):
421            self.bitmap = None
422            self.redraw()
423    
424      def projection_changed(self, *args):      def projection_changed(self, *args):
425          self.FitMapToWindow()          self.FitMapToWindow()
426          self.redraw()          self.full_redraw()
427    
428      def set_view_transform(self, scale, offset):      def set_view_transform(self, scale, offset):
429          self.scale = scale          self.scale = scale
430          self.offset = offset          self.offset = offset
431          self.redraw()          self.full_redraw()
432    
433      def proj_to_win(self, x, y):      def proj_to_win(self, x, y):
434          """\          """\
# Line 335  class MapCanvas(wxWindow): Line 445  class MapCanvas(wxWindow):
445          return ((x - offx) / self.scale, (offy - y) / self.scale)          return ((x - offx) / self.scale, (offy - y) / self.scale)
446    
447      def FitRectToWindow(self, rect):      def FitRectToWindow(self, rect):
448            """Fit the rectangular region given by rect into the window.
449            
450            Set scale so that rect (in projected coordinates) just fits into
451            the window and center it.
452            """
453          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
454          llx, lly, urx, ury = rect          llx, lly, urx, ury = rect
455            if llx == urx or lly == ury:
456                # zero with or zero height. Do Nothing
457                return
458          scalex = width / (urx - llx)          scalex = width / (urx - llx)
459          scaley = height / (ury - lly)          scaley = height / (ury - lly)
460          scale = min(scalex, scaley)          scale = min(scalex, scaley)
# Line 345  class MapCanvas(wxWindow): Line 463  class MapCanvas(wxWindow):
463          self.set_view_transform(scale, (offx, offy))          self.set_view_transform(scale, (offx, offy))
464    
465      def FitMapToWindow(self):      def FitMapToWindow(self):
466          """\          """Fit the map to the window
467          Set the scale and offset so that the map is centered in the          
468          window          Set the scale so that the map fits exactly into the window and
469            center it in the window.
470          """          """
471          bbox = self.map.ProjectedBoundingBox()          bbox = self.map.ProjectedBoundingBox()
472          if bbox is not None:          if bbox is not None:
473              self.FitRectToWindow(bbox)              self.FitRectToWindow(bbox)
474    
475      def ZoomFactor(self, factor):      def ZoomFactor(self, factor, center = None):
476            """Multiply the zoom by factor and center on center.
477    
478            The optional parameter center is a point in window coordinates
479            that should be centered. If it is omitted, it defaults to the
480            center of the window
481            """
482          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
483          scale = self.scale * factor          scale = self.scale * factor
484          offx, offy = self.offset          offx, offy = self.offset
485          offset = (factor * (offx - width / 2) + width / 2,          if center is not None:
486                    factor * (offy - height / 2) + height / 2)              cx, cy = center
487            else:
488                cx = width / 2
489                cy = height / 2
490            offset = (factor * (offx - cx) + width / 2,
491                      factor * (offy - cy) + height / 2)
492          self.set_view_transform(scale, offset)          self.set_view_transform(scale, offset)
493    
494      def ZoomOutToRect(self, rect):      def ZoomOutToRect(self, rect):
495          # rect is given in window coordinates          """Zoom out to fit the currently visible region into rect.
496    
497            The rect parameter is given in window coordinates
498            """
499          # determine the bbox of the displayed region in projected          # determine the bbox of the displayed region in projected
500          # coordinates          # coordinates
501          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
# Line 401  class MapCanvas(wxWindow): Line 533  class MapCanvas(wxWindow):
533      def CurrentTool(self):      def CurrentTool(self):
534          return self.tool and self.tool.Name() or None          return self.tool and self.tool.Name() or None
535    
536        def CurrentPosition(self):
537            """Return current position of the mouse in projected coordinates.
538    
539            The result is a 2-tuple of floats with the coordinates. If the
540            mouse is not in the window, the result is None.
541            """
542            if self.current_position is not None:
543                x, y = self.current_position
544                return self.win_to_proj(x, y)
545            else:
546                return None
547    
548        def set_current_position(self, event):
549            """Set the current position from event
550    
551            Should be called by all events that contain mouse positions
552            especially EVT_MOTION. The event paramete may be None to
553            indicate the the pointer left the window.
554            """
555            if event is not None:
556                self.current_position = (event.m_x, event.m_y)
557            else:
558                self.current_position = None
559            self.issue(VIEW_POSITION)
560    
561      def OnLeftDown(self, event):      def OnLeftDown(self, event):
562            self.set_current_position(event)
563          if self.tool is not None:          if self.tool is not None:
564              self.drag_dc = wxClientDC(self)              self.drag_dc = wxClientDC(self)
565              self.drag_dc.SetLogicalFunction(wxINVERT)              self.drag_dc.SetLogicalFunction(wxINVERT)
# Line 410  class MapCanvas(wxWindow): Line 568  class MapCanvas(wxWindow):
568              self.tool.MouseDown(event)              self.tool.MouseDown(event)
569              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
570              self.dragging = 1              self.dragging = 1
571            
572      def OnLeftUp(self, event):      def OnLeftUp(self, event):
573          self.ReleaseMouse()          self.set_current_position(event)
574          if self.dragging:          if self.dragging:
575                self.ReleaseMouse()
576              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
577              self.tool.MouseUp(event)              self.tool.MouseUp(event)
578              self.drag_dc = None              self.drag_dc = None
579          self.dragging = 0          self.dragging = 0
580    
581      def OnMotion(self, event):      def OnMotion(self, event):
582            self.set_current_position(event)
583          if self.dragging:          if self.dragging:
584              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
585              self.tool.MouseMove(event)              self.tool.MouseMove(event)
586              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
587    
588        def OnLeaveWindow(self, event):
589            self.set_current_position(None)
590    
591      def OnIdle(self, event):      def OnIdle(self, event):
592          if self.redraw_on_idle:          if self.redraw_on_idle:
593              self.do_redraw()              self.do_redraw()
594          self.redraw_on_idle = 0          self.redraw_on_idle = 0
595    
596        def OnSize(self, event):
597            # the window's size has changed. We have to get a new bitmap. If
598            # we want to be clever we could try to get by without throwing
599            # everything away. E.g. when the window gets smaller, we could
600            # either keep the bitmap or create the new one from the old one.
601            # Even when the window becomes larger some parts of the bitmap
602            # could be reused.
603            self.full_redraw()
604    
605      def shape_selected(self, layer, shape):      def shape_selected(self, layer, shape):
606          self.redraw()          """Redraw the map.
607    
608            Receiver for the SELECTED_SHAPE messages. Try to redraw only
609            when necessary.
610            """
611            # A redraw is necessary when the display has to change, which
612            # means that either the status changes from having no selection
613            # to having a selection shape or vice versa, or when the fact
614            # whether there is a selection at all doesn't change, when the
615            # shape which is selected has changed (which means that layer or
616            # shapeid changes).
617            if ((shape is not None or self.last_selected_shape is not None)
618                and (shape != self.last_selected_shape
619                     or layer != self.last_selected_layer)):
620                self.full_redraw()
621    
622            # remember the selection so we can compare when it changes again.
623            self.last_selected_layer = layer
624            self.last_selected_shape = shape
625    
626        def unprojected_rect_around_point(self, x, y):
627            """return a rect a few pixels around (x, y) in unprojected corrdinates
628    
629            The return value is a tuple (minx, miny, maxx, maxy) suitable a
630            parameter to a layer's ShapesInRegion method.
631            """
632            map_proj = self.map.projection
633            if map_proj is not None:
634                inverse = map_proj.Inverse
635            else:
636                inverse = None
637    
638            xs = []
639            ys = []
640            for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
641                px, py = self.win_to_proj(x + dx, y + dy)
642                if inverse:
643                    px, py = inverse(px, py)
644                xs.append(px)
645                ys.append(py)
646            return (min(xs), min(ys), max(xs), max(ys))
647    
648      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):
649          """Determine the shape at point px, py in window coords          """Determine the shape at point px, py in window coords
650    
651          Return the shape and the corresponding layer as a tuple (layer,          Return the shape and the corresponding layer as a tuple (layer,
# Line 443  class MapCanvas(wxWindow): Line 655  class MapCanvas(wxWindow):
655          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
656          as the shape and None as the layer.          as the shape and None as the layer.
657    
658          If the optional parameter selected_layer is true (default), only          If the optional parameter searched_layer is given (or not None
659          search in the currently selected layer.          which it defaults to), only search in that layer.
660          """          """
661          map_proj = self.map.projection          map_proj = self.map.projection
662          if map_proj is not None:          if map_proj is not None:
# Line 455  class MapCanvas(wxWindow): Line 667  class MapCanvas(wxWindow):
667          scale = self.scale          scale = self.scale
668          offx, offy = self.offset          offx, offy = self.offset
669    
670            box = self.unprojected_rect_around_point(px, py)
671    
672          if select_labels:          if select_labels:
673              labels = self.map.LabelLayer().Labels()              labels = self.map.LabelLayer().Labels()
674                
675              if labels:              if labels:
676                  dc = wxClientDC(self)                  dc = wxClientDC(self)
677                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
678                  dc.SetFont(font)                  dc.SetFont(font)
679                  for i in range(len(labels)):                  for i in range(len(labels) - 1, -1, -1):
680                      label = labels[i]                      label = labels[i]
681                      x = label.x                      x = label.x
682                      y = label.y                      y = label.y
# Line 489  class MapCanvas(wxWindow): Line 703  class MapCanvas(wxWindow):
703                      if x <= px < x + width and y <= py <= y + height:                      if x <= px < x + width and y <= py <= y + height:
704                          return None, i                          return None, i
705    
706          if selected_layer:          if searched_layer:
707              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 = []  
708          else:          else:
709              layers = self.map.Layers()              layers = self.map.Layers()
710    
# Line 509  class MapCanvas(wxWindow): Line 717  class MapCanvas(wxWindow):
717    
718              filled = layer.fill is not None              filled = layer.fill is not None
719              stroked = layer.stroke is not None              stroked = layer.stroke is not None
720                    
721              layer_proj = layer.projection              layer_proj = layer.projection
722              if layer_proj is not None:              if layer_proj is not None:
723                  inverse = layer_proj.Inverse                  inverse = layer_proj.Inverse
724              else:              else:
725                  inverse = None                  inverse = None
726                    
727              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
728    
729              select_shape = -1              select_shape = -1
730    
731                shape_ids = layer.ShapesInRegion(box)
732                shape_ids.reverse()
733    
734              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
735                  for i in range(layer.NumShapes()):                  for i in shape_ids:
736                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
737                                                      i,                                                      i,
738                                                      filled, stroked,                                                      filled, stroked,
# Line 531  class MapCanvas(wxWindow): Line 743  class MapCanvas(wxWindow):
743                          select_shape = i                          select_shape = i
744                          break                          break
745              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
746                  for i in range(layer.NumShapes()):                  for i in shape_ids:
747                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
748                                                      i, 0, 1,                                                      i, 0, 1,
749                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
# Line 541  class MapCanvas(wxWindow): Line 753  class MapCanvas(wxWindow):
753                          select_shape = i                          select_shape = i
754                          break                          break
755              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
756                  for i in range(layer.NumShapes()):                  for i in shape_ids:
757                      shape = layer.Shape(i)                      shape = layer.Shape(i)
758                      x, y = shape.Points()[0]                      x, y = shape.Points()[0]
759                      if inverse:                      if inverse:
# Line 558  class MapCanvas(wxWindow): Line 770  class MapCanvas(wxWindow):
770                  return layer, select_shape                  return layer, select_shape
771          return None, None          return None, None
772    
773      def SelectShapeAt(self, x, y):      def SelectShapeAt(self, x, y, layer = None):
774          layer, shape = self.find_shape_at(x, y)          """\
775            Select and return the shape and its layer at window position (x, y)
776    
777            If layer is given, only search in that layer. If no layer is
778            given, search through all layers.
779    
780            Return a tuple (layer, shapeid). If no shape is found, return
781            (None, None).
782            """
783            layer, shape = result = self.find_shape_at(x, y, searched_layer=layer)
784          # 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
785          # to deselect the currently selected layer, so we simply select          # to deselect the currently selected layer, so we simply select
786          # the already selected layer again.          # the already selected layer again.
787          if layer is None:          if layer is None:
788              layer = self.interactor.SelectedLayer()              layer = self.interactor.SelectedLayer()
789          self.interactor.SelectLayerAndShape(layer, shape)          self.interactor.SelectLayerAndShape(layer, shape)
790            return result
791    
792      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):
793          ox = x; oy = y          ox = x; oy = y

Legend:
Removed from v.43  
changed lines
  Added in v.293

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26