MenuEditor.st
author ca
Fri, 02 Jan 1998 16:57:44 +0100
changeset 391 5c7fa5484d14
parent 382 2a46018227a1
child 398 155310ec83aa
permissions -rw-r--r--
VW compatible

"
 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.
"



ApplicationModel 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'
	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
"

! !

!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 valueHolder 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 the bitmap to be displayed.'

#iconAndLabel
'boolean flag to specify that both the bitmap and textual label shall be shown.'

#indication
'This indication field specifies the name of the aspect (-method or binding) in your application, a valueHolder 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/icon'' is set, and returns a bitmap image, the bitmap is used as the displayed label. Dependent on the state of the ''Icon & Label'' flag, both the bitmap and the label are shown.'

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

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

#retriever
'the name of the class, which implements the bitmap  selector. This selector is specified by ''icon''. If no class is given, the current application should implement the specified bitmap 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 imageItem

!

iconCreateLink
    ^ Painter imageMenuLink

!

iconCreateMenu
    ^ Painter imageMenu

    "Modified: 28.7.1997 / 10:02:21 / cg"
!

iconCreateSep
    ^ Painter imageSeparator

!

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'!

classAndMethodSpec
    "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:#classAndMethodSpec
     MenuEditor new openInterface:#classAndMethodSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'ClassAndMethodSpec'
              #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
              #'label:' 'Painter'
              #'bounds:' #(#Rectangle 0 0 391 170)
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'classLabel'
                    #'layout:' #(#AlignmentOrigin 45 0.11 51 0 1 0.5)
                    #'label:' 'class:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#LabelSpec
                    #'name:' 'selectorLabel'
                    #'layout:' #(#AlignmentOrigin 45 0.11 74 0 1 0.5)
                    #'label:' 'selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'methodNameField'
                    #'layout:' #(#LayoutFrame 47 0.11 64 0 0 1.0 86 0)
                    #'tabable:' true
                    #'model:' #methodNameChannel
                )
                 #(#LabelSpec
                    #'name:' 'boxLabel'
                    #'layout:' #(#Point 5 10)
                    #'label:' 'class & selector for code:'
                    #'adjust:' #left
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'classNameField'
                    #'layout:' #(#LayoutFrame 47 0.11 39 0 0 1.0 61 0)
                    #'tabable:' true
                    #'model:' #classNameChannel
                )
                 #(#HorizontalPanelViewSpec
                    #'name:' 'commitPanel'
                    #'layout:' #(#LayoutFrame 0 0.0 -24 1.0 0 1.0 0 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ActionButtonSpec
                              #'name:' 'button1'
                              #'label:' 'cancel'
                              #'tabable:' true
                              #'model:' #cancel
                              #'extent:' #(#Point 191 24)
                          )
                           #(#ActionButtonSpec
                              #'name:' 'button2'
                              #'label:' 'ok'
                              #'tabable:' true
                              #'isDefault:' true
                              #'model:' #accept
                              #'extent:' #(#Point 191 24)
                          )
                        )
                    )
                    #'horizontalLayout:' #fitSpace
                    #'verticalLayout:' #fit
                    #'horizontalSpace:' 3
                    #'verticalSpace:' 3
                )
              )
          )
      )

    "Modified: 28.7.1997 / 15:40:15 / cg"
!

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:' 'ClassDefineSpec'
              #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
              #'label:' 'Painter'
              #'bounds:' #(#Rectangle 0 0 383 128)
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'classLabel'
                    #'layout:' #(#AlignmentOrigin 45 0.11 51 0 1 0.5)
                    #'label:' 'class:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#LabelSpec
                    #'name:' 'boxLabel'
                    #'layout:' #(#Point 5 10)
                    #'label:' 'class for code:'
                    #'adjust:' #left
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'classNameField'
                    #'layout:' #(#LayoutFrame 47 0.11 39 0 0 1.0 61 0)
                    #'tabable:' true
                    #'model:' #classNameChannel
                )
                 #(#HorizontalPanelViewSpec
                    #'name:' 'commitPanel'
                    #'layout:' #(#LayoutFrame 0 0.0 -24 1.0 0 1.0 0 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ActionButtonSpec
                              #'name:' 'button1'
                              #'label:' 'cancel'
                              #'tabable:' true
                              #'model:' #cancel
                              #'extent:' #(#Point 187 24)
                          )
                           #(#ActionButtonSpec
                              #'name:' 'button2'
                              #'label:' 'ok'
                              #'tabable:' true
                              #'isDefault:' true
                              #'model:' #accept
                              #'extent:' #(#Point 187 24)
                          )
                        )
                    )
                    #'horizontalLayout:' #fitSpace
                    #'verticalLayout:' #fit
                    #'horizontalSpace:' 3
                    #'verticalSpace:' 3
                )
              )
          )
      )

    "Modified: 28.7.1997 / 15:40:39 / cg"
!

menuButtons
    "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:#menuButtons
     (Menu new fromLiteralArrayEncoding:(MenuEditor menuButtons)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'createMenu'
                #'value:' #doCreateMenu
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' 
                 #(#ResourceRetriever
                    #MenuEditor #iconCreateMenu
                )
            )
             #(#MenuItem
                #'label:' 'createLink'
                #'value:' #doCreateLink
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' 
                 #(#ResourceRetriever
                    #MenuEditor #iconCreateLink
                )
            )
             #(#MenuItem
                #'label:' 'createItem'
                #'value:' #doCreateItem
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' 
                 #(#ResourceRetriever
                    #MenuEditor #iconCreateItem
                )
            )
             #(#MenuItem
                #'label:' 'createSeparator'
                #'value:' #doCreateSep
                #'enabled:' #hasAnySingleSelection
                #'labelImage:' 
                 #(#ResourceRetriever
                    #MenuEditor #iconCreateSep
                )
            )
             #(#MenuItem
                #'label:' ''
            )
             #(#MenuItem
                #'label:' 'stepUp'
                #'value:' #doStepUp
                #'enabled:' #enabledStepOver
                #'labelImage:' 
                 #(#ResourceRetriever
                    #UIPainter #iconStepUp
                )
            )
             #(#MenuItem
                #'label:' 'stepDown'
                #'value:' #doStepDown
                #'enabled:' #enabledStepOver
                #'labelImage:' 
                 #(#ResourceRetriever
                    #UIPainter #iconStepDown
                )
            )
             #(#MenuItem
                #'label:' 'stepIn'
                #'value:' #doStepIn
                #'enabled:' #enabledStepIn
                #'labelImage:' 
                 #(#ResourceRetriever
                    #UIPainter #iconStepIn
                )
            )
             #(#MenuItem
                #'label:' 'stepOut'
                #'value:' #doStepOut
                #'enabled:' #enabledStepOut
                #'labelImage:' 
                 #(#ResourceRetriever
                    #UIPainter #iconStepOut
                )
            )
          ) 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:' 'copy'
                #'value:' #doCopy
                #'enabled:' #hasValidSelection
                #'shortcutKeyCharacter:' #Copy
            )
             #(#MenuItem
                #'label:' 'cut'
                #'value:' #doCut
                #'enabled:' #hasValidSelection
                #'shortcutKeyCharacter:' #Cut
            )
             #(#MenuItem
                #'label:' 'paste'
                #'value:' #doPaste
                #'enabled:' #hasAnySingleSelection
                #'shortcutKeyCharacter:' #Paste
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'create'
                #'enabled:' #hasAnySingleSelection
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'submenu static'
                          #'value:' #doCreateMenu
                          #'labelImage:' 
                           #(#ResourceRetriever
                              #MenuEditor #iconCreateMenu
                              'submenu static'
                          )
                      )
                       #(#MenuItem
                          #'label:' 'submenu dynamic'
                          #'value:' #doCreateLink
                          #'labelImage:' 
                           #(#ResourceRetriever
                              #MenuEditor #iconCreateLink
                              'submenu dynamic'
                          )
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'item'
                          #'value:' #doCreateItem
                          #'labelImage:' 
                           #(#ResourceRetriever
                              #MenuEditor #iconCreateItem
                              'item'
                          )
                      )
                       #(#MenuItem
                          #'label:' 'separator'
                          #'value:' #doCreateSep
                          #'labelImage:' 
                           #(#ResourceRetriever
                              #MenuEditor #iconCreateSep
                              'separator'
                          )
                      )
                    ) nil
                    nil
                )
            )
          ) nil
          nil
      )
!

menuPullDown
    "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:#menuPullDown
     (Menu new fromLiteralArrayEncoding:(MenuEditor menuPullDown)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'file'
                #'value:' #file
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'new'
                          #'value:' #doNew
                      )
                       #(#MenuItem
                          #'label:' 'from class ...'
                          #'value:' #doFromClass
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' 'pick a menu'
                          #'value:' #doPickAMenu
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' '='
                      )
                       #(#MenuItem
                          #'label:' 'quit'
                          #'value:' #closeRequest
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'edit'
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'cut'
                          #'value:' #doCut
                      )
                       #(#MenuItem
                          #'label:' '='
                      )
                       #(#MenuItem
                          #'label:' 'create submenu static'
                          #'value:' #doCreateMenu
                      )
                       #(#MenuItem
                          #'label:' 'create summenu dynamic'
                          #'value:' #doCreateLink
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'create item'
                          #'value:' #doCreateItem
                      )
                       #(#MenuItem
                          #'label:' 'create separator'
                          #'value:' #doCreateSep
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'code'
                #'value:' #code
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'class'
                          #'value:' #doDefineClass
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'install menu spec.'
                          #'value:' #doInstallSpec
                      )
                       #(#MenuItem
                          #'label:' 'install help spec.'
                          #'value:' #doInstallHelp
                          #'enabled:' #isStandAlone
                      )
                       #(#MenuItem
                          #'label:' '='
                      )
                       #(#MenuItem
                          #'label:' 'browse application'
                          #'value:' #doBrowseAppClass
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'test'
                #'submenuChannel:' #submenuTest
            )
          ) nil
          nil
      )

    "Modified: 28.7.1997 / 18:12:10 / cg"
!

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:' 'MenuEditor'
              #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
              #'label:' 'Menu Builder'
              #'bounds:' #(#Rectangle 0 0 580 384)
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#ArbitraryComponentSpec
                    #'name:' 'painterView'
                    #'layout:' #(#LayoutFrame 0 0.0 57 0 0 0.5 0 1.0)
                    #'menu:' #menuPainter
                    #'hasHorizontalScrollBar:' true
                    #'hasVerticalScrollBar:' true
                    #'component:' #painter
                    #'hasBorder:' false
                )
                 #(#NoteBookViewSpec
                    #'name:' 'specificationView'
                    #'layout:' #(#LayoutFrame 0 0.5 0 0.0 0 1.0 -25 1.0)
                    #'tabable:' true
                    #'menu:' #tabList
                    #'model:' #tabModel
                    #'tabWidget:' #Window
                    #'useIndex:' true
                    #'canvas:' #noteBookView
                )
                 #(#HorizontalPanelViewSpec
                    #'name:' 'confirmationPanel'
                    #'layout:' #(#LayoutFrame 0 0.5 -24 1.0 0 1.0 0 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ActionButtonSpec
                              #'name:' 'cancelButton'
                              #'label:' 'cancel'
                              #'model:' #cancel
                              #'enableChannel:' #modifiedChannel
                              #'extent:' #(#Point 140 24)
                          )
                           #(#ActionButtonSpec
                              #'name:' 'acceptButton'
                              #'label:' 'ok'
                              #'model:' #accept
                              #'enableChannel:' #modifiedChannel
                              #'extent:' #(#Point 141 24)
                          )
                        )
                    )
                    #'horizontalLayout:' #fitSpace
                    #'verticalLayout:' #fit
                    #'horizontalSpace:' 3
                    #'verticalSpace:' 3
                )
                 #(#MenuPanelSpec
                    #'name:' 'pullDownMenu'
                    #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 0.5 24 0)
                    #'tabable:' true
                    #'menu:' #menuPullDown
                )
                 #(#MenuPanelSpec
                    #'name:' 'menuPanel1'
                    #'layout:' #(#LayoutFrame 0 0 28 0 0 0.5 53 0)
                    #'menu:' #menuButtons
                    #'showSeparatingLines:' true
                )
              )
          )
      )
! !

!MenuEditor class methodsFor:'slices'!

slicesItem
    ^#(
            (Basics     basicsItemSpec)
            (Details    detailsEditSpec)
            (Misc       miscEditSpec)
      )

!

slicesLink
    ^#(
            (Basics     basicsLinkSpec)
            (Details    detailsEditSpec)
            (Misc       miscEditSpec)
      )

!

slicesMenu
    ^#(
            (Basics     basicsMenuSpec)
            (Details    detailsEditSpec)
            (Misc       miscEditSpec)
      )

!

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 377 0 282 0 643 0 600 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 377 282 644 601)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 26 0 1 0.5)
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 91 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 53 0 1 0.5)
                    #'label:' 'Label'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 91 0 42 0 0 1.0 64 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #label
                )
                 #(#LabelSpec
                    #'name:' 'valueLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 90 0 1 0.5)
                    #'label:' 'Value:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'valueField'
                    #'layout:' #(#LayoutFrame 91 0 79 0 0 1.0 101 0)
                    #'activeHelpKey:' #value
                    #'tabable:' true
                    #'model:' #value
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'argumentLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 116 0 1 0.5)
                    #'label:' 'Argument:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'argumentField'
                    #'layout:' #(#LayoutFrame 91 0 105 0 0 1.0 127 0)
                    #'activeHelpKey:' #argument
                    #'tabable:' true
                    #'model:' #argument
                    #'type:' #string
                )
                 #(#LabelSpec
                    #'name:' 'indicationLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 156 0 1 0.5)
                    #'label:' 'Indication:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'indicationField'
                    #'layout:' #(#LayoutFrame 91 0 145 0 0 1.0 167 0)
                    #'activeHelpKey:' #indication
                    #'tabable:' true
                    #'model:' #indication
                    #'type:' #symbolOrNil
                )
              )
          )
      )
!

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 219 0 193 0 485 0 511 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 219 193 486 512)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 26 0 1 0.5)
                    #'activeHelpKey:' #nameKey
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 91 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 53 0 1 0.5)
                    #'label:' 'Label'
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 91 0 42 0 0 1.0 64 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #label
                )
                 #(#InputFieldSpec
                    #'name:' 'menuField'
                    #'layout:' #(#LayoutFrame 91 0 69 0 0 1.0 91 0)
                    #'activeHelpKey:' #submenuChannel
                    #'tabable:' true
                    #'model:' #submenuChannel
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'menuLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 80 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 219 0 193 0 485 0 511 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 219 193 486 512)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'nameKeyLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 26 0 1 0.5)
                    #'label:' 'NameKey:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'nameKeyField'
                    #'layout:' #(#LayoutFrame 91 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #nameKey
                    #'tabable:' true
                    #'model:' #nameKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'labelLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 53 0 1 0.5)
                    #'label:' 'Label'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'labelField'
                    #'layout:' #(#LayoutFrame 91 0 42 0 0 1.0 64 0)
                    #'activeHelpKey:' #label
                    #'tabable:' true
                    #'model:' #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 219 0 193 0 485 0 511 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 219 193 486 512)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'selectorLabel'
                    #'layout:' #(#AlignmentOrigin 78 0 53 0 1 0.5)
                    #'label:' 'Selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'selectorField'
                    #'layout:' #(#LayoutFrame 82 0 42 0 0 1.0 64 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 219 0 193 0 485 0 511 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 219 193 486 512)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'separatorLabel'
                    #'layout:' #(#AlignmentOrigin 127 0 22 0 1 0.5)
                    #'label:' 'Separator Type:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#ComboListSpec
                    #'name:' 'seperatorList'
                    #'layout:' #(#LayoutFrame 132 0 11 0 0 1.0 33 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 219 0 193 0 477 0 480 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 219 193 478 481)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'shortcutKeyLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 33 0 1 0.5)
                    #'label:' 'Accelerator:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'shortcutKeyField'
                    #'layout:' #(#LayoutFrame 91 0 22 0 0 1.0 44 0)
                    #'activeHelpKey:' #shortcutKey
                    #'tabable:' true
                    #'model:' #shortcutKey
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'enabledLabel'
                    #'layout:' #(#AlignmentOrigin 87 0 59 0 1 0.5)
                    #'label:' 'Enabled:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'enabledField'
                    #'layout:' #(#LayoutFrame 91 0 48 0 0 1.0 70 0)
                    #'activeHelpKey:' #enbled
                    #'tabable:' true
                    #'model:' #enabled
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'accessCharLabel'
                    #'layout:' #(#AlignmentOrigin 211 0 127 0 1 0.5)
                    #'label:' 'Access Character Position:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'accessCharField'
                    #'layout:' #(#LayoutFrame 215 0 116 0 0 1.0 138 0)
                    #'activeHelpKey:' #accessCharaterPos
                    #'tabable:' true
                    #'model:' #accessCharaterPos
                    #'type:' #numberOrNil
                )
              )
          )
      )
