#Mouse Gestures
-#Version 0.0.0 ALPHA
+#Version 0.0.1
#By Daniel Pozmanter
#drpython@bluebottle.com
#Released under the terms of the wxWindows License.
-#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)
-#
-#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.
-#
-#An example is provided in the demo.
-#The parent window is where the mouse events will be recorded.
-#(So if you want to record them in a pop up window, use manual mode,
-#and set the pop up as the parent).
-#
-#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.
+"""
+This is a class to add Mouse Gestures to a program.
+It can be used in two ways:
-#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.
+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.
-#Recognized: L, R, U, D, 1, 3, 7, 9
+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.
-#Styles: Manual (Automatic By Default), DisplayNumbersForDiagonals (Off By Default).
-#Not Yet Implemented
+An example is provided in the demo.
+The parent window is where the mouse events will be recorded.
+(So if you want to record them in a pop up window, use manual mode,
+and set the pop up as the parent).
-#The criteria for a direction is as follows:
-#x in a row. (Where x is the WobbleTolerance).
-#So if the WobbleTolerance is 9
-# 'URUUUUUUUUUUUUUUURUURUUUU1' is Up.
+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 higher this number, the less sensitive this class is.
-#So the more likely something like 1L will translate to 1.
+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.
-#This is good, since the mouse does tend to wobble somewhat,
-#and a higher number allows for this.
+Recognized: L, R, U, D, 1, 3, 7, 9
-#To change this, use SetWobbleTolerance
+Styles: Manual (Automatic By Default), DisplayNumbersForDiagonals (Off By Default).
+Not Yet Implemented
-#Also, to help with recognition of a diagonal versus
-#a vey messy straight line, if the greater absolute value
-#is not greater than twice the lesser, only the grater value
-#is counted.
+The criteria for a direction is as follows:
+x in a row. (Where x is the WobbleTolerance).
+So if the WobbleTolerance is 9
+ 'URUUUUUUUUUUUUUUURUURUUUU1' is Up.
-#ToDo:
+The higher this number, the less sensitive this class is.
+So the more likely something like 1L will translate to 1.
+
+This is good, since the mouse does tend to wobble somewhat,
+and a higher number allows for this.
+
+To change this, use SetWobbleTolerance
+
+Also, to help with recognition of a diagonal versus
+a vey messy straight line, if the greater absolute value
+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.
+"""
-#Add in modifier code (Ctrl, Alt, etc).
+###########################################
+
+'''
+Changelog:
+0.0.1: Treats a mouse leaving event as mouse up.
+ (Bug Report, Thanks Peter Damoc).
+
+
+0.0.0: Initial Release.
+'''
+
+###########################################
+#ToDo:
-#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
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)
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 = ''
if g == possiblechange:
tempstring = g + g
else:
- possiblechange = g
+ possiblechange = g
else:
tempstring += g
if len(tempstring) >= self.wobbletolerance:
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
elif av > ah:
if (av / ah) > 2:
horizontal = 0
- horizontalchange = False
+ horizontalchange = False
if horizontalchange and verticalchange:
#Diagonal
elif (horizontal < 0) and (vertical > 0):
return '1'
else:
- return '7'
+ return '7'
else:
#Straight Line
if horizontalchange:
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):
#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:
- self.parent.Refresh()
\ No newline at end of file
+ if self.showgesture:
+ self.parent.Refresh()