Skip to content
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

Add isShowingProperty to dialog? #369

Closed
zepumph opened this issue Jul 7, 2018 · 34 comments
Closed

Add isShowingProperty to dialog? #369

zepumph opened this issue Jul 7, 2018 · 34 comments

Comments

@zepumph
Copy link
Member

zepumph commented Jul 7, 2018

related to phetsims/molecules-and-light#185,

In SpectrumWindowDialog.js [CM: now LightSpectrumDialog.js] in MAL, there is this block:

    // Create a property that both signals changes to the 'shown' state and can also be used to show/hide the dialog
    // remotely.  This is done primarily for PhET-iO support.  TODO: Move into the Dialog type?
    this.shownProperty = new Property( false, {
      tandem: tandem.createTandem( 'shownProperty' ),
      phetioType: PropertyIO( BooleanIO )
    } );

For phet-io especially, but probably elsewhere this may be nice to have in Dialog. I see a boolean property for isShowing, but maybe it could be promoted to a Property?

@pixelzoom @andrealin this is not high priority all, and I don't know the current status of Dialog work, but I know you two have been in there heavily recently, is this something we could do while working in that file? It will make life better for phet-io in the future, even though there isn't active work being done in MAL.

@andrealin
Copy link
Contributor

It should be easy enough to change isShowing on line 152 of Dialog.js to a Property. I would also update its visibility annotation from private to public. @pixelzoom should I proceed with that? I would also replace any this.isShowing within Dialog.js to this.isShowingProperty.get() or .set().

I also see that AboutDialog.js and UpdateDialog.js use this.isShowing. That would also be changed to this.isShowingProperty.get().

@andrealin andrealin removed their assignment Jul 9, 2018
@pixelzoom
Copy link
Contributor

I'm not clear on whether @zepumph was proposing to add isShowingProperty as part of Dialog's public API, or as a private (internal) Property for the purposes of PhET-iO. I'm also not clear on why we need a Property to show the state in the PhET-iO message stream. This seems like a general problem, and do we really want to be adding Properties whose sole purpose is the data stream?

@zepumph?

@zepumph
Copy link
Member Author

zepumph commented Jul 9, 2018

I'm not clear on whether @zepumph was proposing to add isShowingProperty as part of Dialog's public API, or as a private (internal) Property for the purposes of PhET-iO.

I was thinking of continuing to have it be a private instance, but to expose it as a read only Property to the PhET-iO api.

@pixelzoom there are two ways to instrument a property (lower case) for PhET-iO. In this example we COULD add getter and listeners methods to DialogIO like getIsShowingProperty, and make sure it has proper support for phetio state and phetio data stream, but that work is already done for us in Property, so in general it is simpler and easier to convert anything we want to be exposed in PhET-iO to a Property (method 2).

I'm also not clear on why we need a Property to show the state in the PhET-iO message stream. This seems like a general problem, and do we really want to be adding Properties whose sole purpose is the data stream?

Again we don't NEED to convert it, but so far it has been very nice to only interface with Properties when needing the set/get/listener functionality of something. In terms of it being a general problem. I'm not sure I agree. I could be confusing for clients though if sometimes we use Property, and sometimes we use Type.getSubproperty() methods. That's two different apis in PhET-iO for achieving the same thing. This is why @samreid and I, mainly in https://github.com/phetsims/phet-io/issues/1326, decided that, in general, converting things to Property is a good convention.

@pixelzoom
Copy link
Contributor

@zepumph said:

I was thinking of continuing to have it be a private instance, but to expose it as a read only Property to the PhET-iO api.

The doc for SpectrumWindowDialog this.shownProperty says "can also be used to show/hide the dialog remotely". Is that not a requirement?

@zepumph
Copy link
Member Author

zepumph commented Jul 9, 2018

I was thinking no. @samreid please correct me if I am wrong. But to me it seems like is you don't want to show the Dialog, then you hide the button that displayed the Dialog, rather than having a button that displays nothing.

@pixelzoom
Copy link
Contributor

pixelzoom commented Jul 9, 2018

I don't follow the previous comment. The state of the control used to display the Dialog should have nothing to do with this. Taking into account that we are considering adding isShownProperty to Dialog, which will eventually support both modal and non-modal dialogs... Should the visibility of the Dialog be controllable via isShownProperty, or is it // {BooleanProperty} (read-only, phet-io) ?

@pixelzoom
Copy link
Contributor

Btw... The fact that we're having to negotiate the visibility and responsibilities of this Property is the very reason why I don't agree that adding such Properties (that exist solely to provide messages to the PhET-iO data stream) is a good approach.

@pixelzoom
Copy link
Contributor

Related to this discussion... SpectrumWindowDialog is now LightSpectrumDialog.

@samreid
Copy link
Member

samreid commented Jul 9, 2018

The doc for SpectrumWindowDialog this.shownProperty says "can also be used to show/hide the dialog remotely". Is that not a requirement?

I think in general, PhET-iO should have an API for controlling and observing whether dialogs are visible. For example, one wrapper may ask students a question about a phenomenon that the student has to answer without the dialog, then the wrapper pops open the dialog. Having a setVisible/getVisible/linkVisible behavior seems best handled by a Property.

