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

Philipp Tessenow phite at nada1.de
Mon Apr 26 20:36:41 UTC 2010


Hello,

I added some convenience methods to live-adding menus to the DockingBar.
If you load Morphic-phite.431.mcz and the attached file into a current
trunk image, you may do MenuBouncingAtomsMorph new openInWorld.

This opens the well known BouncingAtomsMorph and additionally adds some
MenuEntries addressing this specific Morph. These entries are removed
when the Morph is disposed.

I can imagine a Book Morph that makes menu special contributions *only*
when opened and active.

- Philipp

Am 26.04.2010 20:28, schrieb commits at source.squeak.org:
> A new version of Morphic was added to project The Inbox:
> http://source.squeak.org/inbox/Morphic-phite.431.mcz
> 
> ==================== Summary ====================
> 
> Name: Morphic-phite.431
> Author: phite
> Time: 26 April 2010, 10:28:00.807 pm
> UUID: 370cdcdb-18cf-2d4a-a04e-509206840fac
> Ancestors: Morphic-phite.429, Morphic-laza.430
> 
> Refactored the DockingBar and the WorldMenu to add custom self-defined menus. (See class comment of MenuEntrySpec)
> MenuEntries may be added pasiv (during the DockingBar/WorldMenu creation) or active (by TheWorldMainDockingBar installSpec: a MenuEntrySpec).
> 
> Changed Class comments of TheWorldMenu and TheWorldMainDockingBar. They now reference MenuEntrySpec to explain how new menu entries may be added.
> 
> =============== Diff against Morphic-phite.429 ===============
> 
> Item was added:
> + ----- Method: DockingBarMorph>>install: (in category 'menus') -----
> + install: aMenuEntrySpec
> + 	"Install a menu entry corresponding to the given spec on me."
> + 
> + 	aMenuEntrySpec installOn: self.!
> 
> Item was added:
> + ----- Method: MenuEntrySpec>>findMenuAt:In: (in category 'menu-installation') -----
> + findMenuAt: aLocation In: aMenu
> + 	"find the menu the location points at relative from the given menu."
> + 
> + 	| currentMenu |
> + 	aLocation size = 0 ifTrue: [ ^ aMenu ].
> + 	currentMenu := aMenu.
> + 	(1 to: aLocation size) do: [ :i |
> + 		currentMenu := currentMenu menus detect: [ :m | m contents = (aLocation at: i) ]].
> + 	^ currentMenu!
> 
> Item was changed:
> + ----- Method: MenuEntrySpec>>installOn: (in category 'menu-installation') -----
> - ----- Method: MenuEntrySpec>>installOn: (in category 'menu-creation') -----
>   installOn: aMenu
>   	"Installs a menuEntry corresponding to this specification into the given menu"
>   
>   	| menu |
>   	menu := self findOrCreateLocationIn: aMenu.
>   	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 changed:
>   ----- Method: TheWorldMainDockingBar>>listWindowsOn: (in category 'submenu - windows') -----
>   listWindowsOn: menu
>   
>   	| windows |
>   	windows := SortedCollection sortBlock: [:winA :winB |
>   		winA model name = winB model name
>   			ifTrue: [winA label < winB label]
>   			ifFalse: [winA model name < winB model name]].
>   	windows addAll: self allVisibleWindows.
>   	windows ifEmpty: [ 
>   		menu addItem: [ :item | 
>   			item
>   				contents: 'No Windows' translated;
>   				isEnabled: false ] ].
>   	windows do: [ :each |
>   		menu addItem: [ :item |
>   			item 
>   				contents: (self windowMenuItemLabelFor: each);
> + 				icon: (self colorIcon: each model defaultBackgroundColor);
> - 				icon: (self colorIcon: each paneColor);
>   				target: each;
>   				selector: #comeToFront;
>   				subMenuUpdater: self
>   				selector: #windowMenuFor:on:
>   				arguments: { each };
>   				action: [ each activateAndForceLabelToShow; expand ] ] ].!
> 
> Item was added:
> + ----- Method: DockingBarMorph>>uninstall: (in category 'menus') -----
> + uninstall: aMenuEntrySpec
> + 	"Uninstall the menu entry described by the given spec off me."
> + 
> + 	aMenuEntrySpec uninstallOn: self.!
> 
> Item was added:
> + ----- Method: MorphicProject>>dockingBarInstallMenu: (in category 'docking bars support') -----
> + dockingBarInstallMenu: menuEntrySpec
> + 	"installs a menu entry corresponding to the given spec in all docking bars."
> + 	self world mainDockingBars
> + 		do: [:each | each install: menuEntrySpec]!
> 
> Item was added:
> + ----- Method: MenuEntrySpec>>uninstallOn: (in category 'menu-installation') -----
> + uninstallOn: aMenu
> + 	"uninstalls a menuEntry corresponding to this specification from the given menu"
> + 
> + 	| menu entry |
> + 	menu := self findOrCreateLocationIn: aMenu.
> + 	entry := menu menus detect: [ :m | m contents = self contents] ifNone: [ nil ].
> + 	entry ifNotNil: [menu subMenu removeMorph: entry ].
> + 	self removeEmptySubMenusRecursivelyFrom: self location UpTo: aMenu.!
> 
> Item was added:
> + ----- Method: MorphicProject>>dockingBarUninstallMenu: (in category 'docking bars support') -----
> + dockingBarUninstallMenu: menuEntrySpec
> + 	"uninstalls the menu entry that matches the given menuEntrySpec from all docking bars."
> + 	self world mainDockingBars
> + 		do: [:each | each uninstall: menuEntrySpec]!
> 
> Item was changed:
>   ----- 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 - add after last menu in case I have other morphs like a SearchBar"
> + 	(self menus size > 0)
> + 		ifTrue: [ self addMorph: item behind: (self menus at: self menus size) ]
> + 		ifFalse: [ self addMorphBack: item ].!
> - 	"#last"
> - 	self addMorphBack: item.!
> 
> Item was added:
> + ----- Method: TheWorldMainDockingBar class>>installSpec: (in category 'as yet unclassified') -----
> + installSpec: aMenuEntrySpec
> + 	"Installs the menu entry spec on the docking bar."
> + 
> + 	Project current dockingBarInstallMenu: aMenuEntrySpec.!
> 
> Item was changed:
> + ----- Method: MenuEntrySpec>>findOrCreateLocationIn: (in category 'menu-installation') -----
> - ----- Method: MenuEntrySpec>>findOrCreateLocationIn: (in category 'menu-creation') -----
>   findOrCreateLocationIn: aMenu
>   	"find the menu my location points at - create it, if it does not exist."
>   
>   	| currentMenu |
>   	location size = 0 ifTrue: [ ^ aMenu ].
>   	currentMenu := aMenu.
>   	(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 changed:
>   Object subclass: #TheWorldMainDockingBar
>   	instanceVariableNames: ''
>   	classVariableNames: 'Instance TS'
>   	poolDictionaries: ''
>   	category: 'Morphic-Kernel'!
>   
> + !TheWorldMainDockingBar commentStamp: 'phite 4/26/2010 21:30' prior: 0!
> - !TheWorldMainDockingBar commentStamp: 'phite 4/26/2010 09:48' prior: 0!
>   TheWorldMainDockingBar serves to present a Squeak menu which is always visible whithin a World.
>   
> + It is possible to add custom menu entries to the WorldMenu. Please have a look at the MenuEntrySpec comments for examples.
> + Additionally you may add and remove menus dynamically by:
> + 	| spec |
> + 	spec := MenuEntrySpec newForDockingBarFrom: (Dictionary newFromPairs: #(
> + 		#contents 'Hello?'
> + 		#location #('Help' 'a subMenu' 'another subMenu')
> + 		#target MenuMorph #selector #inform: #arguments #('Hello World!!'))).
> + 	TheWorldMainDockingBar installSpec: spec.
> + 	TheWorldMainDockingBar uninstallSpec: spec.
> + 	!
> - It is possible to add custom menu entries to the WorldMenu. Please have a look at the MenuEntrySpec comments for examples.!
> 
> Item was changed:
>   ----- Method: TheWorldMainDockingBar>>colorIcon: (in category 'private') -----
>   colorIcon: aColor
>   
> + 	"Guess if 'uniform window colors' are used and avoid all icons to be just gray"
> + 	(aColor = Preferences uniformWindowColor or: [Preferences tinyDisplay]) ifTrue: [ ^nil ].
> - 	Preferences tinyDisplay ifTrue: [ ^nil ].
>   	^(aColor iconOrThumbnailOfSize: 14)
>   		borderWidth: 3 color: Preferences menuColor muchDarker;
>   		borderWidth: 2 color: Color transparent!
> 
> Item was changed:
> (excessive method size, no diff calculated)
> 
> Item was added:
> + ----- Method: MenuEntrySpec>>whenEmptyRemove:From: (in category 'menu-installation') -----
> + whenEmptyRemove: menu From: parentMenu
> + 	"Removes the given menu if its submenu is nil or empty"
> + 	menu ifNil: [ ^ self ].
> + 	menu menus size = 0
> + 		ifTrue: [ parentMenu subMenu removeMorph: menu ].!
> 
> Item was added:
> + ----- Method: TheWorldMainDockingBar class>>uninstallSpec: (in category 'as yet unclassified') -----
> + uninstallSpec: aMenuEntrySpec
> + 	"Uninstalls the menu entry spec from the docking bar."
> + 
> + 	Project current dockingBarUninstallMenu: aMenuEntrySpec.!
> 
> Item was added:
> + ----- Method: MenuEntrySpec>>removeEmptySubMenusRecursivelyFrom:UpTo: (in category 'menu-installation') -----
> + removeEmptySubMenusRecursivelyFrom: aLocation UpTo: rootMenu
> + 	"Removes empty submenus from the given menu location up to the top-level menu"
> + 	| loc |
> + 	loc := aLocation copy.
> + 	(1 to: (aLocation size)) do: [ :i || parentMenu menu |
> + 		parentMenu := self findMenuAt: loc allButLast In: rootMenu.
> + 		menu := self findMenuAt: loc In: rootMenu.
> + 		self whenEmptyRemove: menu From: parentMenu.
> + 		loc := loc allButLast ].!
> 
> Item was changed:
>   Object subclass: #MenuEntrySpec
>   	instanceVariableNames: 'contents help icon selectedIcon target selector location arguments position dockingBar worldMenu'
>   	classVariableNames: ''
>   	poolDictionaries: ''
>   	category: 'Morphic-Menus'!
>   
> + !MenuEntrySpec commentStamp: 'phite 4/26/2010 22:16' prior: 0!
> - !MenuEntrySpec commentStamp: 'phite 4/26/2010 10:20' prior: 0!
>   You may define MenuEntrySpecs to add custom menus to TheWorldMainDockingBar or TheWorldMenu.
>   
> + To add custom menu entries your class needs to answer to #menuEntrySpecification.
> - To add add custom menu entries your class needs to answer to #menuEntrySpecification.
>   #menuEntrySpecification may answer an instance of MenuEntrySpec or an array of MenuEntrySpecs for multiple menus.
>   
>   Example:
>   MenuEntrySpec newForDockingBarFrom: (Dictionary newFromPairs: #(
>   		#contents 'Hello?'
>   		#location #('Help' 'a subMenu' 'another subMenu')
>   		#target MenuMorph #selector #inform: #arguments #('Hello World!!')
>   		))
> + Rebuild the DockingBar (Extras - Rebuild Menus)
>   
>   The example above creates a MenuEntrySpec called 'Hello?' located in the Help-menu within some submenus. As you may see MenuEntrySpecs can be created with the help of an options dictionary. The options are explained later. Remember: You do not need to specify option you do not need.
>   
> + MenuEntrySpec newForDockingBarFrom:  a Dictionary - creates a menu entry for the DockingBar
> - MenuEntrySpec newForDockingBarFrom:  a Dictionary - created a menu entry for the DockingBar
>   MenuEntrySpec newForWorldMenuFrom: a Dictionary - creates a menu entry for the WorldMenu
>   MenuEntrySpec newFrom: a Dictionary - creates a menu entry for both
>   
>   Possible options:
>   #contents
>   	A String that is the visible label the user should click on
>   #help
>   	A String that may be shown in a bubble near the menu entry for the user's help
>   #icon
>   	A Form which is displayed near the label
>   #selectedIcon
>   	A Form which is displayed instead of the icon when the menuEntry is selected
>   #target
>   	An Object which is called when the user clicks on the menu entry
>   #selector
>   	A Symol which is sent the the target
>   #argument
>   	An Array of Arguments which are sent with the selector
>   #location
>   	An Arrray of Strings which describes the place the menuEntry should be displayed.
>   	#location -> nil or #() creates the menu entry in the top-level of the menu
>   	#location -> #('Help') creates the menu entry in the Help-menu
>   	#location -> #('Help' 'mySubMenu') creates the entry in a submenu of the Help-menu. If the submenu 'mySubMenu' does not exist it will be created
>   #position
>   	A Symbol or Array describing the position of the menu entry within a menu.
>   	#position -> #first creates the entry in the first slot of a menu
>   	#position -> #last creates the entry in the last slot
>   	#position -> #(#before 'Help') creates the entry just before the Help-menu
>   	#position -> #(#after 'Help') creates the entry just after the Help-menu
>   	If you reference a menu entry with #before or #after, be sure the menu entry exists.
>   #dockingBar
>   	A Boolean that defines whether the menu entry should be displayed in the DockingBar.
>   	This is always true if you use MenuEntrySpec newForDockingBarFrom:  a Dictionary
>   #worldMenu
>   	A Boolean that defines whether the menu entry should be displayed in the WorldMenu.
> + 	This is always true if you use MenuEntrySpec newForWorldMenuFrom:  a Dictionary
> + 	
> + It is possible to add MenuEntrySpecs dynamically to the DockingBar (you see the change without rebuilding the menu):
> + 	TheWorldMainDockingBar installSpec: a MenuEntrySpec.
> + 	TheWorldMainDockingBar uninstallSpec: a MenuEntrySpec
> + 	
> + Dynamically addind rentries to TheWorldMenu just happens by implementing #menuEntrySpecification as described above as a new one is generated every time the menu opens.!
> - 	This is always true if you use MenuEntrySpec newForWorldMenuFrom:  a Dictionary!
> 
> 

-------------- next part --------------
'From Squeak4.1 of 26 April 2010 [latest update: #10016] on 26 April 2010 at 10:32:42 pm'!
BouncingAtomsMorph subclass: #MenuBouncingAtomsMorph
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'philipp'!

!MenuBouncingAtomsMorph methodsFor: 'as yet unclassified' stamp: 'phite 4/26/2010 22:07'!
atomsMenu
	^ MenuEntrySpec newForDockingBarFrom: (Dictionary newFromPairs: #(
		#contents 'Bouncing Atoms'
		#position #(#before 'Help'))).! !

!MenuBouncingAtomsMorph methodsFor: 'as yet unclassified' stamp: 'phite 4/26/2010 22:00'!
delete
	"Deletes the myself and removes menu entries from the docking bar."
	TheWorldMainDockingBar
		uninstallSpec: self startInfectionMenu;
		uninstallSpec: self atomsMenu.
	super delete.! !

!MenuBouncingAtomsMorph methodsFor: 'as yet unclassified' stamp: 'phite 4/26/2010 22:08'!
initialize
	"Creates the usual BouncingAtomsMorph and adds menu entries to the docking bar."
	super initialize.
	TheWorldMainDockingBar
		installSpec: self atomsMenu;
		installSpec: self startInfectionMenu.! !

!MenuBouncingAtomsMorph methodsFor: 'as yet unclassified' stamp: 'phite 4/26/2010 22:03'!
startInfectionMenu
	^ MenuEntrySpec newForDockingBarFrom: (Dictionary newFromPairs: {
		#contents. 'Start Infection'.
		#location. #('Bouncing Atoms').
		#target. self. #selector. #startInfection}).! !


More information about the Squeak-dev mailing list