-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
how to add enabled/disabled feature to UI components? #257
Comments
Options discussed 9/1/16 meeting:
Adding functionality directly to scenery/Node.js is the favorite for now. But would modifying Node.js impact memory or are there other concerns? Assigning to @jonathanolson and @ariel-phet for comments. |
@jessegreenberg @pixelzoom and @jonathanolson, does this still need to be marked for developer meeting? |
Yes, it should remain marked for developer meeting. @ariel-phet is going to get feedback from @jonathanolson before the next meeting, when we will discuss again. |
Looks like @jonathanolson created #19 for this way back on 9/5/13. I'm going to close that issue, since the only useful information is a pointer to phetsims/scenery#17. In phetsims/scenery#17, there was discussion of adding this feature to |
Also worth noting.... At the 9/1/16 meeting, no one seemed to have a clear concept of how "mix-in" is currently implemented, as used by @jonathanolson in scenery. And there were concerns about whether the current mix-in approach prevents the mix-in from accidentally overwriting something in the base type. |
Admission - I spaced on asking @jonathanolson to take a look at this on our skype call, but just requested him to take a look today. He might also be attending dev meeting remotely tomorrow. |
It seems unlikely we'd want to bake in the "only a fixed level of opacity can be used to indicate disabled" into Scenery. Setting pickability also seems weird (usually don't want to set it to false, but null which is the default). Additionally, when it's set to false, input events will go right through it to what is behind. Presumably instead the desired behavior is that it would absorb (but not respond to) the events. Furthermore, the disposeMyComponent appears to be specific to each implemented type (presumably with a dispose function that would forward to it?). This seems like something that we shouldn't bake into Scenery. However I've previously discussed considering adding disposal to Nodes and node trees, as many times this would be very useful.
After the last discussion with the team, the current mix-in strategy is to have a function that takes the type as input, and modifies the prototype, e.g.:
modifies the prototype of Path so that it contains functions specific to being paintable (Text and Path can both have fills and strokes, so the fill/stroke logic is isolated to the Paintable mixin). Much of it is just statements equivalent to: var proto = Path.prototype;
proto.someFunction = function() { ... } but it can also add/modify behavior in more advanced usages.
Not concerned about memory, just about the above. Additionally, I'm not sure I understand why the enabledObserver is unlinked from the property in the code in the top comment. The property and observer are both owned by the same object (MyComponent), and would be garbage collected at the same time, correct? |
@jonathanolson said:
Some (most?) of the current implementations have an option ( Also discussed at dev meeting (but not captured in comments above) was that using opacity would be the default strategy (since that is the approach that was arrived at via consensus), with the ability to specify a different strategy via options. |
@jonathanolson asked:
Because |
Sounds good to me, although it sounds like this should be something like a mix-in (rather than in Node.js directly). The mix-in could live in Scenery, or if it's Sun-specific, in Sun?
Sounds good, I overlooked that it could be provided in options. |
@jonathanolson I don't disagree but could you clarify your reasoning here? |
Node already provides the needed tools (opacity or other visual changes are available) and is much more general than representing just UI controls. Being "enabled" seems like it's part of the element's (e.g. a button's) model. The button's view can then decide whether being disabled means lower opacity, a different gradient, or another effect. We don't just use nodes for UI controls, but also use them for particles in many sims. I would not want to also add 'position' and 'velocity' vectors to Node because of this. The particle's controller modifies the Node's translation (usually) based on the model position. Similarly, a button's controller modifies the Node's opacity (usually) based on whether the button's model is enabled. Node just isn't the place to stuff the enabled/position/velocity/etc.-style logic. |
@jonathanolson mentioned we could create ComponentNode.js which adds enabled/disabled features (instead of using a mixin). |
Let's leave this issue open and unassigned until someone needs to deal more with |
@pixelzoom suggests putting ComponentNode.js in sun, that's OK with me. |
@pixelzoom volunteered to take it for a test drive. |
I implemented the enabled/disabled feature in base type
|
Over in #585 (comment) @pixelzoom said:
I will answer here because this issue is out for review on this exact topic (and the EnabledComponent hierarchy in general). The paper trail for this is from #257 (comment) and the comment right below from April 15th. A trait depends on certain characteristics of the class that it mixes in, so rather than force our only enabled-related mixin to be used on Node (the subtypiest subtype we need to support EnabledComponent logic for), @jbphet and I thought it would be more clear if a hierarchy was created to only expose the particular behavior you expected in it. Alternatively, code would read like:
I prefer the current strategy, and its associated unit tests. I used |
Thanks for the clarification about @zepumph I'm confused about /**
* Trait for PhetioObjects that will add an enabledProperty and confirm its PhET-iO instrumentation is as expected.
* @author Michael Kauzmann (PhET Interactive Simulations)
*/ I don't see where it adds I'm also wondering why it inspects |
Is it covered by this line? // mixin general EnabledComponent logic (parent mixin)
EnabledComponent.mixInto( type ); |
Yes thanks @samreid, even though that logic is from the supertype, I still thought it worth mentioning since that is the main functionality of this Type. Is it not ok to depend on functionality of the supertype? I don't fee like we ever assert that |
@zepumph and I collaborated on refinements to EnabledComponent, as found in the above commit. Summary:
|
CT is showing errors when a
This is because RoundArrowButton sets the enabledProperty value in // @private {function}
this.enabledListener = this.onEnabledChange.bind( this );
this.enabledProperty.link( this.enabledListener );
}
/**
* Sets whether this is enabled.
* @private
*
* @param {boolean} enabled
*/
onEnabledChange( enabled ) {
this.enabled = this.enabledProperty.value;
} This can be averted by changing the DerivedProperty to only throw an error if you try to set a different value. I'm not sure if this is a good solution, or if there should be a guard somewhere else. But setting the same value to a Property is a no-op, so perhaps setting the same value to a DerivedProperty should also be a no-op? I'll commit it and request review. UPDATE: Also |
I committed the change to DerivedProperty, @pixelzoom can you please review/discuss/advise? |
@samreid said:
I don't think that should be the case. Any attempt to directly set a DerivedProperty is incorrect. EDIT: Thinking about this more, I have a strong opinion about phetsims/axon@9b01dfc - it should be reverted. |
Here is a patch that reverts the change to DerivedProperty and moves the guard to RoundButtonView. Index: main/sun/js/buttons/RoundButtonView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- main/sun/js/buttons/RoundButtonView.js (revision a52e5196b2c8a3c02064b005f6142e9b294af415)
+++ main/sun/js/buttons/RoundButtonView.js (date 1602983778136)
@@ -210,7 +210,9 @@
*/
setEnabled( value ) {
assert && assert( typeof value === 'boolean', 'RoundButtonView.enabled must be a boolean value' );
- this.buttonModel.enabledProperty.set( value );
+ if ( !this.buttonModel.enabledProperty.equalsValue( value ) ) {
+ this.buttonModel.enabledProperty.set( value );
+ }
}
/**
Index: main/axon/js/DerivedProperty.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- main/axon/js/DerivedProperty.js (revision 9b01dfccb2456017b771abff767bd3fe2b317e6f)
+++ main/axon/js/DerivedProperty.js (date 1602983684323)
@@ -118,9 +118,7 @@
* @public
*/
set( value ) {
- if ( !this.equalsValue( value ) ) {
- throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value );
- }
+ throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value );
}
/**
The problem is that EnabledComponent allows the user to pass in a |
I hadn't yet thought about the fact that
I do not think this patch gets to the bottom of things. First ask ourselves what is the enabledProperty logic in RoundButtonView doing? It seems like it is vestigial to a time when we didn't run enabled on a Property, and instead things were based on I would recommend removing this code because sun button supertypes now have this enabled support build-in. I tested this patch by running fractions-equality on the first screen. RoundArrowButtons are the colored spinner buttons for changing the fraction. Index: js/common/view/RoundArrowButton.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- js/common/view/RoundArrowButton.js (revision fe9a2b55924b4fcf9cdd6d9b23ccc8b91dc1a11e)
+++ js/common/view/RoundArrowButton.js (date 1603126483509)
@@ -45,34 +45,6 @@
options.yContentOffset = arrowPath.centerY;
super( options );
-
- // @private {Property.<boolean>}
- this.enabledProperty = options.enabledProperty;
-
- // @private {function}
- this.enabledListener = this.onEnabledChange.bind( this );
- this.enabledProperty.link( this.enabledListener );
- }
-
- /**
- * Sets whether this is enabled.
- * @private
- *
- * @param {boolean} enabled
- */
- onEnabledChange( enabled ) {
- this.enabled = this.enabledProperty.value;
- }
-
- /**
- * Releases references.
- * @public
- * @override
- */
- dispose() {
- this.enabledProperty.unlink( this.enabledListener );
-
- super.dispose();
}
}
There are 263 usages of I would recommending making a new issue to apply this patch so that responsible dev can double check on it. |
@zepumph said:
I think I understand the spirit of this comment. But to clarify... RoundArrowButton DOES support the Property API (which includes @samreid asked in #257 (comment):
I don't like this logic being moved to RoundButtonView (or other classes) either. It's a hack to work around a major design flaw in DerivedProperty (see #257 (comment)). I don't know how to correct that design flaw at this point. Preferable to the hack would be to remove the need to set The best practical solution is to examine the clients that are creating these buttons, and ask why they are passing in I'm also curious... How are you dealing with this for visibleProperty et. al. in phetsims/scenery#1046? Example:
|
This issue dealt with how to add enabled/disabled feature to UI component. We decided that mixin was the correct pattern, and @zepumph implemented the EnabledComponent stack. Conversion to EnableComponent has been completed in #585. So this issue is done, and ready to close. The issue of {DerivedProperty} enabledProperty that @samreid brought up in #257 (comment) is worthy of a separate issue. And I believe that it's not specific to Closing this issue. |
…hetsims/sun#257" and phetsims/sun#641 This reverts commit 9b01dfc
Developer consensus was to use this pattern for implementing enabled/disabled feature: #241 (comment). But as @samreid hinted at in #241 (comment), adding this feature currently requires duplicate/boilerplate code. I've recently added this feature to ComboBox and NumberControl, and thought we should discuss other methods of adding the feature.
Here's the relevant code that needs to be added:
The text was updated successfully, but these errors were encountered: