eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'EnterFieldGroup':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: EnterFieldGroup


Inheritance:

   Object
   |
   +--EnterFieldGroup

Package:
stx:libwidg
Category:
Interface-Support
Version:
rev: 1.48 date: 2023/12/19 20:49:27
user: cg
file: EnterFieldGroup.st directory: libwidg
module: stx stc-classLibrary: libwidg

Description:


EnterFieldGroup controls the interaction between EnterFields
enabling the next/prev field when a field is left. 
Instances of this class keep track of which field of the group is the 
currentField (i.e. the one getting keyboard input) and forwards input
to that one.
This is done by arranging for all of my fields to delegate their
input to me, which is then forwarded to the active field).

The block accessible as leaveAction is evaluated when the last
field of the group is left (by cursor-down or cr). 
Usually this block triggers accept on the fields (if they did not already)
and/or performs some followup processing and possibly closes the topview 
(for example: in a dialog).

EnterFieldGroups can be used as a delegate (of the topView) to forward
input (entered into the topView) to the currently active field.

Stepping to previous field is via CursorUp/PreviousField,
to next field via CursorDown/NextField/Tab.
By default, tabbing via #Tab is disabled - to enable it, send the field
a #makeTabable or #makeAllTabable to the group.

All of this here is low level stuff, providing a lot of freedom in
which keys are handled and how they perform.
Normally, these are not required for most users - the DialogBox sets up
things correctly for most cases.


[Instance variables:]

    fields          <Collection of EditField>       the fields of the group

    currentField    <EditField>                     the active field

    leaveAction     <nil|Block>                     action to perform, when the
                                                    last field is left by a non-wrap

    wrap            <Boolean>                       if true, non-return next-keys wrap
                                                    back to the first field.
                                                    If false (the default), next in
                                                    the last field is taken as return.
                                                    This is ignored, if no leaveAction was 
                                                    defined.

    leaveOnTabLast  <Boolean>                       if true, tabbing out of the last
                                                    field leaves the group.
                                                    The default is false.

copyright

COPYRIGHT (c) 1992 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

Instance protocol:

accessing
o  currentField
return the field which currently has the focus

o  fields
return a collection of the inputFields contained in the group.

o  leaveAction: aBlock
set the action to perform when the last field is left.
Usually, this is to accept the values of all fields and perform
some additional processing (such as closing a dialog).

o  leaveOnTabLast: aBoolean
specifies if leaving the last field via Tab
should leave the group or stay in the group.
(if staying, either wrap or not, depending on the setting of wrap)
The default is to stay in the group

o  makeAllTabable
make all fields tabable

o  wrap: aBoolean
specifies if leaving the last field via non-Return
(i.e. Tab or Cursor-Down) should wrap back to the first,
or leave the group.
The default is to not leave the group and wrap back to the first field.

adding & removing
o  add: aField
add another field to the group.
Cursor motion out of the previous field will lead to the next
one and vice versa.

o  add: aField before: anotherField
add another field to the group into a particular position
within the tabbing order.
Cursor motion out of the previous field will lead to the next
one and vice versa.

o  remove: aField
remove a field from the group.

event forwarding
o  buttonPress: button x: x y: y view: aView
clicking on a field activates it and forwards the click to it

o  handlesButtonPress: button inView: aView
query from event processor: am I interested in button-events ?
yes I am (to activate the clicked-on field).

o  handlesKeyPress: key inView: aView
query from event processor: am I interested in key-events ?
yes I am (to forward it to the active field).

o  handlesKeyRelease: key inView: aView
query from event processor: am I interested in key-events ?
yes I am (to forward it to the active field).

o  keyPress: key x: x y: y view: aView
key-press in any field - forward the key to the active field
(with nil coordinates to indicate that the key was pressed
outside. However, this info is not used by any view currently)

o  keyRelease: key x: x y: y view: aView
key-release in any field - forward the key to the active field.
(with -1/-1 as coordinate to indicate that the key was pressed
outside. However, this info is not used by any view currently)

o  showFocus: onOrOff
forward focus display to the active field

o  showNoFocus: onOrOff
forward nofocus display to the active field

group control
o  fieldLeft: aField withKey: key
some of my fields was left using key.
Figure out, which one to give the focus:
If there are more fields, go to that one;
otherwise, handle this like tabbing to the next component

misc
o  activateFirst
pass control to my first field

o  activateFirstIfNoCurrent
pass control to my first field, if there is no current field

o  activateLast
pass control to my last field

o  delegatesTo: aView

o  makeActive: aField
make a specific field the active one

o  makeInactive
make the current field inActive (take its focus)

o  makeInactive: aField
make a specific field inActive


Examples:


without a group - user has to enter mouse into the next field to activate it; Cursor-keys don't work:
    |top panel field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    top open
with a group - Return-key or CursorKey enables next field: (but still, mouse pointer has to be moved into any of the fields, because the topView does not forward its input into the fields. Also, tabbing is not possible here)
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.

    top open
