[Cuis-dev] PreferenceBrowser tool

Mariano Montone marianomontone at gmail.com
Wed Jun 14 17:28:17 PDT 2023


El 14/6/23 a las 21:18, Mariano Montone escribió:
>
> Hi,
>
>     I'd like to present this tool for your consideration for including 
> in Cuis (not necessarily in Core, perhaps as extra package).
>
> It is a browser for system preferences.
>
> It features:
>
> - Browse by category.
>
> - Filter by name.
>
> - Custom widgets for editing Booleans, Strings, Fonts, Options.
>
> - Inspect and browse references of a preference (right click on 
> preference).
>
> It is an standalone package (doesn't depend on other packages).
>
> To try, load the package, then open via World Menu -> Preferences -> 
> All preferences ..
>
I attach another version with some cleanups and less agressive colors.


    Mariano
-------------- next part --------------
'From Cuis 6.0 [latest update: #5861] on 14 June 2023 at 9:25:10 pm'!
'Description Tool for browsing and editing Cuis preferences.'!
!provides: 'PreferenceBrowser' 1 57!
SystemOrganization addCategory: 'PreferenceBrowser'!


!classDefinition: #PreferenceEditorMorph category: 'PreferenceBrowser'!
LayoutMorph subclass: #PreferenceEditorMorph
	instanceVariableNames: 'preference'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferenceEditorMorph class' category: 'PreferenceBrowser'!
PreferenceEditorMorph class
	instanceVariableNames: ''!

!classDefinition: #PreferencesPanel category: 'PreferenceBrowser'!
LayoutMorph subclass: #PreferencesPanel
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferencesPanel class' category: 'PreferenceBrowser'!
PreferencesPanel class
	instanceVariableNames: ''!

!classDefinition: #PreferenceButtonMorph category: 'PreferenceBrowser'!
PluggableButtonMorph subclass: #PreferenceButtonMorph
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferenceButtonMorph class' category: 'PreferenceBrowser'!
PreferenceButtonMorph class
	instanceVariableNames: ''!

!classDefinition: #PreferenceBrowser category: 'PreferenceBrowser'!
SystemWindow subclass: #PreferenceBrowser
	instanceVariableNames: 'categoriesList selectedCategory selectedPreference preferencesPane scroller categories filter'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferenceBrowser class' category: 'PreferenceBrowser'!
PreferenceBrowser class
	instanceVariableNames: ''!

!classDefinition: #PreferenceSelectionButtonMorph category: 'PreferenceBrowser'!
BoxedMorph subclass: #PreferenceSelectionButtonMorph
	instanceVariableNames: 'elems model placeHolder button printer getter setter selectionStrategy'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferenceSelectionButtonMorph class' category: 'PreferenceBrowser'!
PreferenceSelectionButtonMorph class
	instanceVariableNames: ''!

!classDefinition: #PreferenceToggleButtonMorph category: 'PreferenceBrowser'!
BoxedMorph subclass: #PreferenceToggleButtonMorph
	instanceVariableNames: 'model getStateSelector isPressed actWhen actionSelector'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PreferenceBrowser'!
!classDefinition: 'PreferenceToggleButtonMorph class' category: 'PreferenceBrowser'!
PreferenceToggleButtonMorph class
	instanceVariableNames: ''!


!PreferenceEditorMorph commentStamp: '<historical>' prior: 0!
The editor row for a single preference!

!PreferenceBrowser commentStamp: '<historical>' prior: 0!
Cuis Smalltalk preferences editor.

PreferenceBrowser open.!

!PreferenceSelectionButtonMorph commentStamp: '<historical>' prior: 0!
Button morph that opens a selection menu for selecting a value.

See examples in class side.

Structure:
 model Object -- The object that holds the selected value.
 elems Collection -- The collection of elements to choose from.
 printer Symbol|Block -- Block or Symbol with which to print the elements to choose from.
 getter Symbol -- Selector to use on the model for getting its value. Default is #value.
 setter Symbol -- Selector to use on the model for setting its value. Default is #value:.
 selectionStrategy Number|Symbol -- When #menu, a MenuMorph is used for selecting values.
                                                          When #list, a LIstSelectionMorph is used for selecting values.
                                                          When a Number, a MenuMorph is used if elems size is <= that number, and a ListSelectionMorph if elems size > that number.
                                                          Default is number with value 20.!

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:06:15'!
evaluatePreferenceValue
	
	| input |
	
	input := FillInTheBlankMorph 
					request: 'Preference value (evaluate and set)' 
					initialAnswer: preference value printString
					onCancel: #cancelPreferenceValue.

	(input = #cancelPreferenceValue) ifFalse: [ | val |
		val  := Compiler evaluate: input.
		self setPreferenceTo: val.
		self changed: preference. "Trick to update PluggableButtons"
		]! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 16:43'!
handlesMouseDown: aMouseEvent
	^ true! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 16:53'!
handlesMouseOver: aMouseEvent
	^ true! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 19:43:37'!
initialize: aPreference
	
	| preferenceName nameMorph |
	
	preference := aPreference.
	
	self color: Color white.
	preferenceName := self printSymbol: aPreference name.
	self setBalloonText: aPreference description.
	nameMorph := LabelMorph contents: preferenceName.
	self addMorph: nameMorph
		proportionalWidth: 0.95;
		addMorph: (	self widgetForPreference: aPreference)! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 18:18'!
inspectPreference
	preference inspect! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 21:39:41'!
mouseButton2Activity
	
	self openPreferenceMenu! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 17:10'!
mouseEnter: aMouseEvent
	self color: (Color r: 0.942 g: 0.942 b: 0.942).! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 17:08'!
mouseLeave: aMouseEvent
	self color: Color white.! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 21:43:37'!
openPreferenceMenu

	| menu |
	
	menu := MenuMorph new defaultTarget: self; yourself.
	
	menu addTitle: ((self printSymbol: preference name) squeezedTo: 30).
	
	"menu add: 'Set default (', (preference defaultValue printString), ')'
		    target: self
		    action: #setDefault."
		
	menu add: 'Set value'
		    target: self
		    action: #evaluatePreferenceValue.
		
	menu add: 'Inspect'
		     target: self
			action: #inspectPreference.
			
	menu add: 'Browse references' 
		target: [Smalltalk browseAllCallsOn: preference name]
		action: #value.		
	
	(preference description isNil not and: [
		preference description isEmpty not]) ifTrue: [
		menu addMorphBack: (TextModelMorph withText: preference description)].
		
	menu popUpInWorld: self world! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 16:25'!
printSymbol: aSymbol
	| stream printed |
	stream _ aSymbol string readStream.
	printed _ WriteStream on: ''.
	printed nextPut: stream next asUppercase.
	[ stream atEnd ] whileFalse: [ | char |
		char _ stream next.
		char isUppercase ifTrue: [
			printed nextPut: Character space.
			char _ char asLowercase ].
		printed nextPut: char ].
	^ printed contents.! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 18:34:54'!
realTypeOfPreference: aPreference

	(aPreference type = BlockClosure) ifTrue: [^ aPreference value class].
	^ aPreference type! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:04:19'!
requestString

	self request: 'String:' initialAnswer: preference value 
		do: [:answer | self setPreference: preference to: answer.
					self changed: preference "Update Button morph"
					]! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 18:37:51'!
setPreference: aPreference to: anObject

	aPreference value: 
		((aPreference type = BlockClosure) 
			ifTrue: [	[anObject]]
			ifFalse: [anObject]) ! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 18:38:37'!
setPreferenceTo: anObject

	preference value: 
		((preference type = BlockClosure) 
			ifTrue: [	[anObject]]
			ifFalse: [anObject]) ! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:46:35'!
widgetForBooleanPreference: aPreference label: aLabel

	|model|
	
	model := Switch new
		onAction: [ self setPreferenceTo: true ];
		offAction: [ self setPreferenceTo: false ];
		yourself.
	aPreference value
		ifTrue: [ model turnOn ]
		ifFalse: [ model turnOff ].
	^ PreferenceToggleButtonMorph
		model: model
		stateGetter: #isOn
		action: #switch	! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 16:48:21'!
widgetForDefaultPreference: aPreference label: aLabel

	| widget |
	widget := PreferenceButtonMorph 
					model: self 
					action: #evaluatePreferenceValue  
					label: aLabel .
	widget setBalloonText: preference value printString.
	widget fitContents.
	
	^ widget! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:09:24'!
widgetForFontPreference: aPreference label: aLabel

	^ PreferenceButtonMorph 
		model: [| fontFamily |
			fontFamily := FontFamily promptUser.
			fontFamily ifNotNil: [
				self request:  'Point size' do: [:pointSizeStr | 
					self setPreference: aPreference to: (fontFamily atPointSize: pointSizeStr asNumber)]	]]
		action: #value
		label: aLabel

	! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:50:47'!
widgetForOptionsPreference: aPreference label: aLabel

	^ PreferenceSelectionButtonMorph on: aPreference elems: aPreference type! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:01:41'!
widgetForPreference: aPreference

	| valString preferenceType |
	
	valString := preference value printString truncateWithElipsisTo: 20.
	preferenceType := self realTypeOfPreference: aPreference.
	
	"Booleans"	
	(preferenceType = Boolean) ifTrue: [ ^ self widgetForBooleanPreference: aPreference	 label: valString].
	
	"Array with options"	
	(preferenceType isArray) ifTrue: [^ self widgetForOptionsPreference: aPreference label: valString].
		
	"Strings"	
	((preferenceType = CharacterSequence) or: [preferenceType inheritsFrom: CharacterSequence]) 
		ifTrue: [^ self widgetForStringPreference: aPreference label: valString		].	
	
	"Fonts"
	((preferenceType = AbstractFont) or: [aPreference type inheritsFrom: AbstractFont])
		ifTrue: [^ self widgetForFontPreference: aPreference label: valString].
	
	"Otherwise, create a button for evaluating a Smalltalk expression and setting the preference value with the result."
	^ self widgetForDefaultPreference: aPreference label: valString! !

!PreferenceEditorMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:03:32'!
widgetForStringPreference: aPreference label: aLabel

	^ PreferenceButtonMorph
			model: self
			action: #requestString
			label: aLabel! !

!PreferenceEditorMorph class methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 16:23'!
on: aPreference
	^ self newRow initialize: aPreference.! !

!PreferencesPanel methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 11:07:59'!
adjustExtent

	self morphWidth: owner morphWidth! !

!PreferenceButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 19:55:20'!
fitContents

	^ self morphExtent: `0 at 0`! !

!PreferenceButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 15:11:39'!
fontToUse

	^ FontFamily defaultFamilyPointSize: FontFamily defaultPointSize - 1! !

!PreferenceButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 19:54:12'!
measureContents
	| f |
	f := self fontToUse.
	^((f widthOfString: label) max: 3)  @ f lineSpacing! !

!PreferenceButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 15:11:14'!
minimumExtent

	^ self measureContents + self extentBorder + (10 at 6)! !

!PreferenceButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 18:51:30'!
update: updated

	(updated isKindOf: Preference)
		ifTrue: [
			label := updated value printString.
			^ self redrawNeeded].
		
	^ super update: updated! !

!PreferenceBrowser methodsFor: 'GUI building' stamp: 'MM 7/21/2016 16:23'!
buildPreferenceEditorFor: aPreference
	^ PreferenceEditorMorph on: aPreference! !

!PreferenceBrowser methodsFor: 'GUI building' stamp: 'MM 6/14/2023 11:08:30'!
buildPreferenceEditorsPane
	preferencesPane := PreferencesPanel newColumn.
	"preferencesPane color: Color white."
	self buildPreferencesPane.
	scroller := PluggableScrollPane new.
	scroller scroller: preferencesPane.
	scroller color: Color white.
	scroller scroller color: Color white.
	scroller setScrollDeltas.
	^ scroller.! !

!PreferenceBrowser methodsFor: 'GUI building' stamp: 'MM 6/14/2023 10:21:52'!
buildPreferencesPane
	preferencesPane axisEdgeWeight: 0.
	self selectedCategoryPreferences do: [ :aPreference |
		preferencesPane
			addMorph: (self buildPreferenceEditorFor: aPreference)
			fixedHeight: 20 ].
	
	^ preferencesPane.! !

!PreferenceBrowser methodsFor: 'GUI building' stamp: 'MM 6/14/2023 10:24:07'!
updatePreferencesList

	preferencesPane removeAllMorphs.
	self buildPreferencesPane.
	scroller scroller morphHeight: (self selectedCategoryPreferences size * 20).
	scroller setScrollDeltas.! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 11/1/2018 11:32'!
categories
	^ #(#'-- all --') , (categories ifNil: [categories := Preferences categories. categories])! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 17:51'!
initialExtent
	^  552.0 at 389.0! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 7/21/2016 17:47'!
minimumExtent
	^  546.0 at 163.0! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 11/4/2022 10:52:40'!
preferences
	^ Preferences allPreferences! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 15:01:51'!
preferencesInCategory: aCategory
	
	^ self preferences select: [:aPreference | aPreference category = aCategory]! !

!PreferenceBrowser methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 15:02:39'!
selectedCategoryPreferences

	|preferences|
	
	preferences := (self selectedCategory == #'-- all --') 
		ifTrue: [self preferences]	
		ifFalse: [self preferencesInCategory: self selectedCategory].
		
	filter ifNotEmpty: [
		preferences := preferences select: [:p | p name asString includesSubstring: filter asString caseSensitive: false]].
	
	preferences := preferences sorted: [:p1 :p2 | p1 name < p2 name].
	
	^ preferences! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 7/21/2016 12:16'!
categoriesList
	"Answer the value of categoriesList"

	^ categoriesList! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 7/21/2016 12:16'!
categoriesList: anObject
	"Set the value of categoriesList"

	categoriesList _ anObject! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 11/1/2018 11:51'!
filter

	^ filter! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 11/1/2018 12:17'!
filter: aText

	filter _ aText.
	
	self changed: #clearUserEdits.
	self updatePreferencesList ! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 7/21/2016 12:16'!
selectedCategory
	"Answer the value of selectedCategory"

	^ selectedCategory! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 11/1/2018 12:13'!
selectedCategory: anObject
	"Set the value of selectedCategory"
	selectedCategory _ anObject.
	
	self updatePreferencesList.! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 7/21/2016 12:16'!
selectedPreference
	"Answer the value of selectedPreference"

	^ selectedPreference! !

!PreferenceBrowser methodsFor: 'accessing' stamp: 'MM 7/21/2016 12:16'!
selectedPreference: anObject
	"Set the value of selectedPreference"

	selectedPreference _ anObject! !

!PreferenceBrowser methodsFor: 'initialization' stamp: 'MM 6/14/2023 14:59:05'!
initialize
	
	| row leftPane filterInput |
	
	super initialize.
	self setLabel: 'Preferences'.
	selectedCategory := self categories first.
	filter := ''.
	
	row := LayoutMorph newRow.
	
	leftPane := LayoutMorph newColumn.
	leftPane axisEdgeWeight: 0.
	
	categoriesList := PluggableListMorphByItem
		model: self
		listGetter: #categories
		indexGetter: #selectedCategory
		indexSetter: #selectedCategory:.
		
	leftPane addMorphUseAll: categoriesList.
	
	filterInput := 	(TextModelMorph
						textProvider: self
						textGetter: #filter
						textSetter: #filter:) 
						acceptOnCR: true;
						hideScrollBarsIndefinitely;
						borderWidth: 1;
						setBalloonText: 'Preferences filter';
						yourself.
	leftPane addMorph: filterInput layoutSpec: (LayoutSpec proportionalWidth: 1 fixedHeight: 15).
	
	row
		addMorph: leftPane
		proportionalWidth: 0.3.
	row addAdjusterAndMorph:  self buildPreferenceEditorsPane layoutSpec: LayoutSpec useAll.
	self addMorph: row.! !

!PreferenceBrowser class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 19:33:13'!
initialize

	"This is a fix to Cuis core. Should be moved to core, and removed from here."
	Preferences at: #classFinder put:  [ [BrowserWindow findClass] ].! !

!PreferenceBrowser class methodsFor: 'as yet unclassified' stamp: 'MM 6/13/2023 19:33:42'!
open
	
	"self open"
	
	self new openInWorld! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
button
	"Answer the value of button"

	^ button! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
button: anObject
	"Set the value of button"

	button _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
elems
	"Answer the value of elems"

	^ elems isBlock ifTrue: [elems value]
		ifFalse: [elems]! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
elems: anObject
	"Set the value of elems"

	elems _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
getter
	"Answer the value of getter"

	^ getter! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
getter: anObject
	"Set the value of getter"

	getter _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
model
	"Answer the value of model"

	^ model! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
model: anObject
	"Set the value of model"

	model _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
placeHolder
	"Answer the value of placeHolder"

	^ placeHolder! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
placeHolder: anObject
	"Set the value of placeHolder"

	placeHolder _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:34'!
printer
	"Answer the value of printer"

	^ printer! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:35'!
printer: anObject
	"Set the value of printer"

	printer _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:35'!
selectionStrategy
	"Answer the value of selectionStrategy"

	^ selectionStrategy! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:35'!
selectionStrategy: anObject
	"Set the value of selectionStrategy"

	selectionStrategy _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:35'!
setter
	"Answer the value of setter"

	^ setter! !

!PreferenceSelectionButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:49:35'!
setter: anObject
	"Set the value of setter"

	setter _ anObject! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
color: aColor
	button color: aColor! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
drawOn: aCavas

	"do nothing"! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
fontToUse
	^ FontFamily defaultFamilyAndPointSize! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
initialize: aModel getter: getSymbol setter: setSymbol elems: aCollection printer: aSymbol

	| label |
	
	model := aModel.
	placeHolder := '--'.
	button _ PluggableButtonMorph new model: self.
	printer := aSymbol.
	elems := aCollection.
	getter _ getSymbol.
	setter _ setSymbol.
	selectionStrategy _ 20.
	
	label := self value ifNil: [placeHolder] ifNotNil: [self value perform: printer].
	
	button label: label;
			action: #selectItem;
			color: Color lightGray;
			morphExtent: self measureContents.
			
	self addMorph: button.
	self morphExtent: button morphExtent.! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
layoutSubmorphs
	self submorphsDo: [:m | m morphExtent: self morphExtent]! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
measureContents

	| f label |
	
	label := self value ifNil: [placeHolder] ifNotNil: [self value perform: printer].
	f _ self fontToUse.
	^((f widthOfString: label) + 10) @ (f lineSpacing + 10).! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
minimumExtent
	^ self measureContents! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
morphExtent
	^ self minimumExtent! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:55:27'!
selectItem
	^ self selectItemWithMenu! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
selectItem: item

	self value: item.
	self update.
	self 
		triggerEvent: #itemSelected:
		with: item! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
selectItemWithMenu

	| item menu |
	
	(self elems collect:[:elem | elem perform: printer]) ifNotEmpty: [:labelList |
		menu := self selectionMenuClass labelList: labelList selections: self elems .
		item := menu startUpMenu.
	
		item ifNotNil: [		self selectItem: item ]]
		! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
selectionMenuClass
	^ SelectionMenu! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
someSubmorphPositionOrExtentChanged
	"Our extent, or some submorph changed. Must layout submorphs again."
	super someSubmorphPositionOrExtentChanged .
	
	button morphExtent ifNotNil: [
		self morphExtent: button morphExtent]! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
update

	button label: (self value perform: printer).
	self morphExtent: 0 at 0.
	self redrawNeeded.
	self owner ifNotNil: [:o | o someSubmorphPositionOrExtentChanged]  ! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
value
	^ self model perform: getter! !

!PreferenceSelectionButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:49:35'!
value: anObject
	self model perform: setter with: anObject! !

!PreferenceSelectionButtonMorph class methodsFor: 'instance creation' stamp: 'MM 6/14/2023 20:56:24'!
on: aModel 
	^ self
		on: aModel
		elems: #()
		printer: #asString.! !

!PreferenceSelectionButtonMorph class methodsFor: 'instance creation' stamp: 'MM 6/14/2023 20:56:28'!
on: aModel elems: aCollection
	^ self
		on: aModel
		elems: aCollection
		printer: #asString.! !

!PreferenceSelectionButtonMorph class methodsFor: 'instance creation' stamp: 'MM 6/14/2023 20:49:35'!
on: aModel elems: aCollection printer: aSymbol
	"(SelectionButtonMorph on: (ValueHolder value: #foo))
	elems: #(foo bar baz);
	color: Color lightGray ;
	openInWorld"
	^ self on: aModel getter: #value setter: #value: elems: aCollection printer: aSymbol! !

!PreferenceSelectionButtonMorph class methodsFor: 'instance creation' stamp: 'MM 6/14/2023 20:49:35'!
on: aModel getter: getter setter: setter elems: aCollection printer: aSymbol
	"(SelectionButtonMorph on: (ValueHolder value: #foo))
	elems: #(foo bar baz);
	color: Color lightGray ;
	openInWorld"
	^ self new initialize: aModel getter: getter setter: setter elems: aCollection printer: aSymbol! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
actWhen
	"Answer the value of actWhen"

	^ actWhen! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
actWhen: anObject
	"Set the value of actWhen"

	actWhen _ anObject! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
actionSelector
	"Answer the value of actionSelector"

	^ actionSelector! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
actionSelector: anObject
	"Set the value of actionSelector"

	actionSelector _ anObject! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
getStateSelector
	"Answer the value of getStateSelector"

	^ getStateSelector! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
getStateSelector: anObject
	"Set the value of getStateSelector"

	getStateSelector _ anObject! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:48:42'!
initialize
	super initialize.
	
	getStateSelector := #value.
	self morphExtent: 34 at 20.
	color := Color white.
	actWhen := #buttonDown.
	extent := nil! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
isPressed
	"Answer the value of isPressed"

	^ isPressed! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
isPressed: anObject
	"Set the value of isPressed"

	isPressed _ anObject! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
model
	"Answer the value of model"

	^ model! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
model: anObject
	"Set the value of model"

	model ifNotNil: [model removeDependent: self].
	getStateSelector ifNotNil: [
		anObject ifNotNil: [anObject addDependent: self]].
	model _ anObject! !

!PreferenceToggleButtonMorph methodsFor: 'accessing' stamp: 'MM 6/14/2023 20:45:06'!
update: aSymbol

	super update: aSymbol.
	aSymbol = getStateSelector ifTrue: [
		self redrawNeeded ]! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
defaultExtent

	^ 30 at 16! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 21:23:43'!
drawOn: aCanvas

	|rx ry statusColor |
	
	"Calculate the radius of toggles."
	ry := self morphHeight // 2.
	rx := ry.
	
	"Draw the background."
	
	statusColor := self value ifTrue: [Color green] ifFalse: [Color lightGray].
	
	aCanvas ellipseCenter: rx at ry  
				radius: rx at ry  
				borderWidth: 1  
				borderColor: statusColor
				fillColor: statusColor.
	
	aCanvas ellipseCenter:  ((self morphExtent x - rx)@ry)
			radius: rx at ry  
			borderWidth: 1
			borderColor: statusColor
			fillColor: statusColor.
			
	aCanvas fillRectangle: ((rx at 0) corner: ((self morphExtent x - rx)@self morphExtent y)) color: statusColor.
	
	"Draw either the On or Off toggle." 
	
	self value ifFalse: [
			aCanvas ellipseCenter: rx at ry  
				radius: ((rx at ry) - 2)  
				borderWidth: 0  
				borderColor: color
				fillColor: color]
		ifTrue: [
			aCanvas ellipseCenter:  ((self morphExtent x - rx)@ry)
				radius: ((rx at ry) - 2)  
				borderWidth: 0
				borderColor: color
				fillColor: color] ! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
handlesMouseDown: aMouseButtonEvent
	"Do I want to receive mouseDown events (mouseDown:, mouseMove:, mouseUp:)?"
	^true! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
morphExtent

	^ extent ifNil: [extent := self defaultExtent]! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
morphExtent: aPoint

	"The extent of this widget is set once when initializing it. Then it does not change anymore."
	"We need to ignore further calls from LayoutMorphs so that extent doesn't change."
	extent ifNil: [super morphExtent: aPoint]! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
morphLocalBounds

	^`0 at 0` extent: self morphExtent.! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
mouseButton1Down: aMouseButtonEvent localPosition: localEventPosition

	isPressed _ true.
	self redrawNeeded.
	(actWhen == #buttonDown or: [ actWhen == #buttonStillDown ])
		ifTrue: [
			self performAction ]
		ifFalse: [
			"Don't make multi-click slower if we act on button down, just do multiple actions"
			aMouseButtonEvent hand
				waitForClicksOrDragOrSimulatedMouseButton2: self
				event: aMouseButtonEvent
				clkSel: nil
				clkNHalf: nil
				dblClkSel: #doubleClick:localPosition:
				dblClkNHalfSel: nil
				tripleClkSel: nil ]! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
performAction
	"Inform the model that this button has been pressed. "

	actionSelector ifNotNil: [
		actionSelector isBlock ifTrue: [actionSelector value]
		ifFalse: [	model perform: actionSelector ]]
	! !

!PreferenceToggleButtonMorph methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
value

	^ model perform: getStateSelector ! !

!PreferenceToggleButtonMorph class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:46:47'!
example1

	|s|
	
	s := Switch newOff.
	
	(PreferenceToggleButtonMorph on: s)
		getStateSelector: #isOn;
		actionSelector: #switch;
		morphExtent: 30 at 16;
		openInWorld
	
	! !

!PreferenceToggleButtonMorph class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 21:22:20'!
example2

	|s|
	
	s := Switch newOff.
	
	(PreferenceToggleButtonMorph on: s)
		getStateSelector: #isOn;
		actionSelector: #switch;
		openInWorld
	
	! !

!PreferenceToggleButtonMorph class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
model: aModel

	^ self new 
		model: aModel;
		yourself! !

!PreferenceToggleButtonMorph class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
model: anObject stateGetter: getStateSel action: actionSel

	^ self new
		model: anObject;
		getStateSelector: getStateSel;
		actionSelector: actionSel;
		yourself! !

!PreferenceToggleButtonMorph class methodsFor: 'as yet unclassified' stamp: 'MM 6/14/2023 20:45:06'!
on: aModel

	^ self new 
		model: aModel;
		yourself! !

!Switch methodsFor: '*PreferenceBrowser' stamp: 'MM 7/22/2016 15:54'!
value
	^ on! !

!Switch methodsFor: '*PreferenceBrowser' stamp: 'MM 7/22/2016 15:54'!
value: value
	value ifTrue: [self turnOn] ifFalse: [self turnOff]
	! !

!PreferenceSet class methodsFor: '*PreferenceBrowser' stamp: 'MM 6/14/2023 16:58:57'!
openPreferencesInspector
	PreferenceBrowser open! !
PreferenceBrowser initialize!


More information about the Cuis-dev mailing list