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 > 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.
