eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'PopUpMenu':

Home

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

Class: PopUpMenu


Inheritance:

   Object
   |
   +--GraphicsMedium
      |
      +--DisplaySurface
         |
         +--SimpleView
            |
            +--View
               |
               +--TopView
                  |
                  +--PopUpView
                     |
                     +--PopUpMenu
                        |
                        +--SelectionMenu

Package:
stx:libwidg
Category:
Views-Menus
Version:
rev: 1.123 date: 2019/07/31 15:37:57
user: cg
file: PopUpMenu.st directory: libwidg
module: stx stc-classLibrary: libwidg
Author:
Claus Gittinger

Description:


Warning: this is a very old class which was written well before many improved
successors and tools were added. A lot of stuff you find here is kept for backward
compatibility.

This class provides PopUpMenu functionality;
-> Actually, this class only provides the popup and shadow functionality 
   and wraps ANOTHER view, which shows the actual menu-list 
   (usually an instance of MenuView, but in theory, other views could be wrapped as popup).

PopUpMenus are usually created with a list of labels, selectors and a
receiver. 
Once activated, the specified receiver will be sent a 'selector'-message.

PopupMenus may be either assigned statically to a view (via the #middleButtonMenu:
message) or created dynamically as required.
Static definition makes sense, if the menu stays constant and you want to
assign it once for the lifetime of the view.

Dynamic menus are easier to use, if the number of or look of the entries has to
change according the internal state of some model. Also, this is the ST-80 way
of using popupMenus. For dynamic popups, the view's model is asked for a menu
via the #menuSelector each time a button press occurs.

See examples section for more.


Related information:

    PullDownMenu
    MenuView

Class protocol:

ST-80 instance creation
o  labelArray: labels
ST80R4 compatibility

