Open pixelzoom opened 4 years ago
There's also a memory leak that this introduced in some of the above classes. Because the button model is now instrumented, it needs to be disposed. And some of these classes (RectangularMomentaryButton, ... ) are not overriding dispose, and not handling disposal of buttonModel.
Raising priority since this is an obvious memory leak.
@zepumph can you please explain the // @public (phet-io)
annotation above this.toggleButtonModel
(and other button models).
To clarify... I'm wondering why this.toggleButtonModel
is needed when the superclass already defines this.buttonModel
. This is causing dissonance in cases like RoundToggleButton dispose
:
this.disposeRoundToggleButton = () => {
this.toggleButtonModel.dispose();
this.buttonModel.produceSoundEmitter.removeListener( playSounds );
toggleButtonInteractionStateProperty.dispose();
};
this.toggleButtonModel
and this.buttonModel
are references to the same object here. Very confusing. And in other classes, this.toggleButtonModel
was named this.buttonModel
, overwriting the superclass definition. So unless something in PhET-iO is reaching in and accessing this.toggleButtonModel
, it would be better if it were const toggleButtonModel
.
I think that it is acceptable to give the buttonModel the same tandem as the view, but that is no excuse to do that for all options. I will work to see what usages use the ButtonModel options and likely refactor them to be nested under buttonModelOptions
RE: https://github.com/phetsims/sun/issues/631#issuecomment-701114577:
Agreed! this.toggleButtonModel
should be a local var, only needed for dispose. I also see that this line is redundant, but it isn't obvious since it is opaque that this.buttonModel === toggleButtonModel
.
In the above commit, I got rid of the obvious error where this.toggleButtonModel
and this.buttonModel
both existed.
As for passing options through to the button model, I think I can see it both ways after poking around more. It seems a little bit like an implementation detail that the view and model of sun buttons are separate. They aren't separate for any other common code UI components. Separating the options out into buttonModelOptions
may be the way to go, but I think I'd like a quick discussion at developer meeting to see what people think.
Only the options intended for that subcomponent should be passed.
I'm not sure I think of a button's model as its subcomponent, but rather just an implementation detail as a result of how sun button hierarchy is tied to the view of the buttons.
Reassigning to implement dispose in button models that don't currently.
Changes above:
this.buttonModel
Still marking for dev meeting to discuss the main part of this issue: if we should be passing options directly to the button models instead of splitting it up into buttonModelOptions
.
Raising priority since this is an obvious memory leak.
Dispose methods have been implemented. Reducing priority.
buttonModelOptions
sounds most robust and consistent with the rest of our patterns. Is the main disadvantage of that approach the initial cost to split up the options?
This was discussed in the 10/29/2020 dev meeting and we decided to pursue the nested buttonModelOptions
approach.
Also noted in 10/29/2020 dev meeting: This is not the only case where sun buttons should be using nested options. https://github.com/phetsims/sun/issues/653 identifies the need for nested options related to appearance strategies.
I hit this today over in https://github.com/phetsims/phet-io/issues/1746. Raising priority, as currently there is some confusing buggy behavior in how enabledPropertyOptions are being passed around. In the Button heirarchy they are for ButtonModel, but Node also accepts enabledPropertyOptions. These need to be split out!
Options I'm really not excited about doing this for:
listener
: To me this refactor would be exposing an implementation detail in order to make the call site (at least one per screen with a ResetAllButton
) less suave. UPDATE: likely I just feel this way because of the number of usages of this.enabledProperty
. Right now it is a total implementation detail that the ButtonNode passes its enabledProperty option to the ButtonModel before taking that and passing it up to the Node (so they have the same Property controlling enabled). If this pattern changes in the future, it would be again refactoring this when in reality the client just wants to pass an enabledProperty to the Button and move on with life.enabledPropertyOptions
. I feel weird about this refactor, since it creates asymmetry like so in buttons. I'm still going for it though:
visiblePropertyOptions: { phetioReadOnly: true },
inputEnabledPropertyPhetioInstrumented: true,
buttonModelOptions: {
enabledPropertyOptions: { phetioReadOnly: true }
}
I guess as I go here, it would make sense to just assert in ButtonNode that there are none of the following, making sure that they are passed through buttonModelOptions
instead in the button hierarchy. That could definitely work to avoid gotchas, and it is basically what we already have, just more confusing.
Snapshot comparison was not clean, so I can't commit right now. Here is the patch that covers everything except for listener
and enabledProperty
.
Noted while converting RoundToggleButton to ES6 class for https://github.com/phetsims/tasks/issues/1044.
In 71f10eb7a400db49dd28bf2f5c254bcc00a3eab1, @zepumph passed the complete set of options to the button's model:
Besides the fact that this feels like a hack for making the phetioID tree hide the button model... Passing the complete set of options to a subcomponent is an anti-pattern. Only the options intended for that subcomponent should be passed.
I see the anti-pattern widely used: RectangularMomentaryButton, RectangularPushButton, RectangularStickyToggleButton, RectangularToggleButton, RoundMomentaryButton, RoundPushButton, and RoundStickyToggleButton.
This needs to be corrected.