The Trunk: Morphic-mt.1751.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Morphic-mt.1751.mcz

commits-2
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
- SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
  | method |
+ method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
- method := target class lookupSelector: selector.
  ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
  (Process
  forBlock: [self doButtonAction]
+ runUntil: [:context | context selector = self effectiveActionSelector])
- runUntil: [:context | context selector = self selector])
  debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+
+ ^ self selector = #perform:orSendTo:
+ ifTrue: [self arguments first]
+ ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+ ^ (self selector = #perform:orSendTo:
+ and: [(self target respondsTo: self effectiveActionSelector) not])
+ ifTrue: [self arguments second]
+ ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
- selector == #perform:orSendTo: ifTrue: [^arguments first].
- ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+ "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
- "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
  | method |
+ self updateArguments.
+ method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
- method := model class lookupSelector: actionSelector.
  ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+ self updateArguments.
+
  (Process
+ forBlock: [self doButtonAction]
+ runUntil: [:context | context selector = self effectiveActionSelector])
- forBlock: [self performAction]
- runUntil: [:context | context selector = self actionSelector])
  debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+ ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+
+ ^ self actionSelector = #perform:orSendTo:
+ ifTrue: [arguments first]
+ ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+ ^ (self actionSelector = #perform:orSendTo:
+ and: [(self target respondsTo: self effectiveActionSelector) not])
+ ifTrue: [arguments second]
+ ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
  "We adapt our minimum extent according to our resize behavior."
 
  self hResizing == aSymbol ifTrue: [^ self].
  super hResizing: aSymbol.
  self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
  askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
  actionSelector ifNotNil:
  [actionSelector numArgs = 0
  ifTrue:
  [model perform: actionSelector]
  ifFalse:
+ [self updateArguments.
- [argumentsProvider ifNotNil:
- [arguments := argumentsProvider perform: argumentsSelector].
  model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+ argumentsProvider ifNil: [^ self].
+ argumentsSelector ifNil: [^ self].
+ arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
  "We adapt our minimum extent according to our resize behavior."
 
  self vResizing == aSymbol ifTrue: [^ self].
  super vResizing: aSymbol.
  self updateMinimumExtent.!


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Morphic-mt.1751.mcz

Christoph Thiede

Thank you for improving this! I already had a similar hack in my image for some time, but your solution is cleaner, of course.


When putting further efforts into this construction site, I would like to kindly ask you again to take a look at System-ct.1149. :-) In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.


I refrained from adding the debug/browse interface for button actions to Morph.


I don't really see the problem here, Morph includes a lot of functionalities that are only used by certain subclasses. Anyway, could this be worth a trait, TMorphWithAction, or something similar? On the other hand, one morph might support multiple actions, so a generic solution would have its advantages ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 14. April 2021 11:19:46
An: [hidden email]; [hidden email]
Betreff: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
-        SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
         | method |
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := target class lookupSelector: selector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
         (Process
                 forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                runUntil: [:context | context selector = self selector])
                         debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+       
+        ^ self selector = #perform:orSendTo:
+                ifTrue: [self arguments first]
+                ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+        ^ (self selector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [self arguments second]
+                        ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
-        selector == #perform:orSendTo: ifTrue: [^arguments first].
-        ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+        "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
-        "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
         | method |
+        self updateArguments.
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := model class lookupSelector: actionSelector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+        self updateArguments.
+
         (Process
+                forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                forBlock: [self performAction]
-                runUntil: [:context | context selector = self actionSelector])
                         debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+        ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+       
+        ^ self actionSelector = #perform:orSendTo:
+                ifTrue: [arguments first]
+                ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+        ^ (self actionSelector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [arguments second]
+                        ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self hResizing == aSymbol ifTrue: [^ self].
         super hResizing: aSymbol.
         self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
         askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
         actionSelector ifNotNil:
                 [actionSelector numArgs = 0
                         ifTrue:
                                 [model perform: actionSelector]
                         ifFalse:
+                                [self updateArguments.
-                                [argumentsProvider ifNotNil:
-                                        [arguments := argumentsProvider perform: argumentsSelector].
                                         model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+        argumentsProvider ifNil: [^ self].
+        argumentsSelector ifNil: [^ self].
+        arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self vResizing == aSymbol ifTrue: [^ self].
         super vResizing: aSymbol.
         self updateMinimumExtent.!




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Morphic-mt.1751.mcz

marcel.taeumel
 I think that only checking the selector but not the receiver of the context is a too weak criterion

Sure, we could check both.

Anyway, could this be worth a trait, TMorphWithAction, or something similar?

I suppose not. There is not much redundancy here and the class inheritance is simply extended via cross-cutting protocols and selectors, which can easily be retrieved via senders/implementors; verifiable through tests. As soon as the shared aspect gets more complex, I would vote for object composition like LayoutPolicy.

Best,
Marcel

Am 14.04.2021 12:25:22 schrieb Thiede, Christoph <[hidden email]>:

Thank you for improving this! I already had a similar hack in my image for some time, but your solution is cleaner, of course.


When putting further efforts into this construction site, I would like to kindly ask you again to take a look at System-ct.1149. :-) In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.


I refrained from adding the debug/browse interface for button actions to Morph.


I don't really see the problem here, Morph includes a lot of functionalities that are only used by certain subclasses. Anyway, could this be worth a trait, TMorphWithAction, or something similar? On the other hand, one morph might support multiple actions, so a generic solution would have its advantages ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 14. April 2021 11:19:46
An: [hidden email]; [hidden email]
Betreff: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
-        SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
         | method |
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := target class lookupSelector: selector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
         (Process
                 forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                runUntil: [:context | context selector = self selector])
                         debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+       
+        ^ self selector = #perform:orSendTo:
+                ifTrue: [self arguments first]
+                ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+        ^ (self selector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [self arguments second]
+                        ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
-        selector == #perform:orSendTo: ifTrue: [^arguments first].
-        ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+        "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
-        "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
         | method |
+        self updateArguments.
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := model class lookupSelector: actionSelector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+        self updateArguments.
+
         (Process
+                forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                forBlock: [self performAction]
-                runUntil: [:context | context selector = self actionSelector])
                         debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+        ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+       
+        ^ self actionSelector = #perform:orSendTo:
+                ifTrue: [arguments first]
+                ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+        ^ (self actionSelector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [arguments second]
+                        ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self hResizing == aSymbol ifTrue: [^ self].
         super hResizing: aSymbol.
         self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
         askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
         actionSelector ifNotNil:
                 [actionSelector numArgs = 0
                         ifTrue:
                                 [model perform: actionSelector]
                         ifFalse:
+                                [self updateArguments.
-                                [argumentsProvider ifNotNil:
-                                        [arguments := argumentsProvider perform: argumentsSelector].
                                         model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+        argumentsProvider ifNil: [^ self].
+        argumentsSelector ifNil: [^ self].
+        arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self vResizing == aSymbol ifTrue: [^ self].
         super vResizing: aSymbol.
         self updateMinimumExtent.!




Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Morphic-mt.1751.mcz

marcel.taeumel
In reply to this post by Christoph Thiede
Hi Christoph,

> In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.

Can you give me 1 example? :-) Since we begin directly with calling the target ... how should anything interfere? Are you thinking about MethodWrappers?

Best,
Marcel

Am 14.04.2021 12:25:22 schrieb Thiede, Christoph <[hidden email]>:

Thank you for improving this! I already had a similar hack in my image for some time, but your solution is cleaner, of course.


When putting further efforts into this construction site, I would like to kindly ask you again to take a look at System-ct.1149. :-) In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.


I refrained from adding the debug/browse interface for button actions to Morph.


I don't really see the problem here, Morph includes a lot of functionalities that are only used by certain subclasses. Anyway, could this be worth a trait, TMorphWithAction, or something similar? On the other hand, one morph might support multiple actions, so a generic solution would have its advantages ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 14. April 2021 11:19:46
An: [hidden email]; [hidden email]
Betreff: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
-        SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
         | method |
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := target class lookupSelector: selector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
         (Process
                 forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                runUntil: [:context | context selector = self selector])
                         debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+       
+        ^ self selector = #perform:orSendTo:
+                ifTrue: [self arguments first]
+                ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+        ^ (self selector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [self arguments second]
+                        ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
-        selector == #perform:orSendTo: ifTrue: [^arguments first].
-        ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+        "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
-        "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
         | method |
+        self updateArguments.
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := model class lookupSelector: actionSelector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+        self updateArguments.
+
         (Process
+                forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                forBlock: [self performAction]
-                runUntil: [:context | context selector = self actionSelector])
                         debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+        ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+       
+        ^ self actionSelector = #perform:orSendTo:
+                ifTrue: [arguments first]
+                ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+        ^ (self actionSelector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [arguments second]
+                        ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self hResizing == aSymbol ifTrue: [^ self].
         super hResizing: aSymbol.
         self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
         askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
         actionSelector ifNotNil:
                 [actionSelector numArgs = 0
                         ifTrue:
                                 [model perform: actionSelector]
                         ifFalse:
+                                [self updateArguments.
-                                [argumentsProvider ifNotNil:
-                                        [arguments := argumentsProvider perform: argumentsSelector].
                                         model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+        argumentsProvider ifNil: [^ self].
+        argumentsSelector ifNil: [^ self].
+        arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self vResizing == aSymbol ifTrue: [^ self].
         super vResizing: aSymbol.
         self updateMinimumExtent.!




Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Morphic-mt.1751.mcz

Christoph Thiede

Hi Marcel,


here are some example selectors:


#doButtonAction, #performAction, #value ...


While these all are non-recommended selector names, they can occur indeed (and a have indeed a project that forwards clicks from one button to another so the selector is #doButtonAction), and this is why I think that "debug button action" should be more robust against them. :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Mittwoch, 14. April 2021 13:03:41
An: squeak-dev
Betreff: Re: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Hi Christoph,

> In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.

Can you give me 1 example? :-) Since we begin directly with calling the target ... how should anything interfere? Are you thinking about MethodWrappers?

Best,
Marcel

Am 14.04.2021 12:25:22 schrieb Thiede, Christoph <[hidden email]>:

Thank you for improving this! I already had a similar hack in my image for some time, but your solution is cleaner, of course.


When putting further efforts into this construction site, I would like to kindly ask you again to take a look at System-ct.1149. :-) In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.


I refrained from adding the debug/browse interface for button actions to Morph.


I don't really see the problem here, Morph includes a lot of functionalities that are only used by certain subclasses. Anyway, could this be worth a trait, TMorphWithAction, or something similar? On the other hand, one morph might support multiple actions, so a generic solution would have its advantages ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 14. April 2021 11:19:46
An: [hidden email]; [hidden email]
Betreff: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
-        SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
         | method |
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := target class lookupSelector: selector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
         (Process
                 forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                runUntil: [:context | context selector = self selector])
                         debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+       
+        ^ self selector = #perform:orSendTo:
+                ifTrue: [self arguments first]
+                ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+        ^ (self selector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [self arguments second]
+                        ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
-        selector == #perform:orSendTo: ifTrue: [^arguments first].
-        ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+        "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
-        "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
         | method |
+        self updateArguments.
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := model class lookupSelector: actionSelector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+        self updateArguments.
+
         (Process
+                forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                forBlock: [self performAction]
-                runUntil: [:context | context selector = self actionSelector])
                         debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+        ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+       
+        ^ self actionSelector = #perform:orSendTo:
+                ifTrue: [arguments first]
+                ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+        ^ (self actionSelector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [arguments second]
+                        ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self hResizing == aSymbol ifTrue: [^ self].
         super hResizing: aSymbol.
         self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
         askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
         actionSelector ifNotNil:
                 [actionSelector numArgs = 0
                         ifTrue:
                                 [model perform: actionSelector]
                         ifFalse:
+                                [self updateArguments.
-                                [argumentsProvider ifNotNil:
-                                        [arguments := argumentsProvider perform: argumentsSelector].
                                         model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+        argumentsProvider ifNil: [^ self].
+        argumentsSelector ifNil: [^ self].
+        arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self vResizing == aSymbol ifTrue: [^ self].
         super vResizing: aSymbol.
         self updateMinimumExtent.!




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Morphic-mt.1751.mcz

marcel.taeumel
Hi Christoph,

while I cannot find an example for #doButtonAction (or #performAction) being the actual action to be called, I tried something with #value. 

(PluggableButtonMorph
on: [ Transcript showln: 'foo' ]
getState: nil
action: #value)
label: 'foo';
openInHand

There, I noticed an issue with blocks being the target since those will not show up as receiver on the stack. For blocks, "context closure" should be compared with the target, which is different from PluggableButtonMorphPlus, where "context closure" should be compared with the action.

Best,
Marcel

***

"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away."
― Antoine de Saint-Exupéry

Am 19.04.2021 19:53:24 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


here are some example selectors:


#doButtonAction, #performAction, #value ...


While these all are non-recommended selector names, they can occur indeed (and a have indeed a project that forwards clicks from one button to another so the selector is #doButtonAction), and this is why I think that "debug button action" should be more robust against them. :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Mittwoch, 14. April 2021 13:03:41
An: squeak-dev
Betreff: Re: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Hi Christoph,

> In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.

Can you give me 1 example? :-) Since we begin directly with calling the target ... how should anything interfere? Are you thinking about MethodWrappers?

Best,
Marcel

Am 14.04.2021 12:25:22 schrieb Thiede, Christoph <[hidden email]>:

Thank you for improving this! I already had a similar hack in my image for some time, but your solution is cleaner, of course.


When putting further efforts into this construction site, I would like to kindly ask you again to take a look at System-ct.1149. :-) In particular, I think that only checking the selector but not the receiver of the context is a too weak criterion, I have already experienced a number of "wrong halts" when another method on the stack had the same selector.


I refrained from adding the debug/browse interface for button actions to Morph.


I don't really see the problem here, Morph includes a lot of functionalities that are only used by certain subclasses. Anyway, could this be worth a trait, TMorphWithAction, or something similar? On the other hand, one morph might support multiple actions, so a generic solution would have its advantages ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 14. April 2021 11:19:46
An: [hidden email]; [hidden email]
Betreff: [squeak-dev] The Trunk: Morphic-mt.1751.mcz
 
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1751.mcz

==================== Summary ====================

Name: Morphic-mt.1751
Author: mt
Time: 14 April 2021, 11:19:35.123489 am
UUID: 8fa68c8f-44ca-4d4a-a9e7-f69619be782e
Ancestors: Morphic-mt.1750

Slightly improve browsing and debugging of so-called "button actions" by also supporting #perform:orSendTo:, which yields #effectiveActionTarget and #effectiveActionSelector.

(Note that this design is still to be improved. I refrained from adding the debug/browse interface for button actions to Morph. A next step might be to take a look at all implementors of #doButtonAction. Maybe this will generate some ideas.)

=============== Diff against Morphic-mt.1750 ===============

Item was removed:
- ----- Method: MenuItemMorph>>browseAllImplementorsOfRealSelector (in category 'browse') -----
- browseAllImplementorsOfRealSelector
-        SystemNavigation default browseAllImplementorsOf: self realSelector localTo: target class!

Item was changed:
  ----- Method: MenuItemMorph>>browseImplementationOfActionSelector (in category 'browse') -----
  browseImplementationOfActionSelector
 
         | method |
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := target class lookupSelector: selector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: MenuItemMorph>>debugAction (in category 'browse') -----
  debugAction
 
         (Process
                 forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                runUntil: [:context | context selector = self selector])
                         debugWithTitle: ('Debug menu action "{1}" in model "{2}"' format: {self contents. self target printString}).!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionSelector (in category 'browse') -----
+ effectiveActionSelector
+       
+        ^ self selector = #perform:orSendTo:
+                ifTrue: [self arguments first]
+                ifFalse: [self selector]!

Item was added:
+ ----- Method: MenuItemMorph>>effectiveActionTarget (in category 'browse') -----
+ effectiveActionTarget
+
+        ^ (self selector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [self arguments second]
+                        ifFalse: [self target]!

Item was removed:
- ----- Method: MenuItemMorph>>realSelector (in category 'browse') -----
- realSelector
-        selector == #perform:orSendTo: ifTrue: [^arguments first].
-        ^selector!

Item was changed:
  ----- Method: Morph>>doButtonAction (in category 'button') -----
  doButtonAction
+        "If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions. It is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programmatically from user scripts."!
-        "If the receiver has a button-action defined, do it now.  The default button action of any morph is, well, to do nothing.  Note that there are several ways -- too many ways -- for morphs to have button-like actions.  This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism.  Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts"!

Item was changed:
  ----- Method: PluggableButtonMorph>>browseImplementationOfActionSelector (in category 'debug menu') -----
  browseImplementationOfActionSelector
 
         | method |
+        self updateArguments.
+        method := self effectiveActionTarget class lookupSelector: self effectiveActionSelector.
-        method := model class lookupSelector: actionSelector.
         ToolSet browse: method methodClass selector: method selector.!

Item was changed:
  ----- Method: PluggableButtonMorph>>debugAction (in category 'debug menu') -----
  debugAction
 
+        self updateArguments.
+
         (Process
+                forBlock: [self doButtonAction]
+                runUntil: [:context | context selector = self effectiveActionSelector])
-                forBlock: [self performAction]
-                runUntil: [:context | context selector = self actionSelector])
                         debugWithTitle: ('Debug button action "{1}" in model "{2}"' format: {self label. self target printString}).!

Item was added:
+ ----- Method: PluggableButtonMorph>>doButtonAction (in category 'button') -----
+ doButtonAction
+
+        ^ self performAction!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionSelector (in category 'debug menu') -----
+ effectiveActionSelector
+       
+        ^ self actionSelector = #perform:orSendTo:
+                ifTrue: [arguments first]
+                ifFalse: [self actionSelector]!

Item was added:
+ ----- Method: PluggableButtonMorph>>effectiveActionTarget (in category 'debug menu') -----
+ effectiveActionTarget
+
+        ^ (self actionSelector = #perform:orSendTo:
+                and: [(self target respondsTo: self effectiveActionSelector) not])
+                        ifTrue: [arguments second]
+                        ifFalse: [self target]!

Item was changed:
+ ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>hResizing: (in category 'layout-properties') -----
  hResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self hResizing == aSymbol ifTrue: [^ self].
         super hResizing: aSymbol.
         self updateMinimumExtent.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>performAction (in category 'event handling') -----
- ----- Method: PluggableButtonMorph>>performAction (in category 'accessing') -----
  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"
 
         askBeforeChanging ifTrue: [model okToChange ifFalse: [^ self]].
         actionSelector ifNotNil:
                 [actionSelector numArgs = 0
                         ifTrue:
                                 [model perform: actionSelector]
                         ifFalse:
+                                [self updateArguments.
-                                [argumentsProvider ifNotNil:
-                                        [arguments := argumentsProvider perform: argumentsSelector].
                                         model perform: actionSelector withArguments: arguments]]!

Item was added:
+ ----- Method: PluggableButtonMorph>>updateArguments (in category 'updating') -----
+ updateArguments
+
+        argumentsProvider ifNil: [^ self].
+        argumentsSelector ifNil: [^ self].
+        arguments := argumentsProvider perform: argumentsSelector.!

Item was changed:
+ ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout properties') -----
- ----- Method: PluggableButtonMorph>>vResizing: (in category 'layout-properties') -----
  vResizing: aSymbol
         "We adapt our minimum extent according to our resize behavior."
        
         self vResizing == aSymbol ifTrue: [^ self].
         super vResizing: aSymbol.
         self updateMinimumExtent.!