--- a/EditField.st Tue Jan 16 03:04:32 1996 +0100
+++ b/EditField.st Tue Jan 16 20:07:57 1996 +0100
@@ -14,7 +14,7 @@
instanceVariableNames:'leaveAction enabled enableAction crAction tabAction converter
leaveKeys immediateAccept acceptOnLeave acceptOnReturn
lengthLimit entryCompletionBlock passwordCharacter
- cursorMovementWhenUpdating enableChannel'
+ cursorMovementWhenUpdating enableChannel autoScrollHorizontally'
classVariableNames:'DefaultForegroundColor DefaultBackgroundColor
DefaultSelectionForegroundColor DefaultSelectionBackgroundColor
DefaultFont'
@@ -44,6 +44,56 @@
and forcing its size to 1 line - disabling cursor movement
in the vertical direction.
+ Basically, an editField is an editor for a single line text,
+ and provides the usual access protocol as defined in its superClasses
+ (especially: #contents / #contents:).
+
+ The above underlying internal mechanism can be used for fields which
+ are passive; i.e. into which text can be entered and the value (string)
+ is extracted actively by someone else.
+
+ accepting:
+ The opposite way to use editFields is to connect them to a model
+ and let the field notify changes to it.
+ This notification is called ``accepting''.
+ Unless accepted, the models value is not updated from the editFields contents
+ this default is the normal operation and way things should work, since most
+ uses of editFields are not interrested in every individual change
+ (i.e. getting each keyStroke when a long number is entered).
+ The default behavior is to ``accept'' when either return or a cursorUp/Down
+ key is pressed in a field.
+ However, the field can setup to accept/not accept on leave, on return
+ or on each individual key input.
+ See the methods #acceptOnLeave: / #acceptOnReturn: / #immediateAccept.
+
+ In addition, the set of keys which are considered ``leaveKeys'' can be
+ specified by #leaveKeys: (in case you need keys other than Return, CursorUp/Down).
+
+ models value vs. field contents:
+ Although the field internally keeps its contents as some string object,
+ the application may prefer to think of numbers, floats, yes/no values etc.
+ To support this, a converter may defined, which is responsible for conversion of
+ strings to/from the models domain value.
+ If present (i.e. nonNil), the converter is asked to convert a string to the models
+ domain with #readValueFrom:aString and vice versa, a value to a string by #printStringFor:.
+ The PrintConverter class already provides a number of standard conversions, see the examples.
+ To access a converted value directly (i.e. not via the model), use #editValue.
+
+ grouping:
+ Individual fields do not know about being included in a group. This must be arranged on the
+ outside, by placing multiple fields into an EnterFieldGroup.
+ This groupObject keeps a reference to one active field, and forwards input from any other
+ field to the active one. Also have a look at the examples for this.
+
+ input completion:
+ To support input completion (i.e. filename completion, classname completion etc.),
+ a completionBlock can be defined which (if non-nil) is evaluated when the completion-key
+ is pressed and its value is taken as the new field-contents.
+ 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.
+
+
+
Instance variables:
leaveAction <Block | nil> if non-nil, this is evaluated with
@@ -66,13 +116,14 @@
tabAction <Block | nil> if non-nil, keyboard input of a tab character
is not entered into the text, instead this block
- is evaluated.
+ is evaluated. Also, no input completion is performed if
+ tabAction is nonNil.
converter <PrintConverter | nil> if non-nil, this is supposed to convert between
- the object and its printed representation.
+ the object and its printed representation and vice versa.
Defaults to nil i.e. assume that strings are edited.
- leaveKeys <Collection> keys which are interpreted as 'leving the field'
+ leaveKeys <Collection> keys which are interpreted as 'leaving the field'
immediateAccept <Boolean> if true, every change of the text is immediately
forwarded to the model/acceptBlock. If false,
@@ -95,348 +146,401 @@
see more examples in EnterFieldGroup>>examples.
- basic field in a view:
+ Step-by-step introduction:
+
- |top field|
+ basic field in some view:
+
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@0.0 in:top.
- field width:1.0. 'let its height as-is'.
+ field := EditField origin:0.0@0.0 in:top.
+ field width:1.0. 'let its height as-is'.
- top open
+ top open
forward input in topView to the field:
(currently, the field does not know this - therefore,
its been told here ... this may change)
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@0.0 in:top.
- field width:1.0. 'let its height as-is'.
+ field := EditField origin:0.0@0.0 in:top.
+ field width:1.0. 'let its height as-is'.
- top delegate:(KeyboardForwarder toView:field).
- field hasKeyboardFocus:true.
- top open
+ top delegate:(KeyboardForwarder toView:field).
+ field hasKeyboardFocus:true.
+ top open
to make it look better: set some inset:
- |top field|
+ |top field spacing|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0. 'let its height as-is'.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
+ spacing := View viewSpacing.
+ field := EditField origin:(0.0 @ spacing) in:top.
+ field width:1.0. 'let its height as-is'.
+ field leftInset:spacing; rightInset:spacing.
- top open
+ top open
give it an initial contents:
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello world'.
+ field := EditField origin:(0.0 @ 0@0) in:top.
+ field width:1.0.
- top open
+ field editValue:'hello world'.
+
+ top open
have it preselected:
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello world' selected:true.
+ field := EditField origin:(0.0 @ 0.0) in:top.
+ field width:1.0.
+ field editValue:'hello world' selected:true.
- top open
+ top open
have part of it preselected:
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello world';
- selectFromCharacterPosition:1 to:5.
+ field := EditField origin:(0.0 @ 0.0) in:top.
+ field width:1.0.
- top open
+ field editValue:'hello world'.
+ field selectFromCharacterPosition:1 to:5.
+
+ top open
set a size limit:
- |top field|
+ |top field|
+
+ top := StandardSystemView new.
+ top extent:200@100.
- top := StandardSystemView new.
- top extent:200@100.
+ field := EditField origin:(0.0 @ 0.0) in:top.
+ field width:1.0.
+ field editValue:'hello'.
+
+ field maxChars:8.
+
+ top open
+
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello';
- maxChars:8.
+ set a size limit, initial width and stop it from scrolling
+ notice: you may prefer a constant-pitch font (such as courier):
+
+ |top field|
+
+ top := StandardSystemView new.
+ top extent:200@100.
- top open
+ field := EditField origin:(0.0 @ 0.0) in:top.
+ field innerWidth:(field font widthOf:'00000000').
+ field editValue:'12345678'.
+
+ field maxChars:8.
+ field autoScroll:false.
+
+ top open
enable / disable:
- |top panel check field ena|
+ |top panel check field ena|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.
- panel horizontalLayout:#leftSpace.
+ panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.
+ panel horizontalLayout:#leftSpace.
- check := CheckBox label:'enable' in:panel.
- check turnOn.
- check action:[:onOff | onOff ifTrue:[field enable] ifFalse:[field disable]].
+ check := CheckBox label:'enable' in:panel.
+ check turnOn.
+ check action:[:onOff | onOff ifTrue:[field enable] ifFalse:[field disable]].
- panel add:(View new height:30).
+ panel add:(View new height:30).
- field := EditField in:panel.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello'.
+ field := EditField in:panel.
+ field width:1.0.
+ field editValue:'hello'.
- top open
+ top open
enable / disable using a channel:
- |top panel check field ena|
+ |top panel check field ena|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.
- panel horizontalLayout:#leftSpace.
+ panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.
+ panel horizontalLayout:#leftSpace.
- ena := true asValue.
+ ena := true asValue.
- check := CheckBox label:'enable' in:panel.
- check model:ena.
+ check := CheckBox label:'enable' in:panel.
+ check model:ena.
- panel add:(View new height:30).
+ panel add:(View new height:30).
- field := EditField in:panel.
- field enableChannel:ena.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field editValue:'hello'.
+ field := EditField in:panel.
+ field enableChannel:ena.
+ field width:1.0.
+ field editValue:'hello'.
- top open
+ top open
use a converter:
- numbers (default to 0):
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
+ field := EditField origin:0.0@ViewSpacing in:top.
+ field width:1.0.
+ field leftInset:ViewSpacing;
+ rightInset:ViewSpacing.
- field converter:(PrintConverter new initForNumber).
- field editValue:1234.
- field acceptAction:[:value | Transcript showCr:value].
- field crAction:[field accept. top destroy].
- top open.
+ field converter:(PrintConverter new initForNumber).
+ field editValue:1234.
+ field acceptAction:[:value | Transcript showCr:value].
+ field crAction:[field accept. top destroy].
+ top open.
- dates:
- |top field|
+ |top field|
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
+ field := EditField origin:0.0@ViewSpacing in:top.
+ field width:1.0.
+ field leftInset:ViewSpacing;
+ rightInset:ViewSpacing.
- field converter:(PrintConverter new initForDate).
- field editValue:Date today.
- field acceptAction:[:value | Transcript showCr:value class name , ' ' , value printString].
- field crAction:[field accept. top destroy].
- top open.
+ field converter:(PrintConverter new initForDate).
+ field editValue:Date today.
+ field acceptAction:[:value | Transcript showCr:value class name , ' ' , value printString].
+ field crAction:[field accept. top destroy].
+ top open.
setting immediateAccept, makes the field update with every key:
- immediate accept numbers, defaulting to nil:
- |top field|
+ |top field|
+
+ top := StandardSystemView new.
+ top extent:200@100.
- top := StandardSystemView new.
- top extent:200@100.
+ field := EditField origin:0.0@ViewSpacing in:top.
+ field width:1.0.
+ field leftInset:ViewSpacing;
+ rightInset:ViewSpacing.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
+ field converter:(PrintConverter new initForNumberOrNil).
+ field immediateAccept:true.
+ field editValue:1234.
+ field acceptAction:[:value | Transcript showCr:value].
+ field crAction:[field accept. top destroy].
+ top open.
- field converter:(PrintConverter new initForNumberOrNil).
- field immediateAccept:true.
- field editValue:1234.
- field acceptAction:[:value | Transcript showCr:value].
- field crAction:[field accept. top destroy].
- top open.
+
+
+ grouping multiple fields, and forward keyPres from the outer view to the active field
+ (i.e. actually: to the group):
+
+ |top field1 field2 field3 group|
+ top := StandardSystemView new.
+ top extent:200@100.
+
+ field1 := EditField origin:(0.0 @ 0.0) in:top.
+ field1 width:1.0.
+
+ field2 := EditField origin:(0.0 @ 0.0) in:top.
+ field2 width:0.5.
+ field2 topInset:(field1 height); bottomInset:(field1 height negated).
+
+ field3 := EditField origin:(0.5 @ 0.0) in:top.
+ field3 width:0.5.
+ field3 topInset:(field1 height); bottomInset:(field1 height negated).
+
+ group := EnterFieldGroup new.
+ group add:field1; add:field2; add:field3.
+
+ top delegate:(KeyboardForwarder to:group).
+
+ top open.
+
+
+ in addition: tell the group to close when the last field is left:
+
+ |top field1 field2 field3 group|
+
+
+ top := StandardSystemView new.
+ top extent:200@100.
+
+ field1 := EditField origin:(0.0 @ 0.0) in:top.
+ field1 width:1.0.
+
+ field2 := EditField origin:(0.0 @ 0.0) in:top.
+ field2 width:0.5.
+ field2 topInset:(field1 height); bottomInset:(field1 height negated).
+
+ field3 := EditField origin:(0.5 @ 0.0) in:top.
+ field3 width:0.5.
+ field3 topInset:(field1 height); bottomInset:(field1 height negated).
+
+ group := EnterFieldGroup new.
+ group add:field1; add:field2; add:field3.
+ group leaveAction:[top destroy].
+
+ top delegate:(KeyboardForwarder to:group).
+
+ top open.
use a model:
(see changing model value in inspector when return is pressed in the field)
- |top field model|
+ |top field model|
- model := 'hello world' asValue.
+ model := 'hello world' asValue.
- top := StandardSystemView new.
- top extent:200@100.
+ top := StandardSystemView new.
+ top extent:200@100.
- field := EditField origin:0.0@ViewSpacing in:top.
- field width:1.0.
- field leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field model:model.
- field acceptOnReturn:true.
+ field := EditField origin:(0.0 @ 0.0) in:top.
+ field width:1.0.
+ field model:model.
+ field acceptOnReturn:true.
- top open.
- model inspect.
+ top open.
+ model inspect.
two views on the same model (each accepts on return):
- |top1 top2 field1 field2 model|
+ |top1 top2 field1 field2 model|
- model := 'hello world' asValue.
+ model := 'hello world' asValue.
- top1 := StandardSystemView new.
- top1 extent:200@100.
- field1 := EditField origin:0.0@ViewSpacing in:top1.
- field1 width:1.0.
- field1 leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field1 model:model.
- field1 acceptOnReturn:true.
- top1 open.
+ top1 := StandardSystemView new.
+ top1 extent:200@100.
+ field1 := EditField origin:(0.0 @ 0.0) in:top1.
+ field1 width:1.0.
+ field1 model:model.
+ field1 acceptOnReturn:true.
+ top1 open.
- top2 := StandardSystemView new.
- top2 extent:200@100.
- field2 := EditField origin:0.0@ViewSpacing in:top2.
- field2 width:1.0.
- field2 leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field2 model:model.
- field2 acceptOnReturn:true.
- top2 open.
+ top2 := StandardSystemView new.
+ top2 extent:200@100.
+ field2 := EditField origin:(0.0 @ 0.0) in:top2.
+ field2 width:1.0.
+ field2 model:model.
+ field2 acceptOnReturn:true.
+ top2 open.
two views on the same model (no accept on return):
- |top1 top2 field1 field2 model|
+ |top1 top2 field1 field2 model|
- model := 'hello world' asValue.
+ model := 'hello world' asValue.
- top1 := StandardSystemView new.
- top1 extent:200@100.
- field1 := EditField origin:0.0@ViewSpacing in:top1.
- field1 width:1.0.
- field1 leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field1 model:model; acceptOnReturn:false.
- top1 open.
+ top1 := StandardSystemView new.
+ top1 extent:200@100.
+ field1 := EditField origin:(0.0 @ 0.0) in:top1.
+ field1 width:1.0.
+ field1 model:model; acceptOnReturn:false.
+ top1 open.
- top2 := StandardSystemView new.
- top2 extent:200@100.
- field2 := EditField origin:0.0@ViewSpacing in:top2.
- field2 width:1.0.
- field2 leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field2 model:model; acceptOnReturn:false.
- top2 open.
+ top2 := StandardSystemView new.
+ top2 extent:200@100.
+ field2 := EditField origin:(0.0 @ 0.0) in:top2.
+ field2 width:1.0.
+ field2 model:model; acceptOnReturn:false.
+ top2 open.
- with immediate accept:
+ with immediate accept (every key updates the model):
- |top1 top2 field1 field2 model|
+ |top1 top2 field1 field2 model|
- model := 'hello world' asValue.
+ model := 'hello world' asValue.
- top1 := StandardSystemView new.
- top1 extent:200@100.
- field1 := EditField origin:0.0@ViewSpacing in:top1.
- field1 width:1.0.
- field1 leftInset:ViewSpacing; rightInset:ViewSpacing.
- field1 model:model; immediateAccept:true.
- top1 open.
+ top1 := StandardSystemView new.
+ top1 extent:200@100.
+ field1 := EditField origin:(0.0 @ 0.0) in:top1.
+ field1 width:1.0.
+ field1 model:model; immediateAccept:true.
+ top1 open.
- top2 := StandardSystemView new.
- top2 extent:200@100.
- field2 := EditField origin:0.0@ViewSpacing in:top2.
- field2 width:1.0.
- field2 leftInset:ViewSpacing; rightInset:ViewSpacing.
- field2 model:model; immediateAccept:true.
- top2 open.
+ top2 := StandardSystemView new.
+ top2 extent:200@100.
+ field2 := EditField origin:(0.0 @ 0.0) in:top2.
+ field2 width:1.0.
+ field2 model:model; immediateAccept:true.
+ top2 open.
just an example; a checkBox and an editField on the same model:
- |top1 top2 field1 box model|
+ |top1 top2 field1 box model|
- model := false asValue.
+ model := false asValue.
- top1 := StandardSystemView new.
- top1 extent:200@100.
- field1 := EditField origin:0.0@ViewSpacing in:top1.
- field1 width:1.0.
- field1 leftInset:ViewSpacing;
- rightInset:ViewSpacing.
- field1 converter:(PrintConverter new initForYesNo).
- field1 model:model.
- top1 open.
+ top1 := StandardSystemView new.
+ top1 extent:200@100.
+ field1 := EditField origin:(0.0 @ 0.0) in:top1.
+ field1 width:1.0.
+ field1 converter:(PrintConverter new initForYesNo).
+ field1 model:model.
+ top1 open.
- top2 := StandardSystemView new.
- top2 extent:200@100.
- box := CheckBox on:model.
- box label:'on/off'.
- top2 add:box.
- top2 open.
+ top2 := StandardSystemView new.
+ top2 extent:200@100.
+ box := CheckBox on:model.
+ box label:'on/off'.
+ top2 add:box.
+ top2 open.
- model inspect.
+ model inspect.
connecting fields:
@@ -445,81 +549,81 @@
class, or in a complex model. For the demonstration below, we use
a Plug to simulate the protocol.)
- |application top field1 field2 value1 value2|
+ |application top field1 field2 value1 value2|
- application := Plug new.
- application respondTo:#value1Changed
- with:[value2 value:(value1 value isNil ifTrue:[nil]
- ifFalse:[value1 value squared])].
+ application := Plug new.
+ application respondTo:#value1Changed
+ with:[value2 value:(value1 value isNil ifTrue:[nil]
+ ifFalse:[value1 value squared])].
- value1 := 1 asValue.
- value2 := 1 asValue.
+ value1 := 1 asValue.
+ value2 := 1 asValue.
- top := Dialog new.
- top extent:200@200.
+ top := Dialog new.
+ top extent:200@200.
- (top addTextLabel:'some number:') layout:#left.
- top addVerticalSpace.
+ (top addTextLabel:'some number:') layout:#left.
+ top addVerticalSpace.
- (top addInputFieldOn:value1 tabable:false)
- converter:(PrintConverter new initForNumberOrNil);
- immediateAccept:true.
- top addVerticalSpace.
+ (top addInputFieldOn:value1 tabable:false)
+ converter:(PrintConverter new initForNumberOrNil);
+ immediateAccept:true.
+ top addVerticalSpace.
- (top addTextLabel:'squared:') layout:#left.
- top addVerticalSpace.
- (top addInputFieldOn:value2 tabable:false)
- converter:(PrintConverter new initForNumberOrNil).
+ (top addTextLabel:'squared:') layout:#left.
+ top addVerticalSpace.
+ (top addInputFieldOn:value2 tabable:false)
+ converter:(PrintConverter new initForNumberOrNil).
- value1 onChangeSend:#value1Changed to:application.
+ value1 onChangeSend:#value1Changed to:application.
- top openModeless.
+ top openModeless.
two-way connect:
each field updates the other (notice, that we have to turn off
onChange: notification, to avoid an endless notification cycle)
- |application top field1 field2 value1 value2|
+ |application top field1 field2 value1 value2|
- application := Plug new.
- application respondTo:#value1Changed
- with:[value2 retractInterestsFor:application.
- value2 value:(value1 value isNil ifTrue:[nil]
- ifFalse:[value1 value squared]).
- value2 onChangeSend:#value2Changed to:application.
- ].
- application respondTo:#value2Changed
- with:[value1 retractInterestsFor:application.
- value1 value:(value2 value isNil ifTrue:[nil]
- ifFalse:[value2 value sqrt]).
- value1 onChangeSend:#value1Changed to:application.
- ].
+ application := Plug new.
+ application respondTo:#value1Changed
+ with:[value2 retractInterestsFor:application.
+ value2 value:(value1 value isNil ifTrue:[nil]
+ ifFalse:[value1 value squared]).
+ value2 onChangeSend:#value2Changed to:application.
+ ].
+ application respondTo:#value2Changed
+ with:[value1 retractInterestsFor:application.
+ value1 value:(value2 value isNil ifTrue:[nil]
+ ifFalse:[value2 value sqrt]).
+ value1 onChangeSend:#value1Changed to:application.
+ ].
- value1 := 1 asValue.
- value2 := 1 asValue.
+ value1 := 1 asValue.
+ value2 := 1 asValue.
- top := Dialog new.
- top extent:200@200.
+ top := Dialog new.
+ top extent:200@200.
- (top addTextLabel:'some number:') layout:#left.
- top addVerticalSpace.
+ (top addTextLabel:'some number:') layout:#left.
+ top addVerticalSpace.
- (top addInputFieldOn:value1 tabable:false)
- converter:(PrintConverter new initForNumberOrNil);
- immediateAccept:true.
- top addVerticalSpace.
+ (top addInputFieldOn:value1 tabable:false)
+ converter:(PrintConverter new initForNumberOrNil);
+ immediateAccept:true.
+ top addVerticalSpace.
- (top addTextLabel:'squared:') layout:#left.
- top addVerticalSpace.
- (top addInputFieldOn:value2 tabable:false)
- converter:(PrintConverter new initForNumberOrNil);
- immediateAccept:true.
+ (top addTextLabel:'squared:') layout:#left.
+ top addVerticalSpace.
+ (top addInputFieldOn:value2 tabable:false)
+ converter:(PrintConverter new initForNumberOrNil);
+ immediateAccept:true.
- value1 onChangeSend:#value1Changed to:application.
- value2 onChangeSend:#value2Changed to:application.
+ value1 onChangeSend:#value1Changed to:application.
+ value2 onChangeSend:#value2Changed to:application.
- top openModeless.
+ top openModeless.
"
! !
@@ -553,6 +657,23 @@
"
! !
+!EditField methodsFor:'accepting'!
+
+accept
+ ""
+ |val string|
+
+ super accept.
+ converter notNil ifTrue:[
+ val := self editValue.
+ string := converter printStringFor:val.
+ string ~= self contents ifTrue:[
+ self contents:string.
+ self flash
+ ]
+ ].
+! !
+
!EditField methodsFor:'accessing-behavior'!
acceptOnLeave:aBoolean
@@ -576,6 +697,13 @@
"Modified: 16.12.1995 / 16:25:34 / cg"
!
+autoScroll:aBoolean
+ "turn on/off automatic scrolling upon keyboard entry
+ to make the cursor visible."
+
+ autoScrollHorizontally := aBoolean
+!
+
crAction:aBlock
"define an action to be evaluated when the return key is pressed."
@@ -585,9 +713,9 @@
cursorMovementWhenUpdating:aSymbol
"define what should be done with the cursor, when I update
my contents from the model. Allowed arguments are:
- #keep / nil -> stay where it was
- #endOfLine -> position cursor after the string
- #beginOfLine -> position cursor to the beginning
+ #keep / nil -> stay where it was
+ #endOfLine -> position cursor after the string
+ #beginOfLine -> position cursor to the beginning
The default is #endOfLine.
This may be useful for fields which get new values assigned from
the program (i.e. not from the user)"
@@ -601,8 +729,8 @@
"disable the field; hide the cursor and ignore input"
enabled ifTrue:[
- enabled := false.
- self hideCursor
+ enabled := false.
+ self hideCursor
]
"Modified: 16.12.1995 / 16:28:05 / cg"
@@ -615,8 +743,8 @@
"/ enableAction notNil ifTrue:[
"/ enableAction value
"/ ].
- enabled := true.
- super showCursor
+ enabled := true.
+ super showCursor
]
"Modified: 16.12.1995 / 16:28:09 / cg"
@@ -682,15 +810,15 @@
|wasEnabled|
enableChannel notNil ifTrue:[
- wasEnabled := enableChannel value.
- enableChannel retractInterestsFor:self.
+ wasEnabled := enableChannel value.
+ enableChannel retractInterestsFor:self.
] ifFalse:[
- wasEnabled := enabled
+ wasEnabled := enabled
].
enableChannel := aValueHolder.
aValueHolder onChangeSend:#enableStateChange to:self.
enableChannel value ~~ wasEnabled ifTrue:[
- self enableStateChange
+ self enableStateChange
]
"Created: 16.12.1995 / 16:35:32 / cg"
@@ -854,10 +982,14 @@
"set the maximum number of characters that are allowed in
the field. Additional input will be ignored by the field.
A limit of nil means: unlimited. This is the default.
+ If set, a lengthLimit must be defined before any contents is placed
+ into the field, because the contents is not cut when the max is
+ changed later. I.e. it should be set early after creation of the field.
+
This method has been renamed from #lengthLimit: for ST-80
compatibility."
- lengthLimit := aNumberOrNil
+ lengthLimit := aNumberOrNil.
!
passwordCharacter
@@ -970,9 +1102,9 @@
enableStateChange
enableChannel value ifTrue:[
- self enable
+ self enable
] ifFalse:[
- self disable
+ self disable
].
"Created: 16.12.1995 / 16:35:39 / cg"
@@ -999,56 +1131,56 @@
<resource: #keyboard (#DeleteLine #EndOfText)>
- |leave xCol newOffset oldWidth newWidth s|
+ |leave xCol newOffset newWidth s|
enabled ifFalse:[
- ^ self
+ ^ self
].
(key == #DeleteLine) ifTrue:[
- Smalltalk at:#CopyBuffer put:(self contents).
- self contents:''. ^ self
+ Smalltalk at:#CopyBuffer put:(self contents).
+ self contents:''. ^ self
].
(key == #Tab) ifTrue:[
- tabAction notNil ifTrue:[tabAction value. ^ self].
- entryCompletionBlock notNil ifTrue:[
- s := self contents.
- s isNil ifTrue:[
- s := ''
- ] ifFalse:[
- s := s asString
- ].
- entryCompletionBlock value:s. ^ self
- ]
+ tabAction notNil ifTrue:[tabAction value. ^ self].
+ entryCompletionBlock notNil ifTrue:[
+ s := self contents.
+ s isNil ifTrue:[
+ s := ''
+ ] ifFalse:[
+ s := s asString
+ ].
+ entryCompletionBlock value:s. ^ self
+ ]
].
(key == #Return) ifTrue:[
- crAction notNil ifTrue:[crAction value. ^ self].
+ crAction notNil ifTrue:[crAction value. ^ self].
].
leave := leaveKeys includes:key.
leave ifTrue:[
- ((key == #Return and:[acceptOnReturn])
- or:[key ~~ #Return and:[acceptOnLeave]]) ifTrue:[
- self accept.
- ].
+ ((key == #Return and:[acceptOnReturn])
+ or:[key ~~ #Return and:[acceptOnLeave]]) ifTrue:[
+ self accept.
+ ].
- leaveAction notNil ifTrue:[
- ^ leaveAction value:key
- ].
+ leaveAction notNil ifTrue:[
+ ^ leaveAction value:key
+ ].
- x >= 0 ifTrue:[
- "
- let superview know about the leave ...
- This is a temporary kludge for the tableWidget -
- it is no clean coding style. Should make the tableWidget
- a proper model and handle it via the changed mechanism ....
- "
- (superView notNil and:[superView canHandle:key from:self]) ifTrue:[
- superView keyPress:key x:x y:y.
- ].
- ].
- ^ self
+ x >= 0 ifTrue:[
+ "
+ let superview know about the leave ...
+ This is a temporary kludge for the tableWidget -
+ it is no clean coding style. Should make the tableWidget
+ a proper model and handle it via the changed mechanism ....
+ "
+ (superView notNil and:[superView canHandle:key from:self]) ifTrue:[
+ superView keyPress:key x:x y:y.
+ ].
+ ].
+ ^ self
].
"
@@ -1062,15 +1194,26 @@
"
a normal key - let superclass's method insert it
"
- oldWidth := self widthOfContents.
super keyPress:key x:x y:y.
"
for end-of-text, also move to end-of-line
"
key == #EndOfText ifTrue:[
- super keyPress:#EndOfLine x:x y:y.
+ super keyPress:#EndOfLine x:x y:y.
].
+
+ self resizeOrScroll.
+
+ "Modified: 16.1.1996 / 19:39:14 / cg"
+!
+
+resizeOrScroll
+ "helper for keyPress.
+ Extracted for easier subclass redefinition."
+
+ |xCol newOffset newWidth|
+
newWidth := self widthOfContents.
"
@@ -1078,33 +1221,32 @@
"
xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
(xCol > (width * (5/6))) ifTrue:[
- self changed:#preferredExtent
+ self changed:#preferredExtent
] ifFalse:[
- newWidth < (width * (1/6)) ifTrue:[
- self changed:#preferredExtent
- ]
+ newWidth < (width * (1/6)) ifTrue:[
+ self changed:#preferredExtent
+ ]
].
- "
- did someone react (i.e. has my extent changed) ?
- (if not, we scroll horizontally)
- "
- xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
- (xCol > (width * (5/6))) ifTrue:[
- newOffset := leftOffset + (width // 2).
- ] ifFalse:[
- (xCol < (width * (1/6))) ifTrue:[
- newOffset := 0 max: leftOffset - (width // 2).
- ] ifFalse:[
- newOffset := leftOffset
- ]
+ autoScrollHorizontally ifTrue:[
+ "
+ did someone react (i.e. has my extent changed) ?
+ (if not, we scroll horizontally)
+ "
+ xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
+ (xCol > (width * (5/6))) ifTrue:[
+ newOffset := leftOffset + (width // 2).
+ ] ifFalse:[
+ (xCol < (width * (1/6))) ifTrue:[
+ newOffset := 0 max: leftOffset - (width // 2).
+ ] ifFalse:[
+ newOffset := leftOffset
+ ]
+ ].
+ newOffset ~~ leftOffset ifTrue:[
+ self scrollHorizontalTo:newOffset.
+ ]
].
- newOffset ~~ leftOffset ifTrue:[
- self scrollHorizontalTo:newOffset.
-"/ leftOffset := newOffset.
-"/ self clear.
-"/ self redraw
- ]
! !
!EditField methodsFor:'initialization'!
@@ -1166,6 +1308,7 @@
self height:(font height + font descent + (topMargin * 2)).
enabled := true.
fixedSize := true.
+ autoScrollHorizontally := true.
nFullLinesShown := 1.
nLinesShown := 1.
immediateAccept := false.
@@ -1318,5 +1461,5 @@
!EditField class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libwidg/EditField.st,v 1.37 1996-01-10 14:48:41 ca Exp $'
+ ^ '$Header: /cvs/stx/stx/libwidg/EditField.st,v 1.38 1996-01-16 19:07:53 cg Exp $'
! !