[squeak-dev] The Inbox: Morphic-phite.428.mcz

Hannes Hirzel hannes.hirzel at gmail.com
Mon Apr 26 04:28:12 UTC 2010


Hello Philipp

I loaded your contribution Morphic-phite.428.mcz into a fresh image
updated to #10012.

Then I typed
    Docking
into the search bar and thus found the class
    TheWorldMainDockingBar

Then I clicked onto the class comment tab. What I saw is

      A TheWorldMainDockingBar is xxxxxxxxx.

      Instance Variables



I was expecting at least one or two sentences about your addition.
What does this thing and how do I add menu entries.

OK, you have given the indication in your mail above in this thread.
So I went to the search bar again and typed
     menuEntrySpecification

A message name browser came up but had nothing in it.

I was asking myself - What do I do next?

I decided to stop and write this email.

My three remarks

1) A comment in the class TheWorldMainDockingBar is necessary (if this
is the proper class)

2) An example / test case is necessary as well

3) I like the idea of having MenuEntrySpecs. They fit nicely with the
ToolBuilder approach.


Note: Bert wants to discuss in another thread this approach
(MenuEntrySpecs) and the solution proposal by Steve Wessels (Pragma
based).

Conclusion: I think your proposal needs to be a bit more worked out so
that people can easily see how it works.

--Hannes

