/[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 23 by bh, Wed Sep 5 13:35:22 2001 UTC revision 122 by bh, Mon Apr 29 18:04:54 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 and sy == cy:
133                    # Just a mouse click. Simply zoom in by a factor of two
134                    self.view.ZoomFactor(2, center = (cx, cy))
135                else:
136                    # A drag. Zoom in to the rectangle
137                    self.view.FitRectToWindow(self.proj_rect())
138    
139    
140  class ZoomOutTool(RectTool):  class ZoomOutTool(RectTool):
# Line 142  class ZoomOutTool(RectTool): Line 149  class ZoomOutTool(RectTool):
149              Tool.MouseUp(self, event)              Tool.MouseUp(self, event)
150              sx, sy = self.start              sx, sy = self.start
151              cx, cy = self.current              cx, cy = self.current
152              self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),              if sx == cx and sy == cy:
153                                       max(sx, cx), max(sy, cy)))                  # Just a mouse click. Simply zoom out by a factor of two
154                    self.view.ZoomFactor(0.5, center = (cy, cy))
155                else:
156                    # A drag. Zoom out to the rectangle
157                    self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
158                                             max(sx, cx), max(sy, cy)))
159    
160    
161  class PanTool(Tool):  class PanTool(Tool):
# Line 228  class MapPrintout(wx.wxPrintout): Line 240  class MapPrintout(wx.wxPrintout):
240          return wx.true          return wx.true
241                    
242    
243  class MapCanvas(wxWindow):  class MapCanvas(wxWindow, Publisher):
244    
245      """A widget that displays a map and offers some interaction"""      """A widget that displays a map and offers some interaction"""
246    
# Line 241  class MapCanvas(wxWindow): Line 253  class MapCanvas(wxWindow):
253          self.dragging = 0          self.dragging = 0
254          self.tool = None          self.tool = None
255          self.redraw_on_idle = 0          self.redraw_on_idle = 0
256            self.current_position = None
257          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
258          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
259          EVT_LEFT_UP(self, self.OnLeftUp)          EVT_LEFT_UP(self, self.OnLeftUp)
260          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
261            EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
262          wx.EVT_IDLE(self, self.OnIdle)          wx.EVT_IDLE(self, self.OnIdle)
263          self.interactor = interactor          self.interactor = interactor
264          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)          self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)
265    
266        def __del__(self):
267            wxWindow.__del__(self)
268            Publisher.__del__(self)
269    
270      def OnPaint(self, event):      def OnPaint(self, event):
271          dc = wxPaintDC(self)          dc = wxPaintDC(self)
272          if self.map is None or not self.map.HasLayers():          if self.map is not None and self.map.HasLayers():
273              return              # We have a non-empty map. Redraw it in idle time
274          self.redraw_on_idle = 1              self.redraw_on_idle = 1
275            else:
276                # If we've got no map or if the map is empty, simply clear
277                # the screen.
278                
279                # XXX it's probably possible to get rid of this. The
280                # background color of the window is already white and the
281                # only thing we may have to do is to call self.Refresh()
282                # with a true argument in the right places.
283                dc.BeginDrawing()
284                dc.Clear()            
285                dc.EndDrawing()
286    
287      def do_redraw(self):      def do_redraw(self):
288            # This should only be called if we have a non-empty map. We draw
289            # it into a memory DC and then blit it to the screen.
290          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
291          bitmap = wx.wxEmptyBitmap(width, height)          bitmap = wx.wxEmptyBitmap(width, height)
   
292          dc = wx.wxMemoryDC()          dc = wx.wxMemoryDC()
293          dc.SelectObject(bitmap)          dc.SelectObject(bitmap)
   
294          dc.BeginDrawing()          dc.BeginDrawing()
295    
296            # clear the background
297          dc.SetBrush(wx.wxWHITE_BRUSH)          dc.SetBrush(wx.wxWHITE_BRUSH)
298          dc.SetPen(wx.wxTRANSPARENT_PEN)          dc.SetPen(wx.wxTRANSPARENT_PEN)
299          dc.DrawRectangle(0, 0, width, height)          dc.DrawRectangle(0, 0, width, height)
# Line 274  class MapCanvas(wxWindow): Line 304  class MapCanvas(wxWindow):
304          else:          else:
305              selected_layer = None              selected_layer = None
306              selected_shape = None              selected_shape = None
307                
308            # draw the map into the bitmap
309          renderer = ScreenRenderer(dc, self.scale, self.offset)          renderer = ScreenRenderer(dc, self.scale, self.offset)
310          renderer.RenderMap(self.map, selected_layer, selected_shape)          renderer.RenderMap(self.map, selected_layer, selected_shape)
311    
312            dc.EndDrawing()
313    
314            # blit the bitmap to the screen
315          clientdc = wxClientDC(self)          clientdc = wxClientDC(self)
316          clientdc.BeginDrawing()          clientdc.BeginDrawing()
317          clientdc.Blit(0, 0, width, height, dc, 0, 0)          clientdc.Blit(0, 0, width, height, dc, 0, 0)
318          clientdc.EndDrawing()          clientdc.EndDrawing()
319    
   
