MenuEditor.st
author tz
Sat, 10 Jan 1998 12:12:09 +0100
changeset 406 a519e0d547f6
parent 398 155310ec83aa
child 407 578a7aaed19e
permissions -rw-r--r--
widgets rearranged for different fonts + comfortable menu load support

"
 COPYRIGHT (c) 1997 by eXept Software AG / 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.
"



ToolApplicationModel subclass:#MenuEditor
	instanceVariableNames:'isModified specClass specCanvas helpCanvas tabSelection aspects
		slices didInstall'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-UIPainter'
!

Object subclass:#Item
	instanceVariableNames:'activeHelpKey enabled label value nameKey indication shortcutKey
		accessCharaterPos retriever icon iconAndLabel submenuChannel
		argument translateLabel isButton'
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

SelectionInTreeView subclass:#Painter
	instanceVariableNames:'images'
	classVariableNames:'CopyBuffer Images'
	poolDictionaries:''
	privateIn:MenuEditor
!

!MenuEditor class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1997 by eXept Software AG / 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.
"


!

documentation
"
    create and modify or inspect popup and pullDown menus of the
    new style( derives from Menu).

    [start with:]
        MenuEditor open
        MenuEditor new openOnClass:MenuEditor andSelector:#menuPullDown

    [see also:]
        UIPainter
        UIHelpTool
        UISpecificationTool
        SelectionInTreeView

    [author:]
        Claus Atzkern, Thomas Zwick
"

! !

!MenuEditor class methodsFor:'initialization'!

initialize

    Painter initialize
! !

!MenuEditor class methodsFor:'code generation'!

generateCodeFor:aClass menuSelector:aSelector

    |code category|

    category := self sourceCategory.

    code := Character excla asString 
            , aClass name , ' methodsFor:' , category storeString
            , Character excla asString , '\\'

            , aSelector , '\'
            , '    "this window spec was automatically generated by the UI Builder"\\'
            , '    ^ self class ', aSelector, '\\'
            , '\'
            , Character excla asString
            , ' '
            , Character excla asString
            , '\\'.
    ^ code

"
self generateCodeFor:MenuEditor menuSelector:#menu
"
!

sourceCategory
    "returns the catagory where to instal the menu
    "
    ^ 'accessing menu'
! !

!MenuEditor class methodsFor:'help specs'!

helpSpec
    "return a dictionary filled with helpKey -> helptext associations.
     These are used by the activeHelp tool."

    "
    UIHelpTool openOnClass:MenuEditor    
    "

  ^ super helpSpec addPairsFrom:#(

#accessCharaterPos
'The index of the access character position
into the textual label (optional).'

#argument
'An argument passed to the value method, if the value 
selector is a one- or two-arg selector (i.e. ends with '':'').
The argument is passed as a string.'

#enbled
'This enabled field specifies the name of the aspect (-method or binding)
in your application, which returns a value holder holding a boolean,
a block which evaluates to either true or false, a selector which returns
either true or false or simply true or false. The value, true or false,
specifies whether  the respective field can be selected, a value of true,
or not, a value of false.'

#icon
'Selector which returns an image to be displayed.'

#iconAndLabel
'Boolean flag to specify that both image and textual label shall be shown.'

#indication
'This indication field specifies the name of the aspect (-method or binding)
in your application, a value holder holding a boolean, a block which evaluates
to either true or false, a selector which returns either true or false or
simply true or false. The value, true or false, specifies whether the shown
indicator is switched on or off.'

#label
'The label of the item. If the ''retriever/selector'' is set, 
and returns an image, the image is used as the displayed label. 
Dependent on the state of the ''Image & Label'' flag, both
the image and the label are shown.'

#menuSelector
'The name of the selector under which the generated 
menu should be installed and is accessable.'

#nameKey
'An unique identifier of the item (optional)'

#retriever
'The name of the class, which implements the image selector. 
This selector is specified by ''selector''. If no class is given, 
the current application should implement the specified image selector.'

#seperatorList
'The list of valid separators'

#shortcutKey
'The key to be pressed, to select the menu item from the keyboard (accelerator key).'

#submenuChannel
'A value holder, which provides the submenu (Menu) to be opened
if the item is selected. Useful if the items submenu is to be 
changed dynamically.'

#value
'An action which can be either a block or a selector. Depending on the number
of arguments to the action, the action will be called with the respective arguments.
There can either zero, one or two arguments. The first argument to the action is the
argument derived from the argument field and the second argument the selected item.'

)
! !

!MenuEditor class methodsFor:'icons'!

iconCreateItem
    ^ Painter menuItemImage

!

iconCreateLink
    ^ Painter linkSubmenuImage

!

iconCreateMenu
    ^ Painter closedSubmenuImage
!

iconCreateSep
    ^ Painter menuSeparatorImage

!

iconUnknown
    "returns an image used for picked items containing an image
    "

    <resource: #fileImage>

    ^ Image fromFile:'brokenImage.xpm'

    "Modified: / 29.10.1997 / 03:22:06 / cg"
! !

!MenuEditor class methodsFor:'interface specs'!

classDefineSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#classDefineSpec
     MenuEditor new openInterface:#classDefineSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'MenuEditor'
              #'layout:' #(#LayoutFrame 197 0 172 0 443 0 265 0)
              #'label:' 'MenuEditor'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1152 900)
              #'bounds:' #(#Rectangle 197 172 444 266)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'boxLabel'
                    #'layout:' #(#LayoutFrame 0 0.0 4 0 0 1.0 24 0)
                    #'label:' 'Class for menu spec:'
                    #'adjust:' #left
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'classNameField'
                    #'layout:' #(#LayoutFrame 0 0.0 27 0 0 1.0 49 0)
                    #'tabable:' true
                    #'model:' #classNameChannel
                )
                 #(#HorizontalPanelViewSpec
                    #'name:' 'commitPanel'
                    #'layout:' #(#LayoutFrame 10 0.0 -29 1.0 -10 1.0 -5 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ActionButtonSpec
                              #'name:' 'button1'
                              #'label:' 'Cancel'
                              #'tabable:' true
                              #'model:' #cancel
                              #'extent:' #(#Point 109 24)
                          )
                           #(#ActionButtonSpec
                              #'name:' 'button2'
                              #'label:' 'OK'
                              #'tabable:' true
                              #'model:' #accept
                              #'isDefault:' true
                              #'extent:' #(#Point 109 24)
                          )
                        )
                    )
                    #'horizontalLayout:' #fitSpace
                    #'verticalLayout:' #fit
                    #'horizontalSpace:' 3
                    #'verticalSpace:' 3
                )
              )
          )
      )
!

menu
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:MenuEditor andSelector:#menu
     (Menu new fromLiteralArrayEncoding:(MenuEditor menu)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'About'
                #'accessCharacterPosition:' 1
                #'labelImage:' #(#ResourceRetriever nil #icon)
                #'submenuChannel:' #menuAbout
            )
             #(#MenuItem
                #'label:' 'File'
                #'translateLabel:' true
                #'value:' #file
                #'accessCharacterPosition:' 1
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'New'
                          #'value:' #doNew
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Load From Class...'
                          #'translateLabel:' true
                          #'value:' #doFromClass
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' 'Load From Class With Superclass...'
                          #'translateLabel:' true
                          #'value:' #loadFromClassWithSuperclass
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Save'
                          #'value:' #doInstallSpec
                      )
                       #(#MenuItem
                          #'label:' 'Save Help Spec'
                          #'value:' #doInstallHelp
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Pick A Menu'
                          #'value:' #doPickAMenu
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' 'Define Class...'
                          #'value:' #doDefineClass
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' 'Browse Class'
                          #'value:' #doBrowseAppClass
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Exit'
                          #'translateLabel:' true
                          #'value:' #closeRequest
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'Edit'
                #'submenuChannel:' #menuPainter
            )
             #(#MenuItem
                #'label:' 'Test'
                #'accessCharacterPosition:' 1
                #'submenuChannel:' #submenuTest
            )
             #(#MenuItem
                #'label:' 'History'
                #'accessCharacterPosition:' 1
                #'submenuChannel:' #menuHistory
            )
             #(#MenuItem
                #'label:' 'Help'
                #'accessCharacterPosition:' 1
                #'submenuChannel:' #menuHelp
            )
          ) nil
          nil
      )
!

menuDefaultLink
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:MenuEditor andSelector:#menuDefaultLink
     (Menu new fromLiteralArrayEncoding:(MenuEditor menuDefaultLink)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' '!! derives from application !!'
            )
          ) nil
          nil
      )
!

menuPainter
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:MenuEditor andSelector:#menuPainter
     (Menu new fromLiteralArrayEncoding:(MenuEditor menuPainter)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'Cut'
                #'value:' #doCut
                #'enabled:' #hasValidSelection
                #'shortcutKeyCharacter:' #Cut
            )
             #(#MenuItem
                #'label:' 'Copy'
                #'value:' #doCopy
                #'enabled:' #hasValidSelection
                #'shortcutKeyCharacter:' #Copy
            )
             #(#MenuItem
                #'label:' 'Paste'
                #'value:' #doPaste
                #'enabled:' #hasAnySingleSelection
                #'shortcutKeyCharacter:' #Paste
            )
             #(#MenuItem
                #'label:' '='
            )
             #(#MenuItem
                #'label:' 'Create Item'
                #'value:' #doCreateItem
                #'labelImage:' #(#ResourceRetriever #MenuEditor #iconCreateItem 'Create Item')
            )
             #(#MenuItem
                #'label:' 'Create Separator'
                #'value:' #doCreateSep
                #'labelImage:' #(#ResourceRetriever #MenuEditor #iconCreateSep 'Create Separator')
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'Create Submenu Static'
                #'value:' #doCreateMenu
                #'labelImage:' #(#ResourceRetriever #MenuEditor #iconCreateMenu 'Create Submenu Static')
            )
             #(#MenuItem
                #'label:' 'Create Submenu Dynamic'
                #'value:' #doCreateLink
                #'labelImage:' #(#ResourceRetriever #MenuEditor #iconCreateLink 'Create Submenu Dynamic')
            )
          ) nil
          nil
      )
!

menuToolbar
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:MenuEditor andSelector:#menuToolbar
     (Menu new fromLiteralArrayEncoding:(MenuEditor menuToolbar)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'New'
                #'isButton:' true
                #'value:' #doNew
                #'labelImage:' #(#ResourceRetriever nil #newIcon)
            )
             #(#MenuItem
                #'label:' 'Load'
                #'isButton:' true
                #'value:' #doFromClass
                #'labelImage:' #(#ResourceRetriever nil #loadIcon)
            )
             #(#MenuItem
                #'label:' 'Save'
                #'isButton:' true
                #'value:' #doInstallSpec
                #'labelImage:' #(#ResourceRetriever nil #saveIcon)
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'createItem'
                #'isButton:' true
                #'value:' #doCreateItem
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' #(#ResourceRetriever nil #iconCreateItem)
            )
             #(#MenuItem
                #'label:' 'createSeparator'
                #'isButton:' true
                #'value:' #doCreateSep
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' #(#ResourceRetriever nil #iconCreateSep)
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'createMenu'
                #'isButton:' true
                #'value:' #doCreateMenu
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' #(#ResourceRetriever nil #iconCreateMenu)
            )
             #(#MenuItem
                #'label:' 'createLink'
                #'isButton:' true
                #'value:' #doCreateLink
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' #(#ResourceRetriever nil #iconCreateLink)
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'stepUp'
                #'isButton:' true
                #'value:' #doStepUp
                #'enabled:' #enabledStepOver
                #'labelImage:' #(#ResourceRetriever nil #upIcon)
            )
             #(#MenuItem
                #'label:' 'stepDown'
                #'isButton:' true
                #'value:' #doStepDown
                #'enabled:' #enabledStepOver
                #'labelImage:' #(#ResourceRetriever nil #downIcon)
            )
             #(#MenuItem
                #'label:' 'stepIn'
                #'isButton:' true
                #'value:' #doStepIn
                #'enabled:' #enabledStepIn
                #'labelImage:' #(#ResourceRetriever nil #downRightIcon)
            )
             #(#MenuItem
                #'label:' 'stepOut'
                #'isButton:' true
                #'value:' #doStepOut
                #'enabled:' #enabledStepOut
                #'labelImage:' #(#ResourceRetriever nil #leftDownIcon)
            )
          ) nil
          nil
      )
!

windowSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#windowSpec
     MenuEditor new openInterface:#windowSpec
    "
    "MenuEditor open"

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'Menu Builder'
              #'layout:' #(#LayoutFrame 227 0 195 0 806 0 578 0)
              #'label:' 'Menu Builder'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1152 900)
              #'bounds:' #(#Rectangle 227 195 807 579)
              #'menu:' #menu
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#MenuPanelSpec
                    #'name:' 'menuToolbarView'
                    #'layout:' #(#LayoutFrame 0 0.0 0 0 0 1.0 34 0)
                    #'menu:' #menuToolbar
                    #'showSeparatingLines:' true
                )
                 #(#VariableHorizontalPanelSpec
                    #'name:' 'variableHorizontalPanel1'
                    #'layout:' #(#LayoutFrame 0 0.0 36 0.0 0 1.0 -22 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ArbitraryComponentSpec
                              #'name:' 'painterView'
                              #'menu:' #menuPainter
                              #'hasHorizontalScrollBar:' true
                              #'hasVerticalScrollBar:' true
                              #'component:' #painter
                              #'hasBorder:' false
                          )
                           #(#ViewSpec
                              #'name:' 'view1'
                              #'component:' 
                               #(#SpecCollection
                                  #'collection:' 
                                   #(
                                     #(#NoteBookViewSpec
                                        #'name:' 'specificationView'
                                        #'layout:' #(#LayoutFrame 1 0.0 0 0.0 0 1.0 -26 1.0)
                                        #'tabable:' true
                                        #'model:' #tabModel
                                        #'menu:' #tabList
                                        #'useIndex:' true
                                        #'canvas:' #noteBookView
                                    )
                                     #(#HorizontalPanelViewSpec
                                        #'name:' 'confirmationPanel'
                                        #'layout:' #(#LayoutFrame 1 0.0 -24 1 0 1.0 0 1.0)
                                        #'component:' 
                                         #(#SpecCollection
                                            #'collection:' 
                                             #(
                                               #(#ActionButtonSpec
                                                  #'name:' 'cancelButton'
                                                  #'label:' 'Cancel'
                                                  #'model:' #cancel
                                                  #'enableChannel:' #modifiedChannel
                                                  #'extent:' #(#Point 171 24)
                                              )
                                               #(#ActionButtonSpec
                                                  #'name:' 'acceptButton'
                                                  #'label:' 'OK'
                                                  #'model:' #accept
                                                  #'enableChannel:' #modifiedChannel
                                                  #'extent:' #(#Point 171 24)
                                              )
                                            )
                                        )
                                        #'horizontalLayout:' #fitSpace
                                        #'verticalLayout:' #fit
                                        #'horizontalSpace:' 3
                                        #'verticalSpace:' 3
                                    )
                                  )
                              )
                              #'level:' -1
                          )
                        )
                    )
                    #'handles:' #(#Any 0.384483 1.0)
                )
                 #(#LabelSpec
                    #'name:' 'infoLabel'
                    #'layout:' #(#LayoutFrame 0 0.0 -22 1 -80 1.0 0 1.0)
                    #'labelChannel:' #valueOfInfoLabel
                    #'level:' 1
                    #'adjust:' #left
                )
                 #(#LabelSpec
                    #'name:' 'timeLabel'
                    #'layout:' #(#LayoutFrame -80 1 -22 1 0 1.0 0 1.0)
                    #'labelChannel:' #valueOfTimeLabel
                    #'level:' 1
                    #'adjust:' #right
                )
              )
          )
      )
! !

!MenuEditor class methodsFor:'slices'!

slicesItem
    ^#(
            (Basics     basicsItemSpec)
            (Details    detailsEditSpec)
            (Image      imageEditSpec)
      )

!

slicesLink
    ^#(
            (Basics     basicsLinkSpec)
            (Details    detailsEditSpec)
            (Image      imageEditSpec)
      )

!

slicesMenu
    ^#(
            (Basics     basicsMenuSpec)
            (Details    detailsEditSpec)
            (Image      imageEditSpec)
      )

!

slicesRootMenu
    ^#(
            (Basics   basicsRootSpec)
      )

!

slicesSeparatorMenu
    ^#(
            (Basics   basicsSeparatorSpec)
      )

! !

!MenuEditor class methodsFor:'specs'!

basicsItemSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#basicsItemSpec
     MenuEditor new openInterface:#basicsItemSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 454 0 288 0 720 0 606 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 454 288 721 607)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                    #'label:' 'Label:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 110 0 40 0 0 1.0 62 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #label
                )
                 #(#LabelSpec
                    #'name:' 'valueLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 90 0 1 0.5)
                    #'label:' 'Value:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'valueField'
                    #'layout:' #(#LayoutFrame 110 0 79 0 0 1.0 101 0)
                    #'activeHelpKey:' #value
                    #'tabable:' true
                    #'model:' #value
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'argumentLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 115 0 1 0.5)
                    #'label:' 'Argument:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'argumentField'
                    #'layout:' #(#LayoutFrame 110 0 104 0 0 1.0 126 0)
                    #'activeHelpKey:' #argument
                    #'tabable:' true
                    #'model:' #argument
                    #'type:' #string
                )
                 #(#LabelSpec
                    #'name:' 'indicationLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 155 0 1 0.5)
                    #'label:' 'Indication:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'indicationField'
                    #'layout:' #(#LayoutFrame 110 0 144 0 0 1.0 166 0)
                    #'activeHelpKey:' #indication
                    #'tabable:' true
                    #'model:' #indication
                    #'type:' #symbolOrNil
                )
                 #(#CheckBoxSpec
                    #'name:' 'translateLabelCheckBox'
                    #'layout:' #(#Point 20 192)
                    #'activeHelpKey:' #translateLabel
                    #'model:' #translateLabel
                    #'label:' 'Translate Label'
                )
                 #(#CheckBoxSpec
                    #'name:' 'isButtonCheckBox'
                    #'layout:' #(#Point 20 221)
                    #'activeHelpKey:' #translateLabel
                    #'model:' #isButton
                    #'label:' 'Is Button'
                )
              )
          )
      )
!

basicsLinkSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#basicsLinkSpec
     MenuEditor new openInterface:#basicsLinkSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 585 0 331 0 851 0 649 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 585 331 852 650)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'activeHelpKey:' #nameKey
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                    #'label:' 'Label:'
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 110 0 40 0 0 1.0 62 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #label
                )
                 #(#InputFieldSpec
                    #'name:' 'menuField'
                    #'layout:' #(#LayoutFrame 110 0 65 0 0 1.0 87 0)
                    #'activeHelpKey:' #submenuChannel
                    #'tabable:' true
                    #'model:' #submenuChannel
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'menuLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 76 0 1 0.5)
                    #'label:' 'Menu:'
                    #'resizeForLabel:' true
                )
              )
          )
      )
!

basicsMenuSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#basicsMenuSpec
     MenuEditor new openInterface:#basicsMenuSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 381 0 278 0 647 0 596 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 381 278 648 597)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                    #'label:' 'Label:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 110 0 40 0 0 1.0 62 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #label
                )
                 #(#CheckBoxSpec
                    #'name:' 'translateLabelCheckBox'
                    #'layout:' #(#Point 20 100)
                    #'activeHelpKey:' #translateLabel
                    #'model:' #translateLabel
                    #'label:' 'Translate Label'
                )
              )
          )
      )
!

basicsRootSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#basicsRootSpec
     MenuEditor new openInterface:#basicsRootSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 427 0 345 0 693 0 663 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 427 345 694 664)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'selectorLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'label:' 'Selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'selectorField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #menuSelector
                    #'tabable:' true
                    #'model:' #label
                )
              )
          )
      )
!

basicsSeparatorSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#basicsSeparatorSpec
     MenuEditor new openInterface:#basicsSeparatorSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 197 0 172 0 463 0 490 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 197 172 464 491)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'separatorLabel'
                    #'layout:' #(#AlignmentOrigin 127 0 26 0 1 0.5)
                    #'label:' 'Separator Type:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#ComboListSpec
                    #'name:' 'seperatorList'
                    #'layout:' #(#LayoutFrame 132 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #seperatorList
                    #'model:' #seperatorSelection
                    #'useIndex:' true
                )
              )
          )
      )
!

detailsEditSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#detailsEditSpec
     MenuEditor new openInterface:#detailsEditSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 196 0 489 0 454 0 776 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 196 489 455 777)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'shortcutKeyLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'label:' 'Accelerator:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'shortcutKeyField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #shortcutKey
                    #'tabable:' true
                    #'model:' #shortcutKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'enabledLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                    #'label:' 'Enabled:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'enabledField'
                    #'layout:' #(#LayoutFrame 110 0 40 0 0 1.0 62 0)
                    #'activeHelpKey:' #enbled
                    #'tabable:' true
                    #'model:' #enabled
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'accessCharLabel'
                    #'layout:' #(#AlignmentOrigin 217 0 90 0 1 0.5)
                    #'label:' 'Access Character Position:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'accessCharField'
                    #'layout:' #(#LayoutFrame 220 0 79 0 0 1.0 101 0)
                    #'activeHelpKey:' #accessCharaterPos
                    #'tabable:' true
                    #'model:' #accessCharaterPos
                    #'type:' #numberOrNil
                )
              )
          )
      )
!

imageEditSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:MenuEditor andSelector:#imageEditSpec
     MenuEditor new openInterface:#imageEditSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 424 0 309 0 668 0 450 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 424 309 669 451)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'retrieverLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 26 0 1 0.5)
                    #'label:' 'Retriever:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'retrieverField'
                    #'layout:' #(#LayoutFrame 110 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #retriever
                    #'tabable:' true
                    #'model:' #retriever
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'iconLabel'
                    #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                    #'label:' 'Selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'iconField'
                    #'layout:' #(#LayoutFrame 110 0 40 0 0 1.0 62 0)
                    #'activeHelpKey:' #icon
                    #'tabable:' true
                    #'model:' #icon
                    #'type:' #symbolOrNil
                )
                 #(#CheckBoxSpec
                    #'name:' 'iconAndLabel'
                    #'layout:' #(#LayoutOrigin 20 0 104 0)
                    #'activeHelpKey:' #iconAndLabel
                    #'tabable:' true
                    #'model:' #iconAndLabel
                    #'label:' 'Image & Label'
                )
                 #(#ActionButtonSpec
                    #'name:' 'imageEditorButton'
                    #'layout:' #(#LayoutFrame 110 0 66 0 0 1 90 0)
                    #'label:' 'Image Editor'
                    #'model:' #doEditImage
                )
              )
          )
      )
! !

!MenuEditor class methodsFor:'startup'!

openModalOnClass:aClass andSelector:aSelector
    ^ self new openModalOnClass:aClass andSelector:aSelector


!

openOnClass:aClass andSelector:aSelector
    ^ self new openOnClass:aClass andSelector:aSelector


! !

!MenuEditor methodsFor:'accessing'!

isModified: aBoolean         

    isModified := aBoolean
!

menuDefaultLink
    ^ self class menuDefaultLink
!

selectorName
    ^ self painter selectorName

    "Created: 31.7.1997 / 14:11:28 / cg"
!

specClass
    ^ specClass
!

specClass:aClass
    aClass isBehavior ifTrue:[specClass := aClass name]
                     ifFalse:[specClass := aClass].
!

submenuTest
    "returns submenu assigned to item test
    "
    |menu|

    menu := self painter asMenu.

    menu allItemsDo:[:anItem|
        anItem value:nil.
        anItem enabled:true.
    ].
  ^ menu
!

useHelpDictionary:aDictionary
    self noteBookView.
    self helpTool dictionary:aDictionary.
! !

!MenuEditor methodsFor:'accessing menu'!

menu
    "this window spec was automatically generated by the UI Builder"

    ^ self class menu


!

menuButtons
    "this window spec was automatically generated by the ST/X MenuEditor"

    ^ self class menuButtons


!

menuPainter
    "this window spec was automatically generated by the ST/X MenuEditor"

    ^ self class menuPainter


!

menuPullDown
    "this window spec was automatically generated by the ST/X MenuEditor"

    ^ self class menuPullDown


!

menuToolbar
    "this window spec was automatically generated by the UI Builder"

    ^ self class menuToolbar


! !

!MenuEditor methodsFor:'actions'!

accept
    "automatically generated by UIPainter ..."

    |painter node cont|

    painter := self painter.
    node := painter selectedNode.

    node notNil ifTrue:[
        self isHelpToolSelected ifTrue:[
            self helpTool accept.
            node contents activeHelpKey:(self helpTool helpKey)
        ] ifFalse:[
            cont := node contents buildFromAspects:aspects.
            painter selectedNodeChanged
        ]
    ].
    self modifiedChannel value:false.
    isModified := true.
!

cancel
    |node|

    (node := self painter selectedNode) notNil ifTrue:[
        self helpTool helpKey:(self helpKey).
        aspects do:[:anAspect| anAspect value:nil ].
        node contents toAspects:aspects.
    ].
    self modifiedChannel value:false.

! !

!MenuEditor methodsFor:'aspects'!

aspectFor:aKey
    "returns aspect for a key or nil
    "
  ^ aspects at:aKey ifAbsent:[ super aspectFor:aKey ]


!

enabledStepIn
    ^ builder booleanValueAspectFor:#enabledStepIn

    "Modified: 28.7.1997 / 12:51:55 / cg"
!

enabledStepOut
    ^ builder booleanValueAspectFor:#enabledStepOut

    "Modified: 28.7.1997 / 12:52:04 / cg"
!

enabledStepOver
    ^ builder booleanValueAspectFor:#enabledStepOver

    "Modified: 28.7.1997 / 12:52:07 / cg"
!

hasAnySingleSelection
    ^ builder booleanValueAspectFor:#hasAnySingleSelection

    "Modified: 28.7.1997 / 12:52:09 / cg"
!

hasValidSelection
    ^ builder booleanValueAspectFor:#hasValidSelection

    "Modified: 28.7.1997 / 12:52:11 / cg"
!

hasValidSingleSelection
    ^ builder booleanValueAspectFor:#hasValidSingleSelection

    "Modified: 28.7.1997 / 12:52:13 / cg"
!

modifiedChannel
    "automatically generated by UIPainter ..."

    ^ builder booleanValueAspectFor:#modifiedChannel

    "Modified: 28.7.1997 / 12:52:14 / cg"
!

noteBookView
    "automatically generated by UIPainter ..."

    |noteBook helpTool|

    (noteBook := builder bindingAt:#noteBookView) isNil ifTrue:[
        noteBook := View new.
        helpTool := UIHelpTool new.

        helpTool masterApplication:self.
        helpCanvas := SubCanvas origin:0.0@0.0 corner:1.0@1.0 in:noteBook.
        specCanvas := SubCanvas origin:0.0@0.0 corner:1.0@1.0 in:noteBook.

        helpCanvas client:helpTool.
        helpTool   masterApplication:self.
        helpTool   modifiedHolder:(self modifiedChannel).

        builder aspectAt:#noteBookView put:noteBook.
    ].
    ^ noteBook
!

tabList
    "automatically generated by UIPainter ..."

    |holder|

    (holder := builder bindingAt:#tabList) isNil ifTrue:[
        builder aspectAt:#tabList put:(holder := #('Properties') asValue).
    ].
    ^ holder


!

tabModel
    "automatically generated by UIPainter ..."

    |holder|

    (holder := builder bindingAt:#tabModel) isNil ifTrue:[
        holder := AspectAdaptor new subject:self; forAspect:#tabSelection.
        builder aspectAt:#tabModel put:holder.
    ].
    ^ holder

! !

!MenuEditor methodsFor:'change & update'!

update:something with:aParameter from:changedObject
    "one of my models changed its value
    "
    self modifiedChannel value:true.
!

updateEnabledChannels
    "update enabled channels
    "
    |node parent next painter state|

    painter := self painter.
    node    := painter selectedNode.
    state   := false.

    node notNil ifTrue:[
        self hasAnySingleSelection value:true.

        (parent := node parent) notNil ifTrue:[
            next := parent childAt:((parent indexOfChild:node) + 1).
            self enabledStepIn           value:(next notNil and:[next hasChildren]).
            self enabledStepOver         value:(parent children size > 1).
            self enabledStepOut          value:(parent parent notNil).
            self hasValidSingleSelection value:true.
            self hasValidSelection       value:true.
          ^ self
        ]
    ] ifFalse:[
        self hasAnySingleSelection value:false.

        painter numberOfSelections ~~ 0 ifTrue:[
            state := (painter isInSelection:1) not
        ]
    ].
    self enabledStepOver         value:false.
    self enabledStepIn           value:false.
    self enabledStepOut          value:false.
    self hasValidSingleSelection value:false.
    self hasValidSelection       value:state.
! !

!MenuEditor methodsFor:'event handling'!

doesNotUnderstand:aMessage
   |painter|

   painter := self painter.

   (painter respondsTo:(aMessage selector)) ifTrue:[
        ^ aMessage sendTo:painter
   ].
   super doesNotUnderstand:aMessage


! !

!MenuEditor methodsFor:'private'!

helpKey
    |node|

    (node := self painter selectedNode) notNil ifTrue:[
        ^ node contents activeHelpKey
    ].
    ^ nil
!

helpTool
    ^ helpCanvas application
! !

!MenuEditor methodsFor:'queries'!

didInstall
    "returns true if the menu was installed
    "

    ^ didInstall
!

isHelpToolSelected
    "returns true if current selection is help tool
    "
    (tabSelection ~~ 0 and:[slices notNil]) ifTrue:[
        ^ (slices at:tabSelection) first = UIHelpTool label
    ].
    ^ false
!

isStandAlone
    "returns true in case of owner of the helptool
    "
    ^ self masterApplication isNil
! !

!MenuEditor methodsFor:'selection'!

