MenuEditor.st
author ca
Wed, 02 Oct 2002 14:44:49 +0200
changeset 1614 46cc531eecc6
parent 1610 cb3e093aa6d5
child 1617 dd4bd2e32826
permissions -rw-r--r--
add code generation

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

"{ Package: 'stx:libtool2' }"

ResourceSpecEditor subclass:#MenuEditor
	instanceVariableNames:'selectionHolder tabHolder listOfItems listOfTabs
		selectedSuperItems notifyDisabledCounter wizards listOfItemsView
		redefineAspectMethods'
	classVariableNames:'ImageRetrieverClasses'
	poolDictionaries:''
	category:'Interface-UIPainter'
!

HierarchicalItem subclass:#Item
	instanceVariableNames:'menuItem'
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::Item subclass:#ItemAction
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::Item subclass:#ItemLinkedMenu
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::Item subclass:#ItemMenu
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::ItemMenu subclass:#ItemRoot
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::Item subclass:#ItemSeparator
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

ApplicationModel subclass:#ResourceEditor
	instanceVariableNames:'selectorHolder iconAndLabelHolder retrieverHolder imageHolder
		imageList imageViewer'
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

HierarchicalItem subclass:#ResourceEditorItem
	instanceVariableNames:'selector icon'
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

!MenuEditor class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1997 by eXept Software AG
	      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
"
    The MenuEditor allows you to create, modify or just inspect
    menus.


    [Instance variables:]

	selectionHolder         <ValueHolder>        collection of current selected items
	tabHolder               <ValueHolder>        selected tab label holder
	listOfItems             <HierarchicalList>   hierarchical list of menu items
	listOfTabs              <List>               list of current shown tab-labels
	wizards                 <IdentityDictionary> keeps all created wizard dialogs
	selectedSuperItems      <Collection>         collection of superItems derived from selection
	notifyDisabledCounter   <SmallInteger>       ~~ 0 than change notifications are discard

    [Class variables:]
	ImageRetrieverClasses   <Collection>        sorted collection of image receivers

    [start with:]
	MenuEditor open
	MenuEditor openOnClass:MenuEditor andSelector:#menu

    [author:]
	Claus Atzkern, eXept Software AG
	Thomas Zwick, eXept Software AG
"
! !

!MenuEditor class methodsFor:'initialization'!

initialize
    ImageRetrieverClasses := #( 
				Icon
				SystemBrowser 
				ToolbarIconLibrary
			      ). 

    "
     self initialize
    "
! !

!MenuEditor class methodsFor:'instance creation'!

openModalOnMenu: aMenu
    "Open a MenuEditor modal on aMenu
     self openModalOnMenu: (self perform: #menu) decodeAsLiteralArray
    "
    ^self new openModalOnMenu:aMenu
! !

!MenuEditor class methodsFor:'accessing image retriever'!

addNewImageRetriever:aSymbolOrClass
    "add a class to the imageRetriever list"

    |key|

    aSymbolOrClass isBehavior ifTrue:[
	key := aSymbolOrClass nameWithNameSpacePrefix
    ] ifFalse:[
	key := aSymbolOrClass
    ].

    key size ~~ 0 ifTrue:[
	key := key asSymbol.

	(ImageRetrieverClasses includes:key) ifFalse:[
	    ImageRetrieverClasses := ImageRetrieverClasses asOrderedCollection.
	    ImageRetrieverClasses add:key.
	    ImageRetrieverClasses sort.
	]
    ].
!

imageRetrieverClasses
    "returns a collection of image retrievers
    "
    ^ ImageRetrieverClasses
! !

!MenuEditor class methodsFor:'aspects'!

aspects
    "get the aspects for the attributes of the menu components"

    ^#(
	rawLabel
	accessCharacterPosition
	showBusyCursorWhilePerforming
	horizontalLayout
	triggerOnDown
	font
	argument
	submenuChannel
	keepLinkedMenu
	enabled
	value
	nameKey
	indication
	choice
	choiceValue
	translateLabel
	isButton
	shortcutKeyCharacter
	startGroup
	isVisible
	hideMenuOnActivated
	auxValue
	activeHelpKey
	resourceRetriever
     )
! !

!MenuEditor class methodsFor:'defaults'!

aboutImage
    "the image to be displayed in my about-box;
     If nil is returned, the ST/X default image is used.
    "
    ^ Image fromFile:'bitmaps/xpmBitmaps/misc_tools/setup_menus.xpm'
!

resourceType
    "get the type of the resource of the method generated by the MenuEditor
    "
    ^ #menu
! !

!MenuEditor class methodsFor:'help specs'!

flyByHelpSpec
    ^super flyByHelpSpec addPairsFrom:(self localHelpSpecStrings)
!

helpSpec
    ^super helpSpec addPairsFrom:(self localHelpSpecStrings)
!

localHelpSpecStrings
    "This resource specification was automatically generated
     by the UIHelpTool of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIHelpTool may not be able to read the specification."

    "
     UIHelpTool openOnClass:MenuEditor    
    "

    <resource: #help>

    ^ #(

#addDelayedMenu
'Add a new delayed menu to item.'

#addDelayedSubMenuLink
'Add a new linked delayed menu to item.'

#addMenuItem
'Add a new menu item.'

#addMenuSeparator
'Add a new menu separator.'

#addSubMenu
'Add a new sub menu.'

#addSubMenuLink
'Add a new linked sub menu.'

#basicsAction
'An action selector with 0, 1 (the argument field), or 2 (the selected item) arguments.'

#basicsArgument
'An optional arg passed with above selector, if it is a 1 or 2 arg selector (enter a Smalltalk literal).'

#basicsChoice
'Aspect for a boolean holder, block or method, specifying the choices state (RadioButton behavior).'

#basicsChoiceValue
'That choices value (typically number or symbol).'

#basicsIndication
'Aspect for boolean holder, block, or method, specifying the indication state (CheckToggle behavior).'

#basicsIsButton
'Enable/disable button-like behavior.'

#basicsKey
'Internal key of the item (optional, for programmed accesses).'

#basicsLabel
'Label of the item.'

#basicsMenu
'Aspect providing the sub menu to be opened if item is selected (provide spec or valueHolder).'

#basicsMenuArgument
'An argument passed with the menu selector.'

#basicsNameKey
'Unique identifier of the item (optional).'

#basicsSelector
'Selector under which the generated menu spec is saved.'

#basicsSeparatorType
'List of valid separators.'

#basicsTranslateLabel
'Translate the label via the classes resource file (internationalization).'

#browseResource
'Search for methods with image resource.'

#detailsAccelerator
'Accelerator key to select the menu item from the keyboard (Cmdx or Ctrlx).'

#detailsAccessCharaterPosition
'Index of the access character position of the textual label (obsolete, VW compatibility).'

#detailsAuxValue
'Some additional value - for arbitrary use by the program'

#detailsEnabled
'Aspect or binding providing a boolean value holder for the enable-state of the menu item.'

#detailsStartGroup
'Specify start of a right-aligned item group.'

#detailsVisibility
'Aspect or binding providing a boolean value holder for the visibility-state of the menu item.'

#fileLoad
'Open a dialog to select and load a menu spec from a class.'

#fileNew
'Create a new menu spec.'

#filePickAMenu
'Select a menu from an open view and read its specification'

#fileSave
'Save the menu spec (and the help spec, if modified).'

#fileSaveAs
'Open a dialog to save the menu spec (and the help spec, if modified).'

#fileShowMenuSpec
'Opens a Workspace showing the current menu spec.'

#generateAspectMethods
'Generates aspect methods for defined aspect selectors of the menu.'

#hideMenuOnActivated
'If on, the menu hides itself after the item was activated.'

#horizontalLayout
'If on, the submenu organizes its items horizontal insteat of vertical (default).'

#imageImageAndLabel
'Toggle display of both image and textual label.'

#imageImageEditor
'Open an Image Editor on the resource method defined by retriever and selector.'

#imageImageList
'Currently existing image resources.'

#imageRetriever
'Class implementing the image resource method. If no class is given, the current application class will be taken.'

#imageSelector
'Selector returning an image (sent to above or the application).'

#keepLinkedMenu
'Keep the linked menu after activation (do not destroy).'

#showBusyCursorWhilePerforming
'If on, a busy cursor is shown while the items action is performing.'

#triggerOnDown
'If on, the items action is performed on mouse-button press (default is on button-release).'

)
! !

!MenuEditor class methodsFor:'image specs'!

iconUnknown
    "returns an image used for picked items containing an image
    "
    <resource: #fileImage>

    ^ MenuPanelSpec icon
! !

!MenuEditor class methodsFor:'interface specs'!

windowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

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

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #windowSpec
        #window: 
       #(#WindowSpec
          #label: 'Menu Editor'
          #name: 'Menu Editor'
          #min: #(#Point 550 385)
          #max: #(#Point 1152 900)
          #bounds: #(#Rectangle 117 275 693 750)
          #menu: #menu
          #returnIsOKInDialog: false
          #escapeIsCancelInDialog: false
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#MenuPanelSpec
              #name: 'toolbar'
              #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
              #tabable: true
              #menu: #toolbar
              #showSeparatingLines: true
            )
           #(#VariableHorizontalPanelSpec
              #name: 'VariableHorizontalPanel'
              #layout: #(#LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0)
              #component: 
             #(#SpecCollection
                #collection: #(
                 #(#HierarchicalListViewSpec
                    #name: 'ListOfItemsView'
                    #model: #selectionHolder
                    #menu: #editMenu
                    #hasHorizontalScrollBar: true
                    #hasVerticalScrollBar: true
                    #miniScrollerHorizontal: true
                    #miniScrollerVertical: true
                    #listModel: #listOfItems
                    #multipleSelectOk: true
                    #useIndex: false
                    #highlightMode: #label
                    #doubleClickSelector: #indicatorClickedAt:
                    #selectConditionSelector: #canSelect:
                    #showLeftIndicators: false
                    #indicatorSelector: #indicatorClickedAt:
                    #properties: 
                   #(#PropertyListDictionary
                      #dragArgument: nil
                      #dropObjectSelector: #dropObjects
                      #dropArgument: nil
                      #canDropSelector: #canDrop:
                      #dropSelector: #doDrop:
                    )
                    #postBuildCallback: #postBuildListOfItemsView:
                  )
                 #(#ViewSpec
                    #name: 'Box'
                    #level: -1
                    #component: 
                   #(#SpecCollection
                      #collection: #(
                       #(#NoteBookViewSpec
                          #name: 'NoteBook'
                          #layout: #(#LayoutFrame 1 0.0 0 0.0 1 1.0 -30 1.0)
                          #enableChannel: #hasSingleSelectionChannel
                          #tabable: true
                          #model: #tabHolder
                          #menu: #listOfTabs
                          #fitLastRow: false
                          #canvas: #wizardHolder
                          #keepCanvasAlive: true
                        )
                       #(#UISubSpecification
                          #name: 'SubSpecification'
                          #layout: #(#LayoutFrame 2 0.0 -26 1 -2 1.0 -2 1.0)
                          #majorKey: #ToolApplicationModel
                          #minorKey: #windowSpecForCommit
                        )
                       )
                     
                    )
                  )
                 )
               
              )
              #handles: #(#Any 0.300493 1.0)
            )
           #(#UISubSpecification
              #name: 'InfoBarSubSpec'
              #layout: #(#LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0)
              #majorKey: #ToolApplicationModel
              #minorKey: #windowSpecForInfoBar
            )
           )
         
        )
      )
! !

!MenuEditor class methodsFor:'menu specs'!

addMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Separator'
            #translateLabel: true
            #value: #doCreateSep
            #activeHelpKey: #addMenuSeparator
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconSeparator '')
          )
         #(#MenuItem
            #label: 'Item'
            #translateLabel: true
            #value: #doCreateItem
            #activeHelpKey: #addMenuItem
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconItem '')
          )
         #(#MenuItem
            #label: 'Menu'
            #translateLabel: true
            #value: #doCreateMenu
            #activeHelpKey: #addMenuItem
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconMenu '')
          )
         #(#MenuItem
            #label: 'Linked Menu'
            #value: #doCreateLinkedMenu
            #activeHelpKey: #addSubMenuLink
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconLinkedMenu '')
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Delayed Menu'
            #value: #doCreateDelayedMenu:
            #enabled: #canCreateDelayedMenuChannel
            #activeHelpKey: #addDelayedMenu
           #argument: #menu
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconDelayedMenu '')
          )
         #(#MenuItem
            #label: 'Delayed Linked Menu'
            #value: #doCreateDelayedMenu:
            #enabled: #canCreateDelayedMenuChannel
            #activeHelpKey: #addDelayedSubMenuLink
            #argument: #linkedMenu
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconDelayedLinkedMenu '')
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Standard Menus'
            #translateLabel: true
            #submenuChannel: #standardMenus
            #keepLinkedMenu: true
          )
         )
        nil
        nil
      )
!

editMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
	#(
	 #(#MenuItem
	    #label: 'Cut'
	    #value: #doCut
	    #activeHelpKey: #editCut
	    #enabled: #hasSelectionChannel
	  )
	 #(#MenuItem
	    #label: 'Copy'
	    #value: #doCopy
	    #activeHelpKey: #editCopy
	    #enabled: #hasSelectionChannel
	  )
	 #(#MenuItem
	    #label: 'Paste'
	    #value: #doPaste
	    #activeHelpKey: #editPaste
	    #enabled: #valueOfCanPaste
	  )
	 #(#MenuItem
	    #label: 'Delete'
	    #value: #doDelete
	    #activeHelpKey: #editDelete
	    #enabled: #hasSelectionChannel
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #label: 'Move Up'
	    #startGroup: #right
	    #value: #doMoveUpOrDown:
	    #activeHelpKey: #editMoveUp
	    #enabled: #valueOfEnableMovingUpOrDown
	    #argument: #up
	    #labelImage: #(#ResourceRetriever #Icon #upIcon 'Move Up')
	  )
	 #(#MenuItem
	    #label: 'Move Down'
	    #value: #doMoveUpOrDown:
	    #activeHelpKey: #editMoveDown
	    #enabled: #valueOfEnableMovingUpOrDown
	    #argument: #down
	    #labelImage: #(#ResourceRetriever #Icon #downIcon 'Move Down')
	  )
	 #(#MenuItem
	    #label: 'Move In'
	    #value: #doMoveIn:
	    #activeHelpKey: #editMoveIn
	    #enabled: #valueOfEnableMovingIn
	    #argument: #inNext
	    #labelImage: #(#ResourceRetriever #Icon #downRightIcon 'Move In')
	  )
	 #(#MenuItem
	    #label: 'Move In Above'
	    #value: #doMoveIn:
	    #activeHelpKey: #editMoveInAbove
	    #enabled: #valueOfEnableMovingInAbove
	    #argument: #inPrev
	    #labelImage: #(#ResourceRetriever #Icon #upRightIcon 'Move In Above')
	  )
	 #(#MenuItem
	    #label: 'Move Out'
	    #value: #doMoveOut
	    #activeHelpKey: #editMoveOut
	    #enabled: #valueOfEnableMovingOut
	    #labelImage: #(#ResourceRetriever #Icon #leftDownIcon 'Move Out')
	  )
	 )
	nil
	nil
      )
!

fileMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'New'
            #translateLabel: true
            #value: #doNew
            #activeHelpKey: #fileNew
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Load...'
            #translateLabel: true
            #value: #doLoad
            #activeHelpKey: #fileLoad
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Save'
            #translateLabel: true
            #value: #doSave
            #activeHelpKey: #fileSave
          )
         #(#MenuItem
            #label: 'Save As...'
            #translateLabel: true
            #value: #doSaveAs
            #activeHelpKey: #fileSaveAs
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Pick a Menu...'
            #translateLabel: true
            #value: #doPickAMenu
            #activeHelpKey: #filePickAMenu
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Show Menu Spec'
            #translateLabel: true
            #value: #doShowMenuSpec
            #activeHelpKey: #fileShowMenuSpec
          )
         #(#MenuItem
            #label: 'Browse Class'
            #translateLabel: true
            #value: #doBrowseClass
            #activeHelpKey: #fileBrowseClass
            #enabled: #hasValidSpecClass
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Exit'
            #translateLabel: true
            #value: #closeRequest
            #activeHelpKey: #fileExit
          )
         )
        nil
        nil
      )
!

generateMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Aspect Methods'
            #value: #doGenerateAspectMethods
            #activeHelpKey: #generateAspectMethods
            #enabled: #hasValidSpecClass
          )
         )
        nil
        nil
      )
!

helpMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Documentation'
            #translateLabel: true
            #value: #openHTMLDocument:
            #activeHelpKey: #helpTutorial
            #argument: 'tools/uipainter/MenuEditor.html'
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Help Tool'
            #translateLabel: true
            #value: #openHTMLDocument:
            #activeHelpKey: #helpHelpTool
            #argument: 'tools/uipainter/HelpTool.html'
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Show Help Texts'
            #translateLabel: true
            #activeHelpKey: #helpShowHelp
            #indication: #showingHelp:
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'About MenuEditor...'
            #translateLabel: true
            #value: #openAboutThisApplication
            #activeHelpKey: #aboutThisAppliaction
          )
         )
        nil
        nil
      )
!

menu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: '&File'
            #translateLabel: true
            #activeHelpKey: #file
            #submenuChannel: #fileMenu
            #keepLinkedMenu: true
          )
         #(#MenuItem
            #label: '&Edit'
            #translateLabel: true
            #activeHelpKey: #edit
            #submenuChannel: #editMenu
            #keepLinkedMenu: true
          )
         #(#MenuItem
            #label: 'Add'
            #translateLabel: true
            #activeHelpKey: #add
            #enabled: #hasSingleSelectionChannel
            #submenuChannel: #addMenu
            #keepLinkedMenu: true
          )
         #(#MenuItem
            #label: 'Test'
            #translateLabel: true
            #activeHelpKey: #test
            #submenuChannel: #submenuTest
          )
         #(#MenuItem
            #label: 'History'
            #translateLabel: true
            #activeHelpKey: #history
            #submenuChannel: #menuHistory
          )
         #(#MenuItem
            #label: 'Generate'
            #translateLabel: true
            #activeHelpKey: #generate
            #submenuChannel: #generateMenu
            #keepLinkedMenu: true
          )
         #(#MenuItem
            #label: '&Help'
            #translateLabel: true
            #startGroup: #right
            #activeHelpKey: #help
            #submenuChannel: #helpMenu
            #keepLinkedMenu: true
          )
         )
        nil
        nil
      )
!

standardMenus
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
	#(
	 #(#MenuItem
	    #label: 'Standard Menu: Edit'
	    #translateLabel: true
	    #value: #doCreateStandardEditMenu
	  )
	 #(#MenuItem
	    #label: 'Standard Menu: Help'
	    #translateLabel: true
	    #value: #doCreateStandardHelpMenu
	  )
	 #(#MenuItem
	    #label: 'Standard Menu: File'
	    #translateLabel: true
	    #value: #doCreateStandardFileMenu
	  )
	 )
	nil
	nil
      )
!

toolbar
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Load'
            #isButton: true
            #value: #doLoad
            #activeHelpKey: #fileLoad
            #labelImage: #(#ResourceRetriever #Icon #loadIcon)
            #submenuChannel: #menuHistory
          )
         #(#MenuItem
            #label: 'Save'
            #isButton: true
            #value: #doSave
            #activeHelpKey: #fileSave
            #labelImage: #(#ResourceRetriever #Icon #saveIcon)
          )
         #(#MenuItem
            #label: ''
          )
         #(#MenuItem
            #label: 'Cut'
            #isButton: true
            #value: #doCut
            #activeHelpKey: #editCut
            #enabled: #hasSelectionChannel
            #labelImage: #(#ResourceRetriever #Icon #cutIcon)
          )
         #(#MenuItem
            #label: 'Copy'
            #isButton: true
            #value: #doCopy
            #activeHelpKey: #editCopy
            #enabled: #hasSelectionChannel
            #labelImage: #(#ResourceRetriever #Icon #copyIcon)
          )
         #(#MenuItem
            #label: 'Paste'
            #isButton: true
            #value: #doPaste
            #activeHelpKey: #editPaste
            #enabled: #valueOfCanPaste
            #labelImage: #(#ResourceRetriever #Icon #pasteIcon)
          )
         #(#MenuItem
            #label: ''
          )
         #(#MenuItem
            #label: 'Add Separator'
            #isButton: true
            #value: #doCreateSep
            #activeHelpKey: #addMenuSeparator
            #enabled: #hasSingleSelectionChannel
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconSeparator)
          )
         #(#MenuItem
            #label: 'Add Item'
            #isButton: true
            #value: #doCreateItem
            #activeHelpKey: #addMenuItem
            #enabled: #hasSingleSelectionChannel
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconItem)
          )
         #(#MenuItem
            #label: 'Add Menu'
            #isButton: true
            #value: #doCreateMenu
            #activeHelpKey: #addSubMenu
            #enabled: #hasSingleSelectionChannel
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconMenu)
            #submenuChannel: #standardMenus
            #keepLinkedMenu: true
          )
         #(#MenuItem
            #label: 'Add Linked Menu'
            #isButton: true
            #value: #doCreateLinkedMenu
            #activeHelpKey: #addSubMenuLink
            #enabled: #hasSingleSelectionChannel
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconLinkedMenu)
          )
         #(#MenuItem
            #label: ''
          )
         #(#MenuItem
            #label: 'Add Delayed Menu'
            #isButton: true
            #value: #doCreateDelayedMenu:
            #activeHelpKey: #addDelayedMenu
            #enabled: #canCreateDelayedMenuChannel
            #argument: #menu
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconDelayedMenu)
          )
         #(#MenuItem
            #label: 'Add Delayed Linked Menu'
            #isButton: true
            #value: #doCreateDelayedMenu:
            #activeHelpKey: #addDelayedSubMenuLink
            #enabled: #canCreateDelayedMenuChannel
            #argument: #linkedMenu
            #labelImage: #(#ResourceRetriever #'MenuEditor::Item' #iconDelayedLinkedMenu)
          )
         #(#MenuItem
            #label: 'Move Up'
            #isButton: true
            #startGroup: #right
            #value: #doMoveUpOrDown:
            #activeHelpKey: #editMoveUp
            #enabled: #valueOfEnableMovingUpOrDown
            #argument: #up
            #labelImage: #(#ResourceRetriever #Icon #upIcon)
          )
         #(#MenuItem
            #label: 'Move Down'
            #isButton: true
            #value: #doMoveUpOrDown:
            #activeHelpKey: #editMoveDown
            #enabled: #valueOfEnableMovingUpOrDown
            #argument: #down
            #labelImage: #(#ResourceRetriever #Icon #downIcon)
          )
         #(#MenuItem
            #label: 'Move In'
            #isButton: true
            #value: #doMoveIn:
            #activeHelpKey: #editMoveIn
            #enabled: #valueOfEnableMovingIn
            #argument: #inNext
            #labelImage: #(#ResourceRetriever #Icon #downRightIcon)
          )
         #(#MenuItem
            #label: 'Move In Above'
            #isButton: true
            #value: #doMoveIn:
            #activeHelpKey: #editMoveInAbove
            #enabled: #valueOfEnableMovingInAbove
            #argument: #inPrev
            #labelImage: #(#ResourceRetriever #Icon #upRightIcon)
          )
         #(#MenuItem
            #label: 'Move Out'
            #isButton: true
            #value: #doMoveOut
            #activeHelpKey: #editMoveOut
            #enabled: #valueOfEnableMovingOut
            #labelImage: #(#ResourceRetriever #Icon #leftDownIcon)
          )
         )
        nil
        nil
      )
! !

!MenuEditor class methodsFor:'menu specs - standard'!

standardEditMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
	#(
	 #(#MenuItem
	    #label: 'Copy'
	    #translateLabel: true
	    #value: #copySelection
	  )
	 #(#MenuItem
	    #label: 'Cut'
	    #translateLabel: true
	    #value: #cutSelection
	  )
	 #(#MenuItem
	    #label: 'Paste'
	    #translateLabel: true
	    #value: #paste
	  )
	 )
	nil
	nil
      )
!

standardFileMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
	#(
	 #(#MenuItem
	    #label: 'New'
	    #translateLabel: true
	    #value: #menuNew
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #label: 'Open...'
	    #translateLabel: true
	    #value: #menuOpen
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #label: 'Save'
	    #translateLabel: true
	    #value: #menuSave
	  )
	 #(#MenuItem
	    #label: 'Save As...'
	    #translateLabel: true
	    #value: #menuSaveAs
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #label: 'Exit'
	    #translateLabel: true
	    #value: #closeRequest
	  )
	 )
	nil
	nil
      )
!

standardHelpMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

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

    <resource: #menu>

    ^ 
     #(#Menu
	#(
	 #(#MenuItem
	    #label: 'Documentation'
	    #translateLabel: true
	    #value: #openDocumentation
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #label: 'About this Application'
	    #translateLabel: true
	    #value: #openAboutThisApplication
	  )
	 )
	nil
	nil
      )
! !

!MenuEditor methodsFor:'accessing'!

helpTool
    "get the help tool application
    "
  ^ wizards at:#help ifAbsentPut:[ |tool|
	tool := UIHelpTool new createBuilder.
	tool masterApplication:self.
	tool modifiedHolder: self valueOfEnablingCommitButtons.
	tool builder window:(ApplicationSubView new client:tool).
	tool masterApplication:self.
	tool
    ]
!

imageTool
    "get the image tool application
    "
  ^ wizards at:#image ifAbsentPut:[ |tool|
	tool := ResourceEditor new createBuilder.
	tool masterApplication:self.
	tool modifiedChannel: self valueOfEnablingCommitButtons.
	tool builder window:(ApplicationSubView new client:tool).
	tool
    ]
!

useHelpTool:aHelpTool
    "take the help dictionaries from aHelpTool into my helpTool
    "
    |tool|

    tool := self helpTool.

    tool buildFromClass:(aHelpTool specClass).
    tool   dictionaries:(aHelpTool dictionaries).
    tool     dictionary:(aHelpTool dictionary).
! !

!MenuEditor methodsFor:'actions'!

accept
    "accept modifications
    "
    self accept:true.
!

accept:ok
    "ok if true the modifications are accepted
     than reload from item
    "
    |selectedItem rscRetrHolder helpKeyHolder helpTool imageTool acceptChannel|

    selectedItem := self selectedItem.

    selectedItem ifNotNil:[
        self withoutNotifyDo:[
            rscRetrHolder := aspects at:#resourceRetriever.
            helpKeyHolder := aspects at:#activeHelpKey.
            imageTool     := self imageTool.
            helpTool      := self helpTool.
            acceptChannel := self acceptChannel.

            acceptChannel triggerValue:true.
            acceptChannel setValue:false.

            ok ifTrue:[
                rscRetrHolder value:(imageTool resourceRetriever).
                helpKeyHolder value:(helpTool  helpKey).
                selectedItem  fromAspects:aspects.
                modified := true.

                selectedItem isRootItem ifTrue:[
                    "/ update specSelector
                    specSelector := selectedItem rawLabel.
                ].    
            ].
            selectedItem toAspects:aspects.
            helpTool     setHelpKey:(helpKeyHolder value).
            imageTool    resourceRetriever:(rscRetrHolder value).
        ]
    ].
    self updateChannels.
    self clearModified.
!

cancel
    "reload aspects from current selected item; reset modification flag
    "
    self accept:false.
