/[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 45 by bh, Fri Sep 7 15:00:21 2001 UTC revision 303 by bh, Mon Sep 2 16:47:53 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          self.redraw_on_idle = 0  
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            # the bitmap serving as backing store
283            self.bitmap = None
284    
285            # the interactor
286            self.interactor = interactor
287            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
295          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
296          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
297          EVT_LEFT_UP(self, self.OnLeftUp)          EVT_LEFT_UP(self, self.OnLeftUp)
298          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
299          wx.EVT_IDLE(self, self.OnIdle)          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
300          self.interactor = interactor          wx.EVT_SIZE(self, self.OnSize)
301          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)  
302        def __del__(self):
303            wxWindow.__del__(self)
304            Publisher.__del__(self)
305    
306      def OnPaint(self, event):      def OnPaint(self, event):
307          dc = wxPaintDC(self)          dc = wxPaintDC(self)
308          if self.map is None or not self.map.HasLayers():          if self.map is not None and self.map.HasLayers():
309              return              self.do_redraw()
310          self.redraw_on_idle = 1          else:
311                # If we've got no map or if the map is empty, simply clear
312                # the screen.
313    
314                # XXX it's probably possible to get rid of this. The
315                # background color of the window is already white and the
316                # only thing we may have to do is to call self.Refresh()
317                # with a true argument in the right places.
318                dc.BeginDrawing()
319                dc.Clear()
320                dc.EndDrawing()
321    
322      def do_redraw(self):      def do_redraw(self):
323            # This should only be called if we have a non-empty map.
324    
325            # Get the window size.
326          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
         bitmap = wx.wxEmptyBitmap(width, height)  
327    
328          dc = wx.wxMemoryDC()          # If self.bitmap's still there, reuse it. Otherwise redraw it
329          dc.SelectObject(bitmap)          if self.bitmap is not None:
330                bitmap = self.bitmap
331            else:
332                bitmap = wx.wxEmptyBitmap(width, height)
333                dc = wx.wxMemoryDC()
334                dc.SelectObject(bitmap)
335                dc.BeginDrawing()
336    
337                # clear the background
338                dc.SetBrush(wx.wxWHITE_BRUSH)
339                dc.SetPen(wx.wxTRANSPARENT_PEN)
340                dc.DrawRectangle(0, 0, width, height)
341    
342                if 1: #self.interactor.selected_map is self.map:
343                    selected_layer = self.interactor.selected_layer
344                    selected_shape = self.interactor.selected_shape
345                else:
346                    selected_layer = None
347                    selected_shape = None
348    
349          dc.BeginDrawing()              # draw the map into the bitmap
350                renderer = ScreenRenderer(dc, self.scale, self.offset)
351    
352          dc.SetBrush(wx.wxWHITE_BRUSH)              # Pass the entire bitmap as update region to the renderer.
353          dc.SetPen(wx.wxTRANSPARENT_PEN)              # We're redrawing the whole bitmap, after all.
354          dc.DrawRectangle(0, 0, width, height)              renderer.RenderMap(self.map, (0, 0, width, height),
355                                   selected_layer, selected_shape)
356          if 1: #self.interactor.selected_map is self.map:  
357              selected_layer = self.interactor.selected_layer              dc.EndDrawing()
358              selected_shape = self.interactor.selected_shape              dc.SelectObject(wx.wxNullBitmap)
359          else:              self.bitmap = bitmap
             selected_layer = None  
             selected_shape = None  
               
         renderer = ScreenRenderer(dc, self.scale, self.offset)  
         renderer.RenderMap(self.map, selected_layer, selected_shape)  
360    
361            # blit the bitmap to the screen
362            dc = wx.wxMemoryDC()
363            dc.SelectObject(bitmap)
364          clientdc = wxClientDC(self)          clientdc = wxClientDC(self)
365          clientdc.BeginDrawing()          clientdc.BeginDrawing()
366          clientdc.Blit(0, 0, width, height, dc, 0, 0)          clientdc.Blit(0, 0, width, height, dc, 0, 0)
367          clientdc.EndDrawing()          clientdc.EndDrawing()
368    
   