usage example(s):

     (PopUpMenu labelArray:#('one' 'two' 'three')) startUp 

o  labelArray: labels lines: lines values: values
ST80R4 compatibility

o  labelArray: labels values: values
ST80R4 compatibility

o  labelList: labels
ST80R4 compatibility:
given a list consisting of group label entries (to be separated by
lines), convert into standard form (using '-' for lines.

usage example(s):

     (PopUpMenu labels:#('1' '2' '3')) showAtPointer
     (PopUpMenu labelList:#(('1') ('2' '3'))) showAtPointer    
     (PopUpMenu labelList:#(('1') ('2') ('3'))) showAtPointer    

o  labelList: labels lines: lines values: values
mhmh what is that ?

o  labelList: labels values: values
ST80R4 compatibility:
given a list consisting of group label entries (to be separated by
lines), convert into standard form (using '-' for lines.

usage example(s):

     (PopUpMenu labels:#('1' '2' '3') values:#(1 2 3)) showAtPointer
     (PopUpMenu labelList:#(('1') ('2' '3')) values:#(1 2 3)) showAtPointer    
     (PopUpMenu labelList:#(('1') ('2') ('3')) values:#(1 2 3)) showAtPointer    

o  labels: labels
ST80R2 compatibility

o  labels: labels lines: lines
ST80R2 compatibility

o  labels: labels lines: lines values: values
ST80R2 compatibility

o  labels: labels values: values
ST80R2 compatibility

defaults
o  maxClickTimeToStayOpen
if button is pressed shorter, its a click and the menu stays open.

instance creation
o  forMenu: aMenuView
this wraps an already existing menu - allowing to put any
view (not just MenuViews) into popups (for example, menus
with icons, or other components).
Currently, there is only one example of different menus in
the system (PatternMenu in the DrawTool) which could be used
this way.
The view should respond to some of the menuView messages
(such as hideSubmenu, deselectWithoutRedraw etc.)

o  itemList: itemList resources: resources
like labels:selectors:... messages, but expects a single collection,
containing items row-wise (i.e. elements are themself arrays, consisting of
label [selector [accelerator [arg]]]
if resources are non-nil, labels are translated using the translations found there.

o  itemList: itemList resources: resources performer: menuPerformer
like labels:selectors:... messages, but expects a single collection,
containing items row-wise (i.e. elements are themself arrays, consisting of
label [selector [accelerator [arg]]]
if resources are non-nil, labels are translated using the translations found there.

o  itemList: itemList resources: resources performer: menuPerformer for: aView
like labels:selectors:... messages, but expects a single collection,
containing items row-wise (i.e. elements are themself arrays, consisting of
label [selector [accelerator [arg]]]
if resources are non-nil, labels are translated using the translations found there.

o  itemList: itemList resources: resources receiver: menuPerformer for: aView
like labels:selectors:... messages, but expects a single collection,
containing items row-wise (i.e. elements are themself arrays, consisting of
label [selector [accelerator [arg]]]
if resources are non-nil, labels are translated using the translations found there.

o  labels: labels args: args
create and return a menu with label-items and args.
The actionBlock has to be defined later

o  labels: labels selector: aSelector args: args receiver: anObject
create and return a popup menu with labels as entries.
Each item will send aSelector with a corresponding argument from the
args array to anObject. The menu is created on the default DIsplay

usage example(s):

     OBSOLETE protocol: #labels:selectors:... knows how to handle single-symbol selectors-arg

o  labels: labels selector: aSelector args: args receiver: anObject for: aView
create and return a popup menu with labels as entries.
Each item will send aSelector with a corresponding argument from the
args array to anObject. The menu is created on the same physical device
as aView (which is only of interest in multi-Display applications;
typical applications can use the sibbling message without the for: argument).

usage example(s):

     OBSOLETE protocol: #labels:selectors:... knows how to handle single-symbol selectors-arg

o  labels: labels selectors: selectors
create and return a menu with label-items and selectors. The receiver
will either be defined later, or not used at all (if opened via startUp)

o  labels: labels selectors: selectors accelerators: shorties
create and return a menu with label-items and selectors. The receiver
will either be defined later, or not used at all (if opened via startUp)

o  labels: labels selectors: selectors accelerators: shorties args: args receiver: anObject
create and return a popup menu with labels as entries.
Each item will send a corresponding selector:argument from the selectors-
and args array to anObject. The menu is created on the default Display

o  labels: labels selectors: selectors accelerators: shorties args: args receiver: anObject for: aView
create and return a popup menu with labels as entries.
Each item will send a corresponding selector:argument from the selectors-
and args array to anObject. The menu is created on the same physical device
as aView (which is only of interest in multi-Display applications;
typical applications can use the sibbling message without the for: argument).

o  labels: labels selectors: selectors accelerators: shorties receiver: anObject
create and return a popup menu with labels as entries.
Each item will send a message with a selector from the corresponding
selectors-array.
The menu is created on the default Display.

o  labels: labels selectors: selectors args: argArray
create and return a menu with label-items and selectors. The receiver
will either be defined later, or not used at all (if opened via startUp)

o  labels: labels selectors: selectors args: args receiver: anObject
create and return a popup menu with labels as entries.
Each item will send a corresponding selector:argument from the selectors-
and args array to anObject. The menu is created on the default Display

o  labels: labels selectors: selectors args: args receiver: anObject for: aView
create and return a popup menu with labels as entries.
Each item will send a corresponding selector:argument from the selectors-
and args array to anObject. The menu is created on the same physical device
as aView (which is only of interest in multi-Display applications;
typical applications can use the sibbling message without the for: argument).

o  labels: labels selectors: selectors receiver: anObject
create and return a popup menu with labels as entries.
Each item will send a message with a selector from the corresponding
selectors-array.
The menu is created on the default Display.

o  labels: labels selectors: selectors receiver: anObject for: aView
create and return a popup menu with labels as entries.
Each item will send a corresponding selector from the selectors-array
to anObject. The menu is created on the same physical device
as aView (which is only of interest in multi-Display applications;
typical applications can use the sibbling message without the for: argument).


Instance protocol:

ST-80 activation
o  startUp
start the menu modal - return the selected value,
or - if no values where specified - return the index.
If nothing was selected, return 0.
Modal - i.e. stay in the menu until finished.
This is the ST-80 way of launching a menu.

usage example(s):

     Transcript showCR:(PopUpMenu labels:#('foo' 'bar' 'baz')) startUp 
     Transcript showCR:(PopUpMenu labels:#('foo' 'bar' 'baz')
                                  values:#(foo bar baz)) startUp

o  startUpAt: aPoint
start the menu modal - return the selected value,
or - if no values where specified - return the index.
If nothing was selected, return 0.
Modal - i.e. stay in the menu until finished.
This is the ST-80 way of launching a menu.

o  startUpAt: aPoint ifNoneSelected: defaultReturnValue
start the menu modal - return the selected value,
or - if no values where specified - return the index.
If nothing was selected, return defaultReturnValue.
Modal - i.e. stay in the menu until finished.
This is the ST-80 way of launching a menu.

o  startUpFor: originatingWidget

o  startUpOrNil
start the menu modal - return the selected value,
or - if no values where specified - return the index.
If nothing was selected, return nil.
Modal - i.e. stay in the menu until finished.
This is the ST-80 way of launching a menu.

o  startUpWithHeading: aString
start the menu modal - return the selected value,
or - if no values where specified - return the index.
If nothing was selected, return 0.
Modal - i.e. stay in the menu until finished.
This is the ST-80 way of launching a menu.

usage example(s):

     (PopUpMenu
        labels:#('foo' 'bar'))
        startUpWithHeading:'hello'

accessing-behavior
o  hideOnKeyFilter: aBlock
set a filter, which determines if a key should lead to closing the menu.

o  hideOnLeave: aBoolean
set/clear the hideOnLeave attribute, which controls
if the menu should be hidden when the pointer leaves
the view (used with multiple-menus)

o  hideOnRelease: aBoolean
set/clear the hideOnRelease attribute, which controls
if the menu should be hidden when the button is released

o  isEnabled: indexOrName
return true, if the item at anIndexOrName is enabled

o  memorizeLastSelection: index
normally, a popup menu comes up unselected, even if reused.
This can be used to arrange for an initial selection to be shown

accessing-items
o  addItem: anItem

o  atMenuItemLabeled: aString putSubmenu: aMenu visible: visible

o  hasItems
return true, if I have items

o  indexOf: indexOrName
return the index of a submenu - or 0 if there is none

o  labels
return the list of labels

o  labels: labelString lines: lineArrayArg values: valueArray
define the menu the ST-80 way (with labels and lines defined separately)

o  lines
st-80 compatibility

o  menuAt: indexOrName
return the submenu for entry indexOrName.

o  numberOfItems
return the number of items in the menu

o  remove: indexOrName
remove a menu entry

o  subMenuAt: indexOrName
return the submenu for entry indexOrName

o  subMenuAt: indexOrName put: aMenu
define a submenu to be shown for entry indexOrName

o  values
st-80 compatibility

o  values: aValueArray
st-80 compatibility

accessing-look
o  font: aFont
set the menus font.
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  viewBackground: aColor
this is a kludge and will vanish ...

accessing-mvc
o  changeMessage
set the changeMessage from my menu

o  changeMessage: aSymbol
set the changeMessage - forward to my menu

o  menuPerformer
get the menuPerformer - forwarded to my menuViews

o  menuPerformer: someone
set the menuPerformer - forwarded to my menuViews

o  model
return my menuViews model

o  model: aModel
set the model - forwarded to my menuViews

converting
o  asMenu
( an extension from the stx:libtool package )
convert myself into a newStyle Menu instance, from which a MenuPanel is created.
The old PopUpMenu and MenuView is going to be obsoleted
(but still supported for backward compatibility)

deactivation
o  hide
hide the menu - if there are any pop-up-submenus, hide them also

o  hideForAction
hide the menu - if there are any pop-up-submenus, hide them also.
Any superMenu is not asked to regain control, since we are going to
hide them also.

dummy
o  findGuiResourcesIn: aResourceContainerOrApplication
dummy - for compatibility with MenuPanel
(in case an old-style PopUpMenu is returned from a menu message)

event handling
o  buttonMotion: state x: x y: y
state == 0 ifTrue:[^ self].

o  buttonPress: button x: x y: y
(comment from inherited method)
button was pressed - check my components for a hit.

o  buttonRelease: button x: x y: y
(comment from inherited method)
button was released - check my components for a hit.

o  keyPress: key x: x y: y
already redelegated

o  pointerEnter: state x: x y: y
catch quick release of button

o  pointerLeave: state
menuView pointerLeave:state.

initialization
o  initEvents
(comment from inherited method)
will be sent by create - can be redefined by subclasses to enable
view events

o  initStyle
#'popup.borderWidth'

o  initialize

menuview messages
o  doesNotUnderstand: aMessage
forward all menu-view messages

o  regainControl
(comment from inherited method)
get exclusive access to pointer and keyboard

private-accessing
o  isOpenedAsSubmenu
return true, if I have been opened as a submenu of some other
menu.

o  menu: aMenuView
set the actual menu

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

o  menuView
return the actual menu

o  menuView: aMenu
set the actual menu

o  superMenu: aMenu
set the superMenu

realization
o  fixSize
called right before the view is made visible.
adjust my size to the size of the actual menu

o  realize


Examples:


The ST-80 way of opening menus is to startUp a menu, and use the returned value:
  |p|

  p := PopUpMenu
          labels:#('foo' 'bar' 'baz').
  Transcript showCR:p startUp
It returns the index of the selected item or 0 if nothing was selected. This opening is done by either the controller or the view (if it has a middleButtonMenu and/or a menuHolder). If the numeric index is inconvenient, alternative values may be specified as in (here, nil is returned if nothing was selected):
  |p|

  p := PopUpMenu
          labels:#('foo' 'bar' 'baz')
          values:#('hello foo' 'hello bar' 'hello baz').
  Transcript showCR:p startUp
In ST/X, the above is actually done by a mimicri method (#startUp) and menus are typically created in one of the following ways: -> With a single actionBlock. This is convenient, if all actions shall perform a similar task, but require different arguments. this is evaluated, passing the selections index or value as argument. The action block is NOT evaluated, if nothing was selected. With index:
  |p|

  p := PopUpMenu
          labels:#('foo' 'bar' 'baz').
  p action:[:item | Transcript showCR:item].
  p showAtPointer
With individual arguments:
  |p|

  p := PopUpMenu
          labels:#('foo' 'bar' 'baz')
          args:#('hello foo' 'hello bar' 'hello baz').
  p action:[:item | Transcript showCR:item].
  p showAtPointer
-> With an explicit receiver and different selectors. This is convenient, if you have to send per-item messages to some object (typically, the receiver is the view or a model)
  |p m|

  m := Plug new.
  m respondTo:#foo with:[Transcript showCR:'foo received'].
  m respondTo:#bar with:[Transcript showCR:'bar received'].
  m respondTo:#maz with:[Transcript showCR:'maz received'].

  p := PopUpMenu
          labels:#('foo' 'bar' 'baz')
          selectors:#(#foo #bar #baz)
          receiver:m.
  p showAtPointer
More examples: dynamic with action instead of selector being sent:
      |p|

      p := PopUpMenu
              labels:(($a to: $d) collect:[:char | char asString])
              selectors:nil
              receiver:nil.
      p action:[:idx | Transcript showCR:'selected index is '; showCR:idx].
      p showAtPointer
individual actions:
      |p|
      p := PopUpMenu
              labels:#('foo'
                       'bar'
                       'baz')
              selectors:#(
                          #foo
                          #bar
                          #baz).
      p actionAt:#foo put:[Transcript showCR:'foo'].
      p actionAt:#bar put:[Transcript showCR:'bar'].
      p actionAt:#baz put:[Transcript showCR:'baz'].
      p showAtPointer
sometimes, you want to specify both selectors and some arguments to be sent; this is done by:
      |p|
      p := PopUpMenu
              labels:#('foo' 'bar' 'baz')
              selectors:#(#foo: #bar: #foo:)
              args:#(1 2 3)
              receiver:nil.
      p showAtPointer
or, the same selector but different arguments:
      |p|
      p := PopUpMenu
              labels:#('foo' 'bar' 'baz')
              selectors:#foo:
              args:#(1 2 3)
              receiver:nil.
      p showAtPointer
Normally, you do not show the menu explicitely, but install it as a either as middleButtonMenu of some view or return it from a model. (Views/Controllers button-event handler will show it when the middle button is pressed ...) Static menu:
      |v m|

      v := View new.
      m := PopUpMenu
              labels:#('lower'
                       'raise'
                       '-'
                       'destroy')
              selectors:#(#lower #raise nil #destroy)
              receiver:v.
      v middleButtonMenu:m.
      v open
Dynamic menu: (since we need some model which responds to a menu-message, we use a plug in the example below; normally, this would be your model)
      |v model|

      model := Plug new.
      model respondTo:#getMenu with:[PopUpMenu labels:#('foo' 'bar')
                                               selectors:#(foo bar)].
      model respondTo:#foo with:[Transcript showCR:'models foo called'].
      model respondTo:#bar with:[Transcript showCR:'models bar called'].

      v := View new.
      v model:model; menu:#getMenu.
      v open
Dynamic menus are the MVC-way (i.e. ST-80) way of doing things. They are usually easier to use, if the menu changes depending on the models state. (for example, see the systemBrowsers menus being different when things are selected ...) It is also possible, to add check-mark entries, with an entry string starting with the special sequence '\c' (for check-mark). The value passed will be the truth-state of the check-mark.
      |m v|

      v := View new.
      m := PopUpMenu
              labels:#('\c foo'
                       '\c bar')
              selectors:#(#value: #value:)
              receiver:[:v | Transcript show:'arg: '; showCR:v].
      v middleButtonMenu:m.
      v open
The style of the checkmark can be: check (\c), box (\b) or thumbs (\t):
      |m v|

      v := View new.
      m := PopUpMenu
              labels:#('\c foo'
                       '\b bar'
                       '\t baz')
              selectors:#(#value: #value: #value:)
              receiver:[:v | Transcript show:'arg: '; showCR:v].
      v middleButtonMenu:m.
      v open
or at the end (looks better with variable fonts):
      |m v|

      v := View new.
      m := PopUpMenu
              labels:#('foo \c'
                       'bar \b'
                       'baz \t')
              selectors:#(#value: #value: #value:)
              receiver:[:v | Transcript show:'arg: '; showCR:v].
      v middleButtonMenu:m.
      v open
Finally, you can wrap other views into a popup menu (for example, to implement menus with icons or other components). The view should respond to some messages sent from here (for example: #hideSubmenus, #deselectWithoutRedraw and others). Currently there is only one class in the system, which can be used this way (PatternMenu in the DrawTool demo):
      |v p|

      v := View new.
      p := PatternMenu new.
      p patterns:(Array with:Color red
                        with:Color green
                        with:Color blue).
      v middleButtonMenu:(PopUpMenu forMenu:p).
      v open
or try:
      |v p|

      v := View new.
      p := PatternMenu new.
      p patterns:(Array with:Color red
                        with:Color green
                        with:Color blue).
      p selectors:#value:.
      p receiver:[:val | v viewBackground:val. v clear].
      p args:(Array with:Color red
                    with:Color green
                    with:Color blue).
      v middleButtonMenu:(PopUpMenu forMenu:p).
      v open
ST-80 style: The above menus all did some message send on selection; it is also possible, to use Smalltalk-80 style menus (which return some value from their startup method):
      |m selection|

      m := PopUpMenu
              labels:#('one' 'two' 'three').
      selection := m startUp.
      Transcript show:'the selection was: '; showCR:selection
startUp will return the entries index, or 0 if there was no selection. You can also specify an array of values to be returned instead of the index:
      |m selection|

      m := PopUpMenu
              labels:#('one' 'two' 'three')
              values:#(10 20 30).
      selection := m startUp.
      Transcript show:'the value was: '; showCR:selection
In ST/X style menus, separating lines between entries are created by a '-'-string as its label text (and corresponding nil-entries in the selectors- and args-arrays). In ST-80, you have to pass the indices of the lines in an extra array:
      |m selection|

      m := PopUpMenu
              labels:#('one' 'two' 'three' 'four' 'five')
              lines:#(2 4).
      selection := m startUp.
      Transcript show:'the value was: '; showCR:selection
or:
      |m selection|

      m := PopUpMenu
              labels:#('one' 'two' 'three')
              lines:#(2)
              values:#(10 20 30).
      selection := m startUp.
      Transcript show:'the value was: '; showCR:selection
Use whichever interface you prefer.

ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Tue, 23 Apr 2024 13:29:18 GMT