On 4/25/10, Philipp Tessenow <phite at nada1.de> wrote:
> Hi,
>
> I refactored the docking bar to be extendable with custom menu entries.
> Every class may implement #menuEntrySpecification to answer a
> MenuEntrySpec - see:
>
> ^ MenuEntrySpec newFrom: (Dictionary newFromPairs: #(
>         #contents 'Well... hello?'
>         #help 'Displays the Hello World'
>         #location #('Help')
>         #target MenuMorph #selector #inform: #arguments #('Hello World!')
>         #position #first))
>
> Which adds a menuEntry 'Well... Hello?' in the first slot of the Help-menu.
> It is possible to select as many subMenus as you like.
> MenuEntries can be position within a menu by defining it's position
> (#first, #last, #(#before 'aMenu'), #(#after 'aMenu')
>
> As MenuEntrySpecs can are created with a Dictionary you can leave field
> you don't want to declare. (As is did with #icon and #selectedIcon in my
> example).
>
> Comments please :)
>
> regards,
>   Philipp
>
>
> Am 25.04.2010 18:16, schrieb commits at source.squeak.org:
>> A new version of Morphic was added to project The Inbox:
>> http://source.squeak.org/inbox/Morphic-phite.428.mcz
>>
>> ==================== Summary ====================
>>
>> Name: Morphic-phite.428
>> Author: phite
>> Time: 25 April 2010, 8:16:06.137 pm
>> UUID: a876e2b3-d755-1845-9002-16c2c0dde809
>> Ancestors: Morphic-ar.427
>>
>> Refactored DockingBar to add dynamically add entries.
>>
>> Any class that implements #menuEntrySpecification may create a new
>> menuEntry.
>>
>> #menuEntrySpecification answers a MenuEntrySpec.
>> Example:
>> menuEntrySpecification
>> 	"Answer a MenuEntrySpec object that declares my menuEntrie in the world
>> docking"
>>
>> 	^ MenuEntrySpec newFrom: (Dictionary newFromPairs: #(
>> 		#contents 'Well... hello?'
>> 		#help 'Displays the Hello World'
>> 		#location #('Help')
>> 		#target MenuMorph #selector #inform: #arguments #('Hello World!')
>> 		#position #first))
>> 		
>> #location specifies the location within the DockingBar. It may be #() to
>> create a top-level menu or #('Help' 'subMenu1' 'subMenu2') to create a
>> menuEntry within some sub menus in Help.
>>
>> #position may be #first, #last or #(before 'Keyboard Shortcuts'), #(#after
>> ''Keyboard Shortcuts'') to declare the menuEntry's position within the a
>> menu.
>>
>> =============== Diff against Morphic-ar.427 ===============
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>selectedIcon (in category 'accessing')
>> -----
>> + selectedIcon
>> +
>> + 	^ selectedIcon!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>selectedIcon: (in category 'accessing')
>> -----
>> + selectedIcon: anIcon
>> +
>> + 	selectedIcon := anIcon!
>>
>> Item was changed:
>>   ----- Method: DockingBarMorph>>add:icon:selectedIcon:help:subMenu: (in
>> category 'construction') -----
>>   add: wordingString icon: aForm selectedIcon: anotherForm help:
>> helpString subMenu: aMenuMorph
>>   	"Append the given submenu with the given label."
>> +
>> + 	self add: wordingString icon: aForm selectedIcon: anotherForm help:
>> helpString subMenu: aMenuMorph position: {#back}.!
>> - 	| item |
>> - 	item := DockingBarItemMorph new
>> - 		contents: wordingString;
>> - 		subMenu: aMenuMorph;
>> - 		icon: aForm;
>> - 		selectedIcon: anotherForm.
>> - 	helpString isNil ifFalse: [
>> - 		item setBalloonText: helpString ].
>> - 	self addMorphBack: item!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec classSide>>newFrom: (in category 'as yet
>> unclassified') -----
>> + newFrom: aDict
>> + 	"Creates a new MenuEntrySpec from a Dictionary.
>> + 	Possible keys are: #contents, #help, #icon, #selectedIcon,
>> + 	#target, #selector, #argument, #location, #position
>> + 	where #location describes where the menuEntry should be placed
>> + 		#location -> nil creates a new menuEntry in the DockingBar
>> + 		#location -> #('Tools' 'subMenu' 'subMenu2') puts the menuEntry into
>> submenus
>> + 	and where #position describes the position of the menuEntry within a
>> menu eg.
>> + 		#position -> #last - adds the menuEntry at the end of the menu (#first
>> at the beginning)
>> + 		#position -> #(#before 'Help') - adds the menuEntry just before the
>> 'Help' entry (#after adds it after the entry)"
>> +
>> + 	^ self new
>> + 		contents: (aDict at: #contents ifAbsent: '');
>> + 		help: (aDict at: #help ifAbsent: nil);
>> + 		icon: (aDict at: #icon ifAbsent: nil);
>> + 		selectedIcon: (aDict at: #selectedIcon ifAbsent: nil);
>> + 		target: (aDict at: #target ifAbsent: nil);
>> + 		selector: (aDict at: #selector ifAbsent: nil);
>> + 		arguments: (aDict at: #arguments ifAbsent: nil);
>> + 		location: (aDict at: #location ifAbsent: nil);
>> + 		position: (aDict at: #position ifAbsent: #last)!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>selector (in category 'accessing') -----
>> + selector
>> +
>> + 	^ selector!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>installOn: (in category 'menu-creation')
>> -----
>> + installOn: aDockingBar
>> + 	"Installs a menuEntry corresponding to this specification into the
>> given DockingBar"
>> +
>> + 	| menu |
>> + 	menu := self findOrCreateLocationIn: aDockingBar.
>> + 	menu subMenu ifNil: [ menu addSubMenu: [:subMenu |] ].
>> + 	menu subMenu addItem: [ :item |
>> + 		item
>> + 			contents: self contents;
>> + 			help: self help;
>> + 			icon: self icon;
>> + 			target: self target;
>> + 			selector: self selector;
>> + 			arguments: self arguments.
>> + 		(item respondsTo: #selectedIcon:) ifTrue: [ item selectedIcon: self
>> selectedIcon ].]
>> + 		at: self position.!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>target: (in category 'accessing') -----
>> + target: anObject
>> +
>> + 	target := anObject!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>position (in category 'accessing') -----
>> + position
>> +
>> + 	^ position!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>location (in category 'accessing') -----
>> + location
>> + 	"An Array containing the menu and submenues the menu should be placed."
>> + 	
>> + 	^ location!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>contents (in category 'accessing') -----
>> + contents
>> + 	"The label of the menuEntry."
>> + 	
>> + 	^ contents!
>>
>> Item was added:
>> + ----- Method: MenuMorph>>addMenuItem:at: (in category 'construction')
>> -----
>> + addMenuItem: aMenuItemMorph at: position
>> + 	"adds the Menu at the given position. Position is an Array of the form
>> + 		{#last}, {#first}, {#before . 'Help'}, {#after . 'Tools'}"
>> +
>> + 	((position at: 1) = #first) ifTrue: [ ^ self addMorphFront:
>> aMenuItemMorph ].
>> + 	((position at: 1) = #before) ifTrue: [ ^ self addMorph: aMenuItemMorph
>> inFrontOf:
>> + 		(self menus detect: [ :menu | menu contents = (position at: 2) ]) ].
>> + 	((position at: 1) = #after) ifTrue: [ ^ self addMorph: aMenuItemMorph
>> behind:
>> + 		(self menus detect: [ :menu | menu contents = (position at: 2) ]) ].
>> + 	"#last"
>> + 	self addMorphBack: aMenuItemMorph.!
>>
>> Item was added:
>> + ----- Method: DockingBarMenuMorph>>menus (in category 'as yet
>> unclassified') -----
>> + menus
>> + 	"Answers an array of my menuEntries"
>> + 	^ self submorphs select: [:aMorph | aMorph isKindOf: MenuItemMorph]!
>>
>> Item was added:
>> + ----- Method: TheWorldMainDockingBar>>searchForMenuSpecs (in category
>> 'construction') -----
>> + searchForMenuSpecs
>> + 	"This is a one-time only method for creating the worlds DockingBar.
>> Here we scann all classes for #menuEntrySpecification methods and answer
>> an Array of all menuSpecs found."
>> +
>> + 	^ ((self systemNavigation allClassesImplementing:
>> #menuEntrySpecification)
>> + 		collect: [ :aClass | aClass theNonMetaClass menuEntrySpecification])!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>arguments: (in category 'accessing') -----
>> + arguments: anArray
>> +
>> + 	arguments := anArray!
>>
>> Item was added:
>> + ----- Method: DockingBarMorph>>subMenu (in category 'accessing') -----
>> + subMenu
>> + 	"This is for convenience and makes the DockingBar look more like a
>> MenuMorph."
>> +
>> + 	^ self!
>>
>> Item was added:
>> + ----- Method: DockingBarMorph>>addMenu:atPosition: (in category
>> 'construction') -----
>> + addMenu: item atPosition: position
>> + 	"adds the Menu at the given position. Position is an Array of the form
>> + 		{#last}, {#first}, {#before . 'Help'}, {#after . 'Tools'}"
>> +
>> + 	((position at: 1) = #first) ifTrue: [ ^ self addMorphFront: item ].
>> + 	((position at: 1) = #before) ifTrue: [ ^ self addMorph: item inFrontOf:
>> + 		(self menus detect: [ :menu | menu contents = (position at: 2) ]) ].
>> + 	((position at: 1) = #after) ifTrue: [ ^ self addMorph: item behind:
>> + 		(self menus detect: [ :menu | menu contents = (position at: 2) ]) ].
>> + 	"#last"
>> + 	self addMorphBack: item.!
>>
>> Item was added:
>> + ----- Method: TheWorldMainDockingBar>>customMenusOn: (in category
>> 'construction') -----
>> + customMenusOn: aDockingBar
>> + 	"Searches for MenuEntrySpecs and add the corresponding menus to the
>> docking bar."
>> + 	| menuSpecs |
>> + 	menuSpecs := self searchForMenuSpecs sortBy: [ :a :b | a location size
>> > b location size].
>> + 	menuSpecs do: [ :spec |
>> + 		spec installOn: aDockingBar].!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>icon: (in category 'accessing') -----
>> + icon: anIcon
>> +
>> + 	icon := anIcon!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>findOrCreateLocationIn: (in category
>> 'menu-creation') -----
>> + findOrCreateLocationIn: aDockingBar
>> + 	"find the menu my location points at - create it, if it does not
>> exist."
>> +
>> + 	| currentMenu |
>> + 	location size = 0 ifTrue: [ ^ aDockingBar ].
>> + 	currentMenu := aDockingBar.
>> + 	(1 to: location size) do: [ :i |
>> + 		currentMenu := currentMenu menus detect:
>> + 		[ :m | m contents = (location at: i) ]
>> + 		ifNone: [
>> + 			currentMenu subMenu ifNil: [ currentMenu addSubMenu:[:subMenu| ]].
>> + 			currentMenu subMenu addItem: [:item|
>> + 				item contents: (location at: i)].
>> + 			currentMenu menus detect: [ :m | m contents = (location at: i) ]]].
>> + 	^ currentMenu!
>>
>> Item was added:
>> + ----- Method: DockingBarMorph>>addItem:at: (in category 'construction')
>> -----
>> + addItem: aBlock at: position
>> + 	| item |
>> + 	item := DockingBarItemMorph new.
>> + 	aBlock value: item.
>> + 	self addMenu: item atPosition: position.!
>>
>> Item was added:
>> + ----- Method: MenuItemMorph>>menus (in category 'accessing') -----
>> + menus
>> + 	"Answers an array of my submenus"
>> + 	self subMenu ifNil: [ ^ #() ].
>> + 	^ self subMenu submorphs select: [:aMorph | aMorph isKindOf:
>> MenuItemMorph]!
>>
>> Item was added:
>> + ----- Method: DockingBarItemMorph>>menus (in category 'as yet
>> unclassified') -----
>> + menus
>> + 	"Answers an array of my submenus"
>> + 	self subMenu ifNil: [ ^ #() ].
>> + 	^ self subMenu submorphs select: [:aMorph | aMorph isKindOf:
>> MenuItemMorph]!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>target (in category 'accessing') -----
>> + target
>> +
>> + 	^ target!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>location: (in category 'accessing') -----
>> + location: stringOrArray
>> + 	"Encapsulates the parameter into an Array."
>> + 	
>> + 	stringOrArray ifNil: [ location := #() ].
>> + 	stringOrArray isString ifTrue: [ location := #(stringOrArray) ].
>> + 	stringOrArray isArray ifTrue: [ location := stringOrArray ].!
>>
>> Item was added:
>> + ----- Method: MenuMorph>>addItem:at: (in category 'construction') -----
>> + addItem: aBlock at: position
>> + 	| item |
>> + 	item := MenuItemMorph new.
>> + 	aBlock value: item.
>> + 	self addMenuItem: item at: position!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>selector: (in category 'accessing') -----
>> + selector: aSymbol
>> +
>> + 	selector := aSymbol!
>>
>> Item was added:
>> + ----- Method: DockingBarMorph>>menus (in category 'menu') -----
>> + menus
>> + 	"Answers an array of menus in this docking bar"
>> + 	^ self submorphs select: [:aMorph | aMorph isKindOf: MenuItemMorph]!
>>
>> Item was changed:
>>   ----- Method: DockingBarMorph>>add:icon:help:subMenu: (in category
>> 'construction') -----
>>   add: wordingString icon: aForm help: helpString subMenu: aMenuMorph
>>   	"Append the given submenu with the given label."
>> +
>> + 	self add: wordingString icon: aForm selectedIcon: nil help: helpString
>> subMenu: aMenuMorph.!
>> - 	| item |
>> - 	item := DockingBarItemMorph new.
>> - 	item contents: wordingString.
>> - 	item subMenu: aMenuMorph.
>> - 	item icon: aForm.
>> - 	helpString isNil
>> - 		ifFalse: [item setBalloonText: helpString].
>> - 	self addMorphBack: item!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>help: (in category 'accessing') -----
>> + help: aString
>> +
>> + 	help := aString!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>position: (in category 'accessing') -----
>> + position: symbolOrArray
>> + 	"The Array either is kind of #(#symbol) - where #symbol is #first or
>> #last
>> + 	or #(#symbol 'string') - where #symbol is #before or #after and string
>> is the label of a menu"
>> +
>> + 	symbolOrArray isSymbol ifTrue: [ position := { symbolOrArray } ].
>> + 	symbolOrArray isArray ifTrue: [ position := symbolOrArray ].!
>>
>> Item was added:
>> + ----- Method: MenuMorph>>menus (in category 'accessing') -----
>> + menus
>> + 	"Answers an array of my menuEntries"
>> + 	^ self submorphs select: [:aMorph | aMorph isKindOf: MenuItemMorph]!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>arguments (in category 'accessing') -----
>> + arguments
>> +
>> + 	^ arguments!
>>
>> Item was added:
>> + ----- Method:
>> DockingBarMorph>>add:icon:selectedIcon:help:subMenu:position: (in category
>> 'construction') -----
>> + add: wordingString icon: aForm selectedIcon: anotherForm help:
>> helpString subMenu: aMenuMorph position: position
>> + 	"Append the given submenu with the given label."
>> + 	| item |
>> + 	item := DockingBarItemMorph new
>> + 		contents: wordingString;
>> + 		subMenu: aMenuMorph;
>> + 		icon: aForm;
>> + 		selectedIcon: anotherForm.
>> + 	helpString isNil ifFalse: [
>> + 		item setBalloonText: helpString ].
>> + 	self addMenu: item atPosition: position.!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>help (in category 'accessing') -----
>> + help
>> +
>> + 	^ help!
>>
>> Item was added:
>> + Object subclass: #MenuEntrySpec
>> + 	instanceVariableNames: 'contents help icon selectedIcon target selector
>> location arguments position'
>> + 	classVariableNames: ''
>> + 	poolDictionaries: ''
>> + 	category: 'Morphic-Menus-DockingBar'!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>contents: (in category 'accessing') -----
>> + contents: aString
>> + 	"The label of the menuEntry."
>> + 	
>> + 	contents := aString!
>>
>> Item was changed:
>>   ----- Method: DockingBarMorph>>addItem: (in category 'construction')
>> -----
>>   addItem: aBlock
>> +
>> + 	self addItem: aBlock at: { #last }.!
>> - 	| item |
>> - 	item := DockingBarItemMorph new.
>> - 	aBlock value: item.
>> - 	self addMorphBack: item!
>>
>> Item was added:
>> + ----- Method: MenuEntrySpec>>icon (in category 'accessing') -----
>> + icon
>> +
>> + 	^ icon!
>>
>> Item was changed:
>>   ----- Method: TheWorldMainDockingBar>>menusOn: (in category
>> 'construction') -----
>> + menusOn: aDockingBar
>> - menusOn: aDockingBar
>>
>>   	self
>>   		squeakMenuOn: aDockingBar;
>>   		projectsMenuOn: aDockingBar;
>>   		toolsMenuOn: aDockingBar;
>>   		extrasMenuOn: aDockingBar;
>>   		windowsMenuOn: aDockingBar;
>> + 		helpMenuOn: aDockingBar;
>> + 		customMenusOn: aDockingBar.
>> - 		helpMenuOn: aDockingBar.
>>   	aDockingBar addSpacer.
>>   	self
>>   		searchBarOn: aDockingBar;
>>   		clockOn: aDockingBar!
>>
>> Item was changed:
>>   ----- Method: MenuMorph>>addItem: (in category 'construction') -----
>>   addItem: aBlock
>> + 	self addItem: aBlock at: { #last }!
>> - 	| item |
>> - 	item := MenuItemMorph new.
>> - 	aBlock value: item.
>> - 	self addMenuItem: item!
>>
>> Item was removed:
>> - ----- Method: MenuMorph>>addMenuItem: (in category 'construction') -----
>> - addMenuItem: aMenuItemMorph
>> - 	self addMorphBack: aMenuItemMorph!
>>
>>
>>
>
>
>



More information about the Squeak-dev mailing list