Helios-KeyBindings.st 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. Smalltalk current createPackage: 'Helios-KeyBindings' properties: #{}!
  2. Object subclass: #HLBinding
  3. instanceVariableNames: 'key label'
  4. package: 'Helios-KeyBindings'!
  5. !HLBinding methodsFor: 'accessing'!
  6. key
  7. ^ key
  8. !
  9. key: anInteger
  10. key := anInteger
  11. !
  12. label
  13. ^ label
  14. !
  15. label: aString
  16. label := aString
  17. !
  18. shortcut
  19. ^ String fromCharCode: self key
  20. ! !
  21. !HLBinding methodsFor: 'actions'!
  22. applyOn: aKeyBinder
  23. self subclassResponsibility
  24. ! !
  25. !HLBinding methodsFor: 'rendering'!
  26. renderOn: aBindingHelper html: html
  27. ! !
  28. !HLBinding methodsFor: 'testing'!
  29. isBindingAction
  30. ^ false
  31. !
  32. isBindingGroup
  33. ^ false
  34. ! !
  35. !HLBinding class methodsFor: 'instance creation'!
  36. on: anInteger labelled: aString
  37. ^ self new
  38. key: anInteger;
  39. label: aString;
  40. yourself
  41. ! !
  42. HLBinding subclass: #HLBindingAction
  43. instanceVariableNames: 'callback'
  44. package: 'Helios-KeyBindings'!
  45. !HLBindingAction methodsFor: 'accessing'!
  46. callback
  47. ^ callback
  48. !
  49. callback: aBlock
  50. callback := aBlock
  51. ! !
  52. !HLBindingAction methodsFor: 'actions'!
  53. applyOn: aKeyBinder
  54. aKeyBinder applyBindingAction: self
  55. ! !
  56. !HLBindingAction methodsFor: 'testing'!
  57. isBindingAction
  58. ^ true
  59. ! !
  60. HLBinding subclass: #HLBindingGroup
  61. instanceVariableNames: 'bindings'
  62. package: 'Helios-KeyBindings'!
  63. !HLBindingGroup methodsFor: 'accessing'!
  64. add: aBinding
  65. ^ self bindings add: aBinding
  66. !
  67. addActionKey: anInteger labelled: aString callback: aBlock
  68. self add: ((HLBindingAction on: anInteger labelled: aString)
  69. callback: aBlock;
  70. yourself)
  71. !
  72. addGroupKey: anInteger labelled: aString
  73. self add: (HLBindingGroup on: anInteger labelled: aString)
  74. !
  75. at: aString
  76. ^ self bindings
  77. detect: [ :each | each label = aString ]
  78. ifNone: [ nil ]
  79. !
  80. atKey: anInteger
  81. ^ self bindings
  82. detect: [ :each | each key = anInteger ]
  83. ifNone: [ nil ]
  84. !
  85. bindings
  86. ^ bindings ifNil: [ bindings := OrderedCollection new ]
  87. ! !
  88. !HLBindingGroup methodsFor: 'actions'!
  89. applyOn: aKeyBinder
  90. aKeyBinder applyBindingGroup: self
  91. ! !
  92. !HLBindingGroup methodsFor: 'rendering'!
  93. renderOn: aBindingHelper html: html
  94. aBindingHelper renderBindingGroup: self on: html
  95. ! !
  96. !HLBindingGroup methodsFor: 'testing'!
  97. isBindingGroup
  98. ^ true
  99. ! !
  100. Object subclass: #HLKeyBinder
  101. instanceVariableNames: 'modifierKey active helper bindings selectedBinding'
  102. package: 'Helios-KeyBindings'!
  103. !HLKeyBinder methodsFor: 'accessing'!
  104. activationKey
  105. "SPACE"
  106. ^ 32
  107. !
  108. bindings
  109. ^ bindings ifNil: [ bindings := HLBindingGroup new ]
  110. !
  111. escapeKey
  112. "ESC"
  113. ^ 27
  114. !
  115. helper
  116. ^ helper ifNil: [ helper := HLKeyBinderHelper on: self ]
  117. !
  118. selectedBinding
  119. ^ selectedBinding ifNil: [ self bindings ]
  120. ! !
  121. !HLKeyBinder methodsFor: 'actions'!
  122. activate
  123. active := true.
  124. self helper show
  125. !
  126. applyBinding: aBinding
  127. aBinding applyOn: self
  128. !
  129. applyBindingAction: aBinding
  130. aBinding callback value.
  131. self deactivate
  132. !
  133. applyBindingGroup: aBinding
  134. selectedBinding := aBinding.
  135. self helper refresh
  136. !
  137. deactivate
  138. active := false.
  139. selectedBinding := nil.
  140. self helper hide
  141. !
  142. flushBindings
  143. bindings := nil.
  144. helper := nil
  145. ! !
  146. !HLKeyBinder methodsFor: 'events'!
  147. handleActiveKeyDown: event
  148. "ESC or ctrl+g deactivate the keyBinder"
  149. (event which = self escapeKey or: [
  150. event which = 71 and: [ event ctrlKey ] ])
  151. ifTrue: [
  152. self deactivate.
  153. event preventDefault.
  154. ^ false ].
  155. "Handle the keybinding"
  156. ^ self handleBindingFor: event
  157. !
  158. handleBindingFor: anEvent
  159. | binding |
  160. binding := self selectedBinding atKey: anEvent which.
  161. binding ifNotNil: [
  162. self applyBinding: binding.
  163. anEvent preventDefault.
  164. ^ false ]
  165. !
  166. handleInactiveKeyDown: event
  167. event which = self activationKey ifTrue: [
  168. (self systemIsMac
  169. ifTrue: [ event metaKey ]
  170. ifFalse: [ event ctrlKey ]) ifTrue: [
  171. self activate.
  172. event preventDefault.
  173. ^ false ] ]
  174. !
  175. handleKeyDown: event
  176. ^ self isActive
  177. ifTrue: [ self handleActiveKeyDown: event ]
  178. ifFalse: [ self handleInactiveKeyDown: event ]
  179. !
  180. setupEvents
  181. (window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ]
  182. ! !
  183. !HLKeyBinder methodsFor: 'initialization'!
  184. initialize
  185. super initialize.
  186. active := false
  187. ! !
  188. !HLKeyBinder methodsFor: 'testing'!
  189. isActive
  190. ^ active ifNil: [ false ]
  191. !
  192. systemIsMac
  193. ^ navigator platform match: 'Mac'
  194. ! !
  195. HLWidget subclass: #HLKeyBinderHelper
  196. instanceVariableNames: 'keyBinder'
  197. package: 'Helios-KeyBindings'!
  198. !HLKeyBinderHelper methodsFor: 'accessing'!
  199. keyBinder
  200. ^ keyBinder
  201. !
  202. keyBinder: aKeyBinder
  203. keyBinder := aKeyBinder
  204. !
  205. selectedBinding
  206. ^ self keyBinder selectedBinding
  207. ! !
  208. !HLKeyBinderHelper methodsFor: 'actions'!
  209. hide
  210. rootDiv asJQuery remove
  211. !
  212. show
  213. self appendToJQuery: 'body' asJQuery
  214. ! !
  215. !HLKeyBinderHelper methodsFor: 'keyBindings'!
  216. registerBindings
  217. "Do nothing"
  218. ! !
  219. !HLKeyBinderHelper methodsFor: 'rendering'!
  220. renderBindingGroup: aBindingGroup on: html
  221. (aBindingGroup bindings
  222. sorted: [ :a :b | a key < b key ])
  223. do: [ :each |
  224. html span class: 'command'; with: [
  225. html span class: 'label'; with: each shortcut asLowercase.
  226. html a
  227. class: 'action';
  228. with: each label;
  229. onClick: [ self keyBinder applyBinding: each ] ] ]
  230. !
  231. renderBindingOn: html
  232. self selectedBinding renderOn: self html: html
  233. !
  234. renderContentOn: html
  235. html div class: 'key_helper'; with: [
  236. self
  237. renderSelectionOn:html;
  238. renderBindingOn: html ]
  239. !
  240. renderSelectionOn: html
  241. html span
  242. class: 'selected';
  243. with: (self selectedBinding label ifNil: [ 'Action' ])
  244. ! !
  245. !HLKeyBinderHelper class methodsFor: 'instance creation'!
  246. on: aKeyBinder
  247. ^ self new
  248. keyBinder: aKeyBinder;
  249. yourself
  250. ! !