@pixelzoom
Copy link
Contributor

I think a design meeting about this is needed. I can forsee many problems with allowing PhET-iO to control visibility and change the control flow (as proposed by @samreid in #369 (comment)).

@zepumph
Copy link
Member Author

zepumph commented Dec 12, 2018

The phet-io team discussed this today. We think it is appropriate to create a Property in Dialog to expose whether or not the Dialog is "shown" to phet-io. For now we think that this Property should be read only. But we should recognize that potentially there will come a phet-io design in which there is now "Open Dialog" button that you can press instead of directly interfacing with the Dialog itself.

On top of customization (showing/hiding the dialog programmatically), we also want to make sure that we recognize the limitation of the data stream in this way currently. Here is what it looks like to open the AboutDialog in Faradays Law right now:

17 faradaysLaw.navigationBar.phetButton.phetMenu.aboutMenuItem.inputListener.releasedEmitter emitted {}
       18 faradaysLaw.navigationBar.phetButton.phetMenu.aboutMenuItem.inputListener.firedEmitter emitted
               19 faradaysLaw.general.barrierRectangle.visibleProperty changed {"oldValue":true,"newValue":false}
                20 faradaysLaw.general.barrierRectangle.visibleProperty changed {"oldValue":false,"newValue":true}

There is no event for the Dialog being displayed.

Seeing this hole in the data stream, we want to add a read only property now, for the data stream. We will wait for a design meeting to discuss the interoperability with the shown property. @samreid will take care of that

Marking as blocks publication for any sim that has a dialog other than the about dialog (like Molecules and Light).

@pixelzoom
Copy link
Contributor

Rather than something odd/nonstandard like isShowingProperty, how about visibleProperty?

@samreid
Copy link
Member

samreid commented Jan 9, 2019

The preceding commit uses setVisible for the dialog API, and I tested that it works with a11y keyboard navigation and with phet-io studio visibility.

@samreid
Copy link
Member

samreid commented Jan 9, 2019

Attempt to remove Dialog.isShowing and use visible instead:

Index: sun/js/Dialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sun/js/Dialog.js	(revision 73af71879347196ae0dbe61767ff322164c2bfbe)
+++ sun/js/Dialog.js	(date 1547052816000)
@@ -120,6 +120,7 @@
       phetioType: DialogIO,
       phetioReadOnly: false, // default to false so it can pass it through to the close button
       phetioState: false, // default to false so it can pass it through to the close button
+      visible: false, // dialogs are usually setVisible() after creation
 
       // a11y options
       tagName: 'div',
@@ -147,9 +148,6 @@
     // see https://github.com/phetsims/joist/issues/293
     assert && assert( this.isModal, 'Non-modal dialogs not currently supported' );
 
-    // @protected - whether the dialog is showing
-    this.isShowing = false;
-
     // create close button
     const closeButton = new CloseButton( {
 
@@ -305,37 +303,32 @@
      * @public
      */
     setVisible( visible ) {
+      const wasVisible = this.visible;
       Panel.prototype.setVisible.call( this, visible );
-      if ( visible ) {
-        if ( !this.isShowing ) {
-          window.phet.joist.sim.showPopup( this, this.isModal );
-          this.isShowing = true;
+      if ( visible && !wasVisible ) {
+        window.phet.joist.sim.showPopup( this, this.isModal );
 
-          // a11y - store the currently active element before hiding all other accessible content
-          // so that the active element isn't blurred
-          this.activeElement = this.activeElement || Display.focusedNode;
-          this.setAccessibleViewsVisible( false );
+        // a11y - store the currently active element before hiding all other accessible content
+        // so that the active element isn't blurred
+        this.activeElement = this.activeElement || Display.focusedNode;
+        this.setAccessibleViewsVisible( false );
 
-          // In case the window size has changed since the dialog was hidden, we should try layout out again.
-          // See https://github.com/phetsims/joist/issues/362
-          this.updateLayout();
+        // In case the window size has changed since the dialog was hidden, we should try layout out again.
+        // See https://github.com/phetsims/joist/issues/362
+        this.updateLayout();
 
-          // Do this last
-          this.showCallback && this.showCallback();
-        }
+        // Do this last
+        this.showCallback && this.showCallback();
       }
-      else {
-        if ( this.isShowing ) {
+      else if ( !visible && wasVisible ) {
 
-          window.phet.joist.sim.hidePopup( this, this.isModal );
-          this.isShowing = false;
+        window.phet.joist.sim.hidePopup( this, this.isModal );
 
-          // a11y - when the dialog is hidden, make all ScreenView content visible to assistive technology
-          this.setAccessibleViewsVisible( true );
+        // a11y - when the dialog is hidden, make all ScreenView content visible to assistive technology
+        this.setAccessibleViewsVisible( true );
 
-          // Do this last
-          this.hideCallback && this.hideCallback();
-        }
+        // Do this last
+        this.hideCallback && this.hideCallback();
       }
     },
 
Index: joist/js/AboutDialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/AboutDialog.js	(revision 01103f1bd2be1def48fb8a4d6a13633b84c3ca34)
+++ joist/js/AboutDialog.js	(date 1547052229000)
@@ -249,7 +249,7 @@
      * @override
      */
     show: function() {
-      if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
+      if ( UpdateCheck.areUpdatesChecked && !this.visible ) {
         UpdateCheck.resetTimeout();
 
         // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
@@ -273,7 +273,7 @@
      * @override
      */
     hide: function() {
-      if ( this.isShowing ) {
+      if ( this.visible ) {
         Dialog.prototype.hide.call( this );
 
         if ( UpdateCheck.areUpdatesChecked ) {
Index: joist/js/UpdateDialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/UpdateDialog.js	(revision 01103f1bd2be1def48fb8a4d6a13633b84c3ca34)
+++ joist/js/UpdateDialog.js	(date 1547052229000)
@@ -101,7 +101,7 @@
      * @public (joist-internal)
      */
     show: function() {
-      if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
+      if ( UpdateCheck.areUpdatesChecked && !this.visible ) {
         UpdateCheck.resetTimeout();
 
         // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
@@ -124,7 +124,7 @@
      * @public (joist-internal)
      */
     hide: function() {
-      if ( this.isShowing ) {
+      if ( this.visible ) {
         Dialog.prototype.hide.call( this );
 
         if ( UpdateCheck.areUpdatesChecked ) {
Index: joist/js/PhetMenu.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/PhetMenu.js	(revision 01103f1bd2be1def48fb8a4d6a13633b84c3ca34)
+++ joist/js/PhetMenu.js	(date 1547052283000)
@@ -311,7 +311,7 @@
             aboutDialog = new AboutDialog( sim.name, sim.version, sim.credits, Brand, sim.locale, phetButton,
               tandem.createTandem( 'aboutDialog' ) );
           }
-          aboutDialog.show();
+          aboutDialog.setVisible( true );
         },
         tandem: tandem.createTandem( 'aboutMenuItem' ),
         phetioDocumentation: 'This menu item shows a dialog with information about the simulation.',

@zepumph
Copy link
Member Author

zepumph commented Jan 9, 2019

I was able to find many (all?) of the usages of hide by searching the regex (self|this|ialog)\.hide\(\).

I was brought to this issue from #437, and because I saw that hide has been marked deprecated, but Dialog.dispose uses it. Though it is understandable that we may not have gotten to that step yet, I think a type shouldn't use its own deprecated methods even more so than other types/public usages.

@samreid
Copy link
Member

samreid commented Jan 9, 2019

Yes, I've made intermediate progress on this issue, I'd like to remove show/hide but haven't got to it yet.

@samreid
Copy link
Member

samreid commented Jan 18, 2019

I made progress in my working copy converting show/hide to setVisible(true|false), but was concerned that it may not be a good match. I reached out to @zepumph to discuss it, and we discussed that currently Dialog has an API that doesn't match typical Node APIs. For instance, most dialogs are currently created like so:

callback: function() {
  if ( !aboutDialog ) {
    var phetButton = sim.navigationBar.phetButton;
    aboutDialog = new AboutDialog( sim.name, sim.version, sim.credits, Brand, sim.locale, phetButton,
      tandem.createTandem( 'aboutDialog' ) );
  }
  aboutDialog.show();
},

That is, they are lazily created and require an extra show function to make them seen, and they do not require an addChild call, because that is encapsulated in Dialog.

I was wondering if we should eliminate show/hide and use setVisible(true|false) instead, and make the parentNode an option to dialog, which defaults to phet.joist.sim.dialogLayer. This could unify the API between Dialog and regular Nodes, but other than that it is unclear if there is any advantage. There may be an advantage for PhET-iO in (a) standardizing the APIs and (b) creating some dialogs eagerly instead of lazily, but as argued in #369 (comment) that may not be necessary at all.

Maybe one way to proceed will be to go with a read-only isShowing Property for now, and wait until larger team discussions about where we want to go with Dialog (if anywhere) before doing more intensive work.

@samreid
Copy link
Member

samreid commented Jan 18, 2019

Here is a patch of changes that move more occurrences of hide/show to setVisible(true|false):

Index: pendulum-lab/js/energy/view/EnergyBox.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- pendulum-lab/js/energy/view/EnergyBox.js	(revision 37dd756308df508e39e4de4bd1d144802891f961)
+++ pendulum-lab/js/energy/view/EnergyBox.js	(date 1547845666000)
@@ -210,7 +210,7 @@
         if ( !energyDialog ) {
           energyDialog = new EnergyLegendDialog();
         }
-        energyDialog.show();
+        energyDialog.setVisible( true );
       },
       touchAreaXDilation: 10,
       touchAreaYDilation: 5
Index: make-a-ten/js/make-a-ten/game/view/MakeATenGameScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- make-a-ten/js/make-a-ten/game/view/MakeATenGameScreenView.js	(revision 7d573c5eb1b2081d153b694974874239957472f6)
+++ make-a-ten/js/make-a-ten/game/view/MakeATenGameScreenView.js	(date 1547837621000)
@@ -103,7 +103,7 @@
         if ( !dialog ) {
           dialog = new InfoDialog( model.levels );
         }
-        dialog.show();
+        dialog.setVisible( true );
       },
       scale: 0.7,
       top: this.layoutBounds.top + 20,
@@ -240,7 +240,7 @@
           rewardDialog.dispose();
         }
       } );
-      rewardDialog.show();
+      rewardDialog.setVisible( true );
     },
 
     /**
Index: curve-fitting/js/curve-fitting/view/DeviationsAccordionBox.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- curve-fitting/js/curve-fitting/view/DeviationsAccordionBox.js	(revision 9181e17f77dc809f5592f6abf4c021288ecbcf1a)
+++ curve-fitting/js/curve-fitting/view/DeviationsAccordionBox.js	(date 1547837499000)
@@ -87,7 +87,7 @@
         if ( !dialog ) {
           dialog = new ReducedChiSquaredStatisticDialog();
         }
-        dialog.show();
+        dialog.setVisible( true );
       },
       baseColor: 'rgb( 204, 204, 204 )',
       maxWidth: 30,
Index: masses-and-springs/js/common/view/EnergyGraphNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- masses-and-springs/js/common/view/EnergyGraphNode.js	(revision c8180a89f669d89db1e7c953db4621dd262cd63e)
+++ masses-and-springs/js/common/view/EnergyGraphNode.js	(date 1547845666000)
@@ -224,27 +224,26 @@
 
     // a placeholder for the dialog - constructed lazily so that Dialog has access to
     // sim bounds
-    var dialog = null;
-
-    // Button that pops up dialog box for the graph's legend
-    var infoButton = new InfoButton( {
-      maxHeight: 1.1 * zoomInButton.height,
-      centerY: zoomOutButton.centerY,
-      iconFill: 'rgb( 41, 106, 163 )',
-      listener: function() {
-        if ( !dialog ) {
-          dialog = new Dialog( dialogContent, {
-            modal: true,
-            ySpacing: 20,
-            bottomMargin: 20,
-            title: new Text( energyLegendString, {
-              font: new PhetFont( 22 ),
-              maxWidth: MAX_WIDTH*2
-            } )
-          } );
-        }
+    var dialog = new Dialog( dialogContent, {
+      tandem: tandem.createTandem( 'dialog' ),
+      modal: true,
+      ySpacing: 20,
+      bottomMargin: 20,
+      title: new Text( energyLegendString, {
+        font: new PhetFont( 22 ),
+        maxWidth: MAX_WIDTH * 2
+      } ),
+      // visible: false
+    } );
+    // parent.addChild( dialog );
 
-        dialog.show();
+    // Button that pops up dialog box for the graph's legend
+    var infoButton = new InfoButton( {
+      maxHeight: 1.1 * zoomInButton.height,
+      centerY: zoomOutButton.centerY,
+      iconFill: 'rgb( 41, 106, 163 )',
+      listener: function() {
+        dialog.setVisible( true );
       }
     } );
 
@@ -279,7 +278,7 @@
     AccordionBox.call( this, accordionBoxContent, {
       buttonYMargin: 4,
       cornerRadius: MassesAndSpringsConstants.PANEL_CORNER_RADIUS,
-      titleNode: new Text( energyGraphString, { font: MassesAndSpringsConstants.TITLE_FONT, maxWidth: MAX_WIDTH+40 } )
+      titleNode: new Text( energyGraphString, { font: MassesAndSpringsConstants.TITLE_FONT, maxWidth: MAX_WIDTH + 40 } )
     } );
     this.maxHeight = 720;
   }
Index: models-of-the-hydrogen-atom/js/spectra/view/SpectraScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- models-of-the-hydrogen-atom/js/spectra/view/SpectraScreenView.js	(revision b3ea63742074041171356a8aa7f2e707b69b7926)
+++ models-of-the-hydrogen-atom/js/spectra/view/SpectraScreenView.js	(date 1547837621000)
@@ -160,7 +160,7 @@
         if ( !dialog ) {
           dialog = new SnapshotsDialog( viewProperties.numberOfSnapshotsProperty );
         }
-        dialog.show();
+        dialog.setVisible( true );
       },
       right: spectrometerNode.right,
       bottom: spectrometerNode.top - 10
Index: vegas/js/demo/RewardScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- vegas/js/demo/RewardScreenView.js	(revision 179489f77f656c42da83af9509b3d7cbbb39a967)
+++ vegas/js/demo/RewardScreenView.js	(date 1547845666000)
@@ -43,7 +43,7 @@
             rewardDialog.dispose();
           }
         } );
-        rewardDialog.show();
+        rewardDialog.setVisible( true );
       },
       center: this.layoutBounds.center.plusXY( -20, 0 )
     } );
Index: equality-explorer/js/common/view/EqualityExplorerSceneNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- equality-explorer/js/common/view/EqualityExplorerSceneNode.js	(revision e29bf19e52364ecc7bfa0bcc367043d2f9ab8469)
+++ equality-explorer/js/common/view/EqualityExplorerSceneNode.js	(date 1547837499000)
@@ -64,7 +64,7 @@
       phet.log && phet.log( 'maxInteger exceeded' );
       scene.disposeTermsNotOnScale();
       dialog = dialog || new OopsDialog( numberTooBigString );
-      dialog.show();
+      dialog.setVisible( true );
     };
 
     scene.allTermCreators.forEach( function( termCreator ) {
Index: equality-explorer/js/common/view/SeparateTermsDragListener.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- equality-explorer/js/common/view/SeparateTermsDragListener.js	(revision e29bf19e52364ecc7bfa0bcc367043d2f9ab8469)
+++ equality-explorer/js/common/view/SeparateTermsDragListener.js	(date 1547837499000)
@@ -97,7 +97,7 @@
         var thisIsLeft = ( this.termCreator.positiveLocation.x < this.equivalentTermCreator.positiveLocation.x );
         var message = thisIsLeft ? rightSideFullString : leftSideFullString;
         var oopsDialog = new OopsDialog( message );
-        oopsDialog.show();
+        oopsDialog.setVisible( true );
 
         // interrupt this drag sequence, since we can't take term off the plate
         this.interrupt();
Index: equality-explorer/js/solveit/view/SolveItSceneNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- equality-explorer/js/solveit/view/SolveItSceneNode.js	(revision e29bf19e52364ecc7bfa0bcc367043d2f9ab8469)
+++ equality-explorer/js/solveit/view/SolveItSceneNode.js	(date 1547845666000)
@@ -291,12 +291,12 @@
 
           // 'Keep Going' hides the dialog
           keepGoingButtonListener: function() {
-            rewardDialog.hide();
+            rewardDialog.setVisible( false );
           },
 
           // 'New Level' has the same effect as the back button in the status bar
           newLevelButtonListener: function() {
-            rewardDialog.hide();
+            rewardDialog.setVisible( false );
             backButtonListener();
           },
 
@@ -323,7 +323,7 @@
           }
         } );
 
-        rewardDialog.show();
+        rewardDialog.setVisible( true );
       }
       else {
 
Index: equality-explorer/js/solveit/view/LevelSelectionNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- equality-explorer/js/solveit/view/LevelSelectionNode.js	(revision e29bf19e52364ecc7bfa0bcc367043d2f9ab8469)
+++ equality-explorer/js/solveit/view/LevelSelectionNode.js	(date 1547837621000)
@@ -87,7 +87,7 @@
       maxHeight: 0.75 * chooseYourLevelNode.height,
       listener: function() {
         infoDialog = infoDialog || new InfoDialog( model.levelDescriptions );
-        infoDialog.show();
+        infoDialog.setVisible( true );
       },
       left: chooseYourLevelNode.right + 20,
       centerY: chooseYourLevelNode.centerY
@@ -136,7 +136,7 @@
             leftMargin: 20,
             rightMargin: 20
           } );
-          dialog.show();
+          dialog.setVisible( true );
         },
         centerX: layoutBounds.centerX,
         bottom: layoutBounds.bottom - 20
Index: sun/js/demo/DialogsScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sun/js/demo/DialogsScreenView.js	(revision e571c4ba773dc3c9fc6177b9d3c0093b5613165f)
+++ sun/js/demo/DialogsScreenView.js	(date 1547845666000)
@@ -39,7 +39,7 @@
         if ( !dialog ) {
           dialog = createDialog( true );
         }
-        dialog.show();
+        dialog.setVisible( true );
       },
       left: this.layoutBounds.left + 100,
       top: this.layoutBounds.top + 100
Index: sun/js/Dialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sun/js/Dialog.js	(revision e571c4ba773dc3c9fc6177b9d3c0093b5613165f)
+++ sun/js/Dialog.js	(date 1547842591000)
@@ -98,7 +98,7 @@
       layoutStrategy: Dialog.DEFAULT_LAYOUT_STRATEGY,
 
       // close button options
-      closeButtonListener: () => this.hide(),
+      closeButtonListener: () => this.setVisible( false ),
       closeButtonTouchAreaXDilation: 0,
       closeButtonTouchAreaYDilation: 0,
       closeButtonMouseAreaXDilation: 0,
@@ -121,6 +121,8 @@
       phetioReadOnly: false, // default to false so it can pass it through to the close button
       phetioState: false, // default to false so it can pass it through to the close button
 
+      parentNode: phet.joist.sim.dialogLayer,
+
       // a11y options
       tagName: 'div',
       ariaRole: 'dialog',
@@ -131,6 +133,8 @@
     options.xMargin = 0;
     assert && assert( options.yMargin === undefined, 'Dialog sets yMargin' );
     options.yMargin = 0;
+    assert && assert( !options.visible, 'Dialog should be invisible to begin with' );
+    options.visible = false;
 
     // if left margin is specified in options, use it. otherwise, set it to make the left right gutters symmetrical
     if ( options.leftMargin === null ) {
@@ -255,7 +259,7 @@
 
         if ( domEvent.keyCode === KeyboardUtil.KEY_ESCAPE ) {
           domEvent.preventDefault();
-          this.hide();
+          this.setVisible( false );
           this.focusActiveElement();
         }
         else if ( domEvent.keyCode === KeyboardUtil.KEY_TAB && FullScreen.isFullScreen() ) {
@@ -343,28 +347,12 @@
       }
     },
 
-    // @public
-    // @deprecated - use setVisible
-    show() {
-      this.setVisible( true );
-    },
-
-    /**
-     * Hide the dialog.  If you create a new dialog next time you show(), be sure to dispose this
-     * dialog instead.
-     * @public
-     * @deprecated - use setVisible
-     */
-    hide() {
-      this.setVisible( false );
-    },
-
     /**
      * Make eligible for garbage collection.
      * @public
      */
     dispose() {
-      this.hide();
+      this.setVisible( false );
       this.disposeDialog();
       Panel.prototype.dispose.call( this );
     },
Index: gene-expression-essentials/js/multiple-cells/view/MultipleCellsScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- gene-expression-essentials/js/multiple-cells/view/MultipleCellsScreenView.js	(revision e79e06419ca1c8e23e3987fda11c25c1441edb87)
+++ gene-expression-essentials/js/multiple-cells/view/MultipleCellsScreenView.js	(date 1547837621000)
@@ -85,7 +85,7 @@
         if ( !dialog ) {
           dialog = new FluorescentCellsPictureDialog();
         }
-        dialog.show();
+        dialog.setVisible( true );
       }
     } );
 
Index: scenery-phet/js/BarrierRectangle.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- scenery-phet/js/BarrierRectangle.js	(revision d69a377292764228b2b8f5bf009e05e1c7b00d36)
+++ scenery-phet/js/BarrierRectangle.js	(date 1547837924000)
@@ -42,7 +42,7 @@
       tandem: options.tandem.createTandem( 'inputListener' ),
       fire: function( event ) {
         assert && assert( modalNodeStack.length > 0, 'There must be a Node in the stack to hide.' );
-        modalNodeStack.get( modalNodeStack.length - 1 ).hide();
+        modalNodeStack.get( modalNodeStack.length - 1 ).setVisible( false );
       }
     } ) );
 
Index: scenery-phet/js/ContextLossFailureDialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- scenery-phet/js/ContextLossFailureDialog.js	(revision d69a377292764228b2b8f5bf009e05e1c7b00d36)
+++ scenery-phet/js/ContextLossFailureDialog.js	(date 1547837898000)
@@ -31,7 +31,7 @@
   function ContextLossFailureDialog( options ) {
 
     var self = this;
-    
+
     options = _.extend( {
 
       // Provided as an option so that scenery-phet demo app can test without causing automated-testing failures.
@@ -82,9 +82,9 @@
      * @public
      * @override
      */
-    hide: function() {
-      this.reload();
-      Dialog.prototype.hide.call( this );
+    setVisible: function( visible ) {
+      !visible && this.reload();
+      Dialog.prototype.setVisible.call( this, visible );
     }
   } );
 } );
Index: scenery-phet/js/demo/DialogsScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- scenery-phet/js/demo/DialogsScreenView.js	(revision d69a377292764228b2b8f5bf009e05e1c7b00d36)
+++ scenery-phet/js/demo/DialogsScreenView.js	(date 1547845666000)
@@ -43,7 +43,7 @@
             }
           } );
         }
