Helios-KeyBindings.st 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. Smalltalk current createPackage: 'Helios-KeyBindings'!
  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. addActionKey: anInteger labelled: aString command: aCommand
  73. self add: ((HLBindingAction on: anInteger labelled: aString)
  74. command: aCommand;
  75. yourself)
  76. !
  77. addGroupKey: anInteger labelled: aString
  78. self add: (HLBindingGroup on: anInteger labelled: aString)
  79. !
  80. at: aString
  81. ^ self bindings
  82. detect: [ :each | each label = aString ]
  83. ifNone: [ nil ]
  84. !
  85. atKey: anInteger
  86. ^ self bindings
  87. detect: [ :each | each key = anInteger ]
  88. ifNone: [ nil ]
  89. !
  90. bindings
  91. ^ bindings ifNil: [ bindings := OrderedCollection new ]
  92. ! !
  93. !HLBindingGroup methodsFor: 'actions'!
  94. applyOn: aKeyBinder
  95. aKeyBinder applyBindingGroup: self
  96. ! !
  97. !HLBindingGroup methodsFor: 'rendering'!
  98. renderOn: aBindingHelper html: html
  99. aBindingHelper renderBindingGroup: self on: html
  100. ! !
  101. !HLBindingGroup methodsFor: 'testing'!
  102. isBindingGroup
  103. ^ true
  104. ! !
  105. Object subclass: #HLKeyBinder
  106. instanceVariableNames: 'modifierKey active helper bindings selectedBinding'
  107. package: 'Helios-KeyBindings'!
  108. !HLKeyBinder methodsFor: 'accessing'!
  109. activationKey
  110. "SPACE"
  111. ^ 32
  112. !
  113. activationKeyLabel
  114. ^ 'ctrl + space'
  115. !
  116. bindings
  117. ^ bindings ifNil: [ bindings := self defaulBindings ]
  118. !
  119. defaulBindings
  120. | group |
  121. group := HLBindingGroup new
  122. addGroupKey: 79 labelled: 'Open';
  123. addGroupKey: 86 labelled: 'View';
  124. add: HLCloseTabCommand new asBinding;
  125. yourself.
  126. HLOpenCommand allSubclasses do: [ :each |
  127. (group at: each bindingGroup)
  128. add: each new asBinding ].
  129. ^ group
  130. !
  131. escapeKey
  132. "ESC"
  133. ^ 27
  134. !
  135. helper
  136. ^ helper
  137. !
  138. selectedBinding
  139. ^ selectedBinding ifNil: [ self bindings ]
  140. ! !
  141. !HLKeyBinder methodsFor: 'actions'!
  142. activate
  143. active := true.
  144. self helper show
  145. !
  146. applyBinding: aBinding
  147. aBinding applyOn: self
  148. !
  149. applyBindingAction: aBinding
  150. aBinding callback value.
  151. self deactivate
  152. !
  153. applyBindingGroup: aBinding
  154. selectedBinding := aBinding.
  155. self helper refresh
  156. !
  157. deactivate
  158. active := false.
  159. selectedBinding := nil.
  160. self helper hide
  161. !
  162. flushBindings
  163. bindings := nil
  164. ! !
  165. !HLKeyBinder methodsFor: 'events'!
  166. handleActiveKeyDown: event
  167. "ESC or ctrl+g deactivate the keyBinder"
  168. (event which = self escapeKey or: [
  169. event which = 71 and: [ event ctrlKey ] ])
  170. ifTrue: [
  171. self deactivate.
  172. event preventDefault.
  173. ^ false ].
  174. "Handle the keybinding"
  175. ^ self handleBindingFor: event
  176. !
  177. handleBindingFor: anEvent
  178. | binding |
  179. binding := self selectedBinding atKey: anEvent which.
  180. binding ifNotNil: [
  181. self applyBinding: binding.
  182. anEvent preventDefault.
  183. ^ false ]
  184. !
  185. handleInactiveKeyDown: event
  186. event which = self activationKey ifTrue: [
  187. event ctrlKey ifTrue: [
  188. self activate.
  189. event preventDefault.
  190. ^ false ] ]
  191. !
  192. handleKeyDown: event
  193. ^ self isActive
  194. ifTrue: [ self handleActiveKeyDown: event ]
  195. ifFalse: [ self handleInactiveKeyDown: event ]
  196. !
  197. setupEvents
  198. (window jQuery: 'body') keydown: [ :event | self handleKeyDown: event ]
  199. ! !
  200. !HLKeyBinder methodsFor: 'initialization'!
  201. initialize
  202. super initialize.
  203. helper := HLKeyBinderHelper on: self.
  204. helper renderStart.
  205. active := false
  206. ! !
  207. !HLKeyBinder methodsFor: 'testing'!
  208. isActive
  209. ^ active ifNil: [ false ]
  210. !
  211. systemIsMac
  212. ^ navigator platform match: 'Mac'
  213. ! !
  214. HLWidget subclass: #HLKeyBinderHelper
  215. instanceVariableNames: 'keyBinder'
  216. package: 'Helios-KeyBindings'!
  217. !HLKeyBinderHelper methodsFor: 'accessing'!
  218. cssClass
  219. ^ 'key_helper'
  220. !
  221. keyBinder
  222. ^ keyBinder
  223. !
  224. keyBinder: aKeyBinder
  225. keyBinder := aKeyBinder
  226. !
  227. selectedBinding
  228. ^ self keyBinder selectedBinding
  229. ! !
  230. !HLKeyBinderHelper methodsFor: 'actions'!
  231. hide
  232. ('.', self cssClass) asJQuery remove
  233. !
  234. show
  235. self appendToJQuery: 'body' asJQuery
  236. ! !
  237. !HLKeyBinderHelper methodsFor: 'keyBindings'!
  238. registerBindings
  239. "Do nothing"
  240. ! !
  241. !HLKeyBinderHelper methodsFor: 'rendering'!
  242. renderBindingGroup: aBindingGroup on: html
  243. (aBindingGroup bindings
  244. sorted: [ :a :b | a key < b key ])
  245. do: [ :each |
  246. html span class: 'command'; with: [
  247. html span class: 'label'; with: each shortcut asLowercase.
  248. html a
  249. class: 'action';
  250. with: each label;
  251. onClick: [ self keyBinder applyBinding: each ] ] ]
  252. !
  253. renderBindingOn: html
  254. self selectedBinding renderOn: self html: html
  255. !
  256. renderContentOn: html
  257. html div class: self cssClass; with: [
  258. self
  259. renderSelectionOn:html;
  260. renderBindingOn: html ]
  261. !
  262. renderSelectionOn: html
  263. html span
  264. class: 'selected';
  265. with: (self selectedBinding label ifNil: [ 'Action' ])
  266. !
  267. renderStart
  268. [ :html |
  269. html div
  270. id: 'keybinding-start-helper';
  271. with: 'Press ', self keyBinder activationKeyLabel, ' to start' ] appendToJQuery: 'body' asJQuery.
  272. [ (window jQuery: '#keybinding-start-helper') fadeOut: 1000 ]
  273. valueWithTimeout: 2000
  274. ! !
  275. !HLKeyBinderHelper class methodsFor: 'instance creation'!
  276. on: aKeyBinder
  277. ^ self new
  278. keyBinder: aKeyBinder;
  279. yourself
  280. ! !