From 7a0c9b3917093e27a895adbe9bf467917f5226ae Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Mon, 28 Feb 2005 20:03:35 +0000 Subject: [PATCH] Updates for MouseGestures git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32493 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- wxPython/demo/MouseGestures.py | 97 ++++++++++++++++++-- wxPython/wx/lib/gestures.py | 156 +++++++++++++++++++++------------ 2 files changed, 190 insertions(+), 63 deletions(-) diff --git a/wxPython/demo/MouseGestures.py b/wxPython/demo/MouseGestures.py index 3083414f15..0374a0b336 100644 --- a/wxPython/demo/MouseGestures.py +++ b/wxPython/demo/MouseGestures.py @@ -5,11 +5,11 @@ #Thanks to Robin Dunn for taking the time to show me how to do this #via the mailing list. -#Version 0.0.0 ALPHA +#Version 0.0.0 #This is a hacked version of DragAndDrop.py from the wxPython demo 2.5.2.8 -import wx, wx.stc +import wx, wx.stc, wx.lib.dialogs from wx.lib.gestures import MouseGestures #ToDo: @@ -24,6 +24,9 @@ class TestPanel(wx.Panel): wx.Panel.__init__(self, parent, -1) ID_GESTURE = wx.NewId() + ID_MOUSE = wx.NewId() + ID_MODIFIER = wx.NewId() + ID_VISIBLE = wx.NewId() self.log = log @@ -33,14 +36,22 @@ class TestPanel(wx.Panel): self.mg.SetGesturesVisible(True) + self.mg.AddGesture('LR', self.ShowSomethingClever, 'Left then Right!') + self.mg.AddGesture('39', self.ShowSomethingClever, 'You made a V!') self.mg.AddGesture('L', self.LogSomethingClever, 'You moved left') self.mg.AddGesture('9', self.LogSomethingClever, 'You moved right and up') self.mg.AddGesture('U', self.LogSomethingClever, 'You moved up') - self.mg.AddGesture('DR', self.OnDownThenRight) + self.mg.AddGesture('DR', self.OnDownThenRight) + self.mg.AddGesture('LDRU', self.SetToBlue) + self.mg.AddGesture('RDLU', self.SetToOrange) #Widgets: self.btnAddGesture = wx.Button(self, ID_GESTURE, 'Add New Gesture') + self.btnChangeMouseButton = wx.Button(self, ID_MOUSE, 'Change Mouse Button') + self.btnChangeModifier = wx.Button(self, ID_MODIFIER, 'Change Modifier') + self.btnToggleVisible = wx.ToggleButton(self, ID_VISIBLE, 'Toggle Gestures Visible') + self.btnToggleVisible.SetValue(True) msg = "Mouse Gestures" text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) @@ -49,25 +60,37 @@ class TestPanel(wx.Panel): w,h = text.GetTextExtent(msg) text.SetSize(wx.Size(w,h+1)) - text.SetForegroundColour(wx.BLUE) + text.SetForegroundColour(wx.BLUE) + + self.SetBackgroundColour(wx.WHITE) #Sizer: outsideSizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) outsideSizer.Add(wx.StaticText(self, -1, ' '), 0, wx.EXPAND) outsideSizer.Add(wx.StaticText(self, -1, 'Hold The Middle Mouse Button Down to Gesticulate'), 0, wx.EXPAND) - outsideSizer.Add(wx.StaticText(self, -1, 'Left, The Diagonal Up/Right, Down Then Right, and Up are Preset'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Left Then Right, Left, The Diagonal Up/Right, Down Then Right, Diagonal Down/Right Then Diagonal Up/Right, and Up are Preset'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Left,Down,Right,Up Sets the line colour to Blue.'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Right,Down,Left,Up Sets the line colour to Orange.'), 0, wx.EXPAND) outsideSizer.Add(wx.StaticText(self, -1, ' '), 0, wx.EXPAND) - outsideSizer.Add(self.btnAddGesture, 0, wx.SHAPED) + btnSizer.Add(self.btnAddGesture, 0, wx.SHAPED) + btnSizer.Add(self.btnChangeMouseButton, 0, wx.SHAPED) + btnSizer.Add(self.btnChangeModifier, 0, wx.SHAPED) + btnSizer.Add(self.btnToggleVisible, 0, wx.SHAPED) + outsideSizer.Add(btnSizer, 0, wx.SHAPED) self.SetAutoLayout(True) self.SetSizer(outsideSizer) - #Events: - self.Bind(wx.EVT_BUTTON, self.OnAddGesture, id=ID_GESTURE) + self.Bind(wx.EVT_BUTTON, self.OnAddGesture, id=ID_GESTURE) + self.Bind(wx.EVT_BUTTON, self.OnChangeMouseButton, id=ID_MOUSE) + self.Bind(wx.EVT_BUTTON, self.OnChangeModifiers, id=ID_MODIFIER) + self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleVisible, id=ID_VISIBLE) def LogSomethingClever(self, somethingclever): self.log.WriteText(somethingclever) @@ -77,16 +100,73 @@ class TestPanel(wx.Panel): answer1 = d.ShowModal() gesture = d.GetValue() d.Destroy() + d = wx.TextEntryDialog(self, 'Print the following text on "%s":' % gesture, "Gesture Action", "") answer2 = d.ShowModal() text = d.GetValue() d.Destroy() + if (answer1 == wx.ID_OK) and (answer2 == wx.ID_OK): self.mg.AddGesture(gesture.upper(), self.LogSomethingClever, text) + + def OnChangeModifiers(self, event): + choices = [wx.WXK_CONTROL, wx.WXK_SHIFT, wx.WXK_ALT] + schoices = ['Control', 'Shift', 'Alt'] + + d = wx.lib.dialogs.MultipleChoiceDialog(self, 'Select Modifier Keys:\n(Select None if you do not want to use modifier keys\n\n', "Change Modifier Keys", schoices) + answer = d.ShowModal() + tuply = d.GetValue() + d.Destroy() + + if (answer == wx.ID_OK): + if len(tuply) > 0: + modifiers = [] + modstring = '' + for x in tuply: + modifiers.append(choices[x]) + modstring += schoices[x] + ' ' + self.mg.SetModifiers(modifiers) + self.log.WriteText('Set Modifiers to: ' + modstring) + else: + self.mg.SetModifiers() + self.log.WriteText('UnSet All Modifiers') + + def OnChangeMouseButton(self, event): + choices = [wx.MOUSE_BTN_LEFT, wx.MOUSE_BTN_MIDDLE, wx.MOUSE_BTN_RIGHT] + schoices = ['Left', 'Middle', 'Right'] + d = wx.SingleChoiceDialog(self, "Set Mouse Button To", "Change Mouse Button", schoices, wx.OK|wx.CANCEL) + d.SetSize(wx.Size(250, 200)) + answer = d.ShowModal() + i = d.GetSelection() + d.Destroy() + if (answer == wx.ID_OK): + self.mg.SetMouseButton(choices[i]) + self.log.WriteText('Set the Mouse Button to ' + schoices[i]) def OnDownThenRight(self): self.log.WriteText('You made an "L"!') + def OnToggleVisible(self, event): + visual = self.btnToggleVisible.GetValue() + self.mg.SetGesturesVisible(visual) + if visual: + self.log.WriteText('Made Gestures Visible') + else: + self.log.WriteText('Made Gestures Invisible') + + def SetToBlue(self): + self.mg.SetGesturePen(wx.Colour(0, 144, 255), 5) + self.log.WriteText('Set Gesture Colour to Blue') + + def SetToOrange(self): + self.mg.SetGesturePen(wx.Colour(255, 156, 0), 5) + self.log.WriteText('Set Gesture Colour to Orange') + + def ShowSomethingClever(self, somethingclever): + d = wx.MessageDialog(self, somethingclever, 'Mouse Gesture Action', wx.OK) + d.ShowModal() + d.Destroy() + #---------------------------------------------------------------------- def runTest(frame, nb, log): @@ -113,3 +193,4 @@ if __name__ == '__main__': import run run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/wxPython/wx/lib/gestures.py b/wxPython/wx/lib/gestures.py index b4e8beea03..0ab9d149ce 100644 --- a/wxPython/wx/lib/gestures.py +++ b/wxPython/wx/lib/gestures.py @@ -1,6 +1,6 @@ #Mouse Gestures -#Version 0.0.0 ALPHA +#Version 0.0.1 #By Daniel Pozmanter #drpython@bluebottle.com @@ -9,17 +9,15 @@ #This is a class to add Mouse Gestures to a program. #It can be used in two ways: -# -#1. Automatic: -# Automatically runs mouse gestures. -# You need to set the gestures, and their associated actions, -# as well as the Mouse Button/Modifiers to use. # -# (Mouse Buttons are set in init) +#1. Automatic: +# Automatically runs mouse gestures. +# You need to set the gestures, and their associated actions, +# as well as the Mouse Button/Modifiers to use. # #2. Manual: -# Same as above, but you do not need to set the mouse button/modifiers. -# You can launch this from events as you wish. +# Same as above, but you do not need to set the mouse button/modifiers. +# You can launch this from events as you wish. # #An example is provided in the demo. #The parent window is where the mouse events will be recorded. @@ -29,7 +27,7 @@ #Start() starts recording mouse movement. #End() stops the recording, compiles all the gestures into a list, #and looks through the registered gestures to find a match. -#The first matchs associated action is then run. +#The first matchs associated action is then run. #The marginoferror is how much to forgive when calculating movement: #If the margin is 25, then movement less than 25 pixels will not be detected. @@ -57,34 +55,46 @@ #is not greater than twice the lesser, only the grater value #is counted. + +#In automatic mode, EVT_MOUSE_EVENTS is used. +#This allows the user to change the mouse button/modifiers at runtime. + +########################################### + +''' +Changelog: +0.0.1: Treats a mouse leaving event as mouse up. + (Bug Report, Thanks Peter Damoc). + + +0.0.0: Initial Release. +''' + +########################################### #ToDo: -#Add in modifier code (Ctrl, Alt, etc). - -#SetGestureLine(wx.Colour(), int width) +#Fully Implement Manual Mode #Add "Ends With": AddGestureEndsWith(self, gesture, action, args) #Add "Starts With": AddGestuteStartsWith(self, gesture, action, args) -#At the moment, the mouse button can only be set at startup. -#I could use UnBind, but this may limit the wxPython version being used, -#and, what if the user has other events bound? -#So I think, if the user wants to change the mouse button at runtime, -#the best solution is to use manual mode. - +#For better control of when the gesture starts and stops, +#use manual mode. +#At the moment, you need to Bind the OnMouseMotion event if you want to use +#manual mode. import wx class MouseGestures: def __init__(self, parent, Auto=True, MouseButton=wx.MOUSE_BTN_MIDDLE): self.parent = parent - + self.gestures = [] self.actions = [] self.actionarguments = [] self.mousebutton = MouseButton - self.modifiers = 0 + self.modifiers = [] self.recording = False @@ -103,12 +113,22 @@ class MouseGestures: self.SetAuto(Auto) - def Action(self, gesture): - if gesture in self.gestures: - i = self.gestures.index(gesture) - apply(self.actions[i], self.actionarguments[i]) - + def _check_modifiers(self, event): + '''Internal: Returns True if all needed modifiers are down + for the given event.''' + if len(self.modifiers) > 0: + good = True + if wx.WXK_CONTROL in self.modifiers: + good = good and event.ControlDown() + if wx.WXK_SHIFT in self.modifiers: + good = good and event.ShiftDown() + if wx.WXK_ALT in self.modifiers: + good = good and event.AltDown() + return good + return True + def AddGesture(self, gesture, action, *args): + '''Registers a gesture, and an associated function, with any arguments needed.''' #Make Sure not a duplicate: self.RemoveGesture(gesture) @@ -116,13 +136,21 @@ class MouseGestures: self.actions.append(action) self.actionarguments.append(args) + def DoAction(self, gesture): + '''If the gesture is in the array of registered gestures, run the associated function.''' + if gesture in self.gestures: + i = self.gestures.index(gesture) + apply(self.actions[i], self.actionarguments[i]) + def End(self): + '''Stops recording the points to create the mouse gesture from, + and creates the mouse gesture, returns the result as a string.''' self.recording = False #Figure out the gestures (Look for occurances of 5 in a row or more): tempstring = '0' - possiblechange = '0' + possiblechange = '0' directions = '' @@ -132,7 +160,7 @@ class MouseGestures: if g == possiblechange: tempstring = g + g else: - possiblechange = g + possiblechange = g else: tempstring += g if len(tempstring) >= self.wobbletolerance: @@ -143,10 +171,14 @@ class MouseGestures: else: directions += g tempstring = '0' + + if self.showgesture: + self.parent.Refresh() return directions def GetDirection(self, point1, point2): + '''Gets the direction between two points.''' #point1 is the old point #point2 is current @@ -172,7 +204,7 @@ class MouseGestures: elif av > ah: if (av / ah) > 2: horizontal = 0 - horizontalchange = False + horizontalchange = False if horizontalchange and verticalchange: #Diagonal @@ -183,7 +215,7 @@ class MouseGestures: elif (horizontal < 0) and (vertical > 0): return '1' else: - return '7' + return '7' else: #Straight Line if horizontalchange: @@ -196,16 +228,13 @@ class MouseGestures: return 'D' else: return 'U' - - - def OnEnd(self, event): - result = self.End() - - self.Action(result) - - event.Skip() + def GetRecording(self): + '''Returns whether or not Gesture Recording has started.''' + return self.recording + def OnMotion(self, event): + '''Internal. Used if Start() has been run''' if self.recording: currentposition = event.GetPosition() if self.lastposition != (-1, -1): @@ -214,50 +243,67 @@ class MouseGestures: #Draw it! px1, py1 = self.parent.ClientToScreen(self.lastposition) px2, py2 = self.parent.ClientToScreen(currentposition) - - self.dc.DrawLine(px1, py1, px2, py2) + self.dc.DrawLine(px1, py1, px2, py2) self.lastposition = currentposition event.Skip() - def OnStart(self, event): - self.Start() + def OnMouseEvent(self, event): + '''Internal. Used in Auto Mode.''' + if event.ButtonDown(self.mousebutton) and self._check_modifiers(event): + self.Start() + elif (event.ButtonUp(self.mousebutton) or event.Leaving()) and self.GetRecording(): + result = self.End() + self.DoAction(result) event.Skip() def RemoveGesture(self, gesture): + '''Removes a gesture, and its associated action''' if gesture in self.gestures: i = self.gestures.index(gesture) + del self.gestures[i] del self.actions[i] del self.actionarguments[i] def SetAuto(self, auto): - #I was not sure about making this part of init, so I left it as its own method for now. + '''Warning: Once auto is set, it stays set, unless you manually use UnBind''' if auto: - if self.mousebutton == wx.MOUSE_BTN_LEFT: - self.parent.Bind(wx.EVT_LEFT_DOWN, self.OnStart) - self.parent.Bind(wx.EVT_LEFT_UP, self.OnEnd) - elif self.mousebutton == wx.MOUSE_BTN_MIDDLE: - self.parent.Bind(wx.EVT_MIDDLE_DOWN, self.OnStart) - self.parent.Bind(wx.EVT_MIDDLE_UP, self.OnEnd) - elif self.mousebutton == wx.MOUSE_BTN_RIGHT: - self.parent.Bind(wx.EVT_RIGHT_DOWN, self.OnStart) - self.parent.Bind(wx.EVT_RIGHT_UP, self.OnEnd) + self.parent.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent) self.parent.Bind(wx.EVT_MOTION, self.OnMotion) + def SetGesturePen(self, pen): + '''Sets the wx pen used to visually represent each gesture''' + self.pen = pen + self.dc.SetPen(self.pen) + + def SetGesturePen(self, colour, width): + '''Sets the colour and width of the line drawn to visually represent each gesture''' + self.pen = wx.Pen(colour, width) + self.dc.SetPen(self.pen) + def SetGesturesVisible(self, vis): + '''Sets whether a line is drawn to visually represent each gesture''' self.showgesture = vis - def SetModifiers(self, modifers): + def SetModifiers(self, modifiers=[]): + '''Takes an array of wx Key constants (Control, Shift, and/or Alt). + Leave empty to unset all modifiers.''' self.modifiers = modifiers + def SetMouseButton(self, mousebutton): + '''Takes the wx constant for the target mousebutton''' + self.mousebutton = mousebutton + def SetWobbleTolerance(self, wobbletolerance): + '''Sets just how much wobble this class can take!''' self.WobbleTolerance = wobbletolerance def Start(self): + '''Starts recording the points to create the mouse gesture from''' self.recording = True - self.rawgesture = '' + self.rawgesture = '' self.lastposition = (-1, -1) - if self.showgesture: + if self.showgesture: self.parent.Refresh() \ No newline at end of file