menuChanged
    |node item slc sel old|

    (node := self painter selectedNode) notNil ifTrue:[
        aspects do:[:anAspect| anAspect value:nil ].
        item := node contents.
        item toAspects:aspects.

        item isSeparator ifFalse:[
            node parent isNil ifFalse:[
                node hasChildren ifTrue:[
                    slc := #slicesMenu
                ] ifFalse:[
                    item submenuChannel isNil ifTrue:[slc := #slicesItem]
                                             ifFalse:[slc := #slicesLink]
                ].
                slc := (self class perform:slc) copyWith:#( 'Help' #dummy ).
            ] ifTrue:[
                slc := self class perform:#slicesRootMenu
            ].
        ] ifTrue:[
            slc := self class perform:#slicesSeparatorMenu.
        ]
    ].
    self helpTool helpKey:(self helpKey).
    self modifiedChannel value:false.

    slc ~= slices  ifTrue:[
        tabSelection ~~ 0 ifTrue:[
            old := (slices at:tabSelection) first
        ].

        (slices := slc) notNil ifTrue:[
            sel := slices collect:[:s| s first].
            tabSelection := 0.
            self tabList value:sel.

            (old notNil and:[(sel := sel findFirst:[:n|n = old]) ~~ 0]) ifFalse:[
                sel := 1
            ].
            self tabModel value:sel
        ] ifFalse:[
            self tabList value:nil.
            self tabSelection:0.
        ]
    ].
    self updateEnabledChannels
!

tabSelection
    ^ tabSelection ? 0
!

tabSelection:aSelection
    |sel|

    tabSelection = aSelection ifTrue:[
        ^ self
    ].
    (aSelection ~~ 0 and:[slices isNil]) ifTrue:[
        ^ self
    ].
    (tabSelection := aSelection) == 0 ifTrue:[
        slices isNil ifTrue:[
            specCanvas client:nil.
            ^ specCanvas raise.
        ].
        tabSelection == 1 ifTrue:[^ self].
        tabSelection := 1
    ].

    self isHelpToolSelected ifTrue:[
        self helpTool helpKey:(self helpKey).
        helpCanvas raise.
    ] ifFalse:[
        sel := (slices at:tabSelection) last.
        specCanvas client:self spec:(self class perform:sel) builder:builder.
        specCanvas raise.
    ]    

! !

!MenuEditor methodsFor:'startup / release'!

buildFrom:aClass andSelector:aSelector
    |oldClass newClass|

    oldClass := self specClass.
    self specClass:aClass.
    newClass := self specClass.

    (self isStandAlone and:[oldClass ~= newClass]) ifTrue:[
        self helpTool helpSpecFrom:newClass
    ].
    self painter buildFrom:newClass andSelector:aSelector.

    aClass notNil & aSelector notNil
    ifTrue:
    [
        |className message|
        aClass isClass ifTrue: [className := aClass name].
        aClass isString ifTrue: [className := aClass].
        message := className, ' ', aSelector.
        self addToHistory: message -> #loadFromMessage:.
        self valueOfInfoLabel value: className, ' << ', aSelector
    ].


!

checkModified
    "check menu modification
    "
    isModified
    ifTrue:
    [
        ((YesNoBox title:'Menu was modified!!')        
            noText:'Cancel';
            yesText:'Waste it and proceed';
            showAtPointer;
            accepted) ifFalse: [^false].
        isModified := false
    ].
    ^true


!

closeRequest
    "close request
    "
    self checkModified ifTrue: [super closeRequest]





!

initialize
    "initialize channels
    "
    |holder|

    super initialize.
    aspects := IdentityDictionary new.
    tabSelection := 0.

    #(
        label
        accessCharaterPos
        argument
        submenuChannel
        enabled
        value
        nameKey
        indication
        translateLabel
        isButton
        shortcutKey
        retriever
        iconAndLabel
        icon

     ) do:[:aKey|
        aspects at:aKey put:(holder := ValueHolder new).
        holder addDependent:self.
    ].

    aspects at:#seperatorSelection put:(holder := SelectionInList new).
    holder list:(Item separatorList).
    holder addDependent:self.


!

loadFromMessage: aMessage

    ((aMessage size > 0) and: [self checkModified])
    ifTrue:
    [
        |readStream aClass aSelector|
        readStream := aMessage readStream.
        aClass := Smalltalk at: (readStream upTo: $ ) asSymbol.
        aSelector :=  readStream upToEnd asSymbol.
        self buildFrom: aClass andSelector: aSelector.
        self painter selection: nil
    ]
!

openModalOnClass:aClass andSelector:aSelector
    specClass := Association key:aClass value:aSelector.
    super openInterfaceModal.

!

openOnClass:aClass andSelector:aSelector
    specClass := Association key:aClass value:aSelector.
    super openInterface.
    self buildFrom:aClass andSelector:aSelector.

!

postBuildWith:builder
    |cls sel|

    didInstall := false.
    isModified := false.

    specClass isAssociation ifTrue:[
        cls := specClass key.
        sel := specClass value.

        specClass := nil.

        (sel isKindOf:Menu) ifTrue:[
            self buildFrom:cls andSelector:nil.
          ^ self painter buildFromMenu:sel.
        ]
        
    ].
    self buildFrom:cls andSelector:sel.
! !

!MenuEditor methodsFor:'user interactions'!

doBrowseAppClass
    "open a browser on the class"

    |cls|

    cls := self resolveName:(self specClass).

    cls notNil ifTrue:[
        SystemBrowser openInClass:cls class selector:(self painter selectorName)
    ] ifFalse:[
        self information:'No valid class defined!!'.
    ]
!

doDefineClass

    aspects at:#classNameChannel  put:(self specClass asValue).

    (self openDialogInterface:#classDefineSpec) ifTrue:[
        self specClass:((aspects at:#classNameChannel) value)
    ].

!

doEditImage

    |cls resourceClass resourceSelector imageResourceMessage readStream|

    cls := self resolveName:(self specClass).
    cls isNil ifTrue:[
        ^ self information:'No valid class defined!!'.
    ].
    (aspects at:#retriever) value size > 0
        ifTrue:  [resourceClass := (aspects at:#retriever) value]
        ifFalse: [resourceClass := cls].
    (aspects at:#icon) value size > 0
        ifTrue:  [resourceSelector := (aspects at:#icon) value]
        ifFalse: [resourceSelector := #stxIcon].
    imageResourceMessage := ImageEditor openModalOnClass: resourceClass andSelector: resourceSelector.
    readStream := imageResourceMessage readStream.
    resourceClass := (readStream upTo: $ ) asSymbol.
    resourceSelector := readStream upToEnd asSymbol.
    resourceClass size > 0 ifTrue: [(aspects at:#retriever) value: resourceClass].
    resourceSelector size > 0 ifTrue: [(aspects at:#icon) value: resourceSelector].

    (aspects at:#retriever) value = specClass
    ifTrue:
    [
        (aspects at:#retriever) value: nil
    ]

!

doFromClass

    "aspects at:#classNameChannel  put:(self specClass asValue).
    aspects at:#methodNameChannel put:(self painter selectorName asValue).

    (self openDialogInterface:#classAndMethodSpec) ifTrue:[
        self buildFrom:(aspects at:#classNameChannel) value
           andSelector:(aspects at:#methodNameChannel) value
    ]."
    self loadFromInClassesOf:  #Object
!

doInstallHelp
    "install help text
    "
    self isStandAlone ifTrue:[
        self helpTool installHelpSpecInto:(self specClass)
    ]
!

doInstallSpec
    |cls selector painter menu spec mthd category code|

    cls := self resolveName:(self specClass).

    cls isNil ifTrue:[
        ^ self information:'No valid class defined!!'.
    ].
    painter  := self painter.
    selector := painter selectorName.
    menu     := painter asMenu.

    menu isNil ifTrue:[
        ^ self information:'No menu defined.'
    ].
    menu := menu literalArrayEncoding.
    spec := WriteStream on:String new.
    UISpecification prettyPrintSpecArray:menu on:spec indent:5.
    spec := spec contents.

    "/ if that method already exists, do not overwrite the category

    category := 'interface specs'.
    (mthd := cls class compiledMethodAt:selector) notNil ifTrue:[
        category := mthd category.
    ].

    code := Character excla asString 
            , cls name , ' class methodsFor:' , category storeString
            , Character excla asString , '\\'

            , selector , '\'
            , '    "this window spec was automatically generated by the ST/X MenuEditor"\\'
            , '    "do not manually edit this - the builder may not be able to\'
            , '     handle the specification if its corrupted."\\'
            , '    "\'
            , '     MenuEditor new openOnClass:' , cls name , ' andSelector:#' , selector , '\'
            , '     (Menu new fromLiteralArrayEncoding:(' , cls name , ' ' , selector , ')) startUp\'
            , '    "\'.

    code := code 
            , '\'
            , '    <resource: #menu>\\'
            , '    ^\' 
            , '     ', spec
            , '\'
            , Character excla asString
            , ' '
            , Character excla asString
            , '\\'.

    code := code withCRs.
    (ReadStream on:code) fileIn.

    (cls compiledMethodAt:selector) isNil ifTrue:[
        code := self class generateCodeFor:cls menuSelector:selector.
        code := code withCRs.
        (ReadStream on:code) fileIn.
    ].
    didInstall := true.
    isModified := false.

!

doNew

    self buildFrom:nil andSelector:(self painter selectorName)
!

doPickAMenu

    |view|

    view := Screen current viewFromUser.

    (view isNil or:[view == Screen current rootView]) ifTrue:[
        ^ self
    ].
    view specClass == MenuPanelSpec ifTrue:[
        ^ self painter buildFromMenu:(view asMenu)
    ].
    ^ nil
!

doStepDown
    "move selected child after next child
    "
    self painter selectedNodeChangeSequenceOrder:1.
    isModified := true.




!

doStepIn
    "move selected child into next parent node
    "
    self painter selectedNodeBecomeChildOfNext.
    isModified := true.





!

doStepOut
    "move selected child out from parent node
    "
    self painter selectedNodeBecomeSisterOfParent.
    isModified := true.
!

doStepUp
    "move selected child before previous child
    "
    self painter selectedNodeChangeSequenceOrder:-1.
    isModified := true.
!

loadFromClassWithSuperclass

    |box|
    box := EnterBox new.
    box title:'Name of superclass:'.
    box okText:'OK'.
    box abortText:'Cancel'.
    box initialText: 'ApplicationModel'.
    box showAtPointer.
    box accepted
    ifTrue:
    [            
        self loadFromInClassesOf: box contents asSymbol
    ].



!

loadFromInClassesOf: aSuperclassOrSymbol

    self loadFromMessage: 
        (ResourceSelectionBrowser
            request: 'Load Menu From Class'
            onSuperclass: aSuperclassOrSymbol
            andClass: specClass
            andSelector: nil
            withResourceTypes: #(menu))
! !

!MenuEditor methodsFor:'values'!

painter
    "automatically generated by UIPainter ..."

    |painter|

    (painter := builder bindingAt:#painter) isNil ifTrue:[
        painter := Painter new.
        painter action:[:dummy| self menuChanged ].
        builder aspectAt:#painter put:painter.
    ].
  ^ painter
! !

!MenuEditor::Item class methodsFor:'constants'!

separatorList
   ^ #( 'blank' 'single line' 'double line' )
!

separatorSlices
   ^ #(
        ( #blank        ''  )
        ( #single       '-' )
        ( #double       '=' )
      )
! !

!MenuEditor::Item class methodsFor:'documentation'!

documentation
"
    implements the contents assigned to a TreeItem. An instance
    is associated with one item and keeps all its information

    [see also:]
        TreeItem
        MenuEditor

    [author:]
        Claus Atzkern
"


! !

!MenuEditor::Item methodsFor:'accessing'!

activeHelpKey
    ^ activeHelpKey
!

activeHelpKey:aKey
    activeHelpKey := aKey
!

label
    "return the value of the instance variable 'label' (automatically generated)"

    ^ label!

label:something
    "set the value of the instance variable 'label' (automatically generated)"

    label := something ? '-'.
!

separatorType
    "returns separator type assigned to item or nil
    "
    |c|

    label size > 1 ifFalse:[
        label size == 0 ifTrue:[
            ^ #blank
        ].
        c := label first.
        c == $- ifTrue:[^ #single].
        c == $= ifTrue:[^ #double].
    ].    
  ^ nil

!

submenuChannel
    "return the value of the instance variable 'submenuChannel' (automatically generated)"

    ^ submenuChannel
!

submenuChannel:aChannel
    "return the value of the instance variable 'submenuChannel' (automatically generated)"

    submenuChannel := aChannel
! !

!MenuEditor::Item methodsFor:'conversion'!

asMenuItem
    "converts self to a menu item
    "
    |item rcv|

    item := MenuItem labeled:label.

    self isSeparator ifFalse:[    
        item activeHelpKey:activeHelpKey.
        item enabled:enabled.
        item accessCharacterPosition:accessCharaterPos.
        item argument:argument.
        item submenuChannel:submenuChannel.
        item nameKey:nameKey.
        item shortcutKeyCharacter:shortcutKey.
        item value:value.
        item indication:indication.
        item translateLabel: translateLabel.
        item isButton: isButton.

        icon notNil ifTrue:[
            rcv := ResourceRetriever new.
            rcv className:retriever.
            rcv selector:icon.
            iconAndLabel == true ifTrue:[
                rcv labelText:label
            ].
            item labelImage:rcv
        ]
    ].
  ^ item.
!

buildFromAspects:aspects
    |name|

    self isSeparator ifFalse:[
        name  := label.
        label := (aspects at:#label) value.

        (label isNil or:[self isSeparator]) ifTrue:[
            (aspects at:#label) value:(label := name)
        ].

        enabled             := (aspects at:#enabled) value.
        value               := (aspects at:#value) value.
        nameKey             := (aspects at:#nameKey) value.
        indication          := (aspects at:#indication) value.
        shortcutKey         := (aspects at:#shortcutKey) value.
        accessCharaterPos   := (aspects at:#accessCharaterPos) value.
        argument            := (aspects at:#argument) value.
        translateLabel      := (aspects at:#translateLabel) value.
        isButton            := (aspects at:#isButton) value.

        argument isString ifTrue:[
            argument size > 1 ifTrue:[
                (argument at:1) == $# ifTrue:[
                    argument := (argument copyFrom:2) asSymbol
                ]
            ]
        ].
        submenuChannel      := (aspects at:#submenuChannel)    value.
        retriever           := (aspects at:#retriever) value.
        icon                := (aspects at:#icon) value.
        iconAndLabel        := (aspects at:#iconAndLabel) value.
    ] ifTrue:[
        name  := (aspects at:#seperatorSelection) selectionIndex.
        label := (self class separatorSlices at:name) last.
    ]
!

buildFromMenuItem:anItem
    |rtv|

    self label:(anItem label).
    activeHelpKey := anItem activeHelpKey.

    (enabled := anItem enabled) isSymbol ifFalse:[
        enabled := nil
    ].

    (value := anItem value) isSymbol ifFalse:[
        value := nil.
    ].

    (indication := anItem indication) isSymbol ifFalse:[
        indication := nil
    ].

    nameKey           := anItem nameKey.
    shortcutKey       := anItem shortcutKeyCharacter.
    accessCharaterPos := anItem accessCharacterPosition.
    argument          := anItem argument.
    submenuChannel    := anItem submenuChannel.
    translateLabel    := anItem translateLabel.
    isButton          := anItem isButton.

    (    ((rtv := anItem adornment) notNil)
     and:[(rtv := rtv labelImage) isKindOf:ResourceRetriever]
    ) ifTrue:[
        retriever := rtv className.
        icon      := rtv selector.

        (iconAndLabel := rtv labelText notNil) ifTrue:[
            label := rtv labelText.
        ]
    ]
!

toAspects:aspects
    |type|

    (type := self separatorType) notNil ifTrue:[
        type := self class separatorSlices findFirst:[:el| el first == type ].
        (aspects at:#seperatorSelection) selectionIndex:type.
    ] ifFalse:[
        (aspects at:#label)                 value:label.
        (aspects at:#enabled)               value:enabled.
        (aspects at:#value)                 value:value.
        (aspects at:#nameKey)               value:nameKey.
        (aspects at:#indication)            value:indication.
        (aspects at:#shortcutKey)           value:shortcutKey.
        (aspects at:#accessCharaterPos)     value:accessCharaterPos.
        (aspects at:#translateLabel)        value:translateLabel.
        (aspects at:#isButton)              value:isButton.

        argument isSymbol ifTrue:[
            (aspects at:#argument) value:'#', argument
        ] ifFalse:[
            (aspects at:#argument) value:argument.
        ].
        (aspects at:#submenuChannel)        value:submenuChannel.
        (aspects at:#retriever)             value:retriever.
        (aspects at:#icon)                  value:icon.
        (aspects at:#iconAndLabel)          value:iconAndLabel.
    ]
! !

!MenuEditor::Item methodsFor:'queries'!

isSeparator
    "returns true if item is a seperator
    "
    ^ self separatorType notNil
! !

!MenuEditor::Painter class methodsFor:'defaults'!

defaultMenuMessage   
    "This message is the default yo be sent to the menuHolder to get a menu
    "
    ^ #menu


! !

!MenuEditor::Painter class methodsFor:'documentation'!

documentation
"
    menu selection list

    [see also:]
        SelectionInTreeView
        SelectionInTree
        TreeItem

    [author:]
        Claus Atzkern
"


! !

!MenuEditor::Painter class methodsFor:'initialization'!

initialize

    super initialize.

    Images := nil
! !

!MenuEditor::Painter class methodsFor:'resources'!

closedSubmenuImage
    "ImageEditor openOnClass:self andSelector:#closedSubmenuImage"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 21 85 85 85 85 128 26 170 170 170 170 192 26 170 170 170 170 192 31 255 255 255 255 199 16 0 0 0 0 192 21 85 85 85 85 204 26 170 170 170 170 192 26 170 170 170 170 192 31 255 255 255 255 200 16 0 0 0 0 192 21 85 85 85 85 192 26 170 170 170 170 192 26 170 170 170 170 207 31 255 255 255 255 192 16 0 0 0 0 192 21 85 85 85 85 192 26 170 170 170 170 192 26 170 170 170 170 192 47 255 255 255 255 192 0 0 0 0 0 0 0 0 0 0 0 0]) ; colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:66.9978)); at:4 put:((Color grey:49.9962)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; yourself); yourself!

images
    "returns an IdentityDictionary containing a list of images and keys used
    "
    ^ Images ?
        (Images := IdentityDictionary new
            at: #menuItemImage      put: self menuItemImage;
            at: #openedSubmenuImage put: self openedSubmenuImage;
            at: #closedSubmenuImage put: self closedSubmenuImage;
            at: #linkSubmenuImage   put: self linkSubmenuImage;
            at: #menuSeparatorImage put: self menuSeparatorImage;
            yourself)



!

linkSubmenuImage
    "ImageEditor openOnClass:self andSelector:#linkSubmenuImage"

    <resource: #image>
    ^(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 0 0 0 0 0 1 17 17 17 17 17 17 17 17 17 32 1 34 34 34 34 34 34 34 34 34 240 1 34 34 34 34 34 34 34 34 34 240 1 255 255 255 255 255 255 255 255 255 240 1 0 0 0 0 0 0 0 0 0 240 1 3 51 51 1 17 17 17 17 17 240 1 3 51 51 48 34 34 34 34 34 240 1 3 51 51 51 2 34 34 34 34 240 1 3 51 51 51 48 255 255 255 255 240 1 0 0 0 51 51 0 0 0 0 240 1 17 17 17 3 51 48 16 48 17 240 1 34 34 34 32 51 51 0 51 2 240 1 34 34 34 34 3 51 51 51 48 240 1 255 255 255 255 240 51 51 51 51 0 1 0 0 0 0 0 3 51 51 48 240 1 17 17 17 17 17 16 0 51 1 240 1 34 34 34 34 34 34 32 48 34 240 1 34 34 34 34 34 34 32 2 34 240 2 255 255 255 255 255 255 255 255 255 240 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; colorMap:((OrderedCollection new add:(Color black); add:(Color white); add:(Color grey:66.9978); add:(Color red:100.0 green:0.0 blue:0.0); add:(Color red:0.0 green:100.0 blue:0.0); add:(Color red:0.0 green:0.0 blue:100.0); add:(Color red:0.0 green:100.0 blue:100.0); add:(Color red:100.0 green:100.0 blue:0.0); add:(Color red:100.0 green:0.0 blue:100.0); add:(Color red:49.9962 green:0.0 blue:0.0); add:(Color red:0.0 green:49.9962 blue:0.0); add:(Color red:0.0 green:0.0 blue:49.9962); add:(Color red:0.0 green:49.9962 blue:49.9962); add:(Color red:49.9962 green:49.9962 blue:0.0); add:(Color red:49.9962 green:0.0 blue:49.9962); add:(Color grey:49.9962); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; yourself); yourself!

menuItemImage
    "ImageEditor openOnClass:self andSelector:#menuItemImage"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[85 85 85 85 85 81 85 85 85 85 85 80 85 85 85 85 85 95 85 85 85 85 85 80 85 85 85 85 85 80 0 0 0 0 0 0 21 85 85 85 85 129 26 170 170 170 170 200 27 175 235 235 174 192 27 171 171 171 254 192 27 171 171 235 174 192 27 171 171 171 174 192 27 171 171 235 174 192 26 170 170 170 170 196 47 255 255 255 255 193 0 0 0 0 0 0 85 85 85 85 85 80 85 85 85 85 85 88 85 85 85 85 85 80 85 85 85 85 85 80 85 85 85 85 85 80 85 85 85 85 85 88]) ; colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:66.9978)); at:4 put:((Color grey:49.9977)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; yourself); yourself!

menuSeparatorImage
    "ImageEditor openOnClass:self andSelector:#menuSeparatorImage"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[85 85 85 85 85 82 85 85 85 85 85 80 85 85 85 85 85 80 85 85 85 85 85 80 85 85 85 85 85 80 0 0 0 0 0 0 21 85 85 85 85 128 26 170 170 170 170 196 26 170 170 170 170 195 27 255 255 255 250 192 27 0 0 0 6 192 26 85 85 85 86 200 26 170 170 170 170 192 26 170 170 170 170 192 47 255 255 255 255 206 0 0 0 0 0 8 85 85 85 85 85 80 85 85 85 85 85 80 85 85 85 85 85 87 85 85 85 85 85 88 85 85 85 85 85 80 85 85 85 85 85 80]) ; colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:66.9978)); at:4 put:((Color grey:49.9977)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; yourself); yourself!

openedSubmenuImage
    "ImageEditor openOnClass:self andSelector:#openedSubmenuImage"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 13 21 85 85 85 85 128 26 170 170 170 170 192 26 170 170 170 170 192 31 255 255 255 255 192 16 0 0 0 0 192 21 85 85 85 85 192 26 170 170 170 170 200 26 170 170 170 170 192 31 255 255 255 255 192 16 0 0 0 0 192 21 85 85 85 85 200 26 170 170 170 170 192 26 170 170 170 170 200 31 255 255 255 255 192 16 0 0 0 0 192 21 85 85 85 85 192 26 170 170 170 170 192 26 170 170 170 170 192 47 255 255 255 255 192 0 0 0 0 0 0 0 0 0 0 0 0]) ; colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:66.9978)); at:4 put:((Color grey:49.9962)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 255 255 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]) ; yourself); yourself! !

!MenuEditor::Painter methodsFor:'accessing'!

selectorName
    ^ (listOfNodes first contents label) asSymbol
! !

!MenuEditor::Painter methodsFor:'building'!

buildFrom:aClass andSelector:aSelector
    |spec cls menu node|

    (aClass notNil and:[aSelector notNil]) ifTrue:[
        cls := self application resolveName:aClass.

        (cls respondsTo:aSelector) ifTrue:[
            spec := cls perform:aSelector
        ]
    ].

    spec isNil ifFalse:[
        (spec isMemberOf:Menu) ifFalse:[
            menu := Menu new fromLiteralArrayEncoding:spec.
        ] ifTrue:[
            menu := spec.
        ].
        node := self nodeLabel:(aSelector asString).
        self subMenu:menu parent:node.
    ] ifTrue:[
        aSelector notNil ifTrue:[cls := aSelector asString]
                        ifFalse:[cls := 'menu'].

        node := self nodeLabel:cls.
    ].

    node hasChildren ifFalse:[
        node add:(self nodeLabel:'undefined')
    ].
    node expand.
    model root:node.

!

buildFromMenu:aMenu

    |node|

    node := self nodeLabel:'menu'.
    self subMenu:aMenu parent:node.

    node hasChildren ifFalse:[
        node add:(self nodeLabel:'undefined')
    ].
    node expand.
    model root:node.

!

menuItem:anItem

    |node|

    node := self nodeLabel:(anItem label).
    node contents buildFromMenuItem:anItem.
    node name:(node contents label).
    self subMenu:(anItem submenu) parent:node.
  ^ node.


!

subMenu:aMenu parent:aParent
    |idx grp|

    aMenu isNil ifFalse:[
        grp := aMenu groupSizes.
        aMenu itemsDo:[:i| aParent add:(self menuItem:i)].

        grp notNil ifTrue:[
            idx := 0.

            grp do:[:i|
                idx := idx + i + 1.
                aParent add:(self nodeLabel:nil) beforeIndex:idx.
            ]
        ]
    ]
! !

!MenuEditor::Painter methodsFor:'conversion'!

asMenu
    |menu root|

    root := self root.

    root hasChildren ifTrue:[
        menu := Menu new.
        root children do:[:aChild| menu addItem:(self asMenuItem:aChild)].
    ].
  ^ menu
!

asMenuItem:aNode

    |menu item|

    item := aNode contents asMenuItem.

    aNode hasChildren ifTrue:[
        menu := Menu new.
        aNode children do:[:aChild| menu addItem:(self asMenuItem:aChild)].
        item submenu:menu
    ].
  ^ item

! !

!MenuEditor::Painter methodsFor:'drawing basics'!

drawLabelIndex:anIndex atX:x y:yCenter
    "draw text label assigned to a node at x y( center)
    "
    |y x2 type item|

    item := (listOfNodes at:anIndex) contents.
    type := item separatorType.

    type isNil ifTrue:[
        super drawLabelIndex:anIndex atX:x y:yCenter
    ] ifFalse:[
        type == #blank ifFalse:[
            x2 := x + 80.

            self displayLineFromX:x y:yCenter toX:x2 y:yCenter.

            type == #double ifTrue:[
                y := yCenter + 2.
                self displayLineFromX:x y:y toX:x2 y:y.
            ]    
        ]
    ]

    "Modified: 28.7.1997 / 13:13:41 / cg"
!

figureFor:aNode
    "access figure for a node
    "
    |item|

    aNode hasChildren ifFalse:[
        item := aNode contents.

        item submenuChannel notNil ifTrue:[
            ^ images at:#linkSubmenuImage
        ].

        item isSeparator ifTrue:[
            ^ images at:#menuSeparatorImage
        ].
        ^ images at:#menuItemImage
    ].

    aNode isExpandable ifTrue:[ 
        ^ images at:#closedSubmenuImage
    ].
    ^ images at:#openedSubmenuImage
! !

!MenuEditor::Painter methodsFor:'event handling'!

keyPress:key x:x y:y
    "any key pressed
    "
    <resource: #keyboard ( #Delete #BackSpace #Cut #Copy #Paste ) >

    (key == #Cut or:[key == #Delete or:[key == #BackSpace]]) ifTrue: [
        ^ self doCut
    ].

    key == #Copy  ifTrue:[ ^ self doCopy].
    key == #Paste ifTrue:[ ^ self doPaste].

    super keyPress:key x:x y:y.

! !

!MenuEditor::Painter methodsFor:'initialization'!

fetchImageResources
    "initialize heavily used device resources - to avoid rendering
     images again and again later; returns maximum extent of the images used.
    "
    |y x t|

    t := super fetchImageResources.
    y := t y.
    x := t x.

    images do:[:anIcon|
        (t := anIcon heightOn:self) > y ifTrue:[y := t].
        (t := anIcon widthOn:self)  > x ifTrue:[x := t].
    ].
  ^ x @ y

!

initialize
    super initialize.

    images := IdentityDictionary new.

    self class images associationsDo:[:el|
        images at:(el key) put:(el value onDevice:device)
    ].
    self multipleSelectOk:true.
! !

!MenuEditor::Painter methodsFor:'menus'!

doCopy

    self hasSelection ifTrue:[
        CopyBuffer := OrderedCollection new.
        self selectionDo:[:i| CopyBuffer add:((listOfNodes at:i) copy)]
    ]
!

doCreateItem

    self addElement:(self nodeLabel:'undefined')

!

doCreateLink
    |node item|

    node := self nodeLabel:'undefined'.
    item := node contents.
    item submenuChannel:#menuDefaultLink.
    self addElement:node.
    self setModified.


!

doCreateMenu

    |node|
    node := self nodeLabel:'undefined'.
    node add:(self nodeLabel:'undefined').
    self addElement:node
!

doCreateSep

    self addElement:(self nodeLabel:nil)
!

doCut

    self doCopy.
    self selectedNodesRemove.
    self setModified.


!

doPaste

    (CopyBuffer notNil and:[self selectedNode notNil]) ifTrue:[
        self addElement:(CopyBuffer collect:[:el| el copy])
    ].
! !

!MenuEditor::Painter methodsFor:'private'!

addElement:something
    "add something after selection
    "
    self selectedNodeAdd:something.
    self setModified.
!

nodeLabel:aLabel
   ^ TreeItem name:aLabel contents:(MenuEditor::Item new label:aLabel).
!

setModified 

    self topView application isModified: true
! !

!MenuEditor::Painter methodsFor:'selection'!

selectedNodeChanged
    |node name index|

    (index := self selectedIndex) ~~ 0 ifTrue:[
        node := listOfNodes at:index.
        name := node contents label.
        list at:index put:name.
        node name:name.
        self redrawLine:index.
    ]
! !

!MenuEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !
MenuEditor initialize!