X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6342fb5e6524edffa219d5843536ea279bba4df..0b0849b5a5d530095bc0da325d0a7a2101ddb0d6:/wxPython/wx/lib/floatcanvas/GUIMode.py?ds=inline diff --git a/wxPython/wx/lib/floatcanvas/GUIMode.py b/wxPython/wx/lib/floatcanvas/GUIMode.py new file mode 100644 index 0000000000..08ca47343f --- /dev/null +++ b/wxPython/wx/lib/floatcanvas/GUIMode.py @@ -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) +