Updates for MouseGestures

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32493 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2005-02-28 20:03:35 +00:00
parent 4860d40db4
commit 7a0c9b3917
2 changed files with 190 additions and 63 deletions

View File

@@ -5,11 +5,11 @@
#Thanks to Robin Dunn for taking the time to show me how to do this #Thanks to Robin Dunn for taking the time to show me how to do this
#via the mailing list. #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 #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 from wx.lib.gestures import MouseGestures
#ToDo: #ToDo:
@@ -24,6 +24,9 @@ class TestPanel(wx.Panel):
wx.Panel.__init__(self, parent, -1) wx.Panel.__init__(self, parent, -1)
ID_GESTURE = wx.NewId() ID_GESTURE = wx.NewId()
ID_MOUSE = wx.NewId()
ID_MODIFIER = wx.NewId()
ID_VISIBLE = wx.NewId()
self.log = log self.log = log
@@ -33,14 +36,22 @@ class TestPanel(wx.Panel):
self.mg.SetGesturesVisible(True) 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('L', self.LogSomethingClever, 'You moved left')
self.mg.AddGesture('9', self.LogSomethingClever, 'You moved right and up') self.mg.AddGesture('9', self.LogSomethingClever, 'You moved right and up')
self.mg.AddGesture('U', self.LogSomethingClever, 'You moved 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: #Widgets:
self.btnAddGesture = wx.Button(self, ID_GESTURE, 'Add New Gesture') 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" msg = "Mouse Gestures"
text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
@@ -49,25 +60,37 @@ class TestPanel(wx.Panel):
w,h = text.GetTextExtent(msg) w,h = text.GetTextExtent(msg)
text.SetSize(wx.Size(w,h+1)) text.SetSize(wx.Size(w,h+1))
text.SetForegroundColour(wx.BLUE) text.SetForegroundColour(wx.BLUE)
self.SetBackgroundColour(wx.WHITE)
#Sizer: #Sizer:
outsideSizer = wx.BoxSizer(wx.VERTICAL) outsideSizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
outsideSizer.Add(wx.StaticText(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, '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(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.SetAutoLayout(True)
self.SetSizer(outsideSizer) self.SetSizer(outsideSizer)
#Events: #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): def LogSomethingClever(self, somethingclever):
self.log.WriteText(somethingclever) self.log.WriteText(somethingclever)
@@ -77,16 +100,73 @@ class TestPanel(wx.Panel):
answer1 = d.ShowModal() answer1 = d.ShowModal()
gesture = d.GetValue() gesture = d.GetValue()
d.Destroy() d.Destroy()
d = wx.TextEntryDialog(self, 'Print the following text on "%s":' % gesture, "Gesture Action", "") d = wx.TextEntryDialog(self, 'Print the following text on "%s":' % gesture, "Gesture Action", "")
answer2 = d.ShowModal() answer2 = d.ShowModal()
text = d.GetValue() text = d.GetValue()
d.Destroy() d.Destroy()
if (answer1 == wx.ID_OK) and (answer2 == wx.ID_OK): if (answer1 == wx.ID_OK) and (answer2 == wx.ID_OK):
self.mg.AddGesture(gesture.upper(), self.LogSomethingClever, text) 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): def OnDownThenRight(self):
self.log.WriteText('You made an "L"!') 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): def runTest(frame, nb, log):
@@ -113,3 +193,4 @@ if __name__ == '__main__':
import run import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

View File

@@ -1,6 +1,6 @@
#Mouse Gestures #Mouse Gestures
#Version 0.0.0 ALPHA #Version 0.0.1
#By Daniel Pozmanter #By Daniel Pozmanter
#drpython@bluebottle.com #drpython@bluebottle.com
@@ -9,17 +9,15 @@
#This is a class to add Mouse Gestures to a program. #This is a class to add Mouse Gestures to a program.
#It can be used in two ways: #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: #2. Manual:
# Same as above, but you do not need to set the mouse button/modifiers. # Same as above, but you do not need to set the mouse button/modifiers.
# You can launch this from events as you wish. # You can launch this from events as you wish.
# #
#An example is provided in the demo. #An example is provided in the demo.
#The parent window is where the mouse events will be recorded. #The parent window is where the mouse events will be recorded.
@@ -29,7 +27,7 @@
#Start() starts recording mouse movement. #Start() starts recording mouse movement.
#End() stops the recording, compiles all the gestures into a list, #End() stops the recording, compiles all the gestures into a list,
#and looks through the registered gestures to find a match. #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: #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. #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 not greater than twice the lesser, only the grater value
#is counted. #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: #ToDo:
#Add in modifier code (Ctrl, Alt, etc). #Fully Implement Manual Mode
#SetGestureLine(wx.Colour(), int width)
#Add "Ends With": AddGestureEndsWith(self, gesture, action, args) #Add "Ends With": AddGestureEndsWith(self, gesture, action, args)
#Add "Starts With": AddGestuteStartsWith(self, gesture, action, args) #Add "Starts With": AddGestuteStartsWith(self, gesture, action, args)
#At the moment, the mouse button can only be set at startup. #For better control of when the gesture starts and stops,
#I could use UnBind, but this may limit the wxPython version being used, #use manual mode.
#and, what if the user has other events bound? #At the moment, you need to Bind the OnMouseMotion event if you want to use
#So I think, if the user wants to change the mouse button at runtime, #manual mode.
#the best solution is to use manual mode.
import wx import wx
class MouseGestures: class MouseGestures:
def __init__(self, parent, Auto=True, MouseButton=wx.MOUSE_BTN_MIDDLE): def __init__(self, parent, Auto=True, MouseButton=wx.MOUSE_BTN_MIDDLE):
self.parent = parent self.parent = parent
self.gestures = [] self.gestures = []
self.actions = [] self.actions = []
self.actionarguments = [] self.actionarguments = []
self.mousebutton = MouseButton self.mousebutton = MouseButton
self.modifiers = 0 self.modifiers = []
self.recording = False self.recording = False
@@ -103,12 +113,22 @@ class MouseGestures:
self.SetAuto(Auto) self.SetAuto(Auto)
def Action(self, gesture): def _check_modifiers(self, event):
if gesture in self.gestures: '''Internal: Returns True if all needed modifiers are down
i = self.gestures.index(gesture) for the given event.'''
apply(self.actions[i], self.actionarguments[i]) 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): def AddGesture(self, gesture, action, *args):
'''Registers a gesture, and an associated function, with any arguments needed.'''
#Make Sure not a duplicate: #Make Sure not a duplicate:
self.RemoveGesture(gesture) self.RemoveGesture(gesture)
@@ -116,13 +136,21 @@ class MouseGestures:
self.actions.append(action) self.actions.append(action)
self.actionarguments.append(args) 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): 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 self.recording = False
#Figure out the gestures (Look for occurances of 5 in a row or more): #Figure out the gestures (Look for occurances of 5 in a row or more):
tempstring = '0' tempstring = '0'
possiblechange = '0' possiblechange = '0'
directions = '' directions = ''
@@ -132,7 +160,7 @@ class MouseGestures:
if g == possiblechange: if g == possiblechange:
tempstring = g + g tempstring = g + g
else: else:
possiblechange = g possiblechange = g
else: else:
tempstring += g tempstring += g
if len(tempstring) >= self.wobbletolerance: if len(tempstring) >= self.wobbletolerance:
@@ -143,10 +171,14 @@ class MouseGestures:
else: else:
directions += g directions += g
tempstring = '0' tempstring = '0'
if self.showgesture:
self.parent.Refresh()
return directions return directions
def GetDirection(self, point1, point2): def GetDirection(self, point1, point2):
'''Gets the direction between two points.'''
#point1 is the old point #point1 is the old point
#point2 is current #point2 is current
@@ -172,7 +204,7 @@ class MouseGestures:
elif av > ah: elif av > ah:
if (av / ah) > 2: if (av / ah) > 2:
horizontal = 0 horizontal = 0
horizontalchange = False horizontalchange = False
if horizontalchange and verticalchange: if horizontalchange and verticalchange:
#Diagonal #Diagonal
@@ -183,7 +215,7 @@ class MouseGestures:
elif (horizontal < 0) and (vertical > 0): elif (horizontal < 0) and (vertical > 0):
return '1' return '1'
else: else:
return '7' return '7'
else: else:
#Straight Line #Straight Line
if horizontalchange: if horizontalchange:
@@ -196,16 +228,13 @@ class MouseGestures:
return 'D' return 'D'
else: else:
return 'U' 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): def OnMotion(self, event):
'''Internal. Used if Start() has been run'''
if self.recording: if self.recording:
currentposition = event.GetPosition() currentposition = event.GetPosition()
if self.lastposition != (-1, -1): if self.lastposition != (-1, -1):
@@ -214,50 +243,67 @@ class MouseGestures:
#Draw it! #Draw it!
px1, py1 = self.parent.ClientToScreen(self.lastposition) px1, py1 = self.parent.ClientToScreen(self.lastposition)
px2, py2 = self.parent.ClientToScreen(currentposition) px2, py2 = self.parent.ClientToScreen(currentposition)
self.dc.DrawLine(px1, py1, px2, py2)
self.dc.DrawLine(px1, py1, px2, py2)
self.lastposition = currentposition self.lastposition = currentposition
event.Skip() event.Skip()
def OnStart(self, event): def OnMouseEvent(self, event):
self.Start() '''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() event.Skip()
def RemoveGesture(self, gesture): def RemoveGesture(self, gesture):
'''Removes a gesture, and its associated action'''
if gesture in self.gestures: if gesture in self.gestures:
i = self.gestures.index(gesture) i = self.gestures.index(gesture)
del self.gestures[i] del self.gestures[i]
del self.actions[i] del self.actions[i]
del self.actionarguments[i] del self.actionarguments[i]
def SetAuto(self, auto): 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 auto:
if self.mousebutton == wx.MOUSE_BTN_LEFT: self.parent.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
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_MOTION, self.OnMotion) 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): def SetGesturesVisible(self, vis):
'''Sets whether a line is drawn to visually represent each gesture'''
self.showgesture = vis 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 self.modifiers = modifiers
def SetMouseButton(self, mousebutton):
'''Takes the wx constant for the target mousebutton'''
self.mousebutton = mousebutton
def SetWobbleTolerance(self, wobbletolerance): def SetWobbleTolerance(self, wobbletolerance):
'''Sets just how much wobble this class can take!'''
self.WobbleTolerance = wobbletolerance self.WobbleTolerance = wobbletolerance
def Start(self): def Start(self):
'''Starts recording the points to create the mouse gesture from'''
self.recording = True self.recording = True
self.rawgesture = '' self.rawgesture = ''
self.lastposition = (-1, -1) self.lastposition = (-1, -1)
if self.showgesture: if self.showgesture:
self.parent.Refresh() self.parent.Refresh()