[Cuis-dev] Decentralized menu definition

Hilaire Fernandes hfern at free.fr
Fri Jul 15 08:53:39 PDT 2022


Hi,

Here is a first iteration for decentralized menu definitions .

Check the comment of the MenuBuilder class and its example to execute.

Then check its example class methods to read how write definition of the 
menu.

In theory, this should let third party package smoothly adds entries in 
Cuis menus.

There is place for improvements and to make menu definition more 
compact, but its already gives a general idea.

Thanks

Hilaire

-- 
GNU Dr. Geo
http://drgeo.eu
http://blog.drgeo.eu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20220715/0e14e421/attachment-0001.htm>
-------------- next part --------------
'From Cuis 6.0 [latest update: #5393] on 15 July 2022 at 5:50:42 pm'!
'Description '!
!provides: 'MenuNG' 1 8!
SystemOrganization addCategory: 'MenuNG'!


!classDefinition: #MenuBuilder category: 'MenuNG'!
Object subclass: #MenuBuilder
	instanceVariableNames: 'menuPragma items'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'MenuNG'!
!classDefinition: 'MenuBuilder class' category: 'MenuNG'!
MenuBuilder class
	instanceVariableNames: ''!

!classDefinition: #MenuRecord category: 'MenuNG'!
Object subclass: #MenuRecord
	instanceVariableNames: 'id order menutItem'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'MenuNG'!
!classDefinition: 'MenuRecord class' category: 'MenuNG'!
MenuRecord class
	instanceVariableNames: ''!


!MenuBuilder commentStamp: '<historical>' prior: 0!
I build a menu and its sub-menus. I collect the menus data from class methods tagged with a given pragma.

- items is a dictionnary where:

	- key is the id (symbol) of a menu. 
	Top level menu key is #root, therefore this key should always exist.
	A sub-menu key is the id a MenuRecord refers as its parent (read newEntry:in:)
	
	- value:  is a collection of MenuRecord instances describing a complete menu
	
Test the example:

(MenuBuilder on: #exampleMenu) menu popUpInWorld!

!MenuRecord commentStamp: '<historical>' prior: 0!
I am the record of a menu item.

- id: a symbol identifier
- order: a (possibly float) number, the lowest, the higher in the menu I am placed
- menuItem: a MenuItemMorph instance representing my view!

!MenuBuilder methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 12:33:01'!
menuMethods
" Select all the methods defining the menu records  we are interested in"
	^ Smalltalk allSelect: [:m | m pragmas anySatisfy: [:p | p key == menuPragma ]]. 

! !

!MenuBuilder methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 12:10:26'!
pragma: aSymbol
	menuPragma _ aSymbol asSymbol
! !

!MenuBuilder methodsFor: 'private' stamp: 'hlsf 7/15/2022 16:50:28'!
collectMenuRecords
	items _ Dictionary new.
	self menuMethods do: [:method |
		method methodClass soleInstance 
			perform: method methodSymbol 
			with: self ].
	items valuesDo: [:menuRecords | menuRecords reSort]! !

!MenuBuilder methodsFor: 'private' stamp: 'hlsf 7/15/2022 16:45:35'!
newMenuRecordCollection
	^ SortedCollection sortBlock: [ :menuRec1 :menuRec2 | 		menuRec1 order < menuRec2 order]! !

!MenuBuilder methodsFor: 'menu record creation' stamp: 'hlsf 7/15/2022 16:12:15'!
newEntry: aSymbol
" Create a new menu record in the #root"
	^ self newEntry: aSymbol in: #root! !

!MenuBuilder methodsFor: 'menu record creation' stamp: 'hlsf 7/15/2022 16:24:35'!
newEntry: aSymbol in: parentSymbol
" Create a new menu record in the designated parent menu and remember it in the appropriate collection "
	| menuCollection |
	menuCollection _ items at: parentSymbol ifAbsentPut: [self newMenuRecordCollection].
	^ menuCollection add: (MenuRecord id: aSymbol)! !

!MenuBuilder methodsFor: 'menu' stamp: 'hlsf 7/15/2022 17:31:55'!
buildMenuFrom: menuId
" Build the menu and return it "
	| menu |
	menu _ MenuMorph new.
	(items at: menuId) do: [:aMenuRec | 
		menu addMorphBack: aMenuRec menuItem.
		" is this record a sub menu too? "
		(items 	includesKey: aMenuRec id) ifTrue: [
			" then attach its sub-menu, do it recursively " 
			aMenuRec menuItem subMenu: (self buildMenuFrom: aMenuRec id) ] ].
	^ menu
	! !

!MenuBuilder methodsFor: 'menu' stamp: 'hlsf 7/15/2022 17:19:40'!
menu
" Build the root menu and its sub-menus "
	self collectMenuRecords.
	^ self buildMenuFrom: #root! !

!MenuBuilder class methodsFor: 'instance creation' stamp: 'hlsf 7/14/2022 11:43:12'!
on: aPragmaKeyord
	^ self new ::
		pragma: aPragmaKeyord ! !

!MenuBuilder class methodsFor: 'examples' stamp: 'hlsf 7/15/2022 17:34:48'!
example1_1: menuBuilder
	<exampleMenu>
	menuBuilder newEntry: #entry1 ::
		label: 'Menu entry 1';
		icon: #worldIcon;
		order: 500.
	menuBuilder newEntry: #entry2 ::
		label: 'Menu entry 2';
		help: 'I can have help too';
		order: 100! !

!MenuBuilder class methodsFor: 'examples' stamp: 'hlsf 7/15/2022 16:09:53'!
example1_2: menuBuilder
	<exampleMenu>
	menuBuilder newEntry: #entry3 		in: #entry1 ::
		label: 'Menu entry 3';
		order: 1.
! !

!MenuBuilder class methodsFor: 'examples' stamp: 'hlsf 7/15/2022 17:36:55'!
example1_3: menuBuilder
	<exampleMenu>
	menuBuilder newEntry: #entry4 ::
		label: 'Menu entry 4';
		order: 1.
	menuBuilder newEntry: #'Just a drop place' in: #entry1
! !

!MenuBuilder class methodsFor: 'examples' stamp: 'hlsf 7/15/2022 17:36:20'!
example1_4: menuBuilder
	<exampleMenu>
	menuBuilder newEntry: #entry5 in: #'Just a drop place'::
		label: 'Menu entry 5'
! !

!MenuRecord methodsFor: 'initialization' stamp: 'hlsf 7/15/2022 16:22:12'!
initialize
	super initialize.
	menutItem _ MenuItemMorph new.
	order _ 1! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 11:31:05'!
help: aString
	menutItem setBalloonText: aString ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 11:29:35'!
icon: aSymbolOrForm
	menutItem setIcon: aSymbolOrForm ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/15/2022 17:31:50'!
id
	^ id! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 19:50:47'!
id: aSymbol
	id _ aSymbol ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 11:29:13'!
label: aString
	menutItem contents: aString ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/15/2022 16:56:27'!
menuItem
	^ menutItem ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/15/2022 16:21:29'!
order
	^ order! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 11:31:35'!
order: aNumber
	order _ aNumber ! !

!MenuRecord methodsFor: 'accessing' stamp: 'hlsf 7/14/2022 11:30:22'!
target: anObject selector: aSymbol arguments: aCollection
	menutItem target: anObject selector: aSymbol arguments: aCollection
! !

!MenuRecord methodsFor: 'printing' stamp: 'hlsf 7/15/2022 17:26:20'!
printOn: aStream
	super printOn: aStream.
	aStream 
		nextPut: $(;
		nextPutAll: id printString ;
		nextPutAll: ', order=';
		nextPutAll: order printString;
		nextPut: $)! !

!MenuRecord class methodsFor: 'instance creation' stamp: 'hlsf 7/14/2022 19:50:19'!
id: uniqueIndentifer
	^ self new ::
		id: uniqueIndentifer asSymbol;
		label: uniqueIndentifer asString;
		yourself! !


More information about the Cuis-dev mailing list