[Pharo-project] An idea about Pluggable widgets

Alain Plantec alain.plantec at yahoo.com
Thu Apr 7 18:59:29 CEST 2011


Hi Igor,
I'm not sure to understand.
As an example:
TrafficLight is my model with an action for the red light.
If I build a view for it, I can use a Button with #performAction:

Button>> performAction
     ^ model performAction

So, my TrafficLight must implement a #performAction method.
Now, if I want also an action for the green light performed when another 
button is pressed.
It means that I've to implement a specific model class for the red and 
another for the green ?
cheers
Alain





for example, I have a simple UI with two buttons

Le 07/04/2011 15:26, Igor Stasenko a écrit :
> I have an idea how to refactor the pluggable morphs mess.
>
> The main principle behind all pluggables, that you have a model (which
> is held in instance variable),
> and then morph having additional ivars to speak with this model, which
> the selector names you should use
> to access certain state from model.
>
> For example:
>
> AlignmentMorph subclass: #PluggableButtonMorph
> 	instanceVariableNames: 'model label getStateSelector actionSelector
> getLabelSelector getMenuSelector shortcutCharacter askBeforeChanging
> triggerOnMouseDown offColor onColor feedbackColor
> showSelectionFeedback allButtons arguments argumentsProvider
> argumentsSelector gradientLook enabled actionBlock getColorSelector
> getEnabledSelector'
> 	classVariableNames: 'UseGradientLook'
> 	poolDictionaries: ''
> 	category: 'Morphic-Pluggable Widgets'
>
>
> as you can see it is crowded with all those ivars, where part of them
> used to speak with model,
> and part of them used for keeping flags and additional parameters
> which you can customize when creating a button.
> getStateSelector actionSelector getLabelSelector getMenuSelector
>   arguments argumentsProvider argumentsSelector gradientLook
> actionBlock getColorSelector getEnabledSelector
>
> and this is really messy..
> Take a look at code:
>
> performAction
> 	"Inform the model that this button has been pressed. Sent by the
> controller when this button is pressed. If the button's actionSelector
> takes any arguments, they are obtained dynamically by sending the
> argumentSelector to the argumentsProvider"
>
> 	enabled ifFalse: [^self].
> 	askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
> 	self actionBlock ifNotNil: [ ^ self actionBlock value].
> 	actionSelector ifNotNil:
> 		[actionSelector numArgs == 0
> 			ifTrue: [model perform: actionSelector]
> 			ifFalse:
> 				[argumentsProvider ifNotNil:
> 					[arguments := argumentsProvider perform: argumentsSelector].
> 					model perform: actionSelector withArguments: arguments]]
>
>
> Now think if we could replace this with simple:
>
>
> performAction
> 	"Inform the model that this button has been pressed. Sent by the
> controller when this button is pressed. If the button's actionSelector
> takes any arguments, they are obtained dynamically by sending the
> argumentSelector to the argumentsProvider"
>
> 	enabled ifFalse: [^self].
>          model performAction.
>
>
> so, in this case, we just put an obligation onto model to perform any
> action in response to button clicked,
> and button no longer cares about crappy logic how it should send a
> message to model
> (via action block, via actionSelector ... and whether it should pass
> any additional arguments or not..)
>
> So, in all places which using things in a way like:
>
> getListItems
>    ^ model perform: getListItemsSelector
>
> now will be replaced with clean:
>
> getListItems
>    ^ model getListItems
>
> So, a pluggable morph no longer cares about keeping all those
> selectors and maintain an obscure logic whether selector is nil or not
> nil etc etc..
> Let model handle it!
>
> Then you may ask, what if i have a model, which doesn't implements
> such protocol (required for specific pluggable widget).
> The answer is simple:
>   - create a pluggable model class for given widget, which wraps around
> your object and can keeps all those messy 'getLabelSelector'
> 'getMenuSelector' ,
> inside and mediates between your model and widget.
>
> The benefit of it that widgets code will be much more cleaner.
> And another benefit is that you know what exact protocol is needed if
> you want to use your object as a model to given widget (list, button
> etc).
> And in most of the cases, you don't need to use this messy
> 'getXYZSelector', because you can simply answer to messages sent by
> widget and provide
> necessary data.
> But if you wanna go messy, you just use wrapper model, which contains
> all those 'getXYZSelectors'  which you can set to whatever you like.
>




More information about the Pharo-project mailing list