same, enables tabbing within the group via the Tab key (but still, the mouse pointer must be in one of the fields):
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.

    field1 makeTabable.
    field2 makeTabable.
    field3 makeTabable.
    top open
individual makeTabable messages to the fields allows single fields to be sticky (i.e. explicit click is needed to get out of it) - this is very seldom required. To make all fields tabable (the usual case), there is a shortCut:
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.
    group makeAllTabable.

    top open
use a delagation from the outerView to the group - Return-key or CursorKey enables next field: input for topView is delegated to the group, which also behaves as a unit w.r.t. keyboard focus (move pointer in and out). Again, without tabbing:
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.

    top delegate:group.
    top open
and, with tabbing:
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.
    group makeAllTabable.

    top delegate:group.
    top open
as above, but close the box when the last field is left via return - notice, that tabbing still wraps around:
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.
    group leaveAction:[top destroy].
    group makeAllTabable.

    top delegate:group.
    top open
in the next example, tabbing out of the last field closes the box as well:
    |top panel group field1 field2 field3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.
    group leaveAction:[top destroy].
    group makeAllTabable.
    group leaveOnTabLast:true.

    top delegate:group.
    top open
the next example shows that the input order is defined by the order in the group; NOT by the physical layout of the fields in the superview: (i.e. you can arrange your fields in multiple framedBoxes, panels or subviews - independent of the tab-stepping order)
    |top panel group field1 field2 field3|

    top := StandardSystemView label:'reverse'.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field3; add:field2; add:field1.
    group leaveAction:[top destroy].
    group makeAllTabable.

    top delegate:group.
    top open
using a single model for all fields: (here, we use a Plug to simulate a more complex model):
    |top panel group field1 field2 field3 model
     value1 value2 value3|

    top := StandardSystemView new.
    top extent:200@200.

    panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    panel add:(field1 := EditField extent:(1.0 @ nil)).
    panel add:(field2 := EditField extent:(1.0 @ nil)).
    panel add:(field3 := EditField extent:(1.0 @ nil)).

    group := EnterFieldGroup new.
    group add:field1; add:field2; add:field3.
    group leaveAction:[top destroy].
    group makeAllTabable.

    value1 := 'one'. value2 := 'two'. value3 := 'three'.

    model := Plug new.
    model respondTo:#value1 with:[value1].
    model respondTo:#value1: with:[:arg | value1 := arg].
    model respondTo:#value2 with:[value2].
    model respondTo:#value2: with:[:arg | value2 := arg].
    model respondTo:#value3 with:[value3].
    model respondTo:#value3: with:[:arg | value3 := arg].

    field1 model:model; aspect:#value1; change:#value1:.
    field2 model:model; aspect:#value2; change:#value2:.
    field3 model:model; aspect:#value3; change:#value3:.

    top delegate:group.
    top openModal.

    Transcript showCR:'value1: ' , value1.
    Transcript showCR:'value2: ' , value2.
    Transcript showCR:'value3: ' , value3.
all of the above is done automatically for you, if you add inputFields to a dialogBox. Here, all fields use the same model, but different aspects:
    |box model
     value1 value2 value3|

    box := DialogBox new.
    box extent:200@200.

    value1 := 'one'. value2 := 'two'. value3 := 'three'.

    model := Plug new.
    model respondTo:#value1 with:[value1].
    model respondTo:#value1: with:[:arg | value1 := arg].
    model respondTo:#value2 with:[value2].
    model respondTo:#value2: with:[:arg | value2 := arg].
    model respondTo:#value3 with:[value3].
    model respondTo:#value3: with:[:arg | value3 := arg].

    (box addInputFieldOn:model) aspect:#value1; change:#value1:.
    box addVerticalSpace.
    (box addInputFieldOn:model) aspect:#value2; change:#value2:.
    box addVerticalSpace.
    (box addInputFieldOn:model) aspect:#value3; change:#value3:.

    box addOkButton.

    box open.

    Transcript showCR:'value1: ' , value1.
    Transcript showCR:'value2: ' , value2.
    Transcript showCR:'value3: ' , value3.
Here, the fields use different models, but the same aspect:
    |box model
     valueHolder1 valueHolder2 valueHolder3|

    box := DialogBox new.
    box extent:200@200.

    valueHolder1 := 'one' asValue. 
    valueHolder2 := 'two' asValue. 
    valueHolder3 := 'three' asValue.

    box addInputFieldOn:valueHolder1.
    box addVerticalSpace.
    box addInputFieldOn:valueHolder2.
    box addVerticalSpace.
    box addInputFieldOn:valueHolder3.

    box addOkButton.

    box open.

    Transcript showCR:'value1: ' , valueHolder1 value.
    Transcript showCR:'value2: ' , valueHolder2 value.
    Transcript showCR:'value3: ' , valueHolder3 value.


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Thu, 21 Nov 2024 10:50:40 GMT