PageRenderTime 66ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/env/Lib/site-packages/wx-2.8-msw-unicode/wx/lib/gestures.py

https://bitbucket.org/beqa/nvdadependencyvirtualenvironment
Python | 310 lines | 267 code | 4 blank | 39 comment | 0 complexity | 883ba1bd074379557e3271783fcb94ef MD5 | raw file
  1. #Mouse Gestures
  2. #Version 0.0.1
  3. #By Daniel Pozmanter
  4. #drpython@bluebottle.com
  5. #Released under the terms of the wxWindows License.
  6. """
  7. This is a class to add Mouse Gestures to a program.
  8. It can be used in two ways:
  9. 1. Automatic:
  10. Automatically runs mouse gestures.
  11. You need to set the gestures, and their associated actions,
  12. as well as the Mouse Button/Modifiers to use.
  13. 2. Manual:
  14. Same as above, but you do not need to set the mouse button/modifiers.
  15. You can launch this from events as you wish.
  16. An example is provided in the demo.
  17. The parent window is where the mouse events will be recorded.
  18. (So if you want to record them in a pop up window, use manual mode,
  19. and set the pop up as the parent).
  20. Start() starts recording mouse movement.
  21. End() stops the recording, compiles all the gestures into a list,
  22. and looks through the registered gestures to find a match.
  23. The first matchs associated action is then run.
  24. The marginoferror is how much to forgive when calculating movement:
  25. If the margin is 25, then movement less than 25 pixels will not be detected.
  26. Recognized: L, R, U, D, 1, 3, 7, 9
  27. Styles: Manual (Automatic By Default), DisplayNumbersForDiagonals (Off By Default).
  28. Not Yet Implemented
  29. The criteria for a direction is as follows:
  30. x in a row. (Where x is the WobbleTolerance).
  31. So if the WobbleTolerance is 9
  32. 'URUUUUUUUUUUUUUUURUURUUUU1' is Up.
  33. The higher this number, the less sensitive this class is.
  34. So the more likely something like 1L will translate to 1.
  35. This is good, since the mouse does tend to wobble somewhat,
  36. and a higher number allows for this.
  37. To change this, use SetWobbleTolerance
  38. Also, to help with recognition of a diagonal versus
  39. a vey messy straight line, if the greater absolute value
  40. is not greater than twice the lesser, only the grater value
  41. is counted.
  42. In automatic mode, EVT_MOUSE_EVENTS is used.
  43. This allows the user to change the mouse button/modifiers at runtime.
  44. """
  45. ###########################################
  46. '''
  47. Changelog:
  48. 0.0.1: Treats a mouse leaving event as mouse up.
  49. (Bug Report, Thanks Peter Damoc).
  50. 0.0.0: Initial Release.
  51. '''
  52. ###########################################
  53. #ToDo:
  54. #Fully Implement Manual Mode
  55. #Add "Ends With": AddGestureEndsWith(self, gesture, action, args)
  56. #Add "Starts With": AddGestuteStartsWith(self, gesture, action, args)
  57. #For better control of when the gesture starts and stops,
  58. #use manual mode.
  59. #At the moment, you need to Bind the OnMouseMotion event if you want to use
  60. #manual mode.
  61. import wx
  62. class MouseGestures:
  63. def __init__(self, parent, Auto=True, MouseButton=wx.MOUSE_BTN_MIDDLE):
  64. self.parent = parent
  65. self.gestures = []
  66. self.actions = []
  67. self.actionarguments = []
  68. self.mousebutton = MouseButton
  69. self.modifiers = []
  70. self.recording = False
  71. self.lastposition = (-1, -1)
  72. self.pen = wx.Pen(wx.Colour(0, 144, 255), 5)
  73. self.dc = wx.ScreenDC()
  74. self.dc.SetPen(self.pen)
  75. self.showgesture = False
  76. self.wobbletolerance = 7
  77. self.rawgesture = ''
  78. self.SetAuto(Auto)
  79. def _check_modifiers(self, event):
  80. '''Internal: Returns True if all needed modifiers are down
  81. for the given event.'''
  82. if len(self.modifiers) > 0:
  83. good = True
  84. if wx.WXK_CONTROL in self.modifiers:
  85. good = good and event.ControlDown()
  86. if wx.WXK_SHIFT in self.modifiers:
  87. good = good and event.ShiftDown()
  88. if wx.WXK_ALT in self.modifiers:
  89. good = good and event.AltDown()
  90. return good
  91. return True
  92. def AddGesture(self, gesture, action, *args):
  93. '''Registers a gesture, and an associated function, with any arguments needed.'''
  94. #Make Sure not a duplicate:
  95. self.RemoveGesture(gesture)
  96. self.gestures.append(gesture)
  97. self.actions.append(action)
  98. self.actionarguments.append(args)
  99. def DoAction(self, gesture):
  100. '''If the gesture is in the array of registered gestures, run the associated function.'''
  101. if gesture in self.gestures:
  102. i = self.gestures.index(gesture)
  103. apply(self.actions[i], self.actionarguments[i])
  104. def End(self):
  105. '''Stops recording the points to create the mouse gesture from,
  106. and creates the mouse gesture, returns the result as a string.'''
  107. self.recording = False
  108. #Figure out the gestures (Look for occurances of 5 in a row or more):
  109. tempstring = '0'
  110. possiblechange = '0'
  111. directions = ''
  112. for g in self.rawgesture:
  113. l = len(tempstring)
  114. if g != tempstring[l - 1]:
  115. if g == possiblechange:
  116. tempstring = g + g
  117. else:
  118. possiblechange = g
  119. else:
  120. tempstring += g
  121. if len(tempstring) >= self.wobbletolerance:
  122. ld = len(directions)
  123. if ld > 0:
  124. if directions[ld - 1] != g:
  125. directions += g
  126. else:
  127. directions += g
  128. tempstring = '0'
  129. if self.showgesture:
  130. self.parent.Refresh()
  131. return directions
  132. def GetDirection(self, point1, point2):
  133. '''Gets the direction between two points.'''
  134. #point1 is the old point
  135. #point2 is current
  136. x1, y1 = point1
  137. x2, y2 = point2
  138. #(Negative = Left, Up)
  139. #(Positive = Right, Down)
  140. horizontal = x2 - x1
  141. vertical = y2 - y1
  142. horizontalchange = abs(horizontal) > 0
  143. verticalchange = abs(vertical) > 0
  144. if horizontalchange and verticalchange:
  145. ah = abs(horizontal)
  146. av = abs(vertical)
  147. if ah > av:
  148. if (ah / av) > 2:
  149. vertical = 0
  150. verticalchange = False
  151. elif av > ah:
  152. if (av / ah) > 2:
  153. horizontal = 0
  154. horizontalchange = False
  155. if horizontalchange and verticalchange:
  156. #Diagonal
  157. if (horizontal > 0) and (vertical > 0):
  158. return '3'
  159. elif (horizontal > 0) and (vertical < 0):
  160. return '9'
  161. elif (horizontal < 0) and (vertical > 0):
  162. return '1'
  163. else:
  164. return '7'
  165. else:
  166. #Straight Line
  167. if horizontalchange:
  168. if horizontal > 0:
  169. return 'R'
  170. else:
  171. return 'L'
  172. else:
  173. if vertical > 0:
  174. return 'D'
  175. else:
  176. return 'U'
  177. def GetRecording(self):
  178. '''Returns whether or not Gesture Recording has started.'''
  179. return self.recording
  180. def OnMotion(self, event):
  181. '''Internal. Used if Start() has been run'''
  182. if self.recording:
  183. currentposition = event.GetPosition()
  184. if self.lastposition != (-1, -1):
  185. self.rawgesture += self.GetDirection(self.lastposition, currentposition)
  186. if self.showgesture:
  187. #Draw it!
  188. px1, py1 = self.parent.ClientToScreen(self.lastposition)
  189. px2, py2 = self.parent.ClientToScreen(currentposition)
  190. self.dc.DrawLine(px1, py1, px2, py2)
  191. self.lastposition = currentposition
  192. event.Skip()
  193. def OnMouseEvent(self, event):
  194. '''Internal. Used in Auto Mode.'''
  195. if event.ButtonDown(self.mousebutton) and self._check_modifiers(event):
  196. self.Start()
  197. elif (event.ButtonUp(self.mousebutton) or event.Leaving()) and self.GetRecording():
  198. result = self.End()
  199. self.DoAction(result)
  200. event.Skip()
  201. def RemoveGesture(self, gesture):
  202. '''Removes a gesture, and its associated action'''
  203. if gesture in self.gestures:
  204. i = self.gestures.index(gesture)
  205. del self.gestures[i]
  206. del self.actions[i]
  207. del self.actionarguments[i]
  208. def SetAuto(self, auto):
  209. '''Warning: Once auto is set, it stays set, unless you manually use UnBind'''
  210. if auto:
  211. self.parent.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
  212. self.parent.Bind(wx.EVT_MOTION, self.OnMotion)
  213. def SetGesturePen(self, pen):
  214. '''Sets the wx pen used to visually represent each gesture'''
  215. self.pen = pen
  216. self.dc.SetPen(self.pen)
  217. def SetGesturePen(self, colour, width):
  218. '''Sets the colour and width of the line drawn to visually represent each gesture'''
  219. self.pen = wx.Pen(colour, width)
  220. self.dc.SetPen(self.pen)
  221. def SetGesturesVisible(self, vis):
  222. '''Sets whether a line is drawn to visually represent each gesture'''
  223. self.showgesture = vis
  224. def SetModifiers(self, modifiers=[]):
  225. '''Takes an array of wx Key constants (Control, Shift, and/or Alt).
  226. Leave empty to unset all modifiers.'''
  227. self.modifiers = modifiers
  228. def SetMouseButton(self, mousebutton):
  229. '''Takes the wx constant for the target mousebutton'''
  230. self.mousebutton = mousebutton
  231. def SetWobbleTolerance(self, wobbletolerance):
  232. '''Sets just how much wobble this class can take!'''
  233. self.WobbleTolerance = wobbletolerance
  234. def Start(self):
  235. '''Starts recording the points to create the mouse gesture from'''
  236. self.recording = True
  237. self.rawgesture = ''
  238. self.lastposition = (-1, -1)
  239. if self.showgesture:
  240. self.parent.Refresh()