eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'PopUpList':

Home

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

Class: PopUpList


Inheritance:

   Object
   |
   +--GraphicsMedium
      |
      +--DisplaySurface
         |
         +--SimpleView
            |
            +--View
               |
               +--Label
                  |
                  +--Button
                     |
                     +--PopUpList

Package:
stx:libwidg
Category:
Views-Interactors
Version:
rev: 1.91 date: 2018/11/09 23:27:20
user: cg
file: PopUpList.st directory: libwidg
module: stx stc-classLibrary: libwidg
Author:
Claus Gittinger

Description:


a PopUpList is basically a button with a popup menu.
The PopUpLists label is showing the current selection from the
list.
When an entry is selected, an actionBlock (if nonNil) is evaluated
and (if nonNil), the model is notified via the changeMessage.

If no model is set, the list is assumed to be a static list, which
is defined via #list:, and the popUpList evaluates the action block,
as defined via #action:.

If a model is provided, it should return the current selected items index via the 
aspectMessage (default is #selection or: #selectionIndex, depending on the setting 
of useIndex) and the list via the listMessage (default is #list).
If the listMessage was set to nil, the list is not acquired from the model
and can be set explicitely via #list:.

The defaults are set to allow a PopUpList to be used with a SelectionInList 
as model without further setup.
A simple valueHolder may also be used without further setup.
(if used with some other model, either use an adaptor, or set the
 change/aspect and/or listMessage to something else ..)

If a listHolder is set, this one is always asked for the list instead of the
model, via the #value message. 
This allows the popUpListView to acquire the list and value from different places.


Notice: PopUpList and ComboListView provide a similar protocol and functionality.


[Instance variables:]

    menu                            helpers for the popup menu
    menuAction 
    values 

    useIndex             <Boolean>  if true, the index of the selected entry
                                    is passed to the action block and the
                                    model in a change-message.
                                    If false (the default), the value is passed.
                                    Notice that the default changeMessage is
                                    #selection:, which is not ok to be used
                                    with useIndex:true and a selectionInList model.
                                    (set the changeMessage to #selectionIndex: then)

    listMsg              <Symbol>   message to acquire a new list from the
                                    model. Default is #list.


    listHolder           <Object>   if non-nil, this object is assumed to return the
                                    list via the listMsg (instead of the model).
                                    Default is nil.


Related information:

    SelectionInList
    ValueHolder
    SelectionInListView
    ComboListView

Class protocol:

defaults
o  defaultAspectMessage

o  defaultChangeMessage

o  defaultListMessage


Instance protocol:

accessing
o  contents
return the current contents

o  contents: con
change the contents

o  defaultLabel: aString
set the defaultLabel, to be shown if nothing is selected

o  label: aString

o  list
return the list - i.e. the values shown in the pop-up list

o  list: aList
set the list - i.e. the values shown in the pop-up list

o  selection: indexOrString
set (force) a selection - usually done to set
an initial selection without updating others

o  values: aList
set a value list - these are reported via the action or changeSymbol instead of
the label strings.

accessing-behavior
o  action: aOneArgBlock
set the action to be performed on selection changes;
the argument, aOneArgBlock will be evaluated with the
selection-value as argument

o  ignoreReselect: aBoolean
controls if clicking on an already selected item should
be ignored or should perform the select action again.
By default, these are ignored

o  menu: aMenu
explicit change of the menu;
allows for non-list-based, or MenuBuilder-constructed menus to be used.
Attention: this bypasses the list/listHolder

o  menu: aMenu default: label
explicit change of the menu and default value;
allows for non-list-based, or MenuBuilder-constructed menus to be used.
Attention: this bypasses the list/listHolder

o  useIndex
tell the popuplist to pass the index (instead of the value)
to both the actionBlock and model. Notice, that if you use a model,
the default changeSelector is not ok for using index and a SelectionInList

o  useIndex: aBoolean
tell the popuplist to pass the index (instead of the value)
to both the actionBlock and model. Notice, that if you use a model,
the default changeSelector is not ok for using index and a SelectionInList

accessing-look
o  showHandle
return true if the pull-handle is to be drawn; default is true

o  showHandle: aBoolean
controls if the pull-handle is to be drawn; default is true

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

o  listHolder
return the listHolder if any

o  listHolder: aValueHolder
set the listHolder - if non nil, that one is assumed to provide the
list via #value.
If a listHolder was defined, the model is never asked for the list.

o  listMessage
return the selector by which we ask the model or listHolder for the list.
The default is #list.
If a listHolder was defined, the model is never asked for the list.

o  listMessage: aSelector
set the selector by which we ask the model for the list.
The default is #list.
If a listHolder was defined, the model is never asked for the list.

o  model: aModel
set the model which provides the selection and/or the list

change & update
o  update: something with: aParameter from: changedObject
that one holds the list;

drawing
o  drawWith: fgColor and: bgColor
(comment from inherited method)
redraw myself with fg/bg. Use super to draw the label, add
the return-arrow here.

o  showActive
no need to redraw - will pop menu on top of me anyway ...

o  showPassive
no need to redraw - will redraw from unpopped menu anyway ...

event handling
o  keyPress: key x: x y: y
pull menu on Return and space

o  popMenu
oldStyle - theMenu is a PopUpMenu / MenuPanel

initialization
o  defaultControllerClass

o  initialize
(comment from inherited method)
must be called if redefined

private
o  createMenuFor: aList
old code (uses old PopUpMenu)

o  getListFromModel
if I have a listHolder, ask it for the list;
otherwise, if I have a model and a listMsg, get my list from there

o  getSelectionFromModel
if I have a model and an aspectMsg, get my current value from it

o  rawLabelSizeOf: aLogo
compute the extent needed to hold the label plus the mark

private-controller access
o  menu
return the menu component

queries
o  computePreferredExtent
redefined to make certain that the menu is fully defined

o  specClass
XXX no longer needed (inherited default works here)

testing
o  isPopUpList

user actions
o  select: anIndex
this is sent from the popupmenu when an entry was selected


Examples:


non-MVC use:
   |p|
   p := PopUpList label:'healthy fruit'.
   p list:#('apples' 'bananas' 'grape' 'lemon' 'margaritas').
   p open
with an initial selection:
   |p|
   p := PopUpList label:'dummy'.
   p list:#('apples' 'bananas' 'grape' 'lemon' 'margaritas').
   p selection:'apples'.
   p open
with separating lines:
   |p|
   p := PopUpList label:'fruit'.
   p list:#('apples' 'bananas' 'grape' 'lemon' '-' 'margaritas').
   p selection:'apples'.
   p open
draw without menu-handle:
   |p|
   p := PopUpList label:'fruit'.
   p list:#('apples' 'bananas' 'grape' 'lemon' '-' 'margaritas').
   p showHandle:false.
   p open
with an action:
   |p|
   p := PopUpList label:'dummy'.
   p list:#('apples' 'bananas' 'grape' 'lemon' '-' 'margaritas').
   p selection:'apples'.
   p action:[:what | Transcript showCR:'you selected: ' , what].
   p open
sometimes, you may like the index instead of the value: (notice, that the separating line counts, so you have to take care ...)
   |p|
   p := PopUpList label:'dummy'.
   p list:#('apples' 'bananas' 'grape' 'lemon' '-' 'margaritas').
   p selection:'apples'.
   p action:[:what | Transcript show:'you selected: '; showCR:what].
   p useIndex:true.
   p open
since the list is actually a popupMenu, you can add double-separators: also, here values are different from the labels
   |p|
   p := PopUpList label:'dummy'.
   p list:#('apples' 'bananas' 'grape' 'lemon' 
            '=' 
            'margaritas' 'pina colada'
            '=' 
            'smalltalk' 'c++' 'eiffel' 'java').
   p values:#(apples bananas grape lemon 
              nil 
              'mhmh - so good' 'makes headache'
              nil
              'great' 'another headache' 'not bad' 'neat').
   p selection:'apples'.
   p action:[:what | Transcript show:'you selected: '; showCR:what].
   p open