369      def Print(self):      def Print(self):
370          printer = wx.wxPrinter()          printer = wx.wxPrinter()
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)
378          if self.map is not None:          if self.map is not None:
379              for channel in redraw_channels:              for channel in redraw_channels:
380                  self.map.Unsubscribe(channel, self.redraw)                  self.map.Unsubscribe(channel, self.full_redraw)
381              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,
382                                   self.projection_changed)                                   self.projection_changed)
383          self.map = map          self.map = map
384          if self.map is not None:          if self.map is not None:
385              for channel in redraw_channels:              for channel in redraw_channels:
386                  self.map.Subscribe(channel, self.redraw)                  self.map.Subscribe(channel, self.full_redraw)
387              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)
388          self.FitMapToWindow()          self.FitMapToWindow()
389            # force a redraw. If map is not empty, it's already been called
390            # by FitMapToWindow but if map is empty it hasn't been called
391            # yet so we have to explicitly call it.
392            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):
399          self.Refresh(0)          self.Refresh(0)
400    
401        def full_redraw(self, *args):
402            self.bitmap = None
403            self.redraw()
404    
405      def projection_changed(self, *args):      def projection_changed(self, *args):
406          self.FitMapToWindow()          self.FitMapToWindow()
407          self.redraw()          self.full_redraw()
408    
409      def set_view_transform(self, scale, offset):      def set_view_transform(self, scale, offset):
410          self.scale = scale          self.scale = scale
411          self.offset = offset          self.offset = offset
412          self.redraw()          self.full_redraw()
413    
414      def proj_to_win(self, x, y):      def proj_to_win(self, x, y):
415          """\          """\
# Line 335  class MapCanvas(wxWindow): Line 426  class MapCanvas(wxWindow):
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 348  class MapCanvas(wxWindow): Line 444  class MapCanvas(wxWindow):
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:
454              self.FitRectToWindow(bbox)              self.FitRectToWindow(bbox)
455    
456      def ZoomFactor(self, factor):      def ZoomFactor(self, factor, center = None):
457            """Multiply the zoom by factor and center on center.
458    
459            The optional parameter center is a point in window coordinates
460            that should be centered. If it is omitted, it defaults to the
461            center of the window
462            """
463          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
464          scale = self.scale * factor          scale = self.scale * factor
465          offx, offy = self.offset          offx, offy = self.offset
466          offset = (factor * (offx - width / 2) + width / 2,          if center is not None:
467                    factor * (offy - height / 2) + height / 2)              cx, cy = center
468            else:
469                cx = width / 2
470                cy = height / 2
471            offset = (factor * (offx - cx) + width / 2,
472                      factor * (offy - cy) + height / 2)
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 383  class MapCanvas(wxWindow): Line 493  class MapCanvas(wxWindow):
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):
525            """Return current position of the mouse in projected coordinates.
526    
527            The result is a 2-tuple of floats with the coordinates. If the
528            mouse is not in the window, the result is None.
529            """
530            if self.current_position is not None:
531                x, y = self.current_position
532                return self.win_to_proj(x, y)
533            else:
534                return None
535    
536        def set_current_position(self, event):
537            """Set the current position from event
538    
539            Should be called by all events that contain mouse positions
540            especially EVT_MOTION. The event paramete may be None to
541            indicate the the pointer left the window.
542            """
543            if event is not None:
544                self.current_position = (event.m_x, event.m_y)
545            else:
546                self.current_position = None
547            self.issue(VIEW_POSITION)
548    
549      def OnLeftDown(self, event):      def OnLeftDown(self, event):
550            self.set_current_position(event)
551          if self.tool is not None:          if self.tool is not None:
552              self.drag_dc = wxClientDC(self)              self.drag_dc = wxClientDC(self)
553              self.drag_dc.SetLogicalFunction(wxINVERT)              self.drag_dc.SetLogicalFunction(wxINVERT)
# Line 413  class MapCanvas(wxWindow): Line 556  class MapCanvas(wxWindow):
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):
561          self.ReleaseMouse()          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
567          self.dragging = 0          self.dragging = 0
568    
569      def OnMotion(self, event):      def OnMotion(self, event):
570            self.set_current_position(event)
571          if self.dragging:          if self.dragging:
572              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
573              self.tool.MouseMove(event)              self.tool.MouseMove(event)
574              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
575    
576      def OnIdle(self, event):      def OnLeaveWindow(self, event):
577          if self.redraw_on_idle:          self.set_current_position(None)
578              self.do_redraw()  
579          self.redraw_on_idle = 0      def OnSize(self, event):
580            # 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
582            # everything away. E.g. when the window gets smaller, we could
583            # either keep the bitmap or create the new one from the old one.
584            # Even when the window becomes larger some parts of the bitmap
585            # could be reused.
586            self.full_redraw()
587    
588      def shape_selected(self, layer, shape):      def shape_selected(self, layer, shape):
589          self.redraw()          """Redraw the map.
590    
591      def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):          Receiver for the SELECTED_SHAPE messages. Try to redraw only
592            when necessary.
593            """
594            # A redraw is necessary when the display has to change, which
595            # means that either the status changes from having no selection
596            # to having a selection shape or vice versa, or when the fact
597            # whether there is a selection at all doesn't change, when the
598            # shape which is selected has changed (which means that layer or
599            # shapeid changes).
600            if ((shape is not None or self.last_selected_shape is not None)
601                and (shape != self.last_selected_shape
602                     or layer != self.last_selected_layer)):
603                self.full_redraw()
604    
605            # remember the selection so we can compare when it changes again.
606            self.last_selected_layer = layer
607            self.last_selected_shape = shape
608    
609        def unprojected_rect_around_point(self, x, y, dist):
610            """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
613            parameter to a layer's ShapesInRegion method.
614            """
615            map_proj = self.map.projection
616            if map_proj is not None:
617                inverse = map_proj.Inverse
618            else:
619                inverse = None
620    
621            xs = []
622            ys = []
623            for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
624                px, py = self.win_to_proj(x + dist * dx, y + dist * dy)
625                if inverse:
626                    px, py = inverse(px, py)
627                xs.append(px)
628                ys.append(py)
629            return (min(xs), min(ys), max(xs), max(ys))
630    
631        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 446  class MapCanvas(wxWindow): Line 638  class MapCanvas(wxWindow):
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 460  class MapCanvas(wxWindow): Line 652  class MapCanvas(wxWindow):
652    
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)
659                  dc.SetFont(font)                  dc.SetFont(font)
660                  for i in range(len(labels)):                  for i in range(len(labels) - 1, -1, -1):
661                      label = labels[i]                      label = labels[i]
662                      x = label.x                      x = label.x
663                      y = label.y                      y = label.y
# Line 492  class MapCanvas(wxWindow): Line 684  class MapCanvas(wxWindow):
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 512  class MapCanvas(wxWindow): Line 698  class MapCanvas(wxWindow):
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)
723                shape_ids.reverse()
724    
725              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
726                  for i in range(layer.NumShapes()):                  for i in shape_ids:
727                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
728                                                      i,                                                      i,
729                                                      filled, stroked,                                                      filled, stroked,
# Line 534  class MapCanvas(wxWindow): Line 734  class MapCanvas(wxWindow):
734                          select_shape = i                          select_shape = i
735                          break                          break
736              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
737                  for i in range(layer.NumShapes()):                  for i in shape_ids:
738                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
739                                                      i, 0, 1,                                                      i, 0, 1,
740                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
# Line 544  class MapCanvas(wxWindow): Line 744  class MapCanvas(wxWindow):
744                          select_shape = i                          select_shape = i
745                          break                          break
746              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
747                  for i in range(layer.NumShapes()):                  for i in shape_ids:
748                      shape = layer.Shape(i)                      shape = layer.Shape(i)
749                      x, y = shape.Points()[0]                      x, y = shape.Points()[0]
750                      if inverse:                      if inverse:
# Line 561  class MapCanvas(wxWindow): Line 761  class MapCanvas(wxWindow):
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)          """\
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.45  
changed lines
  Added in v.303

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26