#FEATURE by exept
class: EditField
support cancel key handling
class definition
added:
#cancelKey
#cancelKeys
#cancelKeys:
#onKey:cancelWith:
comment/format in: #leaveKey
changed:
#keyPress:x:y:
#onKey:leaveWith:
class: EditField class
comment/format in: #documentation
--- a/EditField.st Thu Sep 19 14:53:24 2019 +0200
+++ b/EditField.st Thu Sep 19 21:27:13 2019 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
"
COPYRIGHT (c) 1990 by Claus Gittinger
All Rights Reserved
@@ -19,7 +21,8 @@
lengthLimit entryCompletionBlock entryCompletionCharacter
passwordCharacter autoScrollHorizontally acceptOnTab
acceptOnLostFocus acceptOnPointerLeave acceptIfUnchanged leaveKey
- doubleClickAction emptyFieldReplacementText leaveKeyActions'
+ doubleClickAction emptyFieldReplacementText leaveKeyActions
+ cancelKeys cancelKey cancelKeyActions'
classVariableNames:'DefaultForegroundColor DefaultBackgroundColor
DefaultSelectionForegroundColor DefaultSelectionBackgroundColor
DefaultBorderColor DefaultBorderWidth DefaultLevel'
@@ -97,8 +100,26 @@
The physical completion-key is the Tab key (this one cannot be defined by
the keyboardTranslation mechanism, since that would disable the Tab-key on regular text views.
-
-
+ special key handling:
+ usually, editFields are embedded in a form (as in a dialog),
+ which has OK and Cancel buttons at the bottom.
+ However, if the editField is in some other popup, it may be required to customize its behavior
+ upon certain key events.
+ For this, the following flags are used:
+ leaveKeys - the set of keys, which will lead to an accept (of the value into the model),
+ and leave the focus. If that happens, the responsible key is left in the leaveKey variable.
+ Default are CursorUp, Down and Return
+
+ leaveAction - if not nil, that action is called after the accept, passing the leaveKey as argument
+
+ acceptOnLeave - if true, an accept will be performed on leave.
+
+ cancelKeys - the set of keys which will leve without accepting. If that happens, the responsible
+ key is left in the cancelKey variable.
+
+ cancelAction - if not nil, that action is called, passing the cancelKey as argument.
+
+
[Instance variables:]
leaveAction <Block | nil> if non-nil, this is evaluated with
@@ -957,6 +978,30 @@
autoScrollHorizontally := aBoolean
!
+cancelKey
+ "only valid after the editField has been left via a cancelCharacter.
+ Allows for users of the EditField to advance the selection
+ (especially: DataSets to select next/prev if editor is left via CrsrUp/Down).
+ This is probably a stupid interface - better use onKey:cancelWith: for a directed action"
+
+ ^ cancelKey
+!
+
+cancelKeys
+ "return (a copy of) the collection of keys which are interpreted as cancelKeys.
+ I.e. those that make the field inactive and pass the focus to the next field
+ (without accept)"
+
+ ^ cancelKeys copy
+!
+
+cancelKeys:aCollectionOfKeySymbols
+ "define the set of keys which are interpreted as cancelKeys.
+ I.e. those that make the field inactive without accept."
+
+ cancelKeys := aCollectionOfKeySymbols
+!
+
clickAction:aBlock
"define an action to be evaluated when being clicked upon"
@@ -1143,7 +1188,8 @@
leaveKey
"only valid after the editField has been left via a leaveCharacter.
Allows for users of the EditField to advance the selection
- (especially: DataSets to select next/prev if editor is left via CrsrUp/Down)"
+ (especially: DataSets to select next/prev if editor is left via CrsrUp/Down).
+ This is probably a stupid interface - better use onKey:leaveWith: for a directed action"
^ leaveKey
!
@@ -1177,6 +1223,24 @@
"Created: 27.4.1996 / 17:09:48 / cg"
!
+onKey:aKey cancelWith:aBlock
+ "arrange for aKey to leave the field (without accept) and evaluate aBlock.
+ On cancel, the precedence of actions is:
+ 1) explicit cancelAction per key
+ 1) explicit leaveAction per key
+ 2) general leaveAction
+ 3) tab or return action
+ Can be used to arrange for escape to deal with special operations (such as closing some view),
+ The cancel-action block will be called with 0,1 (the key) or 2 (self + key) arguments"
+
+ cancelKeys := (cancelKeys ? #()) asSet.
+ cancelKeys add:aKey.
+ cancelKeyActions isNil ifTrue:[
+ cancelKeyActions := Dictionary new.
+ ].
+ cancelKeyActions at:aKey put:aBlock.
+!
+
onKey:aKey leaveWith:aBlock
"arrange for aKey to leave the field and evaluate aBlock.
On leave, the precedence of actions is:
@@ -1187,7 +1251,7 @@
or to override builtin ctrl- shortcuts.
The leave-action block will be called with 0,1 (the key) or 2 (self + key) arguments"
- leaveKeys := leaveKeys asOrderedCollection.
+ leaveKeys := (leaveKeys ? #()) asSet.
leaveKeys add:aKey.
leaveKeyActions isNil ifTrue:[
leaveKeyActions := Dictionary new.
@@ -1681,7 +1745,7 @@
#DeleteLine #GotoLine #EndOfLine #EndOfText
#CursorDown #CursorUp)>
- |rawKey leave doAccept keyAction numArgs lastEvent|
+ |rawKey leave cancel doAccept keyAction numArgs lastEvent|
enabled ifFalse:[
^ self
@@ -1707,18 +1771,48 @@
keyAction := crAction.
].
- leave := leaveKeys includes:key.
- leave ifFalse:[
- lastEvent := WindowGroup lastEvent.
- (lastEvent notNil and:[lastEvent isKeyEvent]) ifTrue:[
- leave := leaveKeys includes:lastEvent rawKey.
+ lastEvent := WindowGroup lastEvent.
+ (lastEvent notNil and:[lastEvent isKeyEvent]) ifTrue:[
+ rawKey := lastEvent rawKey.
+ ].
+
+ cancel := leave := false.
+
+ cancel := (cancelKeys ? #()) includes:key.
+ cancel ifFalse:[
+ cancel := (cancelKeys ? #()) includes:rawKey.
+ cancel ifFalse:[
+ leave := (leaveKeys ? #()) includes:key.
+ leave ifFalse:[
+ leave := (leaveKeys ? #()) includes:rawKey.
+ ].
].
].
-
- leave ifTrue:[
- leaveKey := key.
- doAccept := doAccept ? acceptOnLeave.
-
+ cancel ifTrue:[
+ cancelKey := key.
+ doAccept := false.
+ ] ifFalse:[
+ leave ifTrue:[
+ leaveKey := key.
+ doAccept := doAccept ? acceptOnLeave.
+ ].
+ ].
+
+ cancel ifTrue:[
+ "/ on cancel, the precedence of actions is:
+ "/ 1) explicit cancelAction per key
+ cancelKeyActions notNil ifTrue:[
+ keyAction := cancelKeyActions
+ at:key
+ ifAbsent:[
+ cancelKeyActions
+ at:rawKey
+ ifAbsent:nil].
+ ].
+ ].
+ ((cancel and:[keyAction isNil])
+ or:[cancel not and:[leave]]
+ ) ifTrue:[
"/ on leave, the precedence of actions is:
"/ 1) explicit leaveAction per key
"/ 2) general leaveAction
@@ -1740,7 +1834,6 @@
keyAction notNil ifTrue:[
numArgs := keyAction argumentCount.
-
numArgs == 2 ifTrue:[
^ keyAction value:self value:key
].