since the list is actually represented by a menuView, which itself is inheriting from listView, which itself can display things different from strings, arbitrary lists can be constructed: (see ListEntry, LabelAndIcon and Text classes)
   |p l|
   p := PopUpList label:'dummy'.
   l := OrderedCollection new.
   l add:(Text string:'apples' color:Color red).
   l add:(Text string:'bananas' color:Color red).
   l add:(Text string:'grape' color:Color red).
   l add:(Text string:'lemon' color:Color red).
   l add:'='.
   l add:(Text string:'margaritas' color:Color green darkened darkened).
   l add:(Text string:'pina colada' color:Color green darkened darkened).
   l add:'='.
   l add:(Text string:'smalltalk' color:Color blue).
   l add:(Text string:'c++' color:Color blue).
   l add:(Text string:'eiffel' color:Color blue).
   l add:(Text string:'java' color:Color blue).
   p list:l.
   p values:#(apples bananas grape lemon 
              nil 
              'mhmh - so good' 'makes headache'
              nil
              'great' 'another headache' 'not bad' 'neat').
   p selection:'apples'.
   p action:[:what | Transcript show:'you selected: '; showCR:what].
   p open
with values different from the label strings:
   |p|
   p := PopUpList label:'dummy'.
   p list:#('apples' 'bananas' 'grape' 'lemon' '-' 'margaritas').
   p selection:'apples'.
   p values:#(10 20 30 40 nil 50).
   p action:[:what | Transcript show:'you selected: '; showCR:what].
   p open
with values different from the label strings:
   |p|

   p := PopUpList label:'language selection'.
   p list:( #(
              'usa'
              'uk'
              'france'
              'germany'       
              'italy'
             ) collect:[:country |
                          LabelAndIcon 
                              icon:(Image fromFile:'bitmaps/xpmBitmaps/countries/' , country , '.xpm')
                              string:country
                       ]
          ).
   p values:#(us england france germany italy).

   p action:[:what | Transcript show:'you selected: '; showCR:what].
   p open
