On 7 April 2011 19:23, Igor Stasenko <[email protected]> wrote: > On 7 April 2011 18:59, Alain Plantec <[email protected]> wrote: >> 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 ? > > For that case you use model adapters. > So, then you do something like: > > button1 model: (self for: #performAction adapt: #turnRed) > button2 model: (self for: #performAction adapt: #turnGreen) > > and so, a receiver (which is a model), will receive #turnRed, or > #turnGreen messages, > while button will still use same message for model - #performAction >
or alternatively, we could ask a widget to create and install an instance of model adaptor (so it will construct a properly initialized model adaptor, when you only need to fill the data in it): (button1 installModelAdaptorFor: self) actionSelector: #turnRed. (button2 installModelAdaptorFor: self) actionSelector: #turnGreen. >> 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. >>> >> >> >> > > > > -- > Best regards, > Igor Stasenko AKA sig. > -- Best regards, Igor Stasenko AKA sig.