-        contextLossFailureDialog.show();
+        contextLossFailureDialog.setVisible( true );
       }
     } );
 
Index: molecule-shapes/js/common/view/MoleculeShapesScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- molecule-shapes/js/common/view/MoleculeShapesScreenView.js	(revision 9a6e668c3be7139f118e14cfd4495a73646dd9fd)
+++ molecule-shapes/js/common/view/MoleculeShapesScreenView.js	(date 1547845666000)
@@ -303,7 +303,7 @@
       if ( !this.contextLossDialog ) {
         this.contextLossDialog = new ContextLossFailureDialog();
       }
-      this.contextLossDialog.show();
+      this.contextLossDialog.setVisible( true );
     },
 
     /**
Index: molecules-and-light/js/moleculesandlight/view/MoleculesAndLightScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- molecules-and-light/js/moleculesandlight/view/MoleculesAndLightScreenView.js	(revision 4b2971ec82a0c3f1ed29b6b861bdeba35c0f933f)
+++ molecules-and-light/js/moleculesandlight/view/MoleculesAndLightScreenView.js	(date 1547845666000)
@@ -199,7 +199,7 @@
         if ( !dialog ) {
           dialog = new LightSpectrumDialog( spectrumButtonLabel, tandem.createTandem( 'lightSpectrumDialog' ) );
         }
-        dialog.show();
+        dialog.setVisible( true );
 
         // if listener was fired because of accessibility
         if ( showLightSpectrumButton.buttonModel.isA11yClicking() ) {
Index: plinko-probability/js/lab/view/LabScreenView.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- plinko-probability/js/lab/view/LabScreenView.js	(revision 5ecdc3ff2153e2dcaf84212f6612f45211fe68eb)
+++ plinko-probability/js/lab/view/LabScreenView.js	(date 1547845666000)
@@ -156,7 +156,7 @@
         if ( !dialog ) {
           dialog = new OutOfBallsDialog();
         }
-        dialog.show();
+        dialog.setVisible( true );
 
         // makes the play button visible
         playPanel.playButtonVisibleProperty.set( true );
Index: joist/js/AboutDialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/AboutDialog.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/AboutDialog.js	(date 1547838483000)
@@ -244,47 +244,43 @@
   return inherit( Dialog, AboutDialog, {
 
     /**
-     * Show the dialog
+     * Remove listeners that should only be called when the dialog is shown.
      * @public
      * @override
      */