!

miscEditSpec
    "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:#miscEditSpec
     MenuEditor new openInterface:#miscEditSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'unnamed canvas'
              #'layout:' #(#LayoutFrame 441 0 301 0 685 0 442 0)
              #'label:' 'unnamed canvas'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1280 1024)
              #'bounds:' #(#Rectangle 441 301 686 443)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'retrieverLabel'
                    #'layout:' #(#AlignmentOrigin 77 0 26 0 1 0.5)
                    #'label:' 'Retriever:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'retrieverField'
                    #'layout:' #(#LayoutFrame 81 0 15 0 0 1.0 37 0)
                    #'activeHelpKey:' #retriever
                    #'tabable:' true
                    #'model:' #retriever
                    #'type:' #symbolOrNil
                )
                 #(#LabelSpec
                    #'name:' 'iconLabel'
                    #'layout:' #(#AlignmentOrigin 77 0 50 0 1 0.5)
                    #'label:' 'Icon:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'iconField'
                    #'layout:' #(#LayoutFrame 81 0 39 0 0 1.0 61 0)
                    #'activeHelpKey:' #icon
                    #'tabable:' true
                    #'model:' #icon
                    #'type:' #symbolOrNil
                )
                 #(#CheckBoxSpec
                    #'name:' 'iconAndLabel'
                    #'layout:' #(#LayoutOrigin 15 0 103 0)
                    #'activeHelpKey:' #iconAndLabel
                    #'tabable:' true
                    #'model:' #iconAndLabel
                    #'label:' 'Icon & Label'
                )
                 #(#ActionButtonSpec
                    #'name:' 'imageEditorButton'
                    #'layout:' #(#LayoutFrame 81 0 65 0 0 1 87 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'!

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'!

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


! !

!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.
!

closeRequest
    "close request
    "
    isModified ifTrue:[
        (self confirm:'quit without without saving your modifications ?') ifFalse:[
            ^ self
        ]
    ].
    super closeRequest.





!

initialize
    "initialize channels
    "
    |holder|

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

    #(
        label
        accessCharaterPos
        argument
        submenuChannel
        enabled
        value
        nameKey
        indication
        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.


!

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

    ImageEditor open loadFromMessage: ((aspects at:#retriever) value ? specClass ? '') , ' ', ((aspects at:#icon) value ? '')
!

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
    ].
!

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
!

doStepIn
    self painter selectedNodeBecomeChildOfNext

!

doStepOut
    self painter selectedNodeBecomeSisterOfParent
!

doStepUp
    "move selected child after next child
    "
    self painter selectedNodeChangeSequenceOrder:-1
! !

!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.

        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.

        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.

    (    ((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.

        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:'constants'!

imageItem
    ^ self images at:#item
!

imageMenu
    ^ self images at:#menuOpen
!

imageMenuLink
    ^ self images at:#menuLink

!

imageSeparator
    ^ self images at:#separator

!

images
    "returns an IdentityDictionary containing a list of images and keys used
    "
    <resource: #fileImage>

    |image|

    Images notNil ifTrue:[
        ^ Images
    ].

    Images := IdentityDictionary new.

    #(
        (#item            'ui_menuitem.xpm')
        (#menuClosed      'ui_submenu.xpm')
        (#menuOpen        'ui_submenu_open.xpm')
        (#menuLink        'ui_submenulink.xpm')
        (#separator       'ui_menusep.xpm')

     ) do:[:el |
        image := Image fromFile:( el last ).
        Images at:(el first) put:image.
    ].

  ^ Images



! !

!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 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:#menuLink
        ].

        item isSeparator ifTrue:[
            ^ images at:#separator
        ].
        ^ images at:#item
    ].

    aNode isExpandable ifTrue:[ 
        ^ images at:#menuClosed
    ].
    ^ images at:#menuOpen
! !

!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



!

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.
!

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
!

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

!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$'
! !