!

indicatorClickedAt:atLine
    "indicator clicked at line number; toggle expand of item at line
    "
    |item|

    item := listOfItems at:atLine ifAbsent:nil.
    item ifNotNil:[
        item toggleExpand.
        self hasSelection ifFalse:[
            self selectedItem:item
        ]
    ].
! !

!MenuEditor methodsFor:'aspects'!

canCreateDelayedMenuChannel
    "boolean holder, true if the current selected item accepts a delayed menu
    "
    ^ builder booleanValueAspectFor:#canCreateDelayedMenuChannel
!

hasSelectionChannel
    "boolean holder, true if any item is selected
    "
    ^ builder booleanValueAspectFor:#hasSelectionChannel
!

hasSingleSelectionChannel
    "boolean holder, true if one item is selected
    "
    ^ builder booleanValueAspectFor:#hasSingleSelectionChannel
!

listOfItems
    "returns the hierarchical list of menuItems
    "
    ^ listOfItems
!

listOfTabs
    "returns the list of current shown tab-labels retrieved
     from the current selected item.
    "
    ^ listOfTabs
!

selectionHolder
    "value holder, which keeps the current selected items
    "
    ^ selectionHolder
!

tabHolder
    "value holder, which keeps the current selected tab label or nil
    "
    ^ tabHolder
!

wizardHolder
    "holder, which keeps the current wizard window
    "
    |holder|

    holder := builder bindingAt:#wizardHolder.

    holder ifNil:[
	holder := nil asValue.
	builder aspectAt:#wizardHolder put:holder.
    ].
    ^ holder
! !

!MenuEditor methodsFor:'building'!

buildFromClass:aSpecClass andSelector:aSpecSelector
    "rebuild menu from a class and selector
    "
    |cls menu|

    menu := nil.

    self isStandAlone ifTrue:[ self helpTool buildFromClass:aSpecClass ].              

    aSpecSelector notNil ifTrue:[
	aSpecClass ifNotNil:[
	    cls  := self resolveName:aSpecClass.
	    menu := cls perform:aSpecSelector ifNotUnderstood:nil.

	    menu ifNotNil:[
		(menu isMemberOf:Menu) ifFalse:[
		    menu := Menu new fromLiteralArrayEncoding:menu
		].
	    ]
	].
    ].
    self buildFromMenu:menu selector:aSpecSelector.
!

buildFromMenu:aMenu selector:aSelector
    "rebuild menu from a Menu
    "
    |root menu|

    aMenu isCollection ifTrue:[menu := aMenu decodeAsLiteralArray]
		      ifFalse:[menu := aMenu].

    self valueOfEnablingCommitButtons value:false.
    root := listOfItems root.

    self withoutNotifyDo:[
	selectionHolder setValue:#().
	root menu:aMenu labeled:(aSelector ? specSelector).
    ].
    self selectedItem:root.
    self updateHistory.
!

buildFromResourceSpec:aResourceSpec
    "rebuild menu from a resource spec
    "
    self buildFromMenu:aResourceSpec selector:nil
! !

!MenuEditor methodsFor:'change & update'!

selectedSuperItems
    "returns collection of superItems derived from selection
    "
    |selection size root|

    selectedSuperItems ifNotNil:[ ^ selectedSuperItems ].

    selection := selectionHolder value.
    size      := selection size.

    size <= 1 ifTrue:[
        selectedSuperItems := selection ? #().
      ^ selectedSuperItems
    ].

    root := listOfItems root.

    (selection includesIdentical:root) ifTrue:[
        selectedSuperItems := Array with:root.
      ^ selectedSuperItems  
    ].
    selectedSuperItems := OrderedCollection new.

    selection do:[:anItem|
        anItem parentsDetect:[:el| selection includesIdentical:el ]
                      ifNone:[ selectedSuperItems add:anItem ].
    ].
    ^ selectedSuperItems
!

selectionChanged
    "called if the selection has changed
    "
    |newTabList selection|

    selection := selectionHolder value.

    selection size == 1 ifTrue:[
        selectedSuperItems := selection.

        newTabList := selection first slices collect:[:el| '   ', el first, '   ' ].
        newTabList = listOfTabs ifFalse:[
            listOfTabs contents:newTabList.
        ].
    ] ifFalse:[
        "must compute selected super items on request
        "
        selectedSuperItems := nil.
    ].
    self cancel.
    self tabChanged.
    self updateChannels.
!

tabChanged
    "called if the tab changed
    "
    |tab selector item canvas wizardHolder|

    wizardHolder := self wizardHolder.
    item := self selectedItem.
    item ifNil:[ ^ wizardHolder value:nil ].

    tab := tabHolder value.

    tab ifNotNil:[
        tab := tab withoutSeparators.
        tab := item slices detect:[:el| el first = tab ] ifNone:nil.
    ].
    tab ifNil:[
        ^ tabHolder value:( listOfTabs at:1 ifAbsent:nil )
    ].
    selector := tab last.

    selector == #help  ifTrue:[ ^ wizardHolder value:(self helpTool  window) ].
    selector == #image ifTrue:[ ^ wizardHolder value:(self imageTool window) ].

    canvas := wizards at:(item class name, selector) asSymbol
              ifAbsentPut:[ SimpleView new client:self
                                             spec:(item class perform:selector)
                                          builder:(self builder)
                          ].

    wizardHolder value:canvas.
!

update:something with:aParameter from:changedObject
    "Invoked when an object that I depend upon sends a change notification.
    "
    notifyDisabledCounter ~~ 0 ifTrue:[ ^ self ].

    changedObject == selectionHolder ifTrue:[ ^ self selectionChanged ].
    changedObject == tabHolder       ifTrue:[ ^ self tabChanged ].

    super update:something with:aParameter from:changedObject
!

updateChannels
    "update all channels
    "
    |selection sizeOfSel selectedItem|

    super updateChannels.

    selection := selectionHolder value.
    sizeOfSel := selection size.

    sizeOfSel == 1 ifTrue:[selectedItem := selection at:1]
		  ifFalse:[selectedItem := nil].

    self hasSelectionChannel       value:(sizeOfSel ~~ 0).
    self hasSingleSelectionChannel value:(selectedItem notNil).

    selectedItem isNil ifTrue:[
	self valueOfEnableMovingIn       value:false.
	self valueOfEnableMovingOut      value:false.
	self valueOfEnableMovingUpOrDown value:false.
	self valueOfEnableMovingInAbove  value:false.
	self canCreateDelayedMenuChannel value:false.
    ] ifFalse:[
	self valueOfEnableMovingUpOrDown value:(selectedItem canMoveUpOrDown).
	self valueOfEnableMovingOut      value:(selectedItem canMoveOut).
	self valueOfEnableMovingIn       value:(selectedItem canMoveInNext).
	self valueOfEnableMovingInAbove  value:(selectedItem canMoveInAbove).
	self canCreateDelayedMenuChannel value:(selectedItem canAddDelayedMenu).
    ].
! !

!MenuEditor methodsFor:'defaults'!

aboutImage
    "the image to be displayed in my about-box;
     If nil is returned, the ST/X default image is used.
    "
    ^ self class aboutImage
! !

!MenuEditor methodsFor:'drag & drop'!

canDrop:aContext
    "return true, if the DropContext can be dropped into
     the hierachical list of items
    "
    |objects modified|

    modified := self valueOfEnablingCommitButtons value.
    modified ifTrue:[^ false].

    self selectedItem ifNil:[^ false].

    aContext sourceWidget == aContext targetWidget ifTrue:[
	^ false
    ].

    objects := aContext dropObjects.
    objects isEmpty ifTrue:[ ^ false ].

    objects do:[:el|
	el theObject class == MenuItem ifFalse:[^ false].
    ].
    ^ true
!

doDrop:aDropContext
    "drop the DropContext into the hierachical list of items
    "
    |objects|

    (self canDrop:aDropContext) ifFalse:[^ false].

    objects := aDropContext dropObjects collect:[:el| el theObject ].
    self doPaste:objects.
  ^ true
!

dropObjects
    "returns list of DropObjects
    "
    |obj items|

    items := self selectedSuperItems.
    items isEmpty ifTrue:[ ^ nil ].

  ^ items collect:[:el|
        obj := DropObject new:(el menuItem).
        obj displayObject:(el rawLabel).
        obj
    ].
! !

!MenuEditor methodsFor:'event processing'!

processEvent:anEvent
    "filter keyboard edit-events typed into the listOfItemsView
    "
    |evView inView rawKey key|

    anEvent isKeyPressEvent ifFalse:[^ false].

    evView := anEvent targetView.
    evView ifNil:[ ^ false ].

    inView := evView isSameOrComponentOf:listOfItemsView.
    inView ifFalse:[^ false].

    key    := anEvent key.
    rawKey := anEvent rawKey.

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

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

  ^ false
! !

!MenuEditor methodsFor:'initialization & release'!

closeRequest
    "ask for modification
    "
    self valueOfEnablingCommitButtons value ifTrue:[
        modified := true.
        self askForListModification.
        modified ifTrue:[^ self].
        self clearModified.
    ].
    ^ super closeRequest
!

initialize
    "setup aspects, ...
    "
    super initialize.
    notifyDisabledCounter := 0.
    redefineAspectMethods := true.

    Item withAllSubclasses do:[:aClass|
        aClass addBindingsTo:aspects for:self.
    ].

    selectionHolder    := #() asValue.
    selectionHolder addDependent:self.

    listOfItems := HierarchicalList new.
    listOfItems application:self.
    listOfItems root:(ItemRoot new).

    tabHolder := nil asValue.
    tabHolder addDependent:self.

    listOfTabs := List new.
    wizards    := IdentityDictionary new.
!

openModalOnMenu:aMenu
    "build a tree from aMenu and open it modal
    "
    self openModalOnResourceSpec:aMenu
!

postBuildListOfItemsView:aView
    listOfItemsView := aView.
!

postOpenWith:aBuilder
    "reset keyboardProcessor for menuBar
    "
    super postOpenWith: aBuilder.
    aBuilder keyboardProcessor menuBar:nil.
    self windowGroup addPreEventHook:self.
! !

!MenuEditor methodsFor:'private'!

addAndSelect:aNoneArgBlockOrItem
    "add an item(s) derived from the block; test if add operation
     is enabled. On success the new item(s) are returned otherwise nil.
    "
    |intoItem index newItem|

    intoItem := self selectedItem.
    intoItem ifNil:[ ^ nil].

    self askForItemModification ifFalse:[ ^ nil ].

    index := 1.

    (     intoItem canAddChildren
     and:[(intoItem isExpanded or:[intoItem isDelayedMenu]) ]
    ) ifFalse:[
	[ intoItem parent canAddChildren ] whileFalse:[
	    intoItem := intoItem parent.
	].
	index := intoItem parent identityIndexOf:intoItem.
	index := index + 1.
	intoItem := intoItem parent.
    ].
    newItem := aNoneArgBlockOrItem value.

    newItem ifNotNil:[
	selectionHolder setValue:nil.
	intoItem expand.

	newItem isCollection ifTrue:[
	    intoItem addAll:newItem beforeIndex:index.
	    selectionHolder value:newItem.
	] ifFalse:[
	    intoItem add:newItem beforeIndex:index.
	    selectionHolder value:(Array with:newItem).
	].
	modified := true.
    ].
    ^ newItem
!

clearModified
    "clear the modifiedChannel and the commitPanel
    "
    self valueOfEnablingCommitButtons value:false.
    self clearModifiedFlag.
!

generateMenuSpec
    "generate and returns the current menu spec or nil
    "
    |menu spec|

    menu := listOfItems root submenu.
    menu ifNil:[^ nil].
    menu := menu literalArrayEncoding.
    spec := WriteStream on:String new.
    UISpecification prettyPrintSpecArray:menu on:spec indent:5.
  ^ spec contents.
!

submenuTest
    "returns a menu on the current editing menu
    "
    |menu indication choice submenu retriever|

    menu := listOfItems root submenu.
    menu ifNil:[^ nil ].

    menu allItemsDo:[:anItem|
        anItem isVisible:true.
        anItem   enabled:true.
        anItem translateLabel:false.

        anItem value ifNotNil:[
            anItem value:[ Transcript showCR:(anItem label) ].
        ].
        anItem indication ifNotNil:[
            indication ifNil:[ indication := true asValue ].
            anItem indication:indication
        ].
        anItem choice ifNotNil:[
            choice ifNil:[ choice := anItem choiceValue asValue ].
            anItem choice:choice
        ].

        anItem submenuChannel ifNotNil:[
            anItem submenuChannel:nil.
            anItem submenu ifNil:[    
                submenu ifNil:[
                    submenu := Menu new.
                    submenu addItem:(MenuItem labeled:'Linked Menu...').
                ].
                anItem submenu:submenu.
            ].
        ].
        retriever := anItem resourceRetriever.
        retriever ifNotNil:[
            retriever labelText ifNotNil:[ retriever labelText:(anItem label) ]
        ].
    ].
    menu findGuiResourcesIn:(self resolveName:specClass).
  ^ menu
!

withoutNotifyDo:aBlock
    "evaluate the block; all change notifications are
     discard during the block is evaluated.
    "
    |blockResult|

    [   notifyDisabledCounter := notifyDisabledCounter + 1.
	blockResult := aBlock value.
    ] valueNowOrOnUnwindDo:[
	notifyDisabledCounter := notifyDisabledCounter - 1
    ].    
    ^ blockResult
! !

!MenuEditor methodsFor:'queries'!

hasValidSpecClass
    "returns true if a valid specClass exists
    "
    |cls|

    specClass ifNil:[^ false].
    cls := self resolveName:specClass.
  ^ cls notNil
! !

!MenuEditor methodsFor:'selection'!

canSelect:anIndex
    "called whenever the selection changed; test whether
     current item is not modified ....
    "
    |oldSelectedItem newSelectedItem|

    self valueOfEnablingCommitButtons value ifFalse:[
	^ true
    ].
    oldSelectedItem := self selectedItem.
    oldSelectedItem ifNil:[^ true].

    newSelectedItem := listOfItems at:anIndex ifAbsent:nil.
    oldSelectedItem == newSelectedItem ifTrue:[
	^ true
    ].
    ^ self askForItemModification
!

hasSelection
    "returns true if a selection exists
    "
    ^ selectionHolder value size ~~ 0
!

selectedItem
    "returns the selected item or nil (none or multiple selected)
    "
    |selection|

    selection := selectionHolder value.
    selection size == 1 ifTrue:[ ^ selection first ].
  ^ nil
!

selectedItem:anItem
    "change selection to an item
    "
    |selection|

    anItem notNil ifTrue:[ selection := Array with:anItem ]
		 ifFalse:[ selection := #() ].

    selectionHolder value:selection.
! !

!MenuEditor methodsFor:'user actions - aspects'!

collectActionSelectors
    |selectors|

    selectors := IdentitySet new.

    listOfItems root recursiveDo:[:el|
        el actionSelectors do:[:s| selectors add:s ].
    ].
    ^ selectors asOrderedCollection
!

collectAspectSelectors
    |selectors|

    selectors := IdentitySet new.

    listOfItems root recursiveDo:[:el|
        el aspectSelectors do:[:s| selectors add:s ].
    ].
    ^ selectors asOrderedCollection
!

doGenerateAspectMethods
    "genearte aspect messages
    "
    |cls stream code|

    specClass ifNil:[
        self warn:'Define the class first !!'.
      ^ self
    ].

    cls := self resolveName:specClass.
    cls ifNil:[
        self warn:'Class ', specClass asString, ' does not exist!!'.
      ^ self  
    ].
    stream := '' writeStream.

    self collectActionSelectors do:[:aSel|
        code := self generateActionMethodFor:aSel inClass:cls.
        code ifNotNil:[ stream nextPutAll:code ].
    ].

    self collectAspectSelectors do:[:aSel|
        code := self generateAspectMethodFor:aSel inClass:cls.
        code ifNotNil:[ stream nextPutAll:code ].
    ].

    code := stream contents.

    code size ~~ 0 ifTrue:[
        code readStream fileIn
    ].
!

generateActionMethodFor:selector inClass:targetClass
    "genearte aspect messages
    "
    | alreadyInSuperclass numArgs method args showIt code|

    (targetClass includesSelector:selector) ifTrue:[
        "/ Transcript showCR:'#' , selector , ' skipped - already implemented in the class'.
      ^ nil
    ].

    alreadyInSuperclass := targetClass superclass canUnderstand:selector.

    alreadyInSuperclass ifTrue:[
        redefineAspectMethods ifFalse:[
            "/ Transcript showCR:'#' , selector , ' skipped - already implemented in superclass'.
          ^ nil
        ]
    ].

    numArgs := selector numArgs.
    method  := selector.

    numArgs == 1 ifTrue:[
        args   := 'anArgument'.
        showIt := ''' , anArgument printString , '' ...''.\'.
    ] ifFalse:[    
        args := ''.
        showIt := ' ...''.\'.

        numArgs ~~ 0 ifTrue:[
            method := ''.

            selector keywords keysAndValuesDo:[:i :key|
                method := method, key, 'arg', i printString, ' '
            ]
        ]
    ].
    code := '!!' , targetClass name , ' methodsFor:''menu actions''!!\\' ,
                method , args , '\' ,
                '    "automatically generated by MenuEditor ..."\\' ,
                '    "*** the code below performs no action"\' ,
                '    "*** (except for some feedback on the Transcript)"\' ,
                '    "*** Please change as required and accept in the browser."\' ,
                '    "*** (and replace this comment by something more useful ;-)"\' ,
                '\' .

    alreadyInSuperclass ifTrue:[
        code := code ,
                    '    "action for ' , selector , ' is already provided in a superclass."\' ,
                    '    "It may be redefined here ..."\\'.
    ] ifFalse:[
        code := code ,
                    '    "action to be added ..."\\'.
    ].

    code := code ,
                '    Transcript showCR:self class name, '': '.
    alreadyInSuperclass ifTrue:[
        code := code , 'inherited '.
    ].
    code := code , 'action for ' , selector , showIt.

    alreadyInSuperclass ifTrue:[
        code := code ,
                        '    super ' , selector , args , '.\'.
    ].

    code := code ,
                '!! !!\\'.
    ^ code withCRs
!

generateAspectMethodFor:aspect inClass:targetClass
    "genearte aspect messages
    "
    | alreadyInSuperclass numArgs method args showIt code|

    (targetClass includesSelector:aspect) ifTrue:[
        "/ Transcript showCR:'#' , aspect , ' skipped - already implemented in the class'.
      ^ nil
    ].

    alreadyInSuperclass := targetClass superclass canUnderstand:aspect.

    alreadyInSuperclass ifTrue:[
        redefineAspectMethods ifFalse:[
            "/ Transcript showCR:'#' , aspect , ' skipped - already implemented in superclass'.
          ^ nil
        ]
    ].

    numArgs := aspect numArgs.
    method  := aspect.

    numArgs == 1 ifTrue:[
        args   := 'anArgument'.
        showIt := ''' , anArgument printString , '' ...''.\'.
    ] ifFalse:[    
        args := ''.
        showIt := ' ...''.\'.

        numArgs ~~ 0 ifTrue:[
            method := ''.

            aspect keywords keysAndValuesDo:[:i :key|
                method := method, key, 'arg', i printString, ' '
            ]
        ]
    ].
    code := '!!' , targetClass name , ' methodsFor:''menu aspect''!!\\' ,
                method , args , '\' ,
                '    "automatically generated by MenuEditor ..."\\' ,
                '    "*** the code below creates a default model when invoked"\' ,
                '    "*** (which may not be the one you wanted)"\' ,
                '    "*** Please change as required and accept in the browser."\' ,
                '    "*** (and replace this comment by something more useful ;-)"\' ,
                '\' .

    alreadyInSuperclass ifTrue:[
        code := code ,
                    '    "aspect for ' , aspect , ' is already provided in a superclass."\' ,
                    '    "It may be redefined here ..."\\'.
    ] ifFalse:[
        code := code ,
                    '    "aspect to be added ..."\\'.
    ].

    code := code ,
                '    Transcript showCR:self class name, '': '.
    alreadyInSuperclass ifTrue:[
        code := code , 'inherited '.
    ].
    code := code , 'aspect for ' , aspect , showIt, '\'.

    alreadyInSuperclass ifTrue:[
        code := code ,
                        '    ^ super ' , aspect , args , '.\'.
    ] ifFalse:[
        code := code ,
                        '    ^ builder valueAspectFor:#' , aspect , ' initialValue:true.\'.
   ].

    code := code ,
                '!! !!\\'.
    ^ code withCRs
! !

!MenuEditor methodsFor:'user actions - building'!

doNew
    "clear editing menu; start from scratch
    "
    super doNew ifTrue:[ self helpTool doNew ].
!

doPickAMenu
    "pick a menu from user
    "
    |view|

    self askForModification ifTrue:[
        (   (view := Screen current viewFromUser) isNil
         or:[view == Screen current rootView]
        ) ifTrue:[
            ^ self
        ].
        view specClass == MenuPanelSpec ifTrue:[
            specSelector := #pickedMenu.
          ^ self buildFromMenu:(view asMenu) selector:specSelector.
        ].
    ].
!

doSave
    "save current editing menu to
           class: specClass
        selector: specSelector
    "
    |cls spec mthd category code excla|

    super doSave ifFalse: [^nil].
    spec := self generateMenuSpec.
    spec ifNil:[^ nil].

    cls  := self resolveName:specClass.

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

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

    excla := Character excla asString.

    code := excla
            , (cls name , ' class methodsFor:' , category storeString)
            , excla , '\\'

            , specSelector , '\'
            , (self class codeGenerationComment replChar:$!! withString:'!!!!')
            , '\\    "\'
            , ('     MenuEditor new openOnClass:' , cls name , ' andSelector:#' , specSelector , '\')
            , ('     (Menu new fromLiteralArrayEncoding:(' , cls name , ' ' , specSelector , ')) startUp\')
            , '    "\'.

    code := code 
            , '\'
            , '    <resource: #menu>\\'
            , '    ^ ' , spec 
            , '\'
            , (excla , ' ' , excla)
            , '\\'.

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

    self isStandAlone ifTrue: [self helpTool installHelpSpecsOnClass:self specClass].

    self updateHistory.
    hasSaved := true.
    modified := false.
!

doSaveAs
    "save current editing menu to class and selector
     defined by the user.
    "
    super doSaveAs ifTrue:[
	listOfItems root rawLabel:specSelector
    ].
!

doShowMenuSpec
    "opens a code view with the contents of the menu spec
    "
    |spec|

    spec := self generateMenuSpec.

    spec ifNotNil:[
        CodeView openWith:spec title: 'Menu Spec'
    ].
! !

!MenuEditor methodsFor:'user actions - creation'!

doCreateDelayedMenu:what
    |selectedItem delayedItem|

    selectedItem := self selectedItem.
    selectedItem ifNil:[^ self].

    selectedItem canAddDelayedMenu      ifFalse:[ ^ self ].
    self askForItemModification ifFalse:[ ^ self ].

    what == #menu ifTrue:[ delayedItem := ItemMenu new ]
                 ifFalse:[ delayedItem := ItemLinkedMenu new ].

    delayedItem setExpanded:true.
    delayedItem := selectedItem add:delayedItem.

    delayedItem ifNotNil:[
        self selectedItem:delayedItem.
    ].
!

doCreateItem
    "create a new Item
    "
    self addAndSelect:[ ItemAction new ].
!

doCreateLinkedMenu
    "create a new Linked Menu
    "
    self addAndSelect:[ ItemLinkedMenu new ].
!

doCreateMenu
    "create a new Menu
    "
    self addAndSelect:[ |item|
	item := ItemMenu new.
	item expand.
	item
    ].
!

doCreateSep
    "create a new Separator Item
    "
    self addAndSelect:[ ItemSeparator new ].
!

doCreateStandardEditMenu
    "create a standart edit menu
    "
    self addAndSelect:[
	ItemMenu menu:(self class standardEditMenu) labeled:'Edit'
    ].
!

doCreateStandardFileMenu
    "create a standart file menu
    "
    self addAndSelect:[
	ItemMenu menu:(self class standardFileMenu) labeled:'File'
    ].
!

doCreateStandardHelpMenu
    "create a standart help menu
    "
    |item|

    self addAndSelect:[
	item := ItemMenu menu:(self class standardHelpMenu) labeled:'Help'.
	item aspectAt:#startGroup put:#right.
	item
    ].
! !

!MenuEditor methodsFor:'user actions - editing'!

doCopy
    "copy selected menuItems to the clipboard
    "
    |clip items|

    items := self selectedSuperItems.
    items isEmpty ifTrue:[ ^ self ].

    clip := OrderedCollection new.
    items do:[:el| clip add:(el menuItem) ].

    self clipboard:clip.
    self updateAllToolInstances.
!

doCut
    "copy selected menuItems to the clipboard and delete
    "
    self doCopy.
    self doDelete.
!

doDelete
    "delete selected menuItems
    "
    |selectedItem parent toDelete behind nextItem prevItem|

    toDelete := self selectedSuperItems.
    toDelete isEmpty ifTrue:[ ^ self ].

    self clearModified.

    selectedItem := toDelete first.

    selectedItem isRootItem ifTrue:[
        ^ selectedItem removeAll.
    ].
    "/ compute the new selection

    prevItem := parent := selectedItem parent.
    nextItem := nil.

    parent children size ~~ 1 ifTrue:[
        behind := false.

        parent do:[:el|
            behind ifTrue:[
                (nextItem notNil or:[toDelete includesIdentical:el]) ifFalse:[ nextItem := el ].
            ] ifFalse:[
                behind := el == selectedItem.
                (behind or:[toDelete includesIdentical:el]) ifFalse:[ prevItem := el ].
            ]
        ]
    ].
    self withoutNotifyDo:[
        toDelete do:[:el| el remove ].
    ].
    self selectedItem:(nextItem ? prevItem).
    modified := true.
    self updateChannels.
!

doPaste
    "paste from clipboard
    "
    ^ self doPaste:(self clipboard)
!

doPaste:aCollection
    "paste collection of MenuItems
    "
    |item loMenuItems|

    aCollection size == 0 ifTrue:[ ^ self ].

    item := self selectedItem.
    item ifNil:[ ^ self ].

    loMenuItems := OrderedCollection new.
    aCollection do:[:el|
	el class == MenuItem ifTrue:[ loMenuItems add:el ].
    ].
    loMenuItems isEmpty ifTrue:[ ^ self ].

    self addAndSelect:[
	loMenuItems collect:[:el| Item menuItem:el ]
    ].
! !

!MenuEditor methodsFor:'user actions - hierarchy'!

doMoveIn:aDirection
    "move selected item into the next (#inNext) or previous (#inPrev) item
    "
    |item idx parent toParent|

    item := self selectedItem.
    item ifNil:[^ self].

    aDirection == #inNext ifTrue:[ item canMoveInNext  ifFalse:[^ self] ]
			 ifFalse:[ item canMoveInAbove ifFalse:[^ self] ].

    self askForItemModification ifFalse:[ ^ self ].

    parent := item parent.
    idx    := parent identityIndexOf:item.

    aDirection == #inNext ifTrue:[ toParent := parent at:(idx + 1) ifAbsent:nil ]
			 ifFalse:[ toParent := parent at:(idx - 1) ifAbsent:nil ].

    self withoutNotifyDo:[
	selectionHolder setValue:#().
	parent removeIndex:idx.

	aDirection == #inNext ifTrue:[ toParent addFirst:item ]
			     ifFalse:[ toParent  addLast:item ].
	item makeVisible.
    ].
    self selectedItem:item.
    modified := true.
!

doMoveOut
    "move selected item out of current item
    "
    |item parent grandParent index|

    item := self selectedItem.
    item ifNil:[^ self].
    item canMoveOut ifFalse:[^ self].

    self askForItemModification ifFalse:[ ^ self ].

    parent      := item parent.
    grandParent := parent parent.
    index       := grandParent identityIndexOf:parent.

    self withoutNotifyDo:[
	selectionHolder setValue:#().
	parent remove:item.
	index > grandParent size ifTrue:[ grandParent add:item ]
				ifFalse:[ grandParent add:item afterIndex:index ]
    ].
    self selectedItem:item.
    modified := true.
!

doMoveUpOrDown:aDirection
    "move selected item up (#up) or down (#down)
    "
    |item index parent children|

    item := self selectedItem.
    item ifNil:[^ self].
    item canMoveUpOrDown ifFalse:[^ self].

    self askForItemModification ifFalse:[ ^ self ].

    self withoutNotifyDo:[
	parent   := item parent.
	children := parent children.
	index    := children identityIndexOf:item.

	selectionHolder setValue:#().
	children removeIndex:index.

	aDirection == #up ifTrue:[
	    index == 1 ifTrue:[ children add:item ]
		      ifFalse:[ children add:item beforeIndex:index - 1 ]
	] ifFalse:[
	    index > children size ifTrue:[ children addFirst:item ]
				 ifFalse:[ children add:item afterIndex:index ]
	].
	parent childrenOrderChanged.
    ].
    self selectedItem:item.
    modified := true.
! !

!MenuEditor::Item class methodsFor:'defaults'!

defaultLabel
    ^ self subclassResponsibility
! !

!MenuEditor::Item class methodsFor:'image specs'!

iconDelayedLinkedMenu
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconDelayedLinkedMenu inspect
     ImageEditor openOnClass:self andSelector:#iconDelayedLinkedMenu
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'MenuEditor::Item class iconDelayedLinkedMenu'
        ifAbsentPut:[(Depth4Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@DQDQDQDQDQDR@AH"H"H"H"H"H0@@@BH"H"@@@BL@QDPBH"H"@@H#@DQDPBH@H"@"H0ADQDPBA@H"H"L@@@QDP@Q@@@@@@ADPQDQDQ@DQD 
@RH QDQDQ@H"L@D"H QDQD@"H#@A@@@@@DP@@@@0@QDQDQA@DQDQL@D"H"H @"H"H#@BL3L3L3L3L3L0@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127 255 0 0]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0') ; yourself); yourself]
!

iconDelayedMenu
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconDelayedMenu inspect
     ImageEditor openOnClass:self andSelector:#iconDelayedMenu
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'MenuEditor::Item class iconDelayedMenu'
        ifAbsentPut:[(Depth2Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@UUUUUVA*****,F***@B0Z***@+A****J,F*****0@@@@@@AUUUUUXF*****0Z****+A@@@@@LEUUUUU0Z****+B?????<@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0') ; yourself); yourself]
!

iconItem
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconItem inspect
     ImageEditor openOnClass:self andSelector:#iconItem
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
	constantNamed:#'MenuEditor::Item class iconItem'
	ifAbsentPut:[(Depth2Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'UUUUUUUUUUUUUP@@@@@@EUUUUU Z****+A.?/;+,F:::/>0[++>:;A...++,F::?..0Z****+B?????<@@@@@@@@@@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@???0???0???0???0???0???0???0???0???0???0???0@@@@@@@@@@@@') ; yourself); yourself]
!

iconLinkedMenu
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconLinkedMenu inspect
     ImageEditor openOnClass:self andSelector:#iconLinkedMenu
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
	constantNamed:#'MenuEditor::Item class iconLinkedMenu'
	ifAbsentPut:[(Depth4Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@QDQDQDQDQDQA@DH"H"H"H"H"HPABH@@@H"H"H"D@PQ@3L0DQDQDQ@D@@L3L0@@@@@PADPCL3L0PCADD@P"@@@3L0@3@!!@DH"H"@3L3L3@P
AADQDQ@3L3L3@@P@@@@@@3L3LA@DQDQDQD@@L0PPABH"H"H"HC@"D@P"H"H"H"@BH!!@BDQDQDQDQDQDP@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 127 127 127 170 170 170 255 0 0 255 255 255]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0') ; yourself); yourself]
!

iconMenu
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconMenu inspect
     ImageEditor openOnClass:self andSelector:#iconMenu
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
	constantNamed:#'MenuEditor::Item class iconMenu'
	ifAbsentPut:[(Depth2Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@?????=C*****$N*****P5UUUUUC@@@@@DO?????P:****)C*****$MUUUUUP0@@@@AC?????4N*****P:****)BUUUUUT@@@@@@@b') ; colorMapFromArray:#[0 0 0 127 127 127 170 170 170 255 255 255]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0???0') ; yourself); yourself]
!

iconSeparator
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     self iconSeparator inspect
     ImageEditor openOnClass:self andSelector:#iconSeparator
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
	constantNamed:#'MenuEditor::Item class iconSeparator'
	ifAbsentPut:[(Depth2Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'UUUUUUUUUUUUUP@@@@@@EUUUUU Z****+A*****,F????:0[@@@@[A)UUUU,F*****0Z****+B?????<@@@@@@@@@@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 20; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@???0???0???0???0???0???0???0???0???0???0???0@@@@@@@@@@@@') ; yourself); yourself]
! !

!MenuEditor::Item class methodsFor:'instance creation'!

classFor:aMenuItem

    aMenuItem ifNil:[ ^ nil ].

    aMenuItem value ifNil:[
	aMenuItem submenu        ifNotNil:[ ^ MenuEditor::ItemMenu ].
	aMenuItem submenuChannel ifNotNil:[ ^ MenuEditor::ItemLinkedMenu ].

	(self separatorTypeOf:(aMenuItem rawLabel)) notNil ifTrue:[
	    ^ MenuEditor::ItemSeparator
	]
    ].
    ^ MenuEditor::ItemAction
!

menuItem:aMenuItem
    |item cls|

    cls := self classFor:aMenuItem.
    cls ifNil:[^ nil].

    item := cls new.
    item menuItem:aMenuItem.
  ^ item
! !

!MenuEditor::Item class methodsFor:'interface - editor'!

addBindingsTo:aspects for:aMenuEditor
    "add additional bindings to the aspects
    "
    aspects at:#notDelayedMenu ifAbsentPut:[
        true asValue
    ].
! !

!MenuEditor::Item class methodsFor:'interface - specs'!

detailsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

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

    <resource: #canvas>

    ^ 
     #(#FullSpec
	#name: #detailsEditSpec
	#window: 
       #(#WindowSpec
	  #label: 'Details Edit'
	  #name: 'Details Edit'
	  #min: #(#Point 10 10)
	  #max: #(#Point 1280 1024)
	  #bounds: #(#Rectangle 43 153 303 398)
	)
	#component: 
       #(#SpecCollection
	  #collection: #(
	   #(#LabelSpec
	      #label: 'Accelerator:'
	      #name: 'shortcutKeyLabel'
	      #layout: #(#AlignmentOrigin 107 0 26 0 1 0.5)
	      #activeHelpKey: #detailsAccelerator
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'shortcutKeyField'
	      #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
	      #activeHelpKey: #detailsAccelerator
	      #tabable: true
	      #model: #shortcutKeyCharacter
	      #group: #inputGroup
	      #type: #symbolOrNil
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Enabled:'
	      #name: 'enabledLabel'
	      #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
	      #activeHelpKey: #detailsEnabled
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'enabledField'
	      #layout: #(#LayoutFrame 110 0 40 0 -5 1.0 62 0)
	      #activeHelpKey: #detailsEnabled
	      #tabable: true
	      #model: #enabled
	      #group: #inputGroup
	      #type: #symbolOrNil
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Visibility:'
	      #name: 'visibilityLabel'
	      #layout: #(#AlignmentOrigin 107 0 76 0 1 0.5)
	      #activeHelpKey: #detailsVisibility
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'isVisibleInputField'
	      #layout: #(#LayoutFrame 110 0 65 0 -5 1.0 87 0)
	      #activeHelpKey: #detailsVisibility
	      #tabable: true
	      #model: #isVisible
	      #group: #inputGroup
	      #type: #symbolOrNil
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Aux Value'
	      #name: 'auxLabel'
	      #layout: #(#AlignmentOrigin 107 0 101 0 1 0.5)
	      #activeHelpKey: #detailsAuxValue
	      #translateLabel: true
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'auxInputField'
	      #layout: #(#LayoutFrame 110 0 90 0 -5 1.0 112 0)
	      #activeHelpKey: #detailsAuxValue
	      #tabable: true
	      #model: #auxValue
	      #group: #inputGroup
	      #type: #smalltalkObject
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Start Group:'
	      #name: 'StartGroupLabel'
	      #layout: #(#AlignmentOrigin 107 0 139 0 1 0.5)
	      #activeHelpKey: #detailsStartGroup
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#PopUpListSpec
	      #label: 'left'
	      #name: 'StartGroupPopUp'
	      #layout: #(#LayoutFrame 110 0 128 0 -5 1.0 150 0)
	      #activeHelpKey: #detailsStartGroup
	      #tabable: true
	      #model: #startGroup
	      #menu: 
	     #(#left
		#right
	      )
	    )
	   #(#LabelSpec
	      #label: 'Access Character Position:'
	      #name: 'accessCharLabel'
	      #layout: #(#AlignmentOrigin 217 0 170 0 1 0.5)
	      #activeHelpKey: #detailsAccessCharaterPosition
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'accessCharField'
	      #layout: #(#LayoutFrame 220 0 159 0 -5 1.0 181 0)
	      #activeHelpKey: #detailsAccessCharaterPosition
	      #tabable: true
	      #model: #accessCharacterPosition
	      #group: #inputGroup
	      #type: #numberOrNil
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Font:'
	      #name: 'fontLabel'
	      #layout: #(#AlignmentOrigin 75 0 219 0 1 0.5)
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#FontMenuSpec
	      #attributes: 
	     #(#tabable
		true
	      )
	      #name: 'fontMenu'
	      #layout: #(#LayoutFrame 78 0 208 0 -5 1.0 230 0)
	      #activeHelpKey: #fontMenu
	      #model: #font
	    )
	   )
         
	)
      )
! !

!MenuEditor::Item class methodsFor:'testing'!

separatorTypeOf:aString
    |size first|

    size := aString size.

    size == 0 ifTrue:[ ^ #blank ].

    size == 1 ifTrue:[
	first := aString first.
	first == $-                ifTrue:[ ^ #single ].
	first == $=                ifTrue:[ ^ #double ].
	first == (Character space) ifTrue:[ ^ #blank  ].
    ].
    ^ nil
! !

!MenuEditor::Item methodsFor:'accessing'!

children
    "optimize access; do not ask the model for unspecified children
    "
    ^ children
!

menuItem
     "returns self as a MenuItem
    "
    ^ MenuItem new fromLiteralArrayEncoding:(menuItem literalArrayEncoding).
!

menuItem:aMenuItem
    "rebuild self from a MenuItem
    "
    |value|

    menuItem := MenuItem labeled:(self rawLabel).

    MenuEditor aspects do:[:aKey|
	value := aMenuItem perform:aKey.
	value ifNotNil:[ self aspectAt:aKey put:value ]
    ].
!

rawLabel
    "returns the label assigned to the item
    "
    ^ menuItem rawLabel
!

rawLabel:aValue
    "set the label assigned to the item
    "
    aValue isString ifTrue:[
	(self class separatorTypeOf:aValue) ifNil:[
	    menuItem rawLabel:aValue
	]
    ].
!

slices
    "returns a sequence of supported slices
    "
    ^ self subclassResponsibility
!

submenu
    "returns the submenu (of class Menu) or nil
    "
    ^ nil
! !

!MenuEditor::Item methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "set a specific aspect named aKey to the aValue
    "
    aKey == #rawLabel       ifTrue:[ ^ self rawLabel:aValue ].
    aKey == #submenuChannel ifTrue:[ ^ self ].

    menuItem perform:((aKey, ':') asSymbol) with:aValue.
!

fromAspects:aspects
    "read values from aspects
    "
    MenuEditor aspects do:[:aKey|
	self aspectAt:aKey put:((aspects at:aKey) value)
    ].
    self changed.
!

toAspects:aspects
    "write values to aspects
    "
    MenuEditor aspects do:[:aKey|
        (aspects at:aKey) value:(menuItem perform:aKey)
    ].
    (aspects at:#notDelayedMenu) value:(self isDelayedMenu not).
! !

!MenuEditor::Item methodsFor:'displaying'!

displayLabel
    "returns the label on default displayed on the screen
    "
    ^ menuItem rawLabel
!

displayOn:aGC x:x y:y h:h
    "display the item in the graphicsContext, aGC.
    "
    |label|

    label := self displayLabel.

    label notNil ifTrue:[
	self displayLabel:label h:(self heightOn:aGC) on:aGC x:x y:y h:h
    ].
!

heightOn:aGC
    "returns the height of the label on a GC
    "
    height ifNil:[ height := parent heightOn:aGC ].
  ^ height
!

label
    "get the rawLabel assigned to the item
    "
    ^ menuItem rawLabel
!

label:aLabel
    "set the rawLabel assigned to the item
    "
    self rawLabel:aLabel
!

widthOn:aGC
    "returns the height of the displayLabel on a GC
    "
    width ifNil:[ width := self widthOf:(self displayLabel) on:aGC ].
  ^ width
! !

!MenuEditor::Item methodsFor:'initialization'!

initialize
    super initialize.
    menuItem := MenuItem label:(self class defaultLabel).
! !

!MenuEditor::Item methodsFor:'queries'!

isAction
    "returns true if the item is an Action
    "
    ^ false
!

isDelayedMenu
    "returns true if the item is a Delayed (Linked) Menu
    "
    ^ parent isAction
!

isKindOfMenu
    "returns true if the item is a Linked Menu or Menu
    "
    ^ false
!

isRootItem
    "returns true if the item is the root item
    "
    ^ false
! !

!MenuEditor::Item methodsFor:'queries - editor'!

actionSelectors
    "returns my action selectors
    "
    |value|

    value := menuItem value.
    value isSymbol ifTrue:[ ^ Array with:value ].
  ^ #()
!

aspectSelectors
    "returns my aspect selectors
    "
    |aspects|

    aspects := OrderedCollection new.

    #( indication choice enabled isVisible ) do:[:aKey| |sel|
        sel := menuItem perform:aKey.
        sel isSymbol ifTrue:[ aspects add:sel ]
    ].    
    ^ aspects
! !

!MenuEditor::Item methodsFor:'queries - operation'!

canAddChildren
    "returns true if children can be added
    "
    ^ false
!

canAddDelayedMenu
    "returns true if a delayed menu can be added;
     on default false is returned
    "
    ^ false
!

canMoveInAbove
    "returns true if the item can become a child of its previous sibling
    "
    |siblings index nextItem|

    siblings := parent children.
    siblings size > 1 ifFalse:[ ^ false ].

    index    := siblings identityIndexOf:self.
    nextItem := siblings at:(index - 1)  ifAbsent:nil.

    nextItem ifNil:[^ false].
  ^ nextItem canAddChildren
!

canMoveInNext
    "returns true if the item can become a child of its next sibling
    "
    |siblings index nextItem|

    siblings := parent children.
    siblings size > 1 ifFalse:[ ^ false ].

    index    := siblings identityIndexOf:self.
    nextItem := siblings at:(index + 1)  ifAbsent:nil.

    nextItem ifNil:[^ false].
  ^ nextItem canAddChildren
!

canMoveOut
    "returns true if the item can be moved out from its current parent
    "
    self   isDelayedMenu ifTrue:[^ false].
    parent isDelayedMenu ifTrue:[^ false].

  ^ parent parent notNil
!

canMoveUpOrDown
    "returns true if the item can change its vertical order in its sibling
    "
    ^ parent children size > 1
! !

!MenuEditor::ItemAction class methodsFor:'defaults'!

defaultLabel
    ^ 'Action'
! !

!MenuEditor::ItemAction class methodsFor:'interface - editor'!

addBindingsTo:aspects for:aMenuEditor
    "add additional bindings to the aspects
    "
    aspects at:#indicationEnabled  ifAbsentPut:[
	BlockValue with:[:a | a size == 0 ] argument:(aspects at:#choice)
    ].

    aspects at:#choiceEnabled ifAbsentPut:[
	BlockValue with:[:a | a size == 0 ] argument:(aspects at:#indication)
    ].

    aspects at:#choiceValueEnabled ifAbsentPut:[
	BlockValue with:[:a | a size ~~ 0 ] argument:(aspects at:#choice)
    ].
    aspects at:#hasNoDelayedMenuValue ifAbsentPut:[
	true asValue
    ].
! !

!MenuEditor::ItemAction class methodsFor:'interface - specs'!

basicsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:MenuEditor::ItemAction andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #basicsEditSpec
        #window: 
       #(#WindowSpec
          #label: 'basicsEditSpec'
          #name: 'basicsEditSpec'
          #min: #(#Point 10 10)
          #max: #(#Point 1160 870)
          #bounds: #(#Rectangle 9 625 349 965)
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#LabelSpec
              #label: 'Name Key:'
              #name: 'nameKeyLabel'
              #layout: #(#AlignmentOrigin 107 0 25 0 1 0.5)
              #activeHelpKey: #basicsKey
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'nameKeyField'
              #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
              #activeHelpKey: #basicsKey
              #tabable: true
              #model: #nameKey
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: false
              #acceptOnLeave: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Label:'
              #name: 'labelLabel'
              #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
              #activeHelpKey: #basicsLabel
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'labelField'
              #layout: #(#LayoutFrame 110 0 40 0 -5 1.0 62 0)
              #activeHelpKey: #basicsLabel
              #tabable: true
              #model: #rawLabel
              #group: #inputGroup
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Action:'
              #name: 'valueLabel'
              #layout: #(#AlignmentOrigin 107 0 82 0 1 0.5)
              #activeHelpKey: #basicsAction
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'valueField'
              #layout: #(#LayoutFrame 110 0 71 0 -5 1.0 93 0)
              #activeHelpKey: #basicsAction
              #tabable: true
              #model: #value
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Argument:'
              #name: 'argumentLabel'
              #layout: #(#AlignmentOrigin 107 0 107 0 1 0.5)
              #activeHelpKey: #basicsArgument
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'argumentField'
              #layout: #(#LayoutFrame 110 0 96 0 -5 1.0 118 0)
              #activeHelpKey: #basicsArgument
              #tabable: true
              #model: #argument
              #group: #inputGroup
              #type: #smalltalkObject
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Indication:'
              #name: 'indicationLabel'
              #layout: #(#AlignmentOrigin 107 0 138 0 1 0.5)
              #activeHelpKey: #basicsIndication
              #visibilityChannel: #hasNoDelayedMenuValue
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'indicationField'
              #layout: #(#LayoutFrame 110 0 127 0 -5 1.0 149 0)
              #activeHelpKey: #basicsIndication
              #visibilityChannel: #hasNoDelayedMenuValue
              #enableChannel: #indicationEnabled
              #tabable: true
              #model: #indication
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: true
              #acceptOnReturn: false
              #acceptOnTab: false
              #acceptOnLostFocus: false
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Choice:'
              #name: 'choiceLabel'
              #layout: #(#AlignmentOrigin 107 0 163 0 1 0.5)
              #activeHelpKey: #basicsChoice
              #visibilityChannel: #hasNoDelayedMenuValue
              #translateLabel: true
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'choiceField'
              #layout: #(#LayoutFrame 110 0 152 0 -5 1.0 174 0)
              #activeHelpKey: #basicsChoice
              #visibilityChannel: #hasNoDelayedMenuValue
              #enableChannel: #choiceEnabled
              #tabable: true
              #model: #choice
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: true
              #acceptOnReturn: false
              #acceptOnTab: false
              #acceptOnLostFocus: false
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Value:'
              #name: 'choiceValueLabel'
              #layout: #(#AlignmentOrigin 107 0 188 0 1 0.5)
              #activeHelpKey: #basicsChoiceValue
              #visibilityChannel: #hasNoDelayedMenuValue
              #translateLabel: true
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'choiceValueField'
              #layout: #(#LayoutFrame 110 0 177 0 -5 1.0 199 0)
              #activeHelpKey: #basicsChoiceValue
              #visibilityChannel: #hasNoDelayedMenuValue
              #enableChannel: #choiceValueEnabled
              #tabable: true
              #model: #choiceValue
              #group: #inputGroup
              #type: #smalltalkObject
              #immediateAccept: false
              #acceptOnLeave: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#CheckBoxSpec
              #label: 'Translate Label'
              #name: 'translateLabelCheckBox'
              #layout: #(#Point 20 213)
              #activeHelpKey: #basicsTranslateLabel
              #tabable: true
              #model: #translateLabel
            )
           #(#CheckBoxSpec
              #label: 'Is Button'
              #name: 'isButtonCheckBox'
              #layout: #(#Point 20 238)
              #activeHelpKey: #basicsIsButton
              #tabable: true
              #model: #isButton
            )
           #(#CheckBoxSpec
              #label: 'Hide Menu after Activation'
              #name: 'hideMenuOnActivated'
              #layout: #(#Point 20 263)
              #activeHelpKey: #hideMenuOnActivated
              #tabable: true
              #model: #hideMenuOnActivated
            )
           #(#CheckBoxSpec
              #label: 'BusyCursor while Active'
              #name: 'showBusyCursorWhilePerforming'
              #layout: #(#Point 20 288)
              #activeHelpKey: #showBusyCursorWhilePerforming
              #tabable: true
              #model: #showBusyCursorWhilePerforming
              #translateLabel: true
            )
           #(#CheckBoxSpec
              #label: 'Trigger On Down'
              #name: 'triggerOnDown'
              #layout: #(#Point 20 313)
              #activeHelpKey: #triggerOnDown
              #visibilityChannel: #hasNoDelayedMenuValue
              #tabable: true
              #model: #triggerOnDown
              #translateLabel: true
            )
           )
         
        )
      )
! !

!MenuEditor::ItemAction methodsFor:'accessing'!

menuItem
    |item|

    item := super menuItem.

    self hasDelayedMenu ifTrue:[
        children first setDelayedAttributesTo:item.

        menuItem value ifNil:[
            menuItem value:#unspecified
        ]
    ].
    ^ item
!

menuItem:anItem
    |submenu item|

    super menuItem:anItem.
    submenu := anItem submenu.

    submenu notNil ifTrue:[
	item := MenuEditor::ItemMenu new
    ] ifFalse:[
	anItem submenuChannel ifNil:[
	    ^ self
	].
	item := MenuEditor::ItemLinkedMenu new
    ].
    item getDelayedAttributesFrom:anItem.
    self add:item.
!

slices
    ^ #(
	    (Basics   basicsEditSpec )
	    (Details  detailsEditSpec)
	    (Image    image  )
	    (Help     help)
       )
! !

!MenuEditor::ItemAction methodsFor:'adding & removing'!

add:anItem
    "add an item; test whether the item is a delayed menu and
     not already a delayed menu exists.
    "
    (anItem isKindOfMenu and:[self canAddDelayedMenu]) ifFalse:[
        ^ nil
    ].
    "/ reset values not setable if a delayed menu is configured

    menuItem        choice:nil.
    menuItem    indication:nil.
    menuItem   choiceValue:nil.
    menuItem triggerOnDown:false.

    anItem argument:(menuItem argument).

    isExpanded := false.
    anItem parent:self.
    children := Array with:anItem.
    self expand.
  ^ anItem
! !

!MenuEditor::ItemAction methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "pass the argument to the delayed menu if existant
    "
    aKey == #argument ifTrue:[
        self hasDelayedMenu ifTrue:[
            children first argument:aValue
        ].
        menuItem argument:aValue.
      ^ self
    ].
    super aspectAt:aKey put:aValue.
!

toAspects:aspects
    "write values to aspects
    "
    super toAspects:aspects.

    (aspects at:#hasNoDelayedMenuValue) value:(self hasDelayedMenu not).
! !

!MenuEditor::ItemAction methodsFor:'displaying'!

icon
    ^ self class iconItem
! !

!MenuEditor::ItemAction methodsFor:'initialization'!

initialize
    super initialize.
    isExpanded := true.
! !

!MenuEditor::ItemAction methodsFor:'queries'!

canCollapse
    ^ false
!

hasDelayedMenu
    "returns true if a delayed menu exists
    "
    ^ children size ~~ 0
!

hasIndicator
    ^ false
!

isAction
    ^ true
! !

!MenuEditor::ItemAction methodsFor:'queries - operation'!

canAddDelayedMenu
    "returns true if a delayed menu can be added;
     no delayed menu exists and the indication or choice is unspecified
    "
    self hasDelayedMenu ifTrue:[ ^ false ].
  ^ (menuItem indication isNil and:[menuItem choice isNil])
! !

!MenuEditor::ItemLinkedMenu class methodsFor:'defaults'!

defaultLabel
    ^ 'Linked Menu'
! !

!MenuEditor::ItemLinkedMenu class methodsFor:'interface - specs'!

basicsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:MenuEditor::ItemLinkedMenu andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #basicsEditSpec
        #window: 
       #(#WindowSpec
          #label: 'basicsEditSpec'
          #name: 'basicsEditSpec'
          #min: #(#Point 10 10)
          #max: #(#Point 1160 870)
          #bounds: #(#Rectangle 93 330 433 670)
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#LabelSpec
              #label: 'Name Key:'
              #name: 'nameKeyLabel'
              #layout: #(#AlignmentOrigin 107 0 25 0 1 0.5)
              #activeHelpKey: #basicsKey
              #visibilityChannel: #notDelayedMenu
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'nameKeyField'
              #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
              #activeHelpKey: #basicsKey
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #nameKey
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: false
              #acceptOnLeave: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Label:'
              #name: 'labelLabel'
              #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
              #activeHelpKey: #basicsLabel
              #visibilityChannel: #notDelayedMenu
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'labelField'
              #layout: #(#LayoutFrame 110 0 40 0 -5 1.0 62 0)
              #activeHelpKey: #basicsLabel
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #rawLabel
              #group: #inputGroup
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Menu:'
              #name: 'menuLabel'
              #layout: #(#AlignmentOrigin 107 0 90 0 1 0.5)
              #activeHelpKey: #basicsLabel
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'menuField'
              #layout: #(#LayoutFrame 110 0 79 0 -5 1.0 101 0)
              #activeHelpKey: #basicsMenu
              #tabable: true
              #model: #submenuChannel
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Argument:'
              #name: 'argumentLabel'
              #layout: #(#AlignmentOrigin 107 0 115 0 1 0.5)
              #activeHelpKey: #basicsLabel
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'argumentField'
              #layout: #(#LayoutFrame 110 0 104 0 -5 1.0 126 0)
              #activeHelpKey: #basicsMenuArgument
              #enableChannel: #notDelayedMenu
              #tabable: true
              #model: #argument
              #group: #inputGroup
              #type: #smalltalkObject
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#CheckBoxSpec
              #label: 'Translate Label'
              #name: 'translateLabelCheckBox'
              #layout: #(#Point 20 213)
              #activeHelpKey: #basicsTranslateLabel
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #translateLabel
            )
           #(#CheckBoxSpec
              #label: 'Is Button'
              #name: 'isButtonCheckBox'
              #layout: #(#Point 20 238)
              #activeHelpKey: #basicsIsButton
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #isButton
            )
           #(#CheckBoxSpec
              #label: 'Has Horizontal Layout'
              #name: 'horizontalLayout'
              #layout: #(#Point 20 263)
              #activeHelpKey: #horizontalLayout
              #tabable: true
              #model: #horizontalLayout
            )
           #(#CheckBoxSpec
              #label: 'Do not destroy linked Menu'
              #name: 'keepLinkedMenu'
              #layout: #(#Point 20 288)
              #activeHelpKey: #keepLinkedMenu
              #tabable: true
              #model: #keepLinkedMenu
              #translateLabel: true
            )
           )
         
        )
      )