with a model (see in the inspector, how the index-holders value changes) the defaults are setup to allow a SelectionInList directly as model:
   |p model|

   model := SelectionInList with:#('apples' 'bananas' 'grape' 'lemon' 'margaritas').

   p := PopUpList label:'healthy fruit'.
   p model:model.
   p open.
   model inspect
model provides selection; list is explicit: must change the aspect, since the default setup is for a SelectionInList
   |model top b|

   model := 'foo' asValue.

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

   b := PopUpList in:top.
   b origin:(0.0 @ 0.0) corner:(1.0 @ 0.0).
   b bottomInset:(b preferredExtent y negated).

   b list:#('hello' 'world' 'this' 'is' 'st/x').
   b model:model; aspect:#value; change:#value:.

   top openModal.
   Transcript showCR:('comboBox''s value: ' , model value).
a popupList and a SelectionInListView on the same model:
   |p slv model|

   model := SelectionInList with:#('apples' 'bananas' 'grape' 'lemon' 'margaritas').
   model selection:'apples'.

   p := PopUpList on:model.
   p open.

   slv := SelectionInListView on:model.
   slv open.
dynamically changing the list (click button(s) to change):
   |p slv model b|

   model := SelectionInList with:#('apples' 'bananas' 'grape' 'lemon' 'margaritas').
   model selection:'apples'.

   p := PopUpList on:model.
   p open.

   slv := SelectionInListView on:model.
   slv open.

   b := Button label:'long list' action:[model list:#('1' '2' '3' '4' '5' '6')].
   b open.
   b := Button label:'short list' action:[model list:#('1' '2' '3')].
   b open.

two PopUpLists on the same model, different aspects:
   |top panel p model|

   model := Plug new.
   model respondTo:#eat: with:[:val | Transcript showCR:'eat: ' , val].
   model respondTo:#drink: with:[:val | Transcript showCR:'drink: ' , val].
   model respondTo:#meals with:[#(taco burrito enchilada)].
   model respondTo:#drinks with:[#(margarita water corona)].

   top := StandardSystemView new.
   top extent:(100@100).
   panel := VerticalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.
   panel horizontalLayout:#fitSpace.

   p := PopUpList label:'meals'.
   p model:model; listMessage:#meals; aspect:nil; change:#eat:.
   panel add:p.

   p := PopUpList label:'drinks'.
   p model:model; listMessage:#drinks; aspect:nil; change:#drink:.
   panel add:p.

   top open
with separate list- and indexHolders:
   |p selectionHolder listHolder|

   listHolder := #('apples' 'bananas' 'grape' 'lemon' 'margaritas') asValue.
   selectionHolder := 'apples' asValue.

   p := PopUpList label:'healthy fruit'.
   p listHolder:listHolder.
   p model:selectionHolder; aspect:#value; change:#value:.
   p open.
   selectionHolder inspect
same, using index:
   |p selectionIndexHolder listHolder|

   listHolder := #('apples' 'bananas' 'grape' 'lemon' 'margaritas') asValue.
   selectionIndexHolder := 3 asValue.

   p := PopUpList new.
   p listHolder:listHolder.
   p model:selectionIndexHolder; aspect:#value; change:#value:.
   p useIndex:true.
   p open.
   selectionIndexHolder inspect
using different values:
   |p selectionHolder listHolder values|

   listHolder := #('apples' 'bananas' 'grape' 'lemon' 'margaritas') asValue.
   values := #(apples bananas grape lemon alcohol).

   selectionHolder := #alcohol asValue.

   p := PopUpList label:'healthy fruit'.
   p listHolder:listHolder.
   p model:selectionHolder; aspect:#value; change:#value:.
   p values:values.
   p open.
   selectionHolder inspect
provide your own menu (spec could come from a specMethod):
   |p myMenu selectionHolder|

   selectionHolder := nil asValue.
   myMenu :=
     #(#Menu
         #(
          #(#MenuItem
              #label: 'Oranges'
              #translateLabel: true
              #value: #oranges
          )
          #(#MenuItem
              #label: 'Lemons'
              #translateLabel: true
              #value: #lemons
          )
          #(#MenuItem
              #label: 'grape'
              #translateLabel: true
              #value: #grape
          )
          #(#MenuItem
              #label: '-'
          )
          #(#MenuItem
             #label: 'other'
             #translateLabel: true
             #value: #other
             #submenu: 
                #(#Menu
                   #(
                    #(#MenuItem
                       #label: 'margarita'
                       #translateLabel: true
                       #value: #margarita
                     )
                    #(#MenuItem
                       #label: 'vine'
                       #translateLabel: true
                       #value: #vine
                     )
                    )
                 )
          )
        )
     ) decodeAsLiteralArray.
   p := PopUpList label:'healthy fruit'.
   p menu:myMenu.
   p model:selectionHolder; aspect:#value; change:#value:.
   selectionHolder inspect.
   p open.


ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Thu, 28 Mar 2024 14:27:07 GMT