Added wx.lib.gestures module from Daniel Pozmanter which supports
using Mouse Gestures in an application. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32148 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
d8b49350e6
commit
51c5e1f21e
@ -50,6 +50,7 @@ _treeList = [
|
|||||||
'StandardPaths',
|
'StandardPaths',
|
||||||
'MediaCtrl',
|
'MediaCtrl',
|
||||||
'DatePickerCtrl',
|
'DatePickerCtrl',
|
||||||
|
'MouseGestures',
|
||||||
]),
|
]),
|
||||||
|
|
||||||
# managed windows == things with a (optional) caption you can close
|
# managed windows == things with a (optional) caption you can close
|
||||||
@ -226,6 +227,7 @@ _treeList = [
|
|||||||
'FileHistory',
|
'FileHistory',
|
||||||
'FontEnumerator',
|
'FontEnumerator',
|
||||||
'Joystick',
|
'Joystick',
|
||||||
|
'MouseGestures',
|
||||||
'OGL',
|
'OGL',
|
||||||
'PrintFramework',
|
'PrintFramework',
|
||||||
'ShapedWindow',
|
'ShapedWindow',
|
||||||
|
115
wxPython/demo/MouseGestures.py
Normal file
115
wxPython/demo/MouseGestures.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#*******************
|
||||||
|
#By Daniel Pozmanter
|
||||||
|
#Under the GPL, etc, etc.
|
||||||
|
|
||||||
|
#Thanks to Robin Dunn for taking the time to show me how to do this
|
||||||
|
#via the mailing list.
|
||||||
|
|
||||||
|
#Version 0.0.0 ALPHA
|
||||||
|
|
||||||
|
#This is a hacked version of DragAndDrop.py from the wxPython demo 2.5.2.8
|
||||||
|
|
||||||
|
import wx, wx.stc
|
||||||
|
from wx.lib.gestures import MouseGestures
|
||||||
|
|
||||||
|
#ToDo:
|
||||||
|
|
||||||
|
#Add a dialog to record gestures (Have it showcase the manual mode)
|
||||||
|
#Allow users to remove gestures
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestPanel(wx.Panel):
|
||||||
|
def __init__(self, parent, log):
|
||||||
|
wx.Panel.__init__(self, parent, -1)
|
||||||
|
|
||||||
|
ID_GESTURE = wx.NewId()
|
||||||
|
|
||||||
|
self.log = log
|
||||||
|
|
||||||
|
#Mouse Gestures:
|
||||||
|
|
||||||
|
self.mg = MouseGestures(self, Auto=True)
|
||||||
|
|
||||||
|
self.mg.SetGesturesVisible(True)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
#Widgets:
|
||||||
|
|
||||||
|
self.btnAddGesture = wx.Button(self, ID_GESTURE, 'Add New Gesture')
|
||||||
|
|
||||||
|
msg = "Mouse Gestures"
|
||||||
|
text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
|
||||||
|
text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
|
||||||
|
text.SetLabel(msg)
|
||||||
|
|
||||||
|
w,h = text.GetTextExtent(msg)
|
||||||
|
text.SetSize(wx.Size(w,h+1))
|
||||||
|
text.SetForegroundColour(wx.BLUE)
|
||||||
|
|
||||||
|
#Sizer:
|
||||||
|
outsideSizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
|
||||||
|
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, ' '), 0, wx.EXPAND)
|
||||||
|
outsideSizer.Add(self.btnAddGesture, 0, wx.SHAPED)
|
||||||
|
|
||||||
|
self.SetAutoLayout(True)
|
||||||
|
self.SetSizer(outsideSizer)
|
||||||
|
|
||||||
|
|
||||||
|
#Events:
|
||||||
|
self.Bind(wx.EVT_BUTTON, self.OnAddGesture, id=ID_GESTURE)
|
||||||
|
|
||||||
|
def LogSomethingClever(self, somethingclever):
|
||||||
|
self.log.WriteText(somethingclever)
|
||||||
|
|
||||||
|
def OnAddGesture(self, event):
|
||||||
|
d = wx.TextEntryDialog(self, "Enter Gesture (LRUD1379) (EG Right Then Up Then DownLeft is RU1):", "Add New Gesture", "")
|
||||||
|
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 OnDownThenRight(self):
|
||||||
|
self.log.WriteText('You made an "L"!')
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
def runTest(frame, nb, log):
|
||||||
|
win = TestPanel(nb, log)
|
||||||
|
return win
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
overview = """\
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This demo shows how to add MouseGestures
|
||||||
|
to your program, and showcases the MouseGestures
|
||||||
|
class in all it's mousey glory.
|
||||||
|
<p><p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys,os
|
||||||
|
import run
|
||||||
|
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
|
||||||
|
|
@ -221,6 +221,11 @@ buttons.
|
|||||||
|
|
||||||
Added wx.DatePickerCtrl.
|
Added wx.DatePickerCtrl.
|
||||||
|
|
||||||
|
wx.html.HtmlWindow now supports background images.
|
||||||
|
|
||||||
|
Added wx.lib.gestures module from Daniel Pozmanter which supports
|
||||||
|
using Mouse Gestures in an application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
263
wxPython/wx/lib/gestures.py
Normal file
263
wxPython/wx/lib/gestures.py
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
#Mouse Gestures
|
||||||
|
|
||||||
|
#Version 0.0.0 ALPHA
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
#Recognized: L, R, U, D, 1, 3, 7, 9
|
||||||
|
|
||||||
|
#Styles: Manual (Automatic By Default), DisplayNumbersForDiagonals (Off By Default).
|
||||||
|
#Not Yet Implemented
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
#ToDo:
|
||||||
|
|
||||||
|
#Add in modifier code (Ctrl, Alt, etc).
|
||||||
|
|
||||||
|
#SetGestureLine(wx.Colour(), int width)
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
|
||||||
|
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.recording = False
|
||||||
|
|
||||||
|
self.lastposition = (-1, -1)
|
||||||
|
|
||||||
|
self.pen = wx.Pen(wx.Colour(0, 144, 255), 5)
|
||||||
|
|
||||||
|
self.dc = wx.ScreenDC()
|
||||||
|
self.dc.SetPen(self.pen)
|
||||||
|
|
||||||
|
self.showgesture = False
|
||||||
|
|
||||||
|
self.wobbletolerance = 7
|
||||||
|
|
||||||
|
self.rawgesture = ''
|
||||||
|
|
||||||
|
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 AddGesture(self, gesture, action, *args):
|
||||||
|
#Make Sure not a duplicate:
|
||||||
|
self.RemoveGesture(gesture)
|
||||||
|
|
||||||
|
self.gestures.append(gesture)
|
||||||
|
self.actions.append(action)
|
||||||
|
self.actionarguments.append(args)
|
||||||
|
|
||||||
|
def End(self):
|
||||||
|
self.recording = False
|
||||||
|
|
||||||
|
#Figure out the gestures (Look for occurances of 5 in a row or more):
|
||||||
|
|
||||||
|
tempstring = '0'
|
||||||
|
possiblechange = '0'
|
||||||
|
|
||||||
|
directions = ''
|
||||||
|
|
||||||
|
for g in self.rawgesture:
|
||||||
|
l = len(tempstring)
|
||||||
|
if g != tempstring[l - 1]:
|
||||||
|
if g == possiblechange:
|
||||||
|
tempstring = g + g
|
||||||
|
else:
|
||||||
|
possiblechange = g
|
||||||
|
else:
|
||||||
|
tempstring += g
|
||||||
|
if len(tempstring) >= self.wobbletolerance:
|
||||||
|
ld = len(directions)
|
||||||
|
if ld > 0:
|
||||||
|
if directions[ld - 1] != g:
|
||||||
|
directions += g
|
||||||
|
else:
|
||||||
|
directions += g
|
||||||
|
tempstring = '0'
|
||||||
|
|
||||||
|
return directions
|
||||||
|
|
||||||
|
def GetDirection(self, point1, point2):
|
||||||
|
#point1 is the old point
|
||||||
|
#point2 is current
|
||||||
|
|
||||||
|
x1, y1 = point1
|
||||||
|
x2, y2 = point2
|
||||||
|
|
||||||
|
#(Negative = Left, Up)
|
||||||
|
#(Positive = Right, Down)
|
||||||
|
|
||||||
|
horizontal = x2 - x1
|
||||||
|
vertical = y2 - y1
|
||||||
|
|
||||||
|
horizontalchange = abs(horizontal) > 0
|
||||||
|
verticalchange = abs(vertical) > 0
|
||||||
|
|
||||||
|
if horizontalchange and verticalchange:
|
||||||
|
ah = abs(horizontal)
|
||||||
|
av = abs(vertical)
|
||||||
|
if ah > av:
|
||||||
|
if (ah / av) > 2:
|
||||||
|
vertical = 0
|
||||||
|
verticalchange = False
|
||||||
|
elif av > ah:
|
||||||
|
if (av / ah) > 2:
|
||||||
|
horizontal = 0
|
||||||
|
horizontalchange = False
|
||||||
|
|
||||||
|
if horizontalchange and verticalchange:
|
||||||
|
#Diagonal
|
||||||
|
if (horizontal > 0) and (vertical > 0):
|
||||||
|
return '3'
|
||||||
|
elif (horizontal > 0) and (vertical < 0):
|
||||||
|
return '9'
|
||||||
|
elif (horizontal < 0) and (vertical > 0):
|
||||||
|
return '1'
|
||||||
|
else:
|
||||||
|
return '7'
|
||||||
|
else:
|
||||||
|
#Straight Line
|
||||||
|
if horizontalchange:
|
||||||
|
if horizontal > 0:
|
||||||
|
return 'R'
|
||||||
|
else:
|
||||||
|
return 'L'
|
||||||
|
else:
|
||||||
|
if vertical > 0:
|
||||||
|
return 'D'
|
||||||
|
else:
|
||||||
|
return 'U'
|
||||||
|
|
||||||
|
|
||||||
|
def OnEnd(self, event):
|
||||||
|
result = self.End()
|
||||||
|
|
||||||
|
self.Action(result)
|
||||||
|
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def OnMotion(self, event):
|
||||||
|
if self.recording:
|
||||||
|
currentposition = event.GetPosition()
|
||||||
|
if self.lastposition != (-1, -1):
|
||||||
|
self.rawgesture += self.GetDirection(self.lastposition, currentposition)
|
||||||
|
if self.showgesture:
|
||||||
|
#Draw it!
|
||||||
|
px1, py1 = self.parent.ClientToScreen(self.lastposition)
|
||||||
|
px2, py2 = self.parent.ClientToScreen(currentposition)
|
||||||
|
|
||||||
|
self.dc.DrawLine(px1, py1, px2, py2)
|
||||||
|
|
||||||
|
self.lastposition = currentposition
|
||||||
|
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def OnStart(self, event):
|
||||||
|
self.Start()
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def RemoveGesture(self, gesture):
|
||||||
|
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.
|
||||||
|
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_MOTION, self.OnMotion)
|
||||||
|
|
||||||
|
def SetGesturesVisible(self, vis):
|
||||||
|
self.showgesture = vis
|
||||||
|
|
||||||
|
def SetModifiers(self, modifers):
|
||||||
|
self.modifiers = modifiers
|
||||||
|
|
||||||
|
def SetWobbleTolerance(self, wobbletolerance):
|
||||||
|
self.WobbleTolerance = wobbletolerance
|
||||||
|
|
||||||
|
def Start(self):
|
||||||
|
self.recording = True
|
||||||
|
self.rawgesture = ''
|
||||||
|
self.lastposition = (-1, -1)
|
||||||
|
if self.showgesture:
|
||||||
|
self.parent.Refresh()
|
Loading…
Reference in New Issue
Block a user