-    show: function() {
-      if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
-        UpdateCheck.resetTimeout();
+    setVisible: function( visible ) {
+      if ( visible ) {
+
+        if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
+          UpdateCheck.resetTimeout();
 
-        // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
-        if ( UpdateCheck.stateProperty.value === 'offline' || UpdateCheck.stateProperty.value === 'unchecked' ) {
-          UpdateCheck.check();
-        }
+          // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
+          if ( UpdateCheck.stateProperty.value === 'offline' || UpdateCheck.stateProperty.value === 'unchecked' ) {
+            UpdateCheck.check();
+          }
 
-        // Hook up our spinner listener when we're shown
-        timer.addListener( this.updateStepListener );
+          // Hook up our spinner listener when we're shown
+          timer.addListener( this.updateStepListener );
 
-        // Hook up our visibility listener
-        UpdateCheck.stateProperty.link( this.updateVisibilityListener );
+          // Hook up our visibility listener
+          UpdateCheck.stateProperty.link( this.updateVisibilityListener );
+        }
       }
+      else {
 
-      Dialog.prototype.show.call( this );
-    },
-
-    /**
-     * Remove listeners that should only be called when the dialog is shown.
-     * @public
-     * @override
-     */
-    hide: function() {
-      if ( this.isShowing ) {
-        Dialog.prototype.hide.call( this );
+        if ( this.isShowing ) {
 
-        if ( UpdateCheck.areUpdatesChecked ) {
+          if ( UpdateCheck.areUpdatesChecked ) {
 
-          // Disconnect our visibility listener
-          UpdateCheck.stateProperty.unlink( this.updateVisibilityListener );
+            // Disconnect our visibility listener
+            UpdateCheck.stateProperty.unlink( this.updateVisibilityListener );
 
-          // Disconnect our spinner listener when we're hidden
-          timer.removeListener( this.updateStepListener );
+            // Disconnect our spinner listener when we're hidden
+            timer.removeListener( this.updateStepListener );
+          }
         }
       }
+      Dialog.prototype.setVisible.call( this, visible );
     },
 
     /**
Index: joist/js/Sim.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/Sim.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/Sim.js	(date 1547837827000)
@@ -679,7 +679,7 @@
 
       // @private list of nodes that are "modal" and hence block input with the barrierRectangle.  Used by modal dialogs
       // and the PhetMenu
-      this.modalNodeStack = new ObservableArray(); // {Node} with node.hide()
+      this.modalNodeStack = new ObservableArray(); // {Node}
 
       // @public (joist-internal) Semi-transparent black barrier used to block input events when a dialog (or other popup)
       // is present, and fade out the background.
@@ -720,14 +720,12 @@
     /*
      * Adds a popup in the global coordinate frame, and optionally displays a semi-transparent black input barrier behind it.
      * Use hidePopup() to remove it.
-     * @param {Node} node - Should have node.hide() implemented to hide the popup (should subsequently call
-     *                      sim.hidePopup()).
+     * @param {Node} node - shown as a popup
      * @param {boolean} isModal - Whether to display the semi-transparent black input barrier behind it.
      * @public
      */
     showPopup: function( node, isModal ) {
       assert && assert( node );
-      assert && assert( !!node.hide, 'Missing node.hide() for showPopup' );
       assert && assert( !this.topLayer.hasChild( node ), 'Popup already shown' );
       if ( isModal ) {
         this.modalNodeStack.push( node );
Index: joist/js/UpdateNodes.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/UpdateNodes.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/UpdateNodes.js	(date 1547845666000)
@@ -143,7 +143,7 @@
               newWindow.focus();
             } } ),
             new TextPushButton( updatesNoThanksString, { baseColor: '#ddd', font: updateTextFont, listener: function() {
-              dialog.hide();
+                dialog.setVisible( false );
               // Closing the dialog is handled by the Dialog listener itself, no need to add code to close it here.
             } } )
           ] } )
Index: joist/js/KeyboardHelpButton.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/KeyboardHelpButton.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/KeyboardHelpButton.js	(date 1547837621000)
@@ -67,7 +67,7 @@
           tandem: tandem.createTandem( 'keyboardHelpDialog' )
         } );
       }
-      keyboardHelpDialog.show();
+      keyboardHelpDialog.setVisible( true );
 
       // if listener was fired because of accessibility
       if ( self.buttonModel.isA11yClicking() ) {
Index: joist/js/UpdateDialog.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/UpdateDialog.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/UpdateDialog.js	(date 1547838371000)
@@ -96,46 +96,40 @@
   return inherit( Dialog, UpdateDialog, {
 
     /**
-     * Show the UpdateDialog, registering listeners that should only be called while
-     * the dialog is shown.
+     * Remove listeners that should only be called when the Dialog is shown.
      * @public (joist-internal)
      */
-    show: function() {
-      if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
-        UpdateCheck.resetTimeout();
+    setVisible: function( visible ) {
+      if ( visible ) {
+        if ( UpdateCheck.areUpdatesChecked && !this.isShowing ) {
+          UpdateCheck.resetTimeout();
 
-        // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
-        if ( UpdateCheck.stateProperty.value === 'offline' || UpdateCheck.stateProperty === 'unchecked' ) {
-          UpdateCheck.check();
-        }
+          // Fire off a new update check if we were marked as offline or unchecked before, and we handle updates.
+          if ( UpdateCheck.stateProperty.value === 'offline' || UpdateCheck.stateProperty === 'unchecked' ) {
+            UpdateCheck.check();
+          }
 
-        // Hook up our spinner listener when we're shown
-        timer.addListener( this.updateStepListener );
+          // Hook up our spinner listener when we're shown
+          timer.addListener( this.updateStepListener );
 
-        // Hook up our visibility listener
-        UpdateCheck.stateProperty.link( this.updateVisibilityListener );
+          // Hook up our visibility listener
+          UpdateCheck.stateProperty.link( this.updateVisibilityListener );
+        }
       }
-
-      Dialog.prototype.show.call( this );
-    },
-
-    /**
-     * Remove listeners that should only be called when the Dialog is shown.
-     * @public (joist-internal)
-     */
-    hide: function() {
-      if ( this.isShowing ) {
-        Dialog.prototype.hide.call( this );
+      else {
+        if ( this.isShowing ) {
 
-        if ( UpdateCheck.areUpdatesChecked ) {
+          if ( UpdateCheck.areUpdatesChecked ) {
 
-          // Disconnect our visibility listener
-          UpdateCheck.stateProperty.unlink( this.updateVisibilityListener );
+            // Disconnect our visibility listener
+            UpdateCheck.stateProperty.unlink( this.updateVisibilityListener );
 
-          // Disconnect our spinner listener when we're hidden
-          timer.removeListener( this.updateStepListener );
+            // Disconnect our spinner listener when we're hidden
+            timer.removeListener( this.updateStepListener );
+          }
         }
       }
+      Dialog.prototype.setVisible.call( this, visible );
     }
   } );
 } );
Index: joist/js/PhetMenu.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- joist/js/PhetMenu.js	(revision 0f1967cb35b7ac9e8337b92d59ea204b3b5fdd9d)
+++ joist/js/PhetMenu.js	(date 1547845666000)
@@ -131,7 +131,7 @@
           if ( !optionsDialog ) {
             optionsDialog = new OptionsDialog( sim.options.optionsNode, { tandem: tandem.createTandem( 'optionsDialog' ) } );
           }
-          optionsDialog.show();
+          optionsDialog.setVisible( true );
         },
         tandem: tandem.createTandem( 'optionsMenuItem' ),
         phetioDocumentation: 'This menu item shows an options dialog.',
@@ -224,7 +224,7 @@
             var phetButton = sim.navigationBar.phetButton;
             updateDialog = new UpdateDialog( phetButton );
           }
-          updateDialog.show();
+          updateDialog.setVisible( true );
         },
 
         // a11y

@samreid
Copy link
Member

samreid commented Jan 19, 2019

In the preceding commits, I added a PHET-iO read-only property that indicates whether a dialog is showing. I tested it with Molecules and Light and it behaves as expected.

On the one hand, I'm somewhat interested in revising the Dialog API like so it matches typical Node API:

const dialog = new Dialog(content); // already visible
phet.joist.sim.dialogLayer.addChild(dialog);

// to hide temporarily
dialog.setVisible(false);

// to remove
dialog.detach();

On the other hand, the existing API exemplified in #369 (comment) may be in a "not broken, don't fix it" situation. But I'm concerned about PhET-iO and accessibility issues and thinking that unifying with standard Node API could make things clearer. But that would be a much more invasive change and would require the dev team to sign off. I'll create a separate issue for that.

@samreid
Copy link
Member

samreid commented Jan 19, 2019

I opened #455 for further discussion with @zepumph @jonathanolson and @pixelzoom. @zepumph and @pixelzoom do you think this issue can be closed?

@pixelzoom
Copy link
Contributor

I haven't been following this issue very closely, and haven't reviewed the solution. So as I mentioned in #369 (comment), I'm going to defer to others on Dialog.

@pixelzoom pixelzoom removed their assignment Jan 19, 2019
samreid added a commit to phetsims/joist that referenced this issue Jan 20, 2019
@zepumph
Copy link
Member Author

zepumph commented Jan 24, 2019

This looks like just what I was thinking, nice work!. I think we are good to close, carrying on in #455.

@pixelzoom
Copy link
Contributor

Potential memory leak for isShowingProperty fixed in the above commit. Since it's @protected, subclasses might add a listener that creates a leak. isShowingProperty.dispose is now called in dialogDispose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants