MenuEditor.st
author Claus Gittinger <cg@exept.de>
Mon, 04 Feb 2008 10:28:33 +0100
changeset 2263 e3784764ba54
parent 2252 e2804df19f8c
child 2270 daa949fce11e
permissions -rw-r--r--
*** empty log message ***

"
 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
		dropOverLine'
	classVariableNames:'ImageRetrieverClasses'
	poolDictionaries:''
	category:'Interface-UIPainter'
!

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

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

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

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

MenuEditor::Item subclass:#RegularMenuItem
	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::RegularMenuItem subclass:#RootItem
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:MenuEditor
!

MenuEditor::Item subclass:#SeparatorItem
	instanceVariableNames:''
	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:]

	listOfItemsView         <HierarcicalListView>  the view which shows the list of items
	listOfItems             <HierarchicalList>     hierarchical list of menu items
	listOfTabs              <List>                 list of current shown tab-labels

	selectionHolder         <ValueHolder>          collection of current selected items
	selectedSuperItems      <Collection>           collection of superItems derived from selection

	tabHolder               <ValueHolder>          selected tab label holder
	notifyDisabledCounter   <SmallInteger>         ~~ 0 than change notifications are discard
	wizards                 <IdentityDictionary>   keeps all created wizard dialogs

	dropOverLine            <nil or SmallInteger>  nil: drop context not dropabel.
						       = 0: drop context dropable but no item specified
						       ~ 0: drop context dropable for item at lineNumber
						       used t6o restore drop indication drawings

    [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
	itemValue
	nameKey
	indication
	choice
	choiceValue
	translateLabel
	isButton
	shortcutKeyCharacter
	startGroup
	isVisible
	hideMenuOnActivated
	auxValue
	activeHelpKey
	resourceRetriever
	sendToOriginator
	ignoreMnemonicKeys
	ignoreShortcutKeys
	isMenuSlice
     )
! !

!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 localFlyHelpSpecStrings)
!

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

    ^ super helpSpec addPairsFrom:#(

#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.'

#addMenuSliceItem
'Add a new menu slice.'

#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
'Button-like look and 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 to enable/disable the menu item.'

#detailsIgnoreAcceleratorKeys
'Ignore accelerator keys in submenu(s).'

#detailsIgnoreMnemonicKeys
'Ignore mnemonic keys (access characters) in submenu(s).'

#detailsStartGroup
'Specify start of a specially aligned group.'

#detailsVisibility
'Boolean, or aspect or binding for a boolean holder controlling the visibility of the menu item.'

#fileLoad
'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 (PopUp/PullDown-Menus only).'

#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 unspecified, the application class is taken.'

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

#keepLinkedMenu
'Keep the linked menu after activation (do not destroy; if off, menu is rebuild for every activation).'

#sendToOriginator
'Send action-Message to widget (instead of application); only valid for PopUpMenus.'

#settingsRedefineAspectMethods
'Toggles the permission to overwrite existing aspect methods.'

#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).'

)

    "Modified: / 16-10-2006 / 13:20:38 / cg"
!

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

    ^ #(

#editCut
'Cut Item'

#editCopy
'Copy Item'

#editPaste
'Paste Item'

#fileLoad
'Load Menuspec from Method'

#fileSave
'Save Menuspec as Method'

#fileSaveAs
'Save Menuspec as Method...'

#addMenuSeparator
'Add Separator'

#addMenuItem
'Add Item'

#addMenuSlice
'Add Menuslice'

#addSubMenu
'Add Submenu'

#addDelayedMenu
'Add Delayed Menu'

#addDelayedSubMenuLink
'Add Delayed Linked Menu'

#addSubMenuLink
'Add Linked Submenu'

#fileNew
'New Menuspec'
)
! !

!MenuEditor class methodsFor:'image specs'!

defaultIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary startMenuEditorIcon
!

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)
	  bounds: (Rectangle 0 0 574 473)
	  menu: menu
	  icon: defaultIcon
	  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: 'mainPanel'
	      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
		      dropSelector: doDrop:
		      dragArgument: nil
		      dropObjectSelector: dropObjects
		      overSelector: dropOver:
		      dropArgument: nil
		      leaveSelector: dropLeave:
		      canDropSelector: canDrop:
		      enterSelector: dropEnter:
		    )
		    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
			  translateLabel: true
			  canvas: wizardHolder
			  keepCanvasAlive: true
			  postBuildCallback: postBuildNoteBook:
			)
		       (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
	    activeHelpKey: addMenuSeparator
	    label: 'Separator'
	    itemValue: doCreateSep
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconSeparator '')
	  )
	 (MenuItem
	    activeHelpKey: addMenuItem
	    label: 'Item'
	    itemValue: doCreateItem
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconItem '')
	  )
	 (MenuItem
	    activeHelpKey: addMenuSliceItem
	    label: 'Menu Slice'
	    itemValue: doCreateMenuSliceItem
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconSliceMenu '')
	  )
	 (MenuItem
	    activeHelpKey: addMenuItem
	    label: 'Menu'
	    itemValue: doCreateMenu
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconMenu '')
	  )
	 (MenuItem
	    activeHelpKey: addSubMenuLink
	    label: 'Linked Menu'
	    itemValue: doCreateLinkedMenu
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconLinkedMenu '')
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: addDelayedMenu
	    enabled: canCreateDelayedMenuChannel
	    label: 'Delayed Menu'
	    itemValue: doCreateDelayedMenu:
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconDelayedMenu '')
	    argument: menu
	  )
	 (MenuItem
	    activeHelpKey: addDelayedSubMenuLink
	    enabled: canCreateDelayedMenuChannel
	    label: 'Delayed Linked Menu'
	    itemValue: doCreateDelayedMenu:
	    translateLabel: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconDelayedLinkedMenu '')
	    argument: linkedMenu
	  )
	 (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
	    activeHelpKey: editCut
	    enabled: hasSelectionChannel
	    label: 'Cut'
	    itemValue: doCut
	    translateLabel: true
	    shortcutKey: Cut
	  )
	 (MenuItem
	    activeHelpKey: editCopy
	    enabled: hasSelectionChannel
	    label: 'Copy'
	    itemValue: doCopy
	    translateLabel: true
	    shortcutKey: Copy
	  )
	 (MenuItem
	    activeHelpKey: editPaste
	    enabled: canPasteHolder
	    label: 'Paste'
	    itemValue: doPaste
	    translateLabel: true
	    shortcutKey: Paste
	  )
	 (MenuItem
	    activeHelpKey: editDelete
	    enabled: hasSelectionChannel
	    label: 'Delete'
	    itemValue: doDelete
	    translateLabel: true
	    isVisible: false
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: editMoveUp
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Up'
	    itemValue: doMoveUpOrDown:
	    translateLabel: true
	    startGroup: right
	    argument: up
	    shortcutKey: CtrlCursorUp
	    labelImage: (ResourceRetriever Icon upIcon 'Move Up')
"/            labelImage: (ResourceRetriever ToolbarIconLibrary up16x16Icon 'Move Up')
	  )
	 (MenuItem
	    activeHelpKey: editMoveDown
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Down'
	    itemValue: doMoveUpOrDown:
	    translateLabel: true
	    shortcutKey: CtrlCursorDown
	    labelImage: (ResourceRetriever Icon downIcon 'Move Down')
	    argument: down
	  )
	 (MenuItem
	    activeHelpKey: editMoveIn
	    enabled: enableMovingInHolder
	    label: 'Move Into Next'
	    itemValue: doMoveIn:
	    translateLabel: true
	    shortcutKey: CtrlCursorRight
	    labelImage: (ResourceRetriever Icon downRightIcon 'Move Into Next')
	    argument: inNext
	  )
	 (MenuItem
	    activeHelpKey: editMoveInAbove
	    enabled: enableMovingInAboveHolder
	    label: 'Move Into Previous'
	    itemValue: doMoveIn:
	    translateLabel: true
	    labelImage: (ResourceRetriever Icon upRightIcon 'Move Into Previous')
	    argument: inPrev
	  )
	 (MenuItem
	    activeHelpKey: editMoveOut
	    enabled: enableMovingOutHolder
	    label: 'Move Out'
	    itemValue: doMoveOut
	    translateLabel: true
	    shortcutKey: CtrlCursorLeft
	    labelImage: (ResourceRetriever Icon leftDownIcon 'Move Out')
	  )
	 )
	nil
	nil
      )
!

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

    <resource: #menu>

    ^
     #(Menu
	(
	 (MenuItem
	    activeHelpKey: editCut
	    enabled: hasSelectionChannel
	    label: 'Cut'
	    itemValue: doCut
	    translateLabel: true
	  )
	 (MenuItem
	    activeHelpKey: editCopy
	    enabled: hasSelectionChannel
	    label: 'Copy'
	    itemValue: doCopy
	    translateLabel: true
	  )
	 (MenuItem
	    activeHelpKey: editPaste
	    enabled: canPasteHolder
	    label: 'Paste'
	    itemValue: doPaste
	    translateLabel: true
	  )
	 (MenuItem
	    activeHelpKey: editDelete
	    enabled: hasSelectionChannel
	    label: 'Delete'
	    itemValue: doDelete
	    translateLabel: true
	    isVisible: false
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: editMoveUp
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Up'
	    itemValue: doMoveUpOrDown:
	    translateLabel: true
	    startGroup: right
	    labelImage: (ResourceRetriever Icon upIcon 'Move Up')
	    argument: up
	  )
	 (MenuItem
	    activeHelpKey: editMoveDown
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Down'
	    itemValue: doMoveUpOrDown:
	    translateLabel: true
	    labelImage: (ResourceRetriever Icon downIcon 'Move Down')
	    argument: down
	  )
	 (MenuItem
	    activeHelpKey: editMoveIn
	    enabled: enableMovingInHolder
	    label: 'Move Into Next'
	    itemValue: doMoveIn:
	    translateLabel: true
	    labelImage: (ResourceRetriever Icon downRightIcon 'Move Into Next')
	    argument: inNext
	  )
	 (MenuItem
	    activeHelpKey: editMoveInAbove
	    enabled: enableMovingInAboveHolder
	    label: 'Move Into Previous'
	    itemValue: doMoveIn:
	    translateLabel: true
	    labelImage: (ResourceRetriever Icon upRightIcon 'Move Into Previous')
	    argument: inPrev
	  )
	 (MenuItem
	    activeHelpKey: editMoveOut
	    enabled: enableMovingOutHolder
	    label: 'Move Out'
	    itemValue: doMoveOut
	    translateLabel: true
	    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
	    activeHelpKey: fileNew
	    label: 'New'
	    itemValue: doNew
	    translateLabel: true
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: fileLoad
	    label: 'Load...'
	    itemValue: doLoad
	    translateLabel: true
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: fileSave
	    label: 'Save'
	    itemValue: doSave
	    translateLabel: true
	  )
	 (MenuItem
	    activeHelpKey: fileSaveAs
	    label: 'Save As...'
	    itemValue: doSaveAs
	    translateLabel: true
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: filePickAMenu
	    label: 'Pick a Menu...'
	    itemValue: doPickAMenu
	    translateLabel: true
	  )
	 (MenuItem
	    label: '-'
	    isVisible: isStandAlone
	  )
	 (MenuItem
	    activeHelpKey: fileBrowseClass
	    enabled: hasValidSpecClass
	    label: 'Browse Class'
	    itemValue: doBrowseClass
	    translateLabel: true
	    isVisible: isStandAlone
	  )
	 (MenuItem
	    activeHelpKey: fileShowMenuSpec
	    label: 'Show Menu Spec'
	    itemValue: doShowMenuSpec
	    translateLabel: true
	    isVisible: isStandAlone
	  )
	 (MenuItem
	    label: '-'
	    isVisible: isStandAlone
	  )
	 (MenuItem
	    activeHelpKey: fileExit
	    label: 'Exit'
	    itemValue: closeRequest
	    translateLabel: true
	    isVisible: isStandAlone
	  )
	 )
	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
	    #activeHelpKey: #generateAspectMethods
	    #enabled: #hasValidSpecClass
	    #label: 'Aspect Methods'
	    #itemValue: #doGenerateAspectMethods
	    #translateLabel: true
	  )
	 )
	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
	    #activeHelpKey: #helpTutorial
	    #label: 'Documentation'
	    #itemValue: #openHTMLDocument:
	    #translateLabel: true
	    #argument: 'tools/uipainter/MenuEditor.html'
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #activeHelpKey: #helpHelpTool
	    #label: 'Help Tool'
	    #itemValue: #openHTMLDocument:
	    #translateLabel: true
	    #argument: 'tools/uipainter/HelpTool.html'
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #activeHelpKey: #helpShowHelp
	    #label: 'Show Help Texts'
	    #translateLabel: true
	    #indication: #showingHelp:
	  )
	 #(#MenuItem
	    #label: '-'
	  )
	 #(#MenuItem
	    #activeHelpKey: #aboutThisAppliaction
	    #label: 'About MenuEditor...'
	    #itemValue: #openAboutThisApplication
	    #translateLabel: true
	  )
	 )
	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
	    submenuChannel: fileMenu
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    label: '&Edit'
	    translateLabel: true
	    submenuChannel: editMenuForMainMenuWithoutAccelerators
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    enabled: hasSingleSelectionChannel
	    label: 'Item'
	    translateLabel: true
	    submenuChannel: addMenu
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    label: 'Generate'
	    translateLabel: true
	    submenuChannel: generateMenu
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    label: 'Test'
	    translateLabel: true
	    submenuChannel: submenuTest
	  )
	 (MenuItem
	    label: 'Settings'
	    translateLabel: true
	    submenuChannel: settingsMenu
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    label: 'History'
	    translateLabel: true
	    isVisible: isStandAlone
	    submenuChannel: menuHistory
	  )
	 (MenuItem
	    label: 'MENU_Help'
	    translateLabel: true
	    startGroup: conditionalRight
	    submenuChannel: helpMenu
	    keepLinkedMenu: true
	  )
	 )
	nil
	nil
      )
!

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

    <resource: #menu>

    ^
     #(#Menu
	#(
	 #(#MenuItem
	    #activeHelpKey: #settingsRedefineAspectMethods
	    #enabled: #hasValidSpecClass
	    #label: 'Redefine Aspect Methods'
	    #translateLabel: true
	    #hideMenuOnActivated: false
	    #indication: #redefineAspectMethodsChannel
	  )
	 #(#MenuItem
	    #activeHelpKey: #settingsRedefineAspectMethods
	    #label: 'AutoAccept on Selection-Change'
	    #translateLabel: true
	    #hideMenuOnActivated: false
	    #indication: #autoAcceptOnSelectionChange
	  )
	 )
	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: File'
	    #itemValue: #doCreateStandardFileMenu
	    #translateLabel: true
	  )
	 #(#MenuItem
	    #label: 'Standard Menu: Edit'
	    #itemValue: #doCreateStandardEditMenu
	    #translateLabel: true
	  )
	 #(#MenuItem
	    #label: 'Standard Menu: Help'
	    #itemValue: #doCreateStandardHelpMenu
	    #translateLabel: true
	  )
	 )
	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
	    activeHelpKey: fileNew
	    label: 'New'
	    itemValue: doNew
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever ToolbarIconLibrary newMenuIcon)
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: fileLoad
	    label: 'Load'
	    itemValue: doLoad
	    translateLabel: true
	    isButton: true
	    submenuChannel: menuHistory
	    labelImage: (ResourceRetriever ToolbarIconLibrary loadFromMethodIcon)
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    activeHelpKey: fileSave
	    label: 'Save'
	    itemValue: doSave
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever ToolbarIconLibrary saveAsMethodIcon)
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: editCut
	    enabled: hasSelectionChannel
	    label: 'Cut'
	    itemValue: doCut
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever ToolbarIconLibrary cutMenuItemIcon)
	  )
	 (MenuItem
	    activeHelpKey: editCopy
	    enabled: hasSelectionChannel
	    label: 'Copy'
	    itemValue: doCopy
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever ToolbarIconLibrary copyMenuItemIcon)
	  )
	 (MenuItem
	    activeHelpKey: editPaste
	    enabled: canPasteHolder
	    label: 'Paste'
	    itemValue: doPaste
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever ToolbarIconLibrary pasteMenuItemIcon)
	  )
	 (MenuItem
	    label: '-'
	  )
	 (MenuItem
	    activeHelpKey: addMenuItem
	    enabled: hasSingleSelectionChannel
	    label: 'Add Item'
	    itemValue: doCreateItem
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconItem)
	  )
	 (MenuItem
	    activeHelpKey: addMenuSeparator
	    enabled: hasSingleSelectionChannel
	    label: 'Add Separator'
	    itemValue: doCreateSep
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconSeparator)
	  )
	 (MenuItem
	    activeHelpKey: addMenuSlice
	    enabled: hasSingleSelectionChannel
	    label: 'Menu Slice'
	    itemValue: doCreateMenuSliceItem
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconSliceMenu)
	  )
	 (MenuItem
	    activeHelpKey: addSubMenu
	    enabled: hasSingleSelectionChannel
	    label: 'Add Menu'
	    itemValue: doCreateMenu
	    translateLabel: true
	    isButton: true
	    submenuChannel: standardMenus
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconMenu)
	    keepLinkedMenu: true
	  )
	 (MenuItem
	    activeHelpKey: addSubMenuLink
	    enabled: hasSingleSelectionChannel
	    label: 'Add Linked Menu'
	    itemValue: doCreateLinkedMenu
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconLinkedMenu)
	  )
	 (MenuItem
	    activeHelpKey: addDelayedMenu
	    enabled: canCreateDelayedMenuChannel
	    label: 'Add Delayed Menu'
	    itemValue: doCreateDelayedMenu:
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconDelayedMenu)
	    argument: menu
	  )
	 (MenuItem
	    activeHelpKey: addDelayedSubMenuLink
	    enabled: canCreateDelayedMenuChannel
	    label: 'Add Delayed Linked Menu'
	    itemValue: doCreateDelayedMenu:
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever #'MenuEditor::Item' iconDelayedLinkedMenu)
	    argument: linkedMenu
	  )
	 (MenuItem
	    label: ''
	  )
	 (MenuItem
	    activeHelpKey: editMoveUp
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Up'
	    itemValue: doMoveUp
	    translateLabel: true
	    isButton: true
	    startGroup: right
	    labelImage: (ResourceRetriever Icon upIcon)
	  )
	 (MenuItem
	    activeHelpKey: editMoveDown
	    enabled: enableMovingUpOrDownHolder
	    label: 'Move Down'
	    itemValue: doMoveDown
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever Icon downIcon)
	  )
	 (MenuItem
	    activeHelpKey: editMoveIn
	    enabled: enableMovingInHolder
	    label: 'Move Into Next'
	    itemValue: doMoveInNext
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever Icon downRightIcon)
	  )
	 (MenuItem
	    activeHelpKey: editMoveInAbove
	    enabled: enableMovingInAboveHolder
	    label: 'Move Into Previous'
	    itemValue: doMoveInPrevious
	    translateLabel: true
	    isButton: true
	    labelImage: (ResourceRetriever Icon upRightIcon)
	  )
	 (MenuItem
	    activeHelpKey: editMoveOut
	    enabled: enableMovingOutHolder
	    label: 'Move Out'
	    itemValue: doMoveOut
	    translateLabel: true
	    isButton: true
	    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: 'Cut'
	    #translateLabel: true
	    #value: #cutSelection
	  )
	 #(#MenuItem
	    #label: 'Copy'
	    #translateLabel: true
	    #value: #copySelection
	  )
	 #(#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'!

helpSpec
    |spec sel t g|

    spec := super helpSpec.
    t := spec at:#detailsStartGroup.
    g := (aspects at:#startGroup ifAbsent:nil) value.
    g == #conditionalRight ifTrue:[
	t := t , ' #conditionalRight means: "right on non-win32 systems"'
    ].
    g == #right ifTrue:[
	t := t , ' #right means: "right align from here"'
    ].
    g == #left ifTrue:[
	t := t , ' #left means: "left align group"'
    ].
    spec at:#detailsStartGroup put:t.

    ^ spec.
"/ #detailsStartGroup
"/ 'Specify start of a right-aligned item group.'

    "Created: / 16-10-2006 / 13:19:14 / cg"
!

helpTool
    "get the help tool application
    "
    ^ wizards at:#help ifAbsentPut:[ |tool|
	tool := UIHelpTool new.
	tool masterApplication:self.
	tool modifiedHolder: self enablingCommitButtonsHolder.
	tool builder window:(ApplicationSubView new client:tool spec:#innerSpec).
	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 enablingCommitButtonsHolder.
	tool builder window:(ApplicationSubView new client:tool).
	tool
    ]
!

useHelpTool:aHelpTool
    "take the help dictionaries from aHelpTool into my helpTool
    "
    self helpTool loadFromHelpTool:aHelpTool.
! !

!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:[
		helpTool accept.
		rscRetrHolder value:(imageTool resourceRetriever).
		helpKeyHolder value:(helpTool  helpKey).
		selectedItem  fromAspects:aspects.
		self setModified.

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

    self enablingCommitButtonsHolder value:false.

    "Modified: / 05-09-2006 / 18:43:30 / cg"
!

cancel
    "reload aspects from current selected item; reset modification flag"

    self accept:false.

    "Modified: / 29-08-2006 / 10:20:46 / cg"
!

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
!

hasItemValue
    "boolean holder, true if any item is selected
    "
    ^ BlockValue
	with:[:holder | holder size > 0]
	argument:(self aspectFor:#itemValue)

    "Modified: / 08-03-2007 / 22:59:42 / cg"
!

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
!

redefineAspectMethodsChannel
    "boolean holder, true if aspects should be generated in only implemented
     in superClass by calling #super ...
    "
    ^ builder booleanValueAspectFor:#redefineAspectMethodsChannel
!

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 isNil ifTrue:[
	holder := nil asValue.
	builder aspectAt:#wizardHolder put:holder.
    ].
    ^ holder
! !

!MenuEditor methodsFor:'building'!

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

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

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

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

buildFromResourceSpec:aResourceSpec
    "rebuild the menu from a resource spec"

    self buildFromMenu:aResourceSpec selector:nil
!

loadFromClass:aClass andSelector:aSelector
    "rebuild menu from a class and selector"

    |cls menu|

    self assert:(aClass isNil or:[aClass isClass]).

    menu := nil.

    self isStandAlone ifTrue:[ self helpTool loadFromClass:aClass ].

    specClass := aClass.
    specSelector := aSelector.

    aSelector notNil ifTrue:[
	aClass notNil ifTrue:[
	    cls := aClass isBehavior ifTrue:[ aClass ] ifFalse:[ self resolveName:aClass].

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

	    menu notNil ifTrue:[
		(menu isCollection) ifTrue:[
		    menu := Menu decodeFromLiteralArray:menu
		].
	    ]
	].
    ].
    self buildFromMenu:menu selector:aSelector.
    self clearModified.

    "Modified: / 27-03-2007 / 11:16:47 / cg"
! !

!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 isNil ifTrue:[ ^ wizardHolder value:nil ].

    tab := tabHolder value.

    tab notNil ifTrue:[
	tab := item slices detect:[:el| el first = tab ] ifNone:nil.
    ].
    tab isNil ifTrue:[
	^ 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
    |lbl|

    notifyDisabledCounter ~~ 0 ifTrue:[ ^ self ].

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

    changedObject == self autoAcceptOnSelectionChange ifTrue:[
	lbl := changedObject value ifTrue:['Apply'] ifFalse:['OK'].
	(builder componentAt:'okButton') label:(resources string:lbl).
	^ self
    ].

    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 enableMovingInHolder        value:false.
	self enableMovingOutHolder       value:false.
	self enableMovingUpOrDownHolder  value:false.
	self enableMovingInAboveHolder   value:false.
	self canCreateDelayedMenuChannel value:false.
    ] ifFalse:[
	self enableMovingUpOrDownHolder  value:(selectedItem canMoveUpOrDown).
	self enableMovingOutHolder       value:(selectedItem canMoveOut).
	self enableMovingInHolder        value:(selectedItem canMoveInNext).
	self enableMovingInAboveHolder   value:(selectedItem canMoveInAbove).
	self canCreateDelayedMenuChannel value:(selectedItem canAddDelayedMenu).
    ].
! !

!MenuEditor methodsFor:'code generation'!

createActionMethodFor:aSelector in:aClass category:aCategory redefine:redefine
    |alreadyInSuperclass numArgs method code|

    (aClass includesSelector:aSelector) ifTrue:[
	^ nil
    ].

    alreadyInSuperclass := aClass superclass canUnderstand:aSelector.

    (alreadyInSuperclass and:[redefine not]) ifTrue:[
	^ nil
    ].

    numArgs := aSelector numArgs.

    numArgs == 1 ifTrue:[
	method := aSelector, 'anArgument'.
    ] ifFalse:[
	numArgs == 0 ifTrue:[
	    method := aSelector
	] ifFalse:[
	    method := ''.
	    aSelector keywords keysAndValuesDo:[:i :key|
		method := method, key, 'arg', i printString, ' '.
	    ].
	]
    ].

    code := '%1
    "automatically generated by UIEditor ..."

    "*** 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 ;-)"

    "action to be added ..."

    Transcript showCR:self class name, '': action for #%2 ...''.
' bindWith:method with:aSelector.

    alreadyInSuperclass ifTrue:[
	code := code, (('\    super %1\' bindWith:method) withCRs).
    ].
    CodeGeneratorTool compile:code forClass:aClass inCategory:(aCategory ? 'actions').
  ^ code
!

createAspectMethodFor:anAspect in:aClass category:aCategory redefine:redefine
    |alreadyInSuperclass numArgs method code text|

    (aClass includesSelector:anAspect) ifTrue:[
	^ nil
    ].

    alreadyInSuperclass := aClass superclass canUnderstand:anAspect.

    (alreadyInSuperclass and:[redefine not]) ifTrue:[
	^ nil
    ].

    numArgs := anAspect numArgs.

    numArgs == 1 ifTrue:[
	method := anAspect, 'anArgument'.
    ] ifFalse:[
	numArgs == 0 ifTrue:[
	    method := anAspect
	] ifFalse:[
	    method := ''.
	    anAspect keywords keysAndValuesDo:[:i :key|
		method := method, key, 'arg', i printString, ' '.
	    ].
	]
    ].

    code := '%1
    "automatically generated by UIEditor ..."

    "*** 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 ;-)"

    "aspect to be added ..."

    Transcript showCR:self class name, '': aspect for #%2 ...''.

' bindWith:method with:anAspect.

    alreadyInSuperclass ifTrue:[
	text := '    ^ super %1\' bindWith:method.
    ] ifFalse:[
	text := '    ^ builder valueAspectFor:#''%1'' initialValue:true\' bindWith:anAspect.
    ].
    code := code, (text withCRs).
    CodeGeneratorTool compile:code forClass:aClass inCategory:(aCategory ? 'actions').
  ^ code
! !

!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:aDropContext
    "return true, if the DropContext can be dropped into the list of items.
     The dropable objects are already validated by: #dropEnter:"

    ^ (dropOverLine notNil and:[dropOverLine ~~ 0])

    "Modified: / 13-10-2006 / 16:03:47 / cg"
!

changeDropLineTo:aLineOrNil in:aContext
    "the over dropLine changed; redraw drop indication stuff
    "
    |x0 x1 y0|

    aLineOrNil == dropOverLine ifTrue:[
	^ self. "/ nothing changed
    ].
    x0 := listOfItemsView margin + 2.
    x1 := listOfItemsView width - x0.

    "/ inform the DragAndDrop handler that the draw contents will change
    aContext contentsWillChange.

    (dropOverLine notNil and:[dropOverLine ~~ 0]) ifTrue:[
	"/ restore old draw
	y0 := listOfItemsView yVisibleOfLine:(dropOverLine + 1).
	y0 := y0 - 3.

	listOfItemsView invalidate:(Rectangle left:x0 top:y0 width:(x1-x0+1) height:2)
			 repairNow:true.
    ].

    dropOverLine := aLineOrNil.

    (dropOverLine notNil and:[dropOverLine ~~ 0]) ifTrue:[
	"/ highlight new drop target
	y0 := listOfItemsView yVisibleOfLine:(dropOverLine + 1).
	y0 := y0 - 3.

	listOfItemsView paint:(Color white).
	listOfItemsView displayLineFromX:x0 y:y0 toX:x1 y:y0.
	y0 := y0 + 1.
	listOfItemsView paint:(Color black).
	listOfItemsView displayLineFromX:x0 y:y0 toX:x1 y:y0.
    ].
!

doDrop:aDropContext
    "drop the dropContext into the hierachical list of items
    "
    |done item|

    dropOverLine isNil ifTrue:[^ false ].      "/ context not valid to me ...

    item := listOfItems at:dropOverLine ifAbsent:nil.
    self dropLeave:aDropContext.
    item isNil ifTrue:[^ false].

    selectionHolder setValue:(Array with:item).

    done := false.

    self addAndSelectValueOf:[
	done := true.
	aDropContext dropObjects collect:[:el| Item menuItem:(el theObject) ]
    ].
    ^ done

    "Modified: / 13-10-2006 / 16:03:54 / cg"
!

dropEnter:aDropContext
    "a drop operation enters my widget; validate dropable objects.
     If the objects are not dropable, dropOverLine is set to nil,
     otherwise to 0 (can drop the contents but not).
    "
    |objects|

    dropOverLine := nil.

    self enablingCommitButtonsHolder value ifTrue:[
	"/ current editing spec is modified (couldn't accept operation)
	^ self
    ].
    objects := aDropContext dropObjects.
    objects isEmpty ifTrue:[ ^ self ].  "/ nothing to drop ???

    "/ test whether all objects are dropable (kind of MenuItem)
    (objects conform:[:el | (el theObject askFor:#isMenuItem)]) ifTrue:[
	"/ ok, the contents is dropable
	dropOverLine := 0.
    ]

    "Modified: / 13-10-2006 / 16:04:14 / cg"
!

dropLeave:aDropContext
    "the widget is leaved; restore drop indications drawn ...
    "
    self changeDropLineTo:nil in:aDropContext.

    "Modified: / 13-10-2006 / 16:03:59 / cg"
!

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

dropOver:aDropContext
    "called during drag & drop while moving over the widget."

    |lnNr item|

    dropOverLine isNil ifTrue:[^ self ].       "/ context not valid to me ...

    lnNr := listOfItemsView yVisibleToLineNr:(aDropContext targetPoint y).
    item := nil.

    lnNr ifNotNil:[
	item := listOfItems at:lnNr ifAbsent:nil.
	item ifNotNil:[
	    (item isAction and:[item hasDelayedMenu]) ifTrue:[
		item := nil
	    ]
	]
    ].
    item isNil ifTrue:[ lnNr := 0 ].   "/ not dropable for item

    "/ redraw drop indication
    self changeDropLineTo:lnNr in:aDropContext.

    "Modified: / 13-10-2006 / 16:04:05 / cg"
! !

!MenuEditor methodsFor:'event processing'!

processEvent:anEvent
    "filter keyboard edit-events typed into the listOfItemsView.
     Return true, if I have eaten the event"

    |evView inView rawKey key|

    anEvent isKeyPressEvent ifFalse:[^ false].

    evView := anEvent targetView.
    evView isNil ifTrue:[ ^ false ].

    "/ only handle keyboard events for the left item list
    "/ (otherwise, copy-paste would not work in the editFields on the right)
    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 ].

    (rawKey == #CtrlCursorUp) ifTrue:[
        self doMoveUp.
        ^ true.
    ].
    (rawKey == #CtrlCursorDown) ifTrue:[
        self doMoveDown.
        ^ true.
    ].
    (rawKey == #CtrlCursorLeft) ifTrue:[
        self doMoveOut.
        ^ true.
    ].
    (rawKey == #CtrlCursorRight) ifTrue:[
        self doMoveInNext.
        ^ true.
    ].

    ^ false.
! !

!MenuEditor methodsFor:'initialization & release'!

closeRequest
    "asks for permission before closing"

    self askForModification ifFalse:[^self].

"/    self enablingCommitButtonsHolder value ifTrue:[
"/        self setModified.
"/        self askForListModification.
"/        modified ifTrue:[^ self].
"/        self clearModified.
"/    ].
    super closeRequest

    "Modified: / 05-09-2006 / 18:44:15 / cg"
!

commonPostBuild
    self autoAcceptOnSelectionChange addDependent:self.
    self autoAcceptOnSelectionChange value ifTrue:[
	(builder componentAt:'okButton') label:(resources string:'Apply')
    ].

    "/ using masters infoHolder ?
    (builder aspectAt:#useAlienInfoLabelHolder) == true ifTrue:[
	(builder componentAt:#mainPanel) layout bottomOffset:0.
	(builder componentAt:#infoBarSubSpec) beInvisible
    ]
!

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

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

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

    listOfItems := HierarchicalList new.
    listOfItems application:self.
    listOfItems root:(RootItem 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:aSrollableView
    listOfItemsView := aSrollableView scrolledView.
!

postBuildNoteBook:aNoteBook
    aNoteBook tabLabelInset:16@4.
!

postOpenWith:aBuilder
    "reset keyboardProcessor for menuBar"

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

!MenuEditor methodsFor:'private'!

addAndSelectValueOf:aBlockOrItem
    "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 isNil ifTrue:[ ^ nil].

    self askForItemModification ifFalse:[ ^ nil ].

    index := 1.

    (intoItem canAddChildren and:[intoItem isExpanded]) ifFalse:[
	intoItem parent notNil ifTrue:[
	    [ intoItem parent canAddChildren ] whileFalse:[
		intoItem := intoItem parent.
	    ].
	    index := intoItem parent identityIndexOf:intoItem.
	    index := index + 1.
	    intoItem := intoItem parent.
	].
    ].
    newItem := aBlockOrItem 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).
	].
	self setModified.
    ].
    ^ newItem
!

clearModified
    "clear the modifiedChannel and the commitPanel"

    super clearModified.
    self enablingCommitButtonsHolder value:false.
    self clearModifiedFlag.
!

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

    menu := listOfItems root submenu.
    menu isNil ifTrue:[^ 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 isNil ifTrue:[^ nil ].

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

	anItem itemValue notNil ifTrue:[
	    anItem itemValue:[ Transcript showCR:(anItem label) ].
	].
	anItem indication notNil ifTrue:[
	    indication isNil ifTrue:[ indication := true asValue ].
	    anItem indication:indication
	].
	anItem choice notNil ifTrue:[
	    choice isNil ifTrue:[ choice := anItem choiceValue asValue ].
	    anItem choice:choice
	].
	anItem isMenuSlice ifTrue:[
	    anItem submenuChannel:nil.
	    anItem label:'... Slice Menu ...'.
	].
	anItem submenuChannel notNil ifTrue:[
	    anItem submenuChannel:nil.
	    anItem submenu isNil ifTrue:[
		submenu isNil ifTrue:[
		    submenu := Menu new.
		    submenu addItem:(MenuItem labeled:'Linked Menu...').
		].
		anItem submenu:submenu.
	    ].
	].
	retriever := anItem resourceRetriever.
	retriever notNil ifTrue:[
	    retriever labelText notNil ifTrue:[ 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.
    ] ensure:[
	notifyDisabledCounter := notifyDisabledCounter - 1
    ].
    ^ blockResult
! !

!MenuEditor methodsFor:'queries'!

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

    specClass isNil ifTrue:[^ 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 anythingChanged|

    self enablingCommitButtonsHolder value ifFalse:[
	^ true
    ].
    oldSelectedItem := self selectedItem.
    oldSelectedItem isNil ifTrue:[^ true].

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

    anythingChanged := self enablingCommitButtonsHolder value.
    anythingChanged ifTrue:[
	self autoAcceptOnSelectionChange value ifTrue:[
	    self accept.
	    ^ 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|
        selectors addAll:(el aspectSelectors).
    ].
    ^ selectors asOrderedCollection
!

doGenerateAspectMethods
    "compile aspect and action methods"

    |cls redefineAspectMethods category|

    specClass isNil ifTrue:[
	self warn:'Define the class first !!'.
	^ self
    ].
    redefineAspectMethods := self redefineAspectMethodsChannel value.

    cls := self resolveName:specClass.
    cls isNil ifTrue:[
	self warn:'Class ', specClass asString, ' does not exist!!'.
	^ self
    ].

    category := UserPreferences current categoryForMenuActionsMethods.

    self collectActionSelectors do:[:aSelector|
	self
	    createActionMethodFor:aSelector in:cls
	    category:category
	    redefine:redefineAspectMethods.
    ].

    self collectAspectSelectors do:[:anAspect|
	self
	    createAspectMethodFor:anAspect in:cls
	    category:category
	    redefine:redefineAspectMethods
    ].
! !

!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.
	(view 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 isNil ifTrue:[^ 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 doSave
    ].

    self updateHistory.
    hasSaved := true.
    self clearModified.
!

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

save
    self doSave
! !

!MenuEditor methodsFor:'user actions-creation'!

doCreateDelayedMenu:what
    |selectedItem delayedItem|

    selectedItem := self selectedItem.
    selectedItem isNil ifTrue:[^ self].

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

    what == #menu ifTrue:[ delayedItem := RegularMenuItem new ]
		 ifFalse:[ delayedItem := LinkedMenuItem new ].

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

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

doCreateItem
    "create a new Item
    "
    self addAndSelectValueOf:[ ActionItem new translateLabel:true ].
!

doCreateLinkedMenu
    "create a new Linked Menu
    "
    self addAndSelectValueOf:[ LinkedMenuItem new ].
!

doCreateMenu
    "create a new Menu
    "
    self addAndSelectValueOf:
	[ |item|
	    item := RegularMenuItem new.
	    "/ --- do not add it expanded - because that makes it hard to add multipe menus
	    "/ item expand.
	    item
	].
!

doCreateMenuSliceItem
    "create a new MenuSlice Item
    "
    self addAndSelectValueOf:[ MenuSliceItem new ].
!

doCreateSep
    "create a new Separator Item
    "
    self addAndSelectValueOf:[ SeparatorItem new ].
!

doCreateStandardEditMenu
    "create a standart edit menu
    "
    self addAndSelectValueOf:[
	RegularMenuItem menu:(self class standardEditMenu) labeled:'Edit' translateLabel:true
    ].
!

doCreateStandardFileMenu
    "create a standart file menu
    "
    self addAndSelectValueOf:[
	RegularMenuItem menu:(self class standardFileMenu) labeled:'File' translateLabel:true
    ].
!

doCreateStandardHelpMenu
    "create a standart help menu
    "
    |item|

    self addAndSelectValueOf:[
	item := RegularMenuItem menu:(self class standardHelpMenu) labeled:'Help' translateLabel:true.
	item aspectAt:#startGroup put:#conditionalRight.
	item
    ].

    "Modified: / 16-10-2006 / 12:49:27 / cg"
! !

!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).
    self setModified.
    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 isNil ifTrue:[ ^ self ].

    loMenuItems := OrderedCollection new.
    aCollection do:[:el|
	(el askFor:#isMenuItem) ifTrue:[ loMenuItems add:el ].
    ].
    loMenuItems isEmpty ifTrue:[ ^ self ].

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

!MenuEditor methodsFor:'user actions-hierarchy'!

doMoveDown
    "move selected item down"

    self doMoveUpOrDown:#down
!

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

    item := self selectedItem.
    item isNil ifTrue:[^ 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.
    self setModified.
!

doMoveInNext
    "move selected item into the next item"

    self doMoveIn:#inNext.
!

doMoveInPrevious
    "move selected item into the previous item"

    self doMoveIn:#inPrev.
!

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

    item := self selectedItem.
    item isNil ifTrue:[^ 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.
    self setModified.
!

doMoveUp
    "move selected item up"

    self doMoveUpOrDown:#up
!

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

    item := self selectedItem.
    item isNil ifTrue:[^ 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.
    self setModified.
! !

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

iconSliceMenu
    "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 iconSliceMenu inspect
     ImageEditor openOnClass:self andSelector:#iconSliceMenu
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
	constantNamed:#'MenuEditor::Item class iconSliceMenu'
	ifAbsentPut:[(Depth2Image new) width: 20; height: 16; photometric:(#palette); bitsPerSample:(#(2)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@O?????0:*****C/?6??XN:*[*) ;*).*&C.*&:*XN5U[UU :*****C*****(@@@@@@@@@@@@@@@@@@@@@@@@@@@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@@@@@@@@@@@@') ; yourself); yourself]
! !

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

classFor:aMenuItem

    aMenuItem isNil ifTrue:[ ^ nil ].

    aMenuItem itemValue isNil ifTrue:[
	aMenuItem isMenuSlice ifTrue:[ ^ MenuEditor::MenuSliceItem ].
	aMenuItem submenu notNil ifTrue:[ ^ MenuEditor::RegularMenuItem ].
	aMenuItem submenuChannel notNil ifTrue:[ ^ MenuEditor::LinkedMenuItem ].

	(self separatorTypeOf:(aMenuItem rawLabel)) notNil ifTrue:[
	    ^ MenuEditor::SeparatorItem
	]
    ].
    ^ MenuEditor::ActionItem
!

menuItem:aMenuItem
    |item cls|

    cls := self classFor:aMenuItem.
    cls isNil ifTrue:[^ nil].

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

!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)
          bounds: (Rectangle 0 0 407 291)
        )
        component:
       (SpecCollection
          collection: (
           (LabelSpec
              label: 'Accelerator:'
              name: 'shortcutKeyLabel'
              layout: (AlignmentOrigin 107 0 26 0 1 0.5)
              activeHelpKey: detailsAccelerator
              translateLabel: true
              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
              translateLabel: true
              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: symbolOrBooleanOrNil
              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
              translateLabel: true
              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: symbolOrBooleanOrNil
              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: smalltalkObjectOrNil
              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
              translateLabel: true
              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 conditionalRight)
            )
           (LabelSpec
              label: 'Access Character Position:'
              name: 'accessCharLabel'
              layout: (AlignmentOrigin 217 0 170 0 1 0.5)
              translateLabel: true
              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
            )
           (CheckBoxSpec
              label: 'Ignore Accelerator (i.e. Display Only)'
              name: 'ignoreShortcutKeysInItem'
              layout: (AlignmentOrigin 42 0 204 0 0 0.5)
              activeHelpKey: detailsIgnoreAcceleratorKeys
              visibilityChannel: hasNoSubmenu
              model: ignoreShortcutKeys
              translateLabel: true
              resizeForLabel: true
            )
           (CheckBoxSpec
              label: 'Ignore Accelerators in Submenu'
              name: 'ignoreShortcutKeys'
              layout: (AlignmentOrigin 42 0 204 0 0 0.5)
              activeHelpKey: detailsIgnoreAcceleratorKeys
              visibilityChannel: hasSubmenu
              model: ignoreShortcutKeys
              translateLabel: true
              resizeForLabel: true
            )
           (CheckBoxSpec
              label: 'Ignore Mnemonics in Submenu'
              name: 'ignoreMnemonicKeys'
              layout: (AlignmentOrigin 42 0 232 0 0 0.5)
              activeHelpKey: detailsIgnoreMnemonicKeys
              visibilityChannel: hasSubmenu
              model: ignoreMnemonicKeys
              translateLabel: true
              resizeForLabel: true
            )
           (LabelSpec
              label: 'Font:'
              name: 'fontLabel'
              layout: (AlignmentOrigin 107 0 271 0 1 0.5)
              translateLabel: true
              resizeForLabel: true
              adjust: right
            )
           (FontMenuSpec
              attributes:
             (tabable
                true
              )
              name: 'fontMenu'
              layout: (LayoutFrame 110 0 260 0 -5 1.0 282 0)
              activeHelpKey: fontMenu
              model: font
            )
           )

        )
      )

    "Modified: / 16-10-2006 / 12:48:12 / cg"
! !

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

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

!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 decodeFromLiteralArray:(menuItem literalArrayEncoding).

    "Modified: / 27-03-2007 / 08:43:14 / cg"
!

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

    menuItem := MenuItem labeled:(self rawLabel).

    MenuEditor aspects do:[:aKey|
	value := self validateValue:(aMenuItem perform:aKey).

	value notNil ifTrue:[
	    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:[
	"/ KLUDGE alarm: '-' and '' indicate a separator
	"/ (there is no separate menuItem class for them)

	(self isKindOfMenu or:[(self class separatorTypeOf:aValue) isNil]) ifTrue:[
	    menuItem rawLabel:aValue
	]
    ].
!

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

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

translateLabel:aBoolean
    menuItem translateLabel:aBoolean
! !

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

    "Modified: / 05-09-2006 / 17:47:19 / cg"
!

fromAspects:aspects
    "read values from aspects
    "
    MenuEditor aspects do:[:aKey|
        self aspectAt:aKey put:((aspects at:aKey) value).
    ].
    self validateMenuItem.
    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).
    (aspects at:#hasSubmenu)     value:(self isKindOfMenu or:[self children size ~~ 0]).
    (aspects at:#hasNoSubmenu)   value:(self isKindOfMenu not ).
!

validateMenuItem
    "validate the menuItem for correctness"

    menuItem isNil ifTrue:[^ self].

    menuItem choice isEmptyOrNil ifTrue:[
        menuItem choice:nil.
        menuItem choiceValue:nil.
    ].
! !

!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 isNil ifTrue:[ 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 isNil ifTrue:[ width := self widthOf:(self displayLabel) on:aGC ].
    ^ width
! !

!MenuEditor::Item methodsFor:'initialization'!

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

!MenuEditor::Item methodsFor:'private'!

validateValue:aValue
    "if we pick a menupanel, the values of an item can be
     a block model, ....
    "
    aValue notNil ifTrue:[
	aValue isBlock      ifTrue:[ ^ #block ].
	aValue isValueModel ifTrue:[ ^ #valueModel ].
    ].
    ^ aValue
! !

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

isMenuEditItem
    ^ true
!

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

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

actionSelectors
    "return my action selectors"

    |value|

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

aspectSelectors
    "return 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 isNil ifTrue:[^ 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 isNil ifTrue:[^ 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::ActionItem class methodsFor:'defaults'!

defaultLabel
    ^ 'Action'
! !

!MenuEditor::ActionItem 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::ActionItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
        name: basicsEditSpec
        window:
       (WindowSpec
          label: 'basicsEditSpec'
          name: 'basicsEditSpec'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 340 340)
        )
        component:
       (SpecCollection
          collection: (
           (LabelSpec
              label: 'Name Key:'
              name: 'nameKeyLabel'
              layout: (AlignmentOrigin 107 0 25 0 1 0.5)
              activeHelpKey: basicsKey
              translateLabel: true
              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
              translateLabel: true
              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
              translateLabel: true
              resizeForLabel: true
              adjust: right
            )
           (InputFieldSpec
              name: 'valueField'
              layout: (LayoutFrame 110 0 71 0 -5 1.0 93 0)
              activeHelpKey: basicsAction
              tabable: true
              model: itemValue
              group: inputGroup
              type: symbolOrNil
              immediateAccept: false
              acceptOnLeave: true
              acceptOnReturn: true
              acceptOnTab: true
              acceptOnLostFocus: true
              acceptChannel: acceptChannel
              modifiedChannel: modifiedChannel
              acceptOnPointerLeave: true
            )
           (LabelSpec
              label: 'Argument:'
              name: 'argumentLabel'
              layout: (AlignmentOrigin 107 0 107 0 1 0.5)
              activeHelpKey: basicsArgument
              translateLabel: true
              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: smalltalkObjectOrNil
              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
              translateLabel: true
              resizeForLabel: true
              adjust: right
            )
           (InputFieldSpec
              name: 'indicationField'
              layout: (LayoutFrame 110 0 127 0 -5 1.0 149 0)
              activeHelpKey: basicsIndication
              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
              translateLabel: true
              resizeForLabel: true
              adjust: right
            )
           (InputFieldSpec
              name: 'choiceField'
              layout: (LayoutFrame 110 0 152 0 -5 1.0 174 0)
              activeHelpKey: basicsChoice
              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
              translateLabel: true
              resizeForLabel: true
              adjust: right
            )
           (InputFieldSpec
              name: 'choiceValueField'
              layout: (LayoutFrame 110 0 177 0 -5 1.0 199 0)
              activeHelpKey: basicsChoiceValue
              enableChannel: choiceValueEnabled
              tabable: true
              model: choiceValue
              group: inputGroup
              type: smalltalkObjectOrNil
              immediateAccept: false
              acceptOnLeave: false
              acceptOnReturn: true
              acceptOnTab: true
              acceptOnLostFocus: false
              acceptChannel: acceptChannel
              modifiedChannel: modifiedChannel
              acceptOnPointerLeave: false
            )
           (CheckBoxSpec
              label: 'Translate Label'
              name: 'translateLabelCheckBox'
              layout: (AlignmentOrigin 7 0 213 0 0 0)
              activeHelpKey: basicsTranslateLabel
              tabable: true
              model: translateLabel
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Is Button'
              name: 'isButtonCheckBox'
              layout: (AlignmentOrigin 7 0 238 0 0 0)
              activeHelpKey: basicsIsButton
              tabable: true
              model: isButton
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Hide Menu after Activation'
              name: 'hideMenuOnActivated'
              layout: (AlignmentOrigin 7 0 263 0 0 0)
              activeHelpKey: hideMenuOnActivated
              tabable: true
              model: hideMenuOnActivated
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'BusyCursor while Active'
              name: 'showBusyCursorWhilePerforming'
              layout: (AlignmentOrigin 7 0 288 0 0 0)
              activeHelpKey: showBusyCursorWhilePerforming
              tabable: true
              model: showBusyCursorWhilePerforming
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Trigger On Down'
              name: 'triggerOnDown'
              layout: (AlignmentOrigin 25 0.5 238 0 0 0)
              activeHelpKey: triggerOnDown
              enableChannel: hasNoDelayedMenuValue
              tabable: true
              model: triggerOnDown
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Send To Originating Widget'
              name: 'sendToOriginator'
              layout: (AlignmentOrigin 7 0 313 0 0 0)
              activeHelpKey: sendToOriginator
              enableChannel: hasItemValue
              tabable: true
              model: sendToOriginator
              translateLabel: true
            )
           )

        )
      )
! !

!MenuEditor::ActionItem 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::ActionItem methodsFor:'accessing'!

menuItem
    |item|

    item := super menuItem.
    self hasDelayedMenu ifTrue:[
	children first setDelayedAttributesTo:item.

	menuItem value isNil ifTrue:[
	    menuItem value:#unspecified
	]
    ].
    ^ item
!

menuItem:anItem
    |submenu item|

    super menuItem:anItem.
    submenu := anItem submenu.

    submenu notNil ifTrue:[
	item := MenuEditor::RegularMenuItem new
    ] ifFalse:[
	anItem submenuChannel isNil ifTrue:[
	    ^ self
	].
	item := MenuEditor::LinkedMenuItem new
    ].
    item getDelayedAttributesFrom:anItem.
    self add:item.
!

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

!MenuEditor::ActionItem 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
    ].

    menuItem triggerOnDown:false.
    anItem argument:(menuItem argument).
    isExpanded := false.
    anItem parent:self.
    children := Array with:anItem.
    self expand.
    ^ anItem

    "Modified: / 05-09-2006 / 17:49:57 / cg"
! !

!MenuEditor::ActionItem methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "set a specific aspect named aKey to the aValue"

    aKey == #argument ifTrue:[
        self hasDelayedMenu ifTrue:[
            children first argument:aValue
        ].
        menuItem argument:aValue.
        ^ self
    ].

    aKey == #triggerOnDown ifTrue:[
        |triggerOnDown|

        self hasDelayedMenu ifTrue:[
            triggerOnDown := false
        ] ifFalse:[
            triggerOnDown := aValue
        ].
        menuItem triggerOnDown:triggerOnDown.
        ^ self.
    ].
    super aspectAt:aKey put:aValue.

    "Modified: / 05-09-2006 / 17:47:24 / cg"
!

toAspects:aspects
    "write values to aspects
    "
    |hasDelayedMenu|

    super toAspects:aspects.

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

    hasDelayedMenu ifTrue:[
	(aspects at:#triggerOnDown) value:false
    ].
! !

!MenuEditor::ActionItem methodsFor:'displaying'!

icon
    ^ self class iconItem
! !

!MenuEditor::ActionItem methodsFor:'initialization'!

initialize
    super initialize.
    isExpanded := true.
! !

!MenuEditor::ActionItem methodsFor:'queries'!

canCollapse
    ^ false
!

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

hasIndicator
    ^ false
!

isAction
    ^ true
! !

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

canAddDelayedMenu
    "returns true if a delayed menu can be added
    "
    ^ self hasDelayedMenu not
! !

!MenuEditor::LinkedMenuItem class methodsFor:'defaults'!

defaultLabel
    ^ 'Linked Menu'
! !

!MenuEditor::LinkedMenuItem 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::LinkedMenuItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
        name: basicsEditSpec
        window:
       (WindowSpec
          label: 'basicsEditSpec'
          name: 'basicsEditSpec'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 340 340)
        )
        component:
       (SpecCollection
          collection: (
           (LabelSpec
              label: 'Name Key:'
              name: 'nameKeyLabel'
              layout: (AlignmentOrigin 107 0 25 0 1 0.5)
              activeHelpKey: basicsKey
              visibilityChannel: notDelayedMenu
              translateLabel: true
              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
              translateLabel: true
              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
              translateLabel: true
              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
              translateLabel: true
              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: smalltalkObjectOrNil
              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
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Is Button'
              name: 'isButtonCheckBox'
              layout: (Point 20 238)
              activeHelpKey: basicsIsButton
              visibilityChannel: notDelayedMenu
              tabable: true
              model: isButton
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Horizontal Layout'
              name: 'horizontalLayout'
              layout: (Point 20 263)
              activeHelpKey: horizontalLayout
              tabable: true
              model: horizontalLayout
              translateLabel: true
            )
           (CheckBoxSpec
              label: 'Do not Destroy Linked Menu'
              name: 'keepLinkedMenu'
              layout: (Point 20 288)
              activeHelpKey: keepLinkedMenu
              tabable: true
              model: keepLinkedMenu
              translateLabel: true
            )
           )

        )
      )
! !

!MenuEditor::LinkedMenuItem 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::LinkedMenuItem 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.

    "Modified: / 05-09-2006 / 17:47:39 / cg"
!

getDelayedAttributesFrom:anItem

    menuItem rawLabel:'Delayed'.

    menuItem   submenuChannel:(self validateValue:(anItem submenuChannel)).
    menuItem horizontalLayout:(self validateValue:(anItem horizontalLayout)).
    menuItem   keepLinkedMenu:(self validateValue:(anItem keepLinkedMenu)).
!

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

!MenuEditor::LinkedMenuItem 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::LinkedMenuItem methodsFor:'initialization'!

initialize
    "setup default values on the item
    "
    super initialize.

    "setting default values
    "
    menuItem keepLinkedMenu:true.
! !

!MenuEditor::LinkedMenuItem methodsFor:'queries'!

isKindOfMenu
    ^ true
! !

!MenuEditor::MenuSliceItem class methodsFor:'defaults'!

defaultLabel
    ^ 'Menu Slice'
! !

!MenuEditor::MenuSliceItem 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::MenuSliceItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
        name: basicsEditSpec
        window:
       (WindowSpec
          label: 'basicsEditSpec'
          name: 'basicsEditSpec'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 344 146)
        )
        component:
       (SpecCollection
          collection: (
           (LabelSpec
              label: 'Name Key:'
              name: 'nameKeyLabel'
              layout: (AlignmentOrigin 107 0 25 0 1 0.5)
              activeHelpKey: basicsKey
              visibilityChannel: notDelayedMenu
              translateLabel: true
              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
              translateLabel: true
              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
              translateLabel: true
              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
              translateLabel: true
              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: smalltalkObjectOrNil
              immediateAccept: false
              acceptOnReturn: true
              acceptOnTab: true
              acceptOnLostFocus: false
              acceptChannel: acceptChannel
              modifiedChannel: modifiedChannel
              acceptOnPointerLeave: false
            )
           )

        )
      )
! !

!MenuEditor::MenuSliceItem methodsFor:'accessing'!

icon
    ^ self class iconSliceMenu
!

menuItem
     "returns self as a MenuItem
    "
    |item|

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

slices
    ^ #(
	    (Basics   basicsEditSpec)
       )
! !

!MenuEditor::MenuSliceItem methodsFor:'aspects'!

argument:aValue
    menuItem argument:aValue.
!

aspectAt:aKey put:aValue
    "set a specific aspect named aKey to the aValue"

    aKey == #submenuChannel ifTrue:[ ^ self submenuChannel:aValue ].
    aKey == #isSliceMenu    ifTrue:[ ^ self ].

    super aspectAt:aKey put:aValue.

    "Modified: / 05-09-2006 / 17:47:42 / cg"
!

submenuChannel
    ^ menuItem submenuChannel ? #unspecified
!

submenuChannel:aValue
    menuItem submenuChannel:aValue.
! !

!MenuEditor::RegularMenuItem class methodsFor:'defaults'!

defaultDelayedLabel
    ^ 'delayed'
!

defaultLabel
    ^ 'Menu'
! !

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

menu:aMenu labeled:aString
    |item|

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

menu:aMenu labeled:aString translateLabel:translateLabel
    |item|

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

!MenuEditor::RegularMenuItem 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::RegularMenuItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
	name: basicsEditSpec
	window:
       (WindowSpec
	  label: 'basicsEditSpec'
	  name: 'basicsEditSpec'
	  min: (Point 10 10)
	  bounds: (Rectangle 0 0 340 340)
	)
	component:
       (SpecCollection
	  collection: (
	   (LabelSpec
	      label: 'Name Key:'
	      name: 'nameKeyLabel'
	      layout: (AlignmentOrigin 107 0 25 0 1 0.5)
	      activeHelpKey: basicsKey
	      visibilityChannel: notDelayedMenu
	      translateLabel: true
	      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
	      translateLabel: true
	      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
	      translateLabel: true
	    )
	   (CheckBoxSpec
	      label: 'Is Button'
	      name: 'isButtonCheckBox'
	      layout: (Point 20 238)
	      activeHelpKey: basicsIsButton
	      visibilityChannel: notDelayedMenu
	      tabable: true
	      model: isButton
	      translateLabel: true
	    )
	   (CheckBoxSpec
	      label: 'Horizontal Layout'
	      name: 'horizontalLayout'
	      layout: (Point 20 263)
	      activeHelpKey: horizontalLayout
	      tabable: true
	      model: horizontalLayout
	      translateLabel: true
	    )
	   )

	)
      )
! !

!MenuEditor::RegularMenuItem 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.

	menu := aMenu value.

	(menu isNil or:[menu isString]) ifTrue:[
	    menu := nil
	] ifFalse:[
	    aMenu isCollection ifTrue:[ menu := Menu decodeFromLiteralArray: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

    "Modified: / 27-03-2007 / 08:43:07 / cg"
!

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::RegularMenuItem methodsFor:'aspects'!

getDelayedAttributesFrom:aMenuItem

    |menu|

    menu := self validateValue:(aMenuItem submenu value).

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

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

!MenuEditor::RegularMenuItem 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::RegularMenuItem methodsFor:'queries'!

canAddChildren
    "children can be added
    "
    ^ true
!

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

hasIndicator
    ^ true
!

isKindOfMenu
    ^ true
! !

!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)
	  bounds: (Rectangle 0 0 288 295)
	)
	component:
       (SpecCollection
	  collection: (
	   (LabelSpec
	      label: 'Retriever:'
	      name: 'retrieverLabel'
	      layout: (AlignmentOrigin 107 0 26 0 1 0.5)
	      activeHelpKey: imageRetriever
	      translateLabel: true
	      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
	      entryCompletionBlock: entryCompletionForRetriever
	      comboList: retrieverList
	      isFilenameBox: false
	    )
	   (LabelSpec
	      label: 'Selector:'
	      name: 'iconLabel'
	      layout: (AlignmentOrigin 107 0 51 0 1 0.5)
	      activeHelpKey: imageSelector
	      translateLabel: true
	      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
		    translateLabel: true
		  )
		 (ActionButtonSpec
		    label: 'Image Editor'
		    name: 'imageEditorButton'
		    layout: (AlignmentOrigin 0 1.0 0 0.5 1 0.5)
		    activeHelpKey: imageImageEditor
		    hasCharacterOrientedLabel: false
		    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"

    |classAndSelector|

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

    classAndSelector isNil ifTrue:[ ^ self ].

    retrieverHolder value:(classAndSelector methodClass) name.
    selectorHolder  value:(classAndSelector methodSelector).
!

doEditImage
    |sel cls item|

    item := imageHolder value.
    item notNil ifTrue:[
	item doEdit
    ] ifFalse:[
	(sel := selectorHolder value) isNil ifTrue:[
	    Dialog warn:'No selector is defined.'.
	] ifFalse:[
	    (cls := retrieverHolder value) isNil ifTrue:[
		Dialog warn:'No resource retriever is defined.'.
	    ] ifFalse:[
		cls := Smalltalk classNamed:cls.
		cls isNil ifTrue:[
		    Dialog warn:'No such resource retriever class.'.
		] ifFalse:[
		    ImageEditor openOnClass:cls andSelector:sel
		]
	    ]
	]
    ].
! !

!MenuEditor::ResourceEditor methodsFor:'aspects'!

entryCompletionForRetriever
    ^ DoWhatIMeanSupport classNameEntryCompletionBlock.

    "Modified: / 10-08-2006 / 12:55:22 / cg"
!

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 isNil ifTrue:[
	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 updateImageHolder.

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

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

selectorChanged
    self updateImageHolder.
!

update:what with:aPara from:aModel
    |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
!

updateImageHolder
    |item selector line|

    imageList isEmpty ifTrue:[^ self].

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

    item     := nil.
    selector := selector asSymbol.

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

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

!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.
    selector numArgs == 0 ifFalse:[^ self].

    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::RootItem class methodsFor:'defaults'!

defaultLabel
    ^ MenuEditor resourceType
! !

!MenuEditor::RootItem 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::RootItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
	name: basicsEditSpec
	window:
       (WindowSpec
	  label: 'basicsEditSpec'
	  name: 'basicsEditSpec'
	  min: (Point 10 10)
	  bounds: (Rectangle 0 0 260 46)
	)
	component:
       (SpecCollection
	  collection: (
	   (LabelSpec
	      label: 'Selector:'
	      name: 'selectorLabel'
	      layout: (AlignmentOrigin 107 0 26 0 1 0.5)
	      activeHelpKey: basicsSelector
	      translateLabel: true
	      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::RootItem class methodsFor:'interface-editor'!

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

!MenuEditor::RootItem 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::RootItem methodsFor:'adding & removing'!

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

!MenuEditor::RootItem methodsFor:'aspects'!

aspectAt:aKey put:aValue
    "ignore all aspects other than the rawLabel"

    aKey == #rawLabel ifTrue:[ self rawLabel:aValue ].

    "Modified: / 05-09-2006 / 17:48:01 / cg"
! !

!MenuEditor::RootItem methodsFor:'displaying'!

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

!MenuEditor::RootItem methodsFor:'initialization'!

initialize
    super initialize.
    isExpanded := true.
! !

!MenuEditor::RootItem methodsFor:'queries'!

canCollapse
    ^ false
!

hasIndicator
    ^ false
!

isDelayedMenu
    ^ false
!

isRootItem
    ^ true
! !

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

actionSelectors
    "return my action selectors"

    ^ #()
!

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

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

canMoveInAbove
    ^ false
!

canMoveInNext
    ^ false
!

canMoveOut
    ^ false
!

canMoveUpOrDown
   ^ false
! !

!MenuEditor::SeparatorItem 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::SeparatorItem andSelector:#basicsEditSpec
    "

    <resource: #canvas>

    ^
     #(FullSpec
	name: basicsEditSpec
	window:
       (WindowSpec
	  label: 'basicsEditSpec'
	  name: 'basicsEditSpec'
	  min: (Point 10 10)
	  bounds: (Rectangle 0 0 260 245)
	)
	component:
       (SpecCollection
	  collection: (
	   (LabelSpec
	      label: 'Separator:'
	      name: 'separatorLabel'
	      layout: (AlignmentOrigin 107 0 26 0 1 0.5)
	      translateLabel: true
	      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)
	      translateLabel: true
	      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: symbolOrBooleanOrNil
	      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)
	      translateLabel: true
	      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 conditionalRight)
	    )
	   )

	)
      )

    "Modified: / 16-10-2006 / 12:48:30 / cg"
! !

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

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

    aspects
	at:#seperatorList
	ifAbsentPut:
	    [
		|l|

		l := self separatorSlices collect:[:el| el last ].
		l := l collect:[:s | self classResources string:s ].
		l
	    ].

    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::SeparatorItem 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::SeparatorItem 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::SeparatorItem 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 isNil ifTrue:[ width := 60 ].
    ^ width
! !

!MenuEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !

MenuEditor initialize!