]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/floatcanvas/GUIMode.py
Forward port recent changes on the 2.8 branch to HEAD
[wxWidgets.git] / wxPython / wx / lib / floatcanvas / GUIMode.py
diff --git a/wxPython/wx/lib/floatcanvas/GUIMode.py b/wxPython/wx/lib/floatcanvas/GUIMode.py
new file mode 100644 (file)
index 0000000..08ca473
--- /dev/null
@@ -0,0 +1,347 @@
+"""
+
+Module that holds the GUI modes used by FloatCanvas
+
+
+Note that this can only be imported after a wx.App() has been created.
+
+This approach was inpired by Christian Blouin, who also wrote the initial
+version of the code.
+
+"""
+
+import wx
+## fixme: events should live in their own module, so all of FloatCanvas
+##        wouldn't have to be imported here.
+import FloatCanvas, Resources
+import numpy as N
+
+## create all the Cursors, so they don't need to be created each time.
+if "wxMac" in wx.PlatformInfo: # use 16X16 cursors for wxMac
+    HandCursor = wx.CursorFromImage(Resources.getHand16Image())
+    GrabHandCursor = wx.CursorFromImage(Resources.getGrabHand16Image())
+
+    img = Resources.getMagPlus16Image()
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 6)
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 6)
+    MagPlusCursor = wx.CursorFromImage(img)
+
+    img = Resources.getMagMinus16Image()
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 6)
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 6)
+    MagMinusCursor = wx.CursorFromImage(img)
+else: # use 24X24 cursors for GTK and Windows
+    HandCursor = wx.CursorFromImage(Resources.getHandImage())
+    GrabHandCursor = wx.CursorFromImage(Resources.getGrabHandImage())
+
+    img = Resources.getMagPlusImage()
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 9)
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 9)
+    MagPlusCursor = wx.CursorFromImage(img)
+
+    img = Resources.getMagMinusImage()
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 9)
+    img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 9)
+    MagMinusCursor = wx.CursorFromImage(img)
+
+
+class GUIBase:
+    """
+    Basic Mouse mode and baseclass for other GUImode.
+
+    This one does nothing with any event
+
+    """
+    def __init__(self, parent):
+        self.parent = parent
+    
+    Cursor = wx.NullCursor
+
+    # Handlers
+    def OnLeftDown(self, event):
+        pass
+    def OnLeftUp(self, event):
+        pass
+    def OnLeftDouble(self, event):
+        pass
+    def OnRightDown(self, event):
+        pass
+    def OnRightUp(self, event):
+        pass
+    def OnRightDouble(self, event):
+        pass
+    def OnMiddleDown(self, event):
+        pass
+    def OnMiddleUp(self, event):
+        pass
+    def OnMiddleDouble(self, event):
+        pass
+    def OnWheel(self, event):
+        pass
+    def OnMove(self, event):
+        pass
+            
+    def UpdateScreen(self):
+        """
+        Update gets called if the screen has been repainted in the middle of a zoom in
+        so the Rubber Band Box can get updated
+        """
+        pass
+
+class GUIMouse(GUIBase):
+    """
+
+    Mouse mode checks for a hit test, and if nothing is hit,
+    raises a FloatCanvas mouse event for each event.
+
+    """
+
+    Cursor = wx.NullCursor
+
+    # Handlers
+    def OnLeftDown(self, event):
+        EventType = FloatCanvas.EVT_FC_LEFT_DOWN
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnLeftUp(self, event):
+        EventType = FloatCanvas.EVT_FC_LEFT_UP
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnLeftDouble(self, event):
+        EventType = FloatCanvas.EVT_FC_LEFT_DCLICK
+        if not self.parent.HitTest(event, EventType):
+                self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnMiddleDown(self, event):
+        EventType = FloatCanvas.EVT_FC_MIDDLE_DOWN
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnMiddleUp(self, event):
+        EventType = FloatCanvas.EVT_FC_MIDDLE_UP
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnMiddleDouble(self, event):
+        EventType = FloatCanvas.EVT_FC_MIDDLE_DCLICK
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnRightDown(self, event):
+        EventType = FloatCanvas.EVT_FC_RIGHT_DOWN
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnRightUp(self, event):
+        EventType = FloatCanvas.EVT_FC_RIGHT_UP
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnRightDouble(self, event):
+        EventType = FloatCanvas.EVT_FC_RIGHT_DCLICK
+        if not self.parent.HitTest(event, EventType):
+            self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnWheel(self, event):
+        EventType = FloatCanvas.EVT_FC_MOUSEWHEEL
+        self.parent._RaiseMouseEvent(event, EventType)
+
+    def OnMove(self, event):
+        ## The Move event always gets raised, even if there is a hit-test
+        self.parent.MouseOverTest(event)
+        self.parent._RaiseMouseEvent(event,FloatCanvas.EVT_FC_MOTION)
+
+
+class GUIMove(GUIBase):
+
+    Cursor = HandCursor
+    GrabCursor = GrabHandCursor
+    def __init__(self, parent):
+        GUIBase.__init__(self, parent)
+        self.StartMove = None
+        self.PrevMoveXY = None
+
+    def OnLeftDown(self, event):
+        self.parent.SetCursor(self.GrabCursor)
+        self.parent.CaptureMouse()
+        self.StartMove = N.array( event.GetPosition() )
+        self.PrevMoveXY = (0,0)
+
+    def OnLeftUp(self, event):
+        if self.StartMove is not None:
+            StartMove = self.StartMove
+            EndMove = N.array(event.GetPosition())
+            DiffMove = StartMove-EndMove
+            if N.sum(DiffMove**2) > 16:
+                self.parent.MoveImage(DiffMove, 'Pixel')
+            self.StartMove = None
+        self.parent.SetCursor(self.Cursor)
+
+    def OnMove(self, event):
+        # Allways raise the Move event.
+        self.parent._RaiseMouseEvent(event,FloatCanvas.EVT_FC_MOTION)
+        if event.Dragging() and event.LeftIsDown() and not self.StartMove is None:
+            xy1 = N.array( event.GetPosition() )
+            wh = self.parent.PanelSize
+            xy_tl = xy1 - self.StartMove
+            dc = wx.ClientDC(self.parent)
+            dc.BeginDrawing()
+            x1,y1 = self.PrevMoveXY
+            x2,y2 = xy_tl
+            w,h = self.parent.PanelSize
+            ##fixme: This sure could be cleaner!
+            if x2 > x1 and y2 > y1:
+                xa = xb = x1
+                ya = yb = y1
+                wa = w
+                ha = y2 - y1
+                wb = x2-  x1
+                hb = h
+            elif x2 > x1 and y2 <= y1:
+                xa = x1
+                ya = y1
+                wa = x2 - x1
+                ha = h
+                xb = x1
+                yb = y2 + h
+                wb = w
+                hb = y1 - y2
+            elif x2 <= x1 and y2 > y1:
+                xa = x1
+                ya = y1
+                wa = w
+                ha = y2 - y1
+                xb = x2 + w
+                yb = y1
+                wb = x1 - x2
+                hb = h - y2 + y1
+            elif x2 <= x1 and y2 <= y1:
+                xa = x2 + w
+                ya = y1
+                wa = x1 - x2
+                ha = h
+                xb = x1
+                yb = y2 + h
+                wb = w
+                hb = y1 - y2
+
+            dc.SetPen(wx.TRANSPARENT_PEN)
+            dc.SetBrush(self.parent.BackgroundBrush)
+            dc.DrawRectangle(xa, ya, wa, ha)
+            dc.DrawRectangle(xb, yb, wb, hb)
+            self.PrevMoveXY = xy_tl
+            if self.parent._ForeDrawList:
+                dc.DrawBitmapPoint(self.parent._ForegroundBuffer,xy_tl)
+            else:
+                dc.DrawBitmapPoint(self.parent._Buffer,xy_tl)
+            dc.EndDrawing()
+
+    def OnWheel(self, event):
+        """
+           By default, zoom in/out by a 0.1 factor per Wheel event.
+        """
+        if event.GetWheelRotation() < 0:
+            self.parent.Zoom(0.9)
+        else:
+            self.parent.Zoom(1.1)
+
+class GUIZoomIn(GUIBase):
+    Cursor = MagPlusCursor
+    def __init__(self, parent):
+        GUIBase.__init__(self, parent)
+        self.StartRBBox = None
+        self.PrevRBBox = None
+
+    def OnLeftDown(self, event):
+        self.StartRBBox = N.array( event.GetPosition() )
+        self.PrevRBBox = None
+        self.parent.CaptureMouse()
+
+    def OnLeftUp(self, event):
+        #if self.parent.HasCapture():
+        #        self.parent.ReleaseMouse()
+        if event.LeftUp() and not self.StartRBBox is None:
+            self.PrevRBBox = None
+            EndRBBox = event.GetPosition()
+            StartRBBox = self.StartRBBox
+            # if mouse has moved less that ten pixels, don't use the box.
+            if ( abs(StartRBBox[0] - EndRBBox[0]) > 10
+                    and abs(StartRBBox[1] - EndRBBox[1]) > 10 ):
+                EndRBBox = self.parent.PixelToWorld(EndRBBox)
+                StartRBBox = self.parent.PixelToWorld(StartRBBox)
+                BB = N.array(((min(EndRBBox[0],StartRBBox[0]),
+                                min(EndRBBox[1],StartRBBox[1])),
+                            (max(EndRBBox[0],StartRBBox[0]),
+                                max(EndRBBox[1],StartRBBox[1]))),N.float_)
+                self.parent.ZoomToBB(BB)
+            else:
+                Center = self.parent.PixelToWorld(StartRBBox)
+                self.parent.Zoom(1.5,Center)
+            self.StartRBBox = None
+
+    def OnMove(self, event):
+        # Allways raise the Move event.
+        self.parent._RaiseMouseEvent(event,FloatCanvas.EVT_FC_MOTION)
+        if event.Dragging() and event.LeftIsDown() and not (self.StartRBBox is None):
+            xy0 = self.StartRBBox
+            xy1 = N.array( event.GetPosition() )
+            wh  = abs(xy1 - xy0)
+            wh[0] = max(wh[0], int(wh[1]*self.parent.AspectRatio))
+            wh[1] = int(wh[0] / self.parent.AspectRatio)
+            xy_c = (xy0 + xy1) / 2
+            dc = wx.ClientDC(self.parent)
+            dc.BeginDrawing()
+            dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.SetLogicalFunction(wx.XOR)
+            if self.PrevRBBox:
+                dc.DrawRectanglePointSize(*self.PrevRBBox)
+            self.PrevRBBox = ( xy_c - wh/2, wh )
+            dc.DrawRectanglePointSize( *self.PrevRBBox )
+            dc.EndDrawing()
+            
+    def UpdateScreen(self):
+        """
+        Update gets called if the screen has been repainted in the middle of a zoom in
+        so the Rubber Band Box can get updated
+        """
+        if self.PrevRBBox is not None:
+            dc = wx.ClientDC(self.parent)
+            dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.SetLogicalFunction(wx.XOR)
+            dc.DrawRectanglePointSize(*self.PrevRBBox)
+
+    def OnRightDown(self, event):
+        self.parent.Zoom(1/1.5, event.GetPosition(), centerCoords="pixel")
+
+    def OnWheel(self, event):
+        if event.GetWheelRotation() < 0:
+            self.parent.Zoom(0.9)
+        else:
+            self.parent.Zoom(1.1)
+
+class GUIZoomOut(GUIBase):
+
+    Cursor = MagMinusCursor
+
+    def OnLeftDown(self, event):
+        self.parent.Zoom(1/1.5, event.GetPosition(), centerCoords="pixel")
+
+    def OnRightDown(self, event):
+        self.parent.Zoom(1.5, event.GetPosition(), centerCoords="pixel")
+
+    def OnWheel(self, event):
+        if event.GetWheelRotation() < 0:
+            self.parent.Zoom(0.9)
+        else:
+            self.parent.Zoom(1.1)
+
+    def OnMove(self, event):
+        # Allways raise the Move event.
+        self.parent._RaiseMouseEvent(event,FloatCanvas.EVT_FC_MOTION)
+