320      def Print(self):      def Print(self):
321          printer = wx.wxPrinter()          printer = wx.wxPrinter()
322          printout = MapPrintout(self.map)          printout = MapPrintout(self.map)
# Line 304  class MapCanvas(wxWindow): Line 337  class MapCanvas(wxWindow):
337                  self.map.Subscribe(channel, self.redraw)                  self.map.Subscribe(channel, self.redraw)
338              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)
339          self.FitMapToWindow()          self.FitMapToWindow()
340            # force a redraw. If map is not empty, it's already been called
341            # by FitMapToWindow but if map is empty it hasn't been called
342            # yet so we have to explicitly call it.
343            self.redraw()
344    
345      def Map(self):      def Map(self):
346          return self.map          return self.map
# Line 337  class MapCanvas(wxWindow): Line 374  class MapCanvas(wxWindow):
374      def FitRectToWindow(self, rect):      def FitRectToWindow(self, rect):
375          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
376          llx, lly, urx, ury = rect          llx, lly, urx, ury = rect
377            if llx == urx or lly == ury:
378                # zero with or zero height. Do Nothing
379                return
380          scalex = width / (urx - llx)          scalex = width / (urx - llx)
381          scaley = height / (ury - lly)          scaley = height / (ury - lly)
382          scale = min(scalex, scaley)          scale = min(scalex, scaley)
# Line 353  class MapCanvas(wxWindow): Line 393  class MapCanvas(wxWindow):
393          if bbox is not None:          if bbox is not None:
394              self.FitRectToWindow(bbox)              self.FitRectToWindow(bbox)
395    
396      def ZoomFactor(self, factor):      def ZoomFactor(self, factor, center = None):
397            """Multiply the zoom by factor and center on center.
398    
399            The optional parameter center is a point in window coordinates
400            that should be centered. If it is omitted, it defaults to the
401            center of the window
402            """
403          width, height = self.GetSizeTuple()          width, height = self.GetSizeTuple()
404          scale = self.scale * factor          scale = self.scale * factor
405          offx, offy = self.offset          offx, offy = self.offset
406          offset = (factor * (offx - width / 2) + width / 2,          if center is not None:
407                    factor * (offy - height / 2) + height / 2)              cx, cy = center
408            else:
409                cx = width / 2
410                cy = height / 2
411            offset = (factor * (offx - cx) + width / 2,
412                      factor * (offy - cy) + height / 2)
413          self.set_view_transform(scale, offset)          self.set_view_transform(scale, offset)
414    
415      def ZoomOutToRect(self, rect):      def ZoomOutToRect(self, rect):
# Line 401  class MapCanvas(wxWindow): Line 452  class MapCanvas(wxWindow):
452      def CurrentTool(self):      def CurrentTool(self):
453          return self.tool and self.tool.Name() or None          return self.tool and self.tool.Name() or None
454    
455        def CurrentPosition(self):
456            """Return current position of the mouse in projected coordinates.
457    
458            The result is a 2-tuple of floats with the coordinates. If the
459            mouse is not in the window, the result is None.
460            """
461            if self.current_position is not None:
462                x, y = self.current_position
463                return self.win_to_proj(x, y)
464            else:
465                return None
466    
467        def set_current_position(self, event):
468            """Set the current position from event
469    
470            Should be called by all events that contain mouse positions
471            especially EVT_MOTION. The event paramete may be None to
472            indicate the the pointer left the window.
473            """
474            if event is not None:
475                self.current_position = (event.m_x, event.m_y)
476            else:
477                self.current_position = None
478            self.issue(VIEW_POSITION)
479    
480      def OnLeftDown(self, event):      def OnLeftDown(self, event):
481            self.set_current_position(event)
482          if self.tool is not None:          if self.tool is not None:
483              self.drag_dc = wxClientDC(self)              self.drag_dc = wxClientDC(self)
484              self.drag_dc.SetLogicalFunction(wxINVERT)              self.drag_dc.SetLogicalFunction(wxINVERT)
# Line 413  class MapCanvas(wxWindow): Line 490  class MapCanvas(wxWindow):
490                    
491      def OnLeftUp(self, event):      def OnLeftUp(self, event):
492          self.ReleaseMouse()          self.ReleaseMouse()
493            self.set_current_position(event)
494          if self.dragging:          if self.dragging:
495              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
496              self.tool.MouseUp(event)              self.tool.MouseUp(event)
# Line 420  class MapCanvas(wxWindow): Line 498  class MapCanvas(wxWindow):
498          self.dragging = 0          self.dragging = 0
499    
500      def OnMotion(self, event):      def OnMotion(self, event):
501            self.set_current_position(event)
502          if self.dragging:          if self.dragging:
503              self.tool.Hide(self.drag_dc)              self.tool.Hide(self.drag_dc)
504              self.tool.MouseMove(event)              self.tool.MouseMove(event)
505              self.tool.Show(self.drag_dc)              self.tool.Show(self.drag_dc)
506    
507        def OnLeaveWindow(self, event):
508            self.set_current_position(None)
509    
510      def OnIdle(self, event):      def OnIdle(self, event):
511          if self.redraw_on_idle:          if self.redraw_on_idle:
512              self.do_redraw()              self.do_redraw()
# Line 433  class MapCanvas(wxWindow): Line 515  class MapCanvas(wxWindow):
515      def shape_selected(self, layer, shape):      def shape_selected(self, layer, shape):
516          self.redraw()          self.redraw()
517    
518      def find_shape_at(self, px, py, select_labels = 0):      def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):
519          """Return a tuple shape at point px, py in window coords."""          """Determine the shape at point px, py in window coords
520    
521            Return the shape and the corresponding layer as a tuple (layer,
522            shape).
523    
524            If the optional parameter select_labels is true (default false)
525            search through the labels. If a label is found return it's index
526            as the shape and None as the layer.
527    
528            If the optional parameter selected_layer is true (default), only
529            search in the currently selected layer.
530            """
531          map_proj = self.map.projection          map_proj = self.map.projection
532          if map_proj is not None:          if map_proj is not None:
533              forward = map_proj.Forward              forward = map_proj.Forward
# Line 451  class MapCanvas(wxWindow): Line 544  class MapCanvas(wxWindow):
544                  dc = wxClientDC(self)                  dc = wxClientDC(self)
545                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)                  font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
546                  dc.SetFont(font)                  dc.SetFont(font)
547                  for i in range(len(labels)):                  for i in range(len(labels) - 1, -1, -1):
548                      label = labels[i]                      label = labels[i]
549                      x = label.x                      x = label.x
550                      y = label.y                      y = label.y
# Line 477  class MapCanvas(wxWindow): Line 570  class MapCanvas(wxWindow):
570                          y = y - height/2                          y = y - height/2
571                      if x <= px < x + width and y <= py <= y + height:                      if x <= px < x + width and y <= py <= y + height:
572                          return None, i                          return None, i
573                    
574          layers = self.map.Layers()          if selected_layer:
575                layer = self.interactor.SelectedLayer()
576                if layer is not None:
577                    layers = [layer]
578                else:
579                    # no layer selected. Use an empty list to effectively
580                    # ignore all layers.
581                    layers = []
582            else:
583                layers = self.map.Layers()
584    
585          for layer_index in range(len(layers) - 1, -1, -1):          for layer_index in range(len(layers) - 1, -1, -1):
586              layer = layers[layer_index]              layer = layers[layer_index]
587    
# Line 499  class MapCanvas(wxWindow): Line 602  class MapCanvas(wxWindow):
602    
603              select_shape = -1              select_shape = -1
604              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
605                  for i in range(layer.NumShapes()):                  for i in range(layer.NumShapes() - 1, -1, -1):
606                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
607                                                      i,                                                      i,
608                                                      filled, stroked,                                                      filled, stroked,
# Line 510  class MapCanvas(wxWindow): Line 613  class MapCanvas(wxWindow):
613                          select_shape = i                          select_shape = i
614                          break                          break
615              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
616                  for i in range(layer.NumShapes()):                  for i in range(layer.NumShapes() - 1, -1, -1):
617                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      result = point_in_polygon_shape(layer.shapefile.cobject(),
618                                                      i, 0, 1,                                                      i, 0, 1,
619                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
# Line 520  class MapCanvas(wxWindow): Line 623  class MapCanvas(wxWindow):
623                          select_shape = i                          select_shape = i
624                          break                          break
625              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
626                  for i in range(layer.NumShapes()):                  for i in range(layer.NumShapes() - 1, -1, -1):
627                      shape = layer.Shape(i)                      shape = layer.Shape(i)
628                      x, y = shape.Points()[0]                      x, y = shape.Points()[0]
629                      if inverse:                      if inverse:
# Line 538  class MapCanvas(wxWindow): Line 641  class MapCanvas(wxWindow):
641          return None, None          return None, None
642    
643      def SelectShapeAt(self, x, y):      def SelectShapeAt(self, x, y):
644          layer, shape = self.find_shape_at(x, y)          layer, shape = self.find_shape_at(x, y, selected_layer = 0)
645            # If layer is None, then shape will also be None. We don't want
646            # to deselect the currently selected layer, so we simply select
647            # the already selected layer again.
648            if layer is None:
649                layer = self.interactor.SelectedLayer()
650          self.interactor.SelectLayerAndShape(layer, shape)          self.interactor.SelectLayerAndShape(layer, shape)
651    
652      def LabelShapeAt(self, x, y):      def LabelShapeAt(self, x, y):

Legend:
Removed from v.23  
changed lines
  Added in v.122

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26