eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Label':

Home

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

Class: Label


Inheritance:

   Object
   |
   +--GraphicsMedium
      |
      +--DisplaySurface
         |
         +--SimpleView
            |
            +--View
               |
               +--Label
                  |
                  +--AnimatedLabel
                  |
                  +--Button
                  |
                  +--CheckLabel

Package:
stx:libwidg
Category:
Views-Layout
Version:
rev: 1.186 date: 2019/06/17 17:17:38
user: cg
file: Label.st directory: libwidg
module: stx stc-classLibrary: libwidg
Author:
Claus Gittinger

Description:


This class implements labels, which are views to display a string or image.
The Label will try to do its best to make its contents fit into the
view. The contents can be a String, a collection of Strings (i.e.
a StringCollection) or a Form/Image. 

The contents is drawn in fgColor/bgColor, which can be changed using:

    aLabel foregroundColor:aColor
    aLabel backgroundColor:aColor

When a label is assigned a contents, it will resize itself to fit
the required size. This resizing can be suppressed by setting the
fixsize attribute to true using:

    aLabel sizeFixed:true

This can be used, if resizing of the label is not wanted.
However, in this case you have to make certain that the size is big enough
to hold any changed logos later. (usually, you create the label first with
the longest string first to have it compute its size, then set the fixSize 
attribute to avoid resizing later).
Be careful when placing self-resizing labels into panels - by default,
panels do not react on the size change - leading to ugly looking geometry.
(but you can tell the panel to watch for changes with #elementsCHangeSize:)

The placement of the contents within the label is controlled by
the adjust attribute, it can be set with:

    aLabel adjust:how

where how is one of the symbols left, #right, #center, #centerEach,
#centerLeft, #centerRight, #leftRight or #rightLeft 
(see the comment in Label>>adjust:). The default is #center.

model-less operation (ok for static labels):
  if no model is set, the labels contents is set with:

    aLabel label:aStringOrImage

  and stays constant unless changed by new calls to #label:.


model operation (ST-80 style):
  labels with a model, aspectMsg and labelMsg react to 
  changes of the aspect, and send a labelMsg-message 
  to the model in order to acquire a new labelString or image.
  The model should send 'self changed:aspectMsg' if it thinks the label 
  should change and return a string or image from the labelMsg-message.

    label model:aModel.
    label aspect:aspectSymbol.
    label labelMessage:labelSymbol.

    model sends #changed:aspectSymbol
    ---> label will redraw its label from value of model perform:labelSymbol

  Having a labelSymbol different from the aspectSymbol allows for two labels
  to react on the same aspect-change, but use different messages when asking
  the model for a new label contents. By default, the labelMsg is nil,
  so the label does NOT update its shown contents.
  The aspectMsg defaults to #value.



channel operation (new ST/X style):

  the label will react on changes of the token found in the
  channels: foregroundChannel, backgroundChannel and labelChannel.
  These are valueHolders and can be shared between labels.


    
[Instance variables:]

    logo                <Object>        the logo, can be a Form, String or Text
    labelWidth          <Integer>       the width of the logo in device units
    labelHeight         <Integer>       the height of the logo in device units
    labelOriginX        <Integer>       the x-position of the logo withing the Label
    labelOriginY        <Integer>       the y-position of the logo withing the Label
    adjust              <Symbol>        controls how the logo is positioned within the
                                        label. Can be one of:#left,#right,#center,
                                        #centerLeft or #centerRight (see comment in adjust:)
    hSpace              <Integer>       number of horizontal pixels around logo
    vSpace              <Integer>       number of vertical pixels around logo

    bgColor             <Color>         background color
    fgColor             <Color>         foreground color

    fixSize             <Boolean>       if true, a change of the logo change will not
                                        resize the label; otherwise, its size is adjusted.
                                        default:false.

    labelMsg            <Symbol>        if non-nil, this is sent to the model to
                                        acquire the labelString or labelImage.
                                        If nil, the label stays as is

[styleSheet parameters:]

  labelForegroundColor    <Color>         color to draw foreground pixels (i.e. the string)
  labelBackgroundColor    <Color>         color to draw background pixels
  labelFont               <Font>          font to use for textual labels


Related information:

    Panel
    HorizontalPanel
    VerticalPanel
    TextView
    EditTextView
    Button
    InfoBox
    WarningBox

Class protocol:

defaults
o  defaultExtent
return the default extent of my instances.
The value returned here is usually ignored, and
the value from preferredExtent taken instead.

o  defaultForegroundColor
return the default foregroundColor of my instances.

o  updateStyleCache
extract values from the styleSheet and cache them in class variables

usage example(s):

     self updateStyleCache

instance creation
o  form: aForm
return a new Label showing a form.
OBSOLETE: you should now use #label: for both text and bitmap labels.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  form: aForm in: aView
return a new Label showing a form.
OBSOLETE: you should now use #label:in: for both text and bitmap labels.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

menu specs
o  middleButtonMenu
This resource specification was automatically generated
by the MenuEditor of ST/X.

usage example(s):

     MenuEditor new openOnClass:Label andSelector:#middleButtonMenu
     (Menu new fromLiteralArrayEncoding:(Label middleButtonMenu)) startUp


Instance protocol:

accessing-channels
o  labelChannel
return the labelChannel - or nil

o  labelChannel: aValueHolder
set the labelChannel - a valueHolder holding a string or image
which is shown as my logo

accessing-color & font
o  backgroundColor
return the background color

o  backgroundColor: aColor
set the background color

o  etchedForegroundColor
return the etched foreground color (or nil)

o  etchedForegroundColor: aColor
set the etched foreground color

o  foregroundColor
return the foreground color

o  foregroundColor: aColor
set the foreground color

o  foregroundColor: fg backgroundColor: bg
set the colors to be used for drawing

o  viewBackground: aColor
for labels, the viewBackground is forced to be the same as
the backgroundColor

accessing-contents
o  form: aForm
set the labels form; adjust extent if not already realized.
OBSOLETE: you should now use #label: for both strings and images

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  label
return the labels string or image

o  label: aStringOrFormOrImage
set the labelString or image;
adjust extent if not already realized and not fixedSize;
also redraw

o  label: aStringOrFormOrImage redraw: doRedraw
set the labelString or image; adjust extent if not already realized and
not fixedSize

o  label: newLabel suppressResize: suppress
change the label and optionally suppress a resize operation

o  labelString: aString
for ST-80 compatibility: same as #label:
set the label-string; adjust extent if not already realized and not fixedSize

o  labelWidth
return the logos width in pixels

o  logo: something
set the labels form or string.
OBSOLETE: the old version used #form: for images and #label: for strings.
you should now use #label: for any.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

accessing-layout
o  adjust
return the adjust symbol. See #adjust: for an explanation.

o  adjust: how
set the adjust, how which must be one of

#left -> left adjust logo
#right -> right adjust logo
#center -> center logo
#centerEach -> like #center, but if it's a multiline logo,
center each line individually.

#centerRight -> center logo if it fits;
BUT, if it does not fit, right adjust the logo
(use with filenames, where the interesting part is
at the right if the label is too small)

#centerLeft -> center logo if it fits;
BUT, if it does not fit, left adjust the logo
(use with strings where the interesting part is at the
left if the label is too small)

#leftRight -> left adjust logo if it fits
BUT, if it does not fit, right adjust the logo
(use with filenames, where the interesting part is
at the right if the label is too small)

#rightLeft -> right adjust logo if it fits
BUT, if it does not fit, left adjust the logo
(use with strings where the interesting part is at the
left if the label is too small)

See examples in the documentation category.

o  extraMarginForBorder
some (round) borders may need more space

o  font: aFont
set the font - if I'm not realized and not fixedSize, adjust my size.
CAVEAT: with the addition of Text objects,
this method is going to be obsoleted by a textStyle
method, which allows specific control over
normalFont/boldFont/italicFont parameters.

o  horizontalSpace
get the number of pixels by which the logo
is horizontally inset from the border

o  horizontalSpace: aNumber
set the number of pixels by which the logo
is horizontally inset from the border

o  layout: something
OBSOLETE compatibility interface. Will vanish.
for protocol compatibility: alias for #adjust:.
Please use #adjust:, since #layout: conflicts with a method
in VW (which has a completely different meaning).
In future versions of ST/X, #layout: will behave the VW way.
In the meantime, try to figure out what is meant ... a kludge

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  sizeFixed
return the fix-size attribute

o  sizeFixed: aBoolean
set/clear the fix-size attribute.
If true, the label will not change its size when the labelString/logo
changes.
If false (the default), it will resize itself to make the logo fit.

o  verticalSpace
get the number of pixels by which the logo
is vertically inset from the border

o  verticalSpace: aNumber
set the number of pixels by which the logo
is vertically inset from the border

accessing-mvc
o  addModelInterfaceTo: aDictionary
see comment in View>>modelInterface

o  converter: aConverter
set the printConverter;
that one is asked to convert the models value to a printed
representation (if non-nil). If nil, the model is supposed to
return a string or bitmap image.

o  labelMessage
return the symbol used to acquire the labelString/image from the model
when the aspect changes.
The default is nil, which means: leave the label unchanged.

o  labelMessage: aSymbol
set the symbol used to acquire the labelString/image from the model.
The default is nil, which means: leave the label unchanged.

o  model: aModel

change & update
o  getLabelFromLabelChannel

o  update: something with: aParameter from: changedObject
the MVC way of changing the label ...

event handling
o  sizeChanged: how
sent whenever size is changed by someone else - recompute the
logos position within the View.

focus handling
o  wantsFocusWithButtonPress

help
o  helpText
if my label is wider, return that as help text

initialization & release
o  fetchDeviceResources
fetch device colors, to avoid reallocation at redraw time

o  initStyle
setup viewStyle specifics

o  initialize
must be called if redefined

o  recreate
after snapin or a migration, labels dimensions may have changed due to
different font parameters

o  release

label animation
o  animationDelay

o  animationDelayTopOrBottom

o  doAnimate
by slow scrolling the label, ensure that the label's text is readable.
(stops when the cursor enters)

o  startAnimation
start an animator, which scrolls the label's text.
(slow scroll which stops when the cursor enters)

o  stopAnimation
ensure that things are in their normal state again

menu
o  canCopyLabelText

o  copyLabelText
copy the label's text to the clipboard

o  middleButtonMenu
not a customized menu

native widget support
o  nativeWindowType
return a symbol describing my native window type
(may be used internally by the device as a native window creation hint,
if the device supports native windows)

private
o  computeLabelOrigin
(re)compute the origin of the label whenever label, font or view-size changes

o  computeLabelSize
compute the extent needed to hold the logo

o  getLabelFromModel
ask my model for the label to show.
Here, we use labelMsg (instead of aspectMsg).
This allows multiple labels to react on the same aspect,
but show different labels when changed
(also, since labelMsg defaults to nil, constant labels
which have a nil labelMsg will not try to acquire a labelString).

o  newLayout
recompute position/size after a change
- helper for form:/font: etc.

o  rawLabelSizeOf: aLogo
compute the extent needed to hold aLogo; aForm or aString

queries
o  computePreferredExtent
compute my preferred extent - this is the minimum size I would like to have

o  isTextLabel

o  redrawsFull

redrawing
o  clearInsideWith: bg
no need to clear before - avoid flicker

o  drawImageLogo: imageOrForm x: x y: y opaque: opaque

o  drawOtherLogo: something x: x y: y opaque: opaque

o  drawStringLogo: aString x: x y: y

o  drawWin95FocusFrame

o  drawWith: fg and: bg
redraw my label with fg/bg - this generic method is also used by subclasses
(especially Button) to redraw the logo in different colors.

o  drawWith: fg and: bg clearInside: doClear etchedFg: etchedFg
redraw my label with fg/bg - this generic method is also used by subclasses
(especially Button) to redraw the logo in different colors.

o  redraw
redraw my label

resizing
o  forceResize
resize myself to make text fit into myself. Here, this is done even if
fixSize is set.

o  forceResizeHorizontally
resize myself horizontally to make text fit into myself.
Here, this is done even if fixSize is set.

o  resize
resize myself to make text fit into myself.
but only do so, if I am not fixedSize and I have NOT been
given a relative extent or an extend computation block.


Private classes:

    AnimatorState

Examples:


Notice, that Buttons and others inherit from Label; therefore, the following geometry examples apply to all subclasses too. simple (default position is 0@0):
    |top l|

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

    l := Label in:top.
    l label:'hello world'.

    top open
    |top l|

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

    l := Label in:top.
    l label:'hello\world' withCRs.

    top open
simple with emphasis:
    |top l|

    top := StandardSystemView new.
    top extent:(300 @ 100).

    l := Label in:top.
    l level:-1.
    l label:('hello world - this is text in a label ' asText 
                    emphasizeFrom:7 to:11 with:#italic;
                    emphasizeFrom:23 to:26 with:#bold).
    top open
there is also a creation message which sets the label:
    |top l|

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

    l := Label label:'hello world' in:top.

    top open
placement:
    |top l|

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

    l := Label in:top.
    l label:'hello world'.
    l origin:50@100.

    top open
level:
    |top l|

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

    l := Label in:top.
    l level:5.
    l label:'hello world'.
    l origin:50@100.

    top open
another level:
    |top l|

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

    l := Label in:top.
    l level:-1.
    l label:'hello world'.
    l origin:50@100.

    top open
colors & font:
    |top l|

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

    l := Label in:top.
    l level:-1.
    l font:(Font family:'Times' size:18).
    l foregroundColor:Color yellow.
    l backgroundColor:Color red.
    l label:'hello world'.
    l origin:50@100.

    top open
border & colors:
    |top l|

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

    l := Label in:top.
    l level:0.
    l borderWidth:1.
    l borderColor:Color red.
    l foregroundColor:Color green darkened.
    l backgroundColor:Color green lightened.
    l label:'hello world'.
    l origin:50@100.

    top open
different adjusts (resize to see):
    |top l|

    top := StandardSystemView new.
    top extent:(300 @ 250).
    top label:'make me smaller'.

    l := Label in:top.
    l borderWidth:1.
    l label:'default - #centered'.
    l origin:0.1@40.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#left.
    l label:'#left adjust'.
    l origin:0.1@70.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#right.
    l label:'#right adjust'.
    l origin:0.1@100.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#centerLeft.
    l label:'#centerLeft adjust with a long text'.
    l origin:0.1@130.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#centerRight.
    l label:'#centerRight adjust with a long text'.
    l origin:0.1@160.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#leftRight.
    l label:'#leftRight adjust with a long text'.
    l origin:0.1@190.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#rightLeft.
    l label:'#rightLeft adjust with a long text'.
    l origin:0.1@220.
    l width:0.8.

    top open
center vs. centerEach adjust (only with multiline labels):
    |top l|

    top := StandardSystemView new.
    top extent:(300 @ 250).
    top label:'resize me'.

    l := Label in:top.
    l borderWidth:1.
    l label:'this labels logo
consists of multiple lines 
with #center adjust'.
    l origin:0.1@0.1.
    l corner:0.9@0.9.
    l adjust:#center.

    top open.

    top := StandardSystemView new.
    top extent:(300 @ 250).
    top label:'resize me'.

    l := Label in:top.
    l borderWidth:1.
    l label:'this labels logo
consists of multiple lines 
with #centerEach adjust'.
    l origin:0.1@0.1.
    l corner:0.9@0.9.
    l adjust:#centerEach.

    top open

fitting-adjust (resize to see): Warning: #fit is experimental and should not be used.
    |top l|

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

    l := Label origin:0.25 @ 0.25 corner:0.75@0.75 in:top.
    l label:'stretch'.
    l level:-1.
    l adjust:#fit.

    top open
or: Warning: #fit is experimental and should not be used.
    |top l|

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

    l := Label origin:0.25 @ 0.25 corner:0.75@0.75 in:top.
    l label:(Image fromFile:'bitmaps/SBrowser.xbm').
    l level:-1.
    l adjust:#fit.

    top open
just a reminder, that instead of doing placement manually as in ...:
    |top l|

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

    l := Label in:top.
    l borderWidth:1.
    l label:'default - centered'.
    l origin:0.1@70.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#left.
    l label:'left adjust'.
    l origin:0.1@100.
    l width:0.8.

    l := Label in:top.
    l borderWidth:1.
    l adjust:#right.
    l label:'right adjust'.
    l origin:0.1@130.
    l width:0.8.

    top open
... it is much easier, to use a geometry handler, such as a VerticalPanel. Try:
    |top panel l|

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

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

    panel horizontalLayout:#fit.
    panel verticalLayout:#center.

    l := Label in:panel.
    l borderWidth:1.
    l label:'default - centered'.

    l := Label in:panel.
    l borderWidth:1.
    l adjust:#left.
    l label:'left adjust'.

    l := Label in:panel.
    l borderWidth:1.
    l adjust:#right.
    l label:'right adjust'.

    top open
labels with bitmaps or images:
    |top l|

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

    l := Label in:top.
    l level:-1.
    l label:((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedBy:0.2 @ 0.2).
    l origin:50@100.

    top open
that even works with #fit:
    |top l|

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

    l := Label in:top.
    l adjust:#fit.
    l level:-1.
    l label:(Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif').
    l origin:0.2@0.2 corner:0.8@0.8.

    top open
notice, that Buttons inherit from Label; thus:
    |top b|

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

    b := Button in:top.
    b adjust:#fit.
    b label:(Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif').
    b origin:0.2@0.2 corner:0.8@0.8.
    b action:[Transcript showCR:'wow'].

    top open
Channel operation (controlling fg, bg and labelText via ValueHolders) -----------------
    |top panel logoChannel fgChannel bgChannel l b|

    top := StandardSystemView new.
    top extent:(450 @ 200).

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

    l := Label in:panel.
    l level:-1.
    l label:'change my colors'.
    l origin:50@100.
    l sizeFixed:true.

    fgChannel := Color blue asValue.
    bgChannel := Color grey asValue.
    logoChannel := 'change me' asValue.

    b := Toggle label:'change fg' in:panel. b showLamp:false; onLevel:-2.
    b pressAction:[fgChannel value:Color red].
    b releaseAction:[fgChannel value:Color blue].

    b := Toggle label:'change bg' in:panel.
    b pressAction:[bgChannel value:Color yellow].
    b releaseAction:[bgChannel value:Color grey].

    b := Toggle label:'change text' in:panel.
    b pressAction:[logoChannel value:'wow'].
    b releaseAction:[logoChannel value:'not bad' ].

    l labelChannel:logoChannel.
    l foregroundChannel:fgChannel.
    l backgroundChannel:bgChannel.

    top open
multiple labels on one channel:
    |l1 l2 b conv|

    l1 := Label label:'label1'.

    l2 := Label label:'label2'.

    b := Button label:'change'.
    conv := (ConvertedValue new
                        conversion:[:input | 
                                    input ifTrue:[
                                        Color red
                                    ] ifFalse:[
                                        Color blue
                                    ]]).
    conv value:false.

    b controller pressChannel:conv.
    l1 foregroundChannel:conv.
    l2 foregroundColor:Color white; backgroundChannel:conv.

    b open.
    l1 open.
    l2 open.
MVC operation ------------- model provides the label): (have to use a plug to simulate a model which responds to the #someAspect message): |top l model| model := Plug new. model respondTo:#someAspect with:['models labelString']. top := StandardSystemView new. top extent:(200 @ 200). l := Label in:top. l model:model; labelMessage:#someAspect. top open ... model changed:#someAspect ... concrete example (track a counters value): (here, the default aspect #value is used both to notify the label about changes and to acquire a new value from the model).
    |top l model|

    model := ValueHolder new.
    model value:'0'.
    [
        1 to:20 do:[:i |
            (Delay forSeconds:1) wait.
            model value:i printString
        ].
        top destroy
    ] fork.

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

    l := Label in:top.
    l level:-1.
    l model:model; labelMessage:#value.

    top open
with a printConverter:
    |top l model|

    model := Date today asValue.
    [
        1 to:50 do:[:i |
            (Delay forSeconds:1) wait.
            model value:(model value addDays:1) 
        ].
        top destroy
    ] fork.

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

    l := Label in:top.
    l level:-1.
    l converter:(PrintConverter new initForDate).
    l model:model; labelMessage:#value.

    top open
model changes aspect after a while; two labels on the same model:
    |top l model|

    model := Plug new.
    model respondTo:#labelValue1 with:['models labelString1'].
    model respondTo:#labelValue2 with:['models labelString2'].

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

    l := Label origin:0.0@0.0 corner:1.0@0.5 in:top.
    l model:model; aspect:#someAspect; labelMessage:#labelValue1.
    l := Label origin:0.0@0.5 corner:1.0@1.0 in:top.
    l model:model; aspect:#someAspect; labelMessage:#labelValue2.

    top open.

    (Delay forSeconds:5) wait.
    model respondTo:#labelValue1 with:['new string1'].
    model respondTo:#labelValue2 with:['new string2'].

    model changed:#someAspect 
plugged MVC operation (getBlock returns the label):
    |top l model|

    model := PluggableAdaptor new
                    getBlock:[:m | 'hello']
                    putBlock:nil
                    updateBlock:nil.

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

    l := Label origin:0.0@0.0 corner:1.0@0.5 in:top.
    l model:model; labelMessage:#value.

    top open.
use different label-selectors to access fields of a complex model:
    |top panel model|

    model := Plug new.
    model respondTo:#field1 with:['value1'].
    model respondTo:#field2 with:['value2'].
    model respondTo:#field3 with:['value3'].
    model respondTo:#field4 with:['value4'].

    top := StandardSystemView new.

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

    panel addSubView:((Label on:model) labelMessage:#field1).
    panel addSubView:((Label on:model) labelMessage:#field2).
    panel addSubView:((Label on:model) labelMessage:#field3).
    panel addSubView:((Label on:model) labelMessage:#field4).

    top extent:(200 @ 200).
    top open.

    (Delay forSeconds:5) wait.

    model respondTo:#field2 with:['new value2'].
    model changed:#value  
same as above, using default aspects in the label, and an adaptor to translate aspects:
    |top panel model v1|

    model := Plug new.
    model respondTo:#field1 with:[v1].
    model respondTo:#field1: with:[:arg | v1 := arg. model changed:#field1].
    model respondTo:#field2 with:['value2'].
    model respondTo:#field2: with:[:arg |].
    model respondTo:#field3 with:['value3'].
    model respondTo:#field3: with:[:arg |].
    model respondTo:#field4 with:['value4'].
    model respondTo:#field4: with:[:arg |].

    top := StandardSystemView new.

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

    panel addSubView:((Label on:((AspectAdaptor subject:model) forAspect:#field1)) labelMessage:#value).
    panel addSubView:((Label on:((AspectAdaptor subject:model) forAspect:#field2)) labelMessage:#value).
    panel addSubView:((Label on:((AspectAdaptor subject:model) forAspect:#field3)) labelMessage:#value).
    panel addSubView:((Label on:((AspectAdaptor subject:model) forAspect:#field4)) labelMessage:#value).

    top extent:(200 @ 200).
    top open.

    (Delay forSeconds:5) wait.

    model field1:'new value1'.
use an adapter to access fields of a complex model:
    |top l panel model|

    model := #('one' 'two' 'three') asValue.

    top := StandardSystemView new.

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

    panel addSubView:((Label on:(ProtocolAdaptor
                                    subjectChannel:model
                                    accessPath:#(1))) labelMessage:#value).
    panel addSubView:((Label on:(ProtocolAdaptor
                                    subjectChannel:model
                                    accessPath:#(2))) labelMessage:#value).
    panel addSubView:((Label on:(ProtocolAdaptor
                                    subjectChannel:model
                                    accessPath:#(3))) labelMessage:#value).

    top extent:(200 @ 200).
    top open.

    (Delay forSeconds:5) wait.

    model value:#('oneone' 'twotwo' 'threethree').


ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Tue, 19 Mar 2024 09:46:07 GMT