Helios-KeyBindings.st 6.4 KB

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