! !

!MenuEditor::ItemLinkedMenu methodsFor:'accessing'!

argument:aValue
    menuItem argument:aValue.
!

menuItem
     "returns self as a MenuItem
    "
    |item|

    item := super menuItem.
    item submenuChannel:(self submenuChannel).
  ^ item
!

slices
    self isDelayedMenu ifTrue:[
        ^ #(
                (Basics   basicsEditSpec )
           )
    ].

    ^ #(
            (Basics   basicsEditSpec )
            (Details  detailsEditSpec)
            (Image    image  )
            (Help     help)
       )
!

submenuChannel
    ^ menuItem submenuChannel ? #unspecified
!

submenuChannel:aValue
    menuItem submenuChannel:aValue.
! !

!MenuEditor::ItemLinkedMenu methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "set a specific aspect named aKey to the aValue
    "
    aKey == #submenuChannel ifTrue:[ ^ self submenuChannel:aValue ].
    super aspectAt:aKey put:aValue.
!

getDelayedAttributesFrom:aMenuItem
    menuItem rawLabel:'Delayed'.

    menuItem   submenuChannel:(aMenuItem submenuChannel).
    menuItem horizontalLayout:(aMenuItem horizontalLayout).
    menuItem   keepLinkedMenu:(aMenuItem keepLinkedMenu).
!

setDelayedAttributesTo:aMenuItem
    aMenuItem   submenuChannel:(self submenuChannel).
    aMenuItem horizontalLayout:(menuItem horizontalLayout).
    aMenuItem   keepLinkedMenu:(menuItem keepLinkedMenu).
! !

!MenuEditor::ItemLinkedMenu methodsFor:'displaying'!

displayLabel
    "returns the label dependent on is delayed or not
    "
    self isDelayedMenu ifTrue:[ ^ self submenuChannel ].
  ^ menuItem rawLabel
!

icon
    self isDelayedMenu ifTrue:[ ^ self class iconDelayedLinkedMenu ].
  ^ self class iconLinkedMenu
! !

!MenuEditor::ItemLinkedMenu methodsFor:'queries'!

isKindOfMenu
    ^ true
! !

!MenuEditor::ItemMenu class methodsFor:'defaults'!

defaultDelayedLabel
    ^ 'delayed'
!

defaultLabel
    ^ 'Menu'
! !

!MenuEditor::ItemMenu class methodsFor:'instance creation'!

menu:aMenu labeled:aString
    |item|

    item := self new.
    item menu:aMenu labeled:aString.
  ^ item
! !

!MenuEditor::ItemMenu class methodsFor:'interface - specs'!

basicsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:MenuEditor::ItemMenu andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #basicsEditSpec
        #window: 
       #(#WindowSpec
          #label: 'basicsEditSpec'
          #name: 'basicsEditSpec'
          #min: #(#Point 10 10)
          #max: #(#Point 1160 870)
          #bounds: #(#Rectangle 810 135 1150 475)
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#LabelSpec
              #label: 'Name Key:'
              #name: 'nameKeyLabel'
              #layout: #(#AlignmentOrigin 107 0 25 0 1 0.5)
              #activeHelpKey: #basicsKey
              #visibilityChannel: #notDelayedMenu
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'nameKeyField'
              #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
              #activeHelpKey: #basicsKey
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #nameKey
              #group: #inputGroup
              #type: #symbolOrNil
              #immediateAccept: false
              #acceptOnLeave: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#LabelSpec
              #label: 'Label:'
              #name: 'labelLabel'
              #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
              #activeHelpKey: #basicsLabel
              #visibilityChannel: #notDelayedMenu
              #resizeForLabel: true
              #adjust: #right
            )
           #(#InputFieldSpec
              #name: 'labelField'
              #layout: #(#LayoutFrame 110 0 40 0 -5 1.0 62 0)
              #activeHelpKey: #basicsLabel
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #rawLabel
              #group: #inputGroup
              #immediateAccept: false
              #acceptOnReturn: true
              #acceptOnTab: true
              #acceptOnLostFocus: false
              #acceptChannel: #acceptChannel
              #modifiedChannel: #modifiedChannel
              #acceptOnPointerLeave: false
            )
           #(#CheckBoxSpec
              #label: 'Translate Label'
              #name: 'translateLabelCheckBox'
              #layout: #(#Point 20 213)
              #activeHelpKey: #basicsTranslateLabel
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #translateLabel
            )
           #(#CheckBoxSpec
              #label: 'Is Button'
              #name: 'isButtonCheckBox'
              #layout: #(#Point 20 238)
              #activeHelpKey: #basicsIsButton
              #visibilityChannel: #notDelayedMenu
              #tabable: true
              #model: #isButton
            )
           #(#CheckBoxSpec
              #label: 'Has Horizontal Layout'
              #name: 'horizontalLayout'
              #layout: #(#Point 20 263)
              #activeHelpKey: #horizontalLayout
              #tabable: true
              #model: #horizontalLayout
            )
           )
         
        )
      )
! !

!MenuEditor::ItemMenu methodsFor:'accessing'!

argument:aValue
    "/ ignorred.
!

menu:aMenu labeled:aString
    |expanded item menu|

    self criticalDo:[
	self isRootItem ifTrue:[ expanded := true ]
		       ifFalse:[ expanded := isExpanded ].

	self removeAll.
	self rawLabel:aString.

	aMenu ifNotNil:[
	    aMenu isCollection ifTrue:[ menu := Menu new fromLiteralArrayEncoding:aMenu ]
			      ifFalse:[ menu := aMenu ].

	    menu numberOfItems == 0 ifTrue:[
		menu := nil
	    ].
	].
	menu ifNotNil:[
	    isExpanded := false.        "/ discard change notifications
	    children   := OrderedCollection new.

	    menu itemsDo:[:el|
		item := self class menuItem:el.
		item parent:self.
		children add:item.
	    ].
	    expanded ifTrue:[ self expand ].
	].
	isExpanded := expanded.
    ].        
    self changed
!

menuItem
    "returns self as a MenuItem
    "
    |item|

    item := super menuItem.
    item submenu:(self submenu).
  ^ item
!

menuItem:anItem

    super menuItem:anItem.
    self  menu:(anItem submenu) labeled:nil.
!

slices
    self isDelayedMenu ifTrue:[
        ^ #(
                (Basics   basicsEditSpec )
           )
    ].

    ^ #(
            (Basics   basicsEditSpec )
            (Details  detailsEditSpec)
            (Image    image  )
            (Help     help)
       )
!

submenu
    |menu|

    menu := Menu new.

    children size ~~ 0 ifTrue:[
	children do:[:el| menu addItem:(el menuItem) ].
    ].
    ^ menu
! !

!MenuEditor::ItemMenu methodsFor:'aspects'!

getDelayedAttributesFrom:aMenuItem

    self menu:(aMenuItem submenu) labeled:nil.
    menuItem horizontalLayout:(aMenuItem horizontalLayout).
!

setDelayedAttributesTo:aMenuItem
    aMenuItem          submenu:(self submenu).
    aMenuItem horizontalLayout:(menuItem horizontalLayout).
! !

!MenuEditor::ItemMenu methodsFor:'displaying'!

displayLabel
    "returns the label dependent on is delayed or not
    "
    self isDelayedMenu ifTrue:[ ^ self class defaultDelayedLabel ].
  ^ menuItem rawLabel
!

icon
    self isDelayedMenu ifTrue:[ ^ self class iconDelayedMenu ].
  ^ self class iconMenu
! !

!MenuEditor::ItemMenu methodsFor:'queries'!

canAddChildren
    "children can be added
    "
    ^ true
!

canExpand
    "returns true if the item is expandable
    "
    ^ isExpanded == false
!

hasIndicator
    ^ true
!

isKindOfMenu
    ^ true
! !

!MenuEditor::ItemRoot class methodsFor:'defaults'!

defaultLabel
    ^ MenuEditor resourceType
! !

!MenuEditor::ItemRoot class methodsFor:'interface - editor'!

addBindingsTo:aspects for:aMenuEditor
    "add additional bindings to the aspects
    "
! !

!MenuEditor::ItemRoot class methodsFor:'interface - specs'!

basicsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:MenuEditor::ItemRoot andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
	#name: #basicsEditSpec
	#window: 
       #(#WindowSpec
	  #label: 'basicsEditSpec'
	  #name: 'basicsEditSpec'
	  #min: #(#Point 10 10)
	  #max: #(#Point 1280 1024)
	  #bounds: #(#Rectangle 644 547 904 593)
	)
	#component: 
       #(#SpecCollection
	  #collection: #(
	   #(#LabelSpec
	      #label: 'Selector:'
	      #name: 'selectorLabel'
	      #layout: #(#AlignmentOrigin 107 0 26 0 1 0.5)
	      #activeHelpKey: #basicsSelector
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'selectorField'
	      #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
	      #activeHelpKey: #basicsSelector
	      #tabable: true
	      #model: #rawLabel
	      #group: #inputGroup
	      #type: #string
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   )
         
	)
      )
! !

!MenuEditor::ItemRoot methodsFor:'accessing'!

menuItem:aMenuItem
    "rebuild self from a MenuItem
    "
    |submenu selector|

    aMenuItem notNil ifTrue:[
	submenu  := aMenuItem submenu.
	selector := aMenuItem rawLabel.
    ] ifFalse:[
	selector := submenu := nil.
    ].
    self menu:submenu labeled:selector.
!

rawLabel:aValue
    "set the label assigned to the item
    "
    |value|

    aValue isString ifTrue:[
        value := aValue withoutSeparators.

        (value notEmpty and:[value first isLetter]) ifTrue:[
            menuItem rawLabel:(value asSymbol)
        ].
    ].
!

slices
    ^ #(
	    (Basics   basicsEditSpec)
       )
! !

!MenuEditor::ItemRoot methodsFor:'adding & removing'!

remove
    "cannot remove the root item; delete all my children
    "
    self removeAll.
! !

!MenuEditor::ItemRoot methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "discard all other than the rawLabel
    "
    aKey == #rawLabel ifTrue:[ self rawLabel:aValue ].
! !

!MenuEditor::ItemRoot methodsFor:'displaying'!

heightOn:aGC
    height ifNil:[ height := aGC font heightOn:aGC device ].
  ^ height
! !

!MenuEditor::ItemRoot methodsFor:'initialization'!

initialize
    super initialize.
    isExpanded := true.
! !

!MenuEditor::ItemRoot methodsFor:'queries'!

canCollapse
    ^ false
!

hasIndicator
    ^ false
!

isDelayedMenu
    ^ false
!

isRootItem
    ^ true
! !

!MenuEditor::ItemRoot methodsFor:'queries - editor'!

actionSelectors
    "returns my action selectors
    "
    ^ #()
!

aspectSelectors
    "returns my aspect selectors
    "
    ^ #()
! !

!MenuEditor::ItemRoot methodsFor:'queries - operation'!

canMoveInAbove
    ^ false
!

canMoveInNext
    ^ false
!

canMoveOut
    ^ false
!

canMoveUpOrDown
   ^ false
! !

!MenuEditor::ItemSeparator class methodsFor:'interface - editor'!

addBindingsTo:aspects for:aMenuEditor
    "add additional bindings to the aspects
    "
    |holder|

    aspects at:#seperatorList  ifAbsentPut:[
	self separatorSlices collect:[:el| el last ]
    ].

    aspects at:#seperatorSelection ifAbsentPut:[
	holder := 0 asValue.
	holder addDependent:aMenuEditor.
	holder
    ].
!

defaultLabel
    ^ '-'
!

separatorSlices
    "get the list of menu spec values of the corresponding separator types
    "
    ^ #(
	( #blank        ''      'blank' )
	( #single       '-'     'single line')
	( #double       '='     'double line')
      )
! !

!MenuEditor::ItemSeparator class methodsFor:'interface - specs'!

basicsEditSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:MenuEditor::ItemSeparator andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
	#name: #basicsEditSpec
	#window: 
       #(#WindowSpec
	  #label: 'basicsEditSpec'
	  #name: 'basicsEditSpec'
	  #min: #(#Point 10 10)
	  #max: #(#Point 1160 870)
	  #bounds: #(#Rectangle 160 398 420 643)
	)
	#component: 
       #(#SpecCollection
	  #collection: #(
	   #(#LabelSpec
	      #label: 'Separator:'
	      #name: 'separatorLabel'
	      #layout: #(#AlignmentOrigin 107 0 26 0 1 0.5)
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#ComboListSpec
	      #name: 'seperatorList'
	      #layout: #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
	      #activeHelpKey: #basicsSeparatorType
	      #tabable: true
	      #model: #seperatorSelection
	      #comboList: #seperatorList
	      #useIndex: true
	    )
	   #(#LabelSpec
	      #label: 'Visibility:'
	      #name: 'visibilityLabel'
	      #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'visibilityInputField'
	      #layout: #(#LayoutFrame 110 0 40 0 -5 1.0 62 0)
	      #activeHelpKey: #detailsVisibility
	      #tabable: true
	      #model: #isVisible
	      #group: #inputGroup
	      #type: #symbolOrNil
	      #immediateAccept: false
	      #acceptOnReturn: true
	      #acceptOnTab: true
	      #acceptChannel: #acceptChannel
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#LabelSpec
	      #label: 'Start Group:'
	      #name: 'startGroupLabel'
	      #layout: #(#AlignmentOrigin 107 0 88 0 1 0.5)
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#PopUpListSpec
	      #label: 'left'
	      #name: 'startGroupPopUp'
	      #layout: #(#LayoutFrame 110 0 77 0 -5 1.0 99 0)
	      #activeHelpKey: #detailsStartGroup
	      #tabable: true
	      #model: #startGroup
	      #menu: 
	     #(#left
		#right
	      )
	    )
	   )
         
	)
      )
! !

!MenuEditor::ItemSeparator methodsFor:'accessing'!

icon
    ^ self class iconSeparator
!

rawLabel:aValue
    |value|

    aValue isString ifTrue:[
	value := aValue withoutSeparators.

	(self class separatorTypeOf:value) ifNotNil:[
	    menuItem rawLabel:value
	]
    ].
!

separatorType
    ^ self class separatorTypeOf:(menuItem rawLabel).
!

slices
    ^ #(
	    (Basics   basicsEditSpec)
       )
! !

!MenuEditor::ItemSeparator methodsFor:'aspects'!

fromAspects:aspects
    "put my values into the values of aspects
    "
    |index slice|

    index  := (aspects at:#seperatorSelection) value ? 0.
    slice  := self class separatorSlices at:index ifAbsent:nil.

    slice ifNotNil:[ slice := slice at:2 ].

    (aspects at:#rawLabel) value:slice.
  ^ super fromAspects:aspects.
!

toAspects:aspects
    "put my values into the values of aspects
    "
    |index type|

    type   := self separatorType.
    index  := self class separatorSlices findFirst:[:el| el first == type ].

    (aspects at:#seperatorSelection) value:index.
  ^ super  toAspects:aspects.
! !

!MenuEditor::ItemSeparator methodsFor:'displaying'!

displayOn:aGC x:x y:y h:h
    "draw the receiver in the graphicsContext, aGC.
    "
    |x1 y0 type|

    type := self separatorType.
    type == #blank ifTrue:[ ^ self ].

    x1 := x + (self widthOn:aGC).
    y0 := y + (h // 2) - 1.

    type == #double ifTrue:[
	y0 := y0 + 1.
	aGC displayLineFromX:x y:y0 toX:x1 y:y0.
	y0 := y0 - 2
    ].
    aGC displayLineFromX:x y:y0 toX:x1 y:y0
!

widthOn:aGC
    width ifNil:[ width := 60 ].
  ^ width
! !

!MenuEditor::ResourceEditor class methodsFor:'interface specs'!

windowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

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

    <resource: #canvas>

    ^ 
     #(#FullSpec
	#name: #windowSpec
	#window: 
       #(#WindowSpec
	  #label: 'Image Item'
	  #name: 'Image Item'
	  #min: #(#Point 10 10)
	  #max: #(#Point 1280 1024)
	  #bounds: #(#Rectangle 333 290 621 585)
	)
	#component: 
       #(#SpecCollection
	  #collection: #(
	   #(#LabelSpec
	      #label: 'Retriever:'
	      #name: 'retrieverLabel'
	      #layout: #(#AlignmentOrigin 107 0 26 0 1 0.5)
	      #activeHelpKey: #imageRetriever
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#ComboBoxSpec
	      #name: 'retrieverHolder'
	      #layout: #(#LayoutFrame 110 0 15 0 -20 1.0 37 0)
	      #activeHelpKey: #imageRetriever
	      #tabable: true
	      #model: #retrieverHolder
	      #type: #symbolOrNil
	      #immediateAccept: true
	      #acceptOnReturn: false
	      #acceptOnTab: false
	      #acceptOnPointerLeave: false
	      #comboList: #retrieverList
	      #isFilenameBox: false
	    )
	   #(#LabelSpec
	      #label: 'Selector:'
	      #name: 'iconLabel'
	      #layout: #(#AlignmentOrigin 107 0 51 0 1 0.5)
	      #activeHelpKey: #imageSelector
	      #resizeForLabel: true
	      #adjust: #right
	    )
	   #(#InputFieldSpec
	      #name: 'selectorHolder'
	      #layout: #(#LayoutFrame 110 0 40 0 -42 1.0 62 0)
	      #activeHelpKey: #imageSelector
	      #tabable: true
	      #model: #selectorHolder
	      #group: #inputGroup
	      #type: #symbolOrNil
	      #immediateAccept: true
	      #acceptOnReturn: false
	      #acceptOnTab: false
	      #modifiedChannel: #modifiedChannel
	      #acceptOnPointerLeave: false
	    )
	   #(#ActionButtonSpec
	      #label: '...'
	      #name: 'browseButton'
	      #layout: #(#LayoutFrame -40 1 40 0 -20 1 62 0)
	      #activeHelpKey: #browseResource
	      #tabable: true
	      #model: #doBrowseForImageResource
	    )
	   #(#HierarchicalListViewSpec
	      #name: 'imageList'
	      #layout: #(#LayoutFrame 20 0.0 67 0 -20 1.0 -30 1.0)
	      #activeHelpKey: #imageImageList
	      #model: #imageHolder
	      #menu: #menuEditImage
	      #hasHorizontalScrollBar: true
	      #hasVerticalScrollBar: true
	      #miniScrollerHorizontal: true
	      #listModel: #imageList
	      #useIndex: false
	      #highlightMode: #label
	      #postBuildCallback: #postBuildImageViewer:
	    )
	   #(#ViewSpec
	      #name: 'Box1'
	      #layout: #(#LayoutFrame 20 0.0 -30 1.0 -20 1.0 0 1.0)
	      #level: 0
	      #component: 
	     #(#SpecCollection
		#collection: #(
		 #(#CheckBoxSpec
		    #label: 'Image & Label'
		    #name: 'iconAndLabelCheckBox'
		    #layout: #(#AlignmentOrigin 0 0 0 0.5 0 0.5)
		    #activeHelpKey: #imageImageAndLabel
		    #tabable: true
		    #model: #iconAndLabelHolder
		  )
		 #(#ActionButtonSpec
		    #label: 'Image Editor'
		    #name: 'imageEditorButton'
		    #layout: #(#AlignmentOrigin 0 1.0 0 0.5 1 0.5)
		    #activeHelpKey: #imageImageEditor
		    #tabable: true
		    #model: #doEditImage
		  )
		 )
               
	      )
	    )
	   )
         
	)
      )
! !

!MenuEditor::ResourceEditor methodsFor:'accessing'!

resourceRetriever
    |rcv sel cls|

    sel := selectorHolder value.
    sel size == 0 ifTrue:[ ^ nil ].
    cls := self retrieverClass.
    cls ifNotNil:[ cls := cls name asSymbol ].

    rcv := ResourceRetriever new.
    rcv className:cls.
    rcv  selector:sel.

    iconAndLabelHolder value ifTrue:[ rcv labelText:'' ].
  ^ rcv
!

resourceRetriever:aResourceRetriever
    |cls sel isOn|

    aResourceRetriever notNil ifTrue:[
	cls := aResourceRetriever className.
	cls ifNotNil:[
	    cls isBehavior ifTrue:[cls := cls name asSymbol].
	].
	sel  := aResourceRetriever selector.
	isOn := aResourceRetriever labelText notNil.
    ] ifFalse:[
	cls := sel := nil.
	isOn := false.
    ].

    retrieverHolder value:cls.
    selectorHolder  value:sel.
    iconAndLabelHolder value:isOn.
!

retrieverClass
    |cls|

    cls  := retrieverHolder value.

    cls size ~~ 0 ifTrue:[
	cls := Smalltalk at:cls ifAbsent:nil.

	(cls notNil and:[cls isBehavior]) ifTrue:[
	    ^ cls
	].
    ].
    ^ nil
! !

!MenuEditor::ResourceEditor methodsFor:'actions'!

doBrowseForImageResource
    "opens a browser on image-resource methods"

    |msg|

    msg := ResourceSelectionBrowser
		 request:'Use Image From Class'
	    onSuperclass:nil
		andClass:(self retrieverClass)
	     andSelector:(selectorHolder value)
       withResourceTypes:#(image fileImage programImage).

    msg ifNil:[ ^ self ].
    msg := msg asCollectionOfWords.
    msg size == 2 ifFalse:[ ^ self ].

    retrieverHolder value:(msg first asSymbol).
    selectorHolder  value:(msg last  asSymbol).
!

doEditImage
    |item|

    item := imageHolder value.
    item ifNotNil:[ item doEdit ].
! !

!MenuEditor::ResourceEditor methodsFor:'aspects'!

iconAndLabelHolder
    ^ iconAndLabelHolder
!

imageHolder
    ^ imageHolder.
!

imageList
    ^ imageList.
!

modifiedChannel
    ^ builder booleanValueAspectFor: #modifiedChannel
!

modifiedChannel:aChannel
    builder aspectAt:#modifiedChannel put:aChannel.
!

retrieverHolder
    ^ retrieverHolder
!

retrieverList
    |list|

    list := builder bindingAt:#retrieverList.

    list ifNil:[
	list := MenuEditor imageRetrieverClasses asList.
	builder aspectAt:#retrieverList put:list.
    ].
    ^ list
!

selectorHolder
    ^ selectorHolder.
! !

!MenuEditor::ResourceEditor methodsFor:'change & update'!

retrieverChanged
    "called if the retriever changed
    "
    |retriever list name|

    retriever := self retrieverClass.
    imageHolder setValue:nil.

    imageList root fromClass:retriever.
    self selectorChanged.

    (retriever notNil and:[imageList size ~~ 0]) ifTrue:[
        list := self retrieverList.
        name := retriever name.

        (list includes:name) ifFalse:[
            list add:(name asSymbol).
        ]
    ].
!

selectorChanged
    |item selector line|

    imageList isEmpty ifTrue:[^ self].

    selector := selectorHolder value.
    selector size == 0 ifTrue:[ ^ imageHolder value:nil ].

    item     := nil.
    selector := selector asSymbol.

    imageList do:[:anItem| |sel|
	sel := anItem selector.
	selector == sel ifTrue:[
	    ^ imageHolder value:anItem
	].
	item ifNil:[
	    (sel startsWith:selector) ifTrue:[ item := anItem ]
	]
    ].
    imageHolder value:nil.

    item ifNotNil:[
	line := imageList identityIndexOf:item.
	imageViewer scrollToLine:line
    ].
!

update:what with:aPara from:aModel
    "Invoked when an object that I depend upon sends a change notification."

    |item|

    self modifiedChannel value:true.

    aModel == retrieverHolder ifTrue:[ ^ self retrieverChanged ].
    aModel == selectorHolder  ifTrue:[ ^ self selectorChanged  ].

    aModel == imageHolder ifTrue:[
	item := imageHolder value.
	item ifNotNil:[ selectorHolder value:(item label) ].
      ^ self
    ].
    super update:what with:aPara from:aModel
! !

!MenuEditor::ResourceEditor methodsFor:'initialization'!

initialize
    super initialize.

    iconAndLabelHolder := true asValue.
    iconAndLabelHolder addDependent:self.

    imageHolder := nil asValue.

    selectorHolder := nil asValue.
    selectorHolder addDependent:self.

    imageList := HierarchicalList new.
    imageList application:self.
    imageList root:(MenuEditor::ResourceEditorItem new).
    imageList showRoot:false.

    imageHolder := nil asValue.
    imageHolder addDependent:self.

    retrieverHolder := nil asValue.
    retrieverHolder addDependent:self.
!

postBuildImageViewer:aWidget
    imageViewer := aWidget.
! !

!MenuEditor::ResourceEditorItem class methodsFor:'instance creation'!

fromClass:aClass selector:aSelector
    |item|

    item := self new.
    item fromClass:aClass selector:aSelector.
  ^ item
! !

!MenuEditor::ResourceEditorItem methodsFor:'accessing'!

icon
    ^ icon
!

label
    ^ selector
!

selector
    ^ selector
! !

!MenuEditor::ResourceEditorItem methodsFor:'instance creation'!

fromClass:aClass
    |r item|

    (aClass notNil and:[aClass isBehavior]) ifFalse:[
	^ self collapse.
    ].
    aClass == selector ifTrue:[
	^ self expand
    ].
    self collapse.

    selector := aClass.
    children := SortedCollection sortBlock:[:a :b| a label < b label ].

    self application withWaitCursorDo:[
	aClass withAllSuperclassesDo:[:aClass|
	    aClass class selectorsAndMethodsDo:[:sel :m| 
		((r := m resourceType) == #image or:[r == #programImage]) ifTrue:[
		    item := self class fromClass:aClass selector:sel.
		    item parent:self.
		    children add:item
		]
	    ]
	].
	self expand
    ].
!

fromClass:aClass selector:aSelector
    |w h magnify|

    selector := aSelector asSymbol.
    icon  := aClass perform:selector.

    w := icon width.
    h := icon height.

    w > 32 ifTrue:[
	magnify := 32 / w.
	h > 32 ifTrue:[ magnify := (32 / h) max:magnify ].
    ] ifFalse:[
	h > 32 ifFalse:[^ self].
	magnify := 32 / h.
    ].
    icon := icon magnifiedBy: magnify.
!

initialize
    super initialize.
    children := #().
! !

!MenuEditor::ResourceEditorItem methodsFor:'user operations'!

doEdit
    "open image browser on self
    "
    |parent|

    parent := self parent.

    parent ifNotNil:[
	ImageEditor openOnClass:(parent selector) andSelector:selector
    ].
! !

!MenuEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !

MenuEditor initialize!