phetsims / vegas

Reusable game components for PhET simulations.
MIT License
1 stars 4 forks source link

Create a reusable Info dialog for games. #107

Closed pixelzoom closed 2 years ago

pixelzoom commented 2 years ago

From https://github.com/phetsims/vegas/issues/104.

It would be nice to have this done by mid June, for use in Number Play.

pixelzoom commented 2 years ago

I immediately hit a problem with generalizing this.

Most game Info dialogs look like this one in Equality Explorer (InfoDialog.js). Each level description is a line of RichText, and they are arrangement in a single VBox.

screenshot_1670

And there is one string for each level description. For example, in equality-explorer-strings_en.json:

  "level1Description": {
    "value": "<b>Level 1</b>  One-step equations"
  },
  "level2Description": {
    "value": "<b>Level 2</b>  One-step equations with negative coefficients"
  },
  "level3Description": {
    "value": "<b>Level 3</b>  Two-step equations"
  },
  "level4Description": {
    "value": "<b>Level 4</b>  Multi-step equations with fractions"
  },
  "level5Description": {
    "value": "<b>Level 5</b>  Multi-step equations with variables on both sides"
  },

Number Play uses an entirely different layout and approach to translated strings. There are separate nodes for the level names vs their descriptions. And the names and descriptions are in separate VBoxes (see number-play/InfoDialog.ts).

screenshot_1669

And there are separate translated strings for level names vs descriptions:

  "gameNameLevelNumberPattern": {
    "value": "{{gameName}}: Level {{levelNumber}}"
  },
 "countFromPattern": {
    "value": "Count from {{minimumChallengeNumber}}-{{maximumChallengeNumber}}"
  },
  "subitizeFromPattern": {
    "value": "Subitize from {{minimumChallengeNumber}}-{{maximumChallengeNumber}}"
  },

So I don't know how to proceed. Can we change the layout in Number Play to be like other sims? Can we change the approach to translated strings in Number Play?

Assigning to @chrisklus and @amanda-phet for feedback. I'm blocked until we determine a general approach that works for all sims.

pixelzoom commented 2 years ago

Pinging @chrisklus and @amanda-phet. I'm still blocked on this feature.

chrisklus commented 2 years ago

Apologies for missing this. @amanda-phet would like me to make a recommendation.

So I don't know how to proceed. Can we change the layout in Number Play to be like other sims? Can we change the approach to translated strings in Number Play?

Seems like in order for this to work in common code, we need to do both. The main down side i see to this design-wise is that the non-bolded text the right will not be left aligned as it is now. The gap in between the two sets doesn't feel as important. But, I think those are acceptable tradeoffs in order to factor this code out.

@pixelzoom if I change the string structure to match what you outlined in EE, and then just delete the existing dialog, is that enough to unblock you on this issue?

chrisklus commented 2 years ago

@pixelzoom I completed those changes in the issue linked above. Let me know if that's what you were looking for.

Here are the new strings:

"countingLevel1Description": {
  "value": "<b>Counting: Level 1</b>  Count from 1-10"
},
"countingLevel2Description": {
  "value": "<b>Counting: Level 2</b>  Count from 11-20"
},
"subitizingLevel1Description": {
  "value": "<b>Subitizing: Level 1</b>  Subitize from 1-5"
},
"subitizingLevel2Description": {
  "value": "<b>Subitizing: Level 2</b>  Subitize from 6-10"
},

Noting that the 4 level descriptions can be accessed directly on the strings object, or you can get one for each level generally via the model: level.gameType.levelDescriptions[ level.levelNumber ]

pixelzoom commented 2 years ago

Currently blocked by https://github.com/phetsims/sun/issues/763. Popupable and Dialog need to be converted to TypeScript.

pixelzoom commented 2 years ago

In the above commits, I created GameInfoDialog. Of special note is the gameLevels option, which callers can set to the value of their gameLevels query parameter. (I did consider making the gameLevels option a Property. And in fact, I went way down that path. But as something to control via PhET-iO, it seems unnecessary.)

I used GameInfoDialog in fourier-making-waves and equality-explorer, and it worked nicely.

For review, I think it would be productive to have @chrisklus do the review, and use GameInfoDialog in number-play (where I suggest renaming InfoDialog to something like NumberPlayGameInfoDialog).

pixelzoom commented 2 years ago

Sims that use GameInfoDialog are blocked for publication until this review is completed.

pixelzoom commented 2 years ago

In the above commit, I added a demo of GameInfoDialog to the vegas demo Components screen.

chrisklus commented 2 years ago

Thanks for these changes - GameInfoDialog looks great and is working well in Number Play. I tested various combos of the gameLevels query parameter.

Patch of my proposed changes (not fully tested):

``` Index: fourier-making-waves/js/waveGame/view/WaveGameInfoDialog.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/fourier-making-waves/js/waveGame/view/WaveGameInfoDialog.js b/fourier-making-waves/js/waveGame/view/WaveGameInfoDialog.js --- a/fourier-making-waves/js/waveGame/view/WaveGameInfoDialog.js (revision cabe08397687b5766e6afc9702f526861fa798e5) +++ b/fourier-making-waves/js/waveGame/view/WaveGameInfoDialog.js (date 1657664018317) @@ -15,8 +15,6 @@ import fourierMakingWaves from '../../fourierMakingWaves.js'; import fourierMakingWavesStrings from '../../fourierMakingWavesStrings.js'; -const MAX_CONTENT_WIDTH = 600; - class WaveGameInfoDialog extends GameInfoDialog { /** @@ -29,14 +27,6 @@ // GameInfoDialogOptions gameLevels: FMWQueryParameters.gameLevels, - descriptionTextOptions: { - font: new PhetFont( 24 ) - }, - vBoxOptions: { - align: 'left', - spacing: 20, - maxWidth: MAX_CONTENT_WIDTH // scale all descriptions uniformly - }, ySpacing: 20, bottomMargin: 20, @@ -48,7 +38,7 @@ assert && assert( !options.title, 'WaveGameInfoDialog sets title' ); options.title = new Text( fourierMakingWavesStrings.levels, { font: new PhetFont( 32 ), - maxWidth: 0.75 * MAX_CONTENT_WIDTH, + maxWidth: 0.75 * GameInfoDialog.DEFAULT_MAX_CONTENT_WIDTH, tandem: options.tandem.createTandem( 'titleText' ) } ); Index: vegas/js/GameInfoDialog.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/vegas/js/GameInfoDialog.ts b/vegas/js/GameInfoDialog.ts --- a/vegas/js/GameInfoDialog.ts (revision af4095eaa70e27dccc31164f7c5f55eec46302b9) +++ b/vegas/js/GameInfoDialog.ts (date 1657664018332) @@ -15,6 +15,7 @@ import Dialog, { DialogOptions } from '../../sun/js/Dialog.js'; import EmptyObjectType from '../../phet-core/js/types/EmptyObjectType.js'; import Tandem from '../../tandem/js/Tandem.js'; +import PhetFont from '../../scenery-phet/js/PhetFont.js'; type SelfOptions = { @@ -33,16 +34,22 @@ export default class GameInfoDialog extends Dialog { + public static DEFAULT_MAX_CONTENT_WIDTH = 600; + /** * @param levelDescriptions - level descriptions, in order of ascending level number * @param providedOptions */ public constructor( levelDescriptions: string[], providedOptions?: GameInfoDialogOptions ) { - const options = optionize, DialogOptions>()( { + const options = optionize, DialogOptions>()( { + descriptionTextOptions: { + font: new PhetFont( 24 ) + }, vBoxOptions: { align: 'left', - spacing: 20 + spacing: 20, + maxWidth: GameInfoDialog.DEFAULT_MAX_CONTENT_WIDTH // scale all descriptions uniformly }, tandem: Tandem.REQUIRED }, providedOptions ); Index: number-play/js/game/view/NumberPlayGameInfoDialog.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/number-play/js/game/view/NumberPlayGameInfoDialog.ts b/number-play/js/game/view/NumberPlayGameInfoDialog.ts --- a/number-play/js/game/view/NumberPlayGameInfoDialog.ts (revision d92591963d848f7580cbde801c8eb91c6de76f38) +++ b/number-play/js/game/view/NumberPlayGameInfoDialog.ts (date 1657664018321) @@ -18,7 +18,6 @@ // constants const TITLE_FONT = new PhetFont( 32 ); -const MAX_CONTENT_WIDTH = 600; class NumberPlayGameInfoDialog extends GameInfoDialog { @@ -28,20 +27,12 @@ const titleNode = new Text( numberPlayStrings.games, { font: TITLE_FONT, - maxWidth: 0.75 * MAX_CONTENT_WIDTH + maxWidth: 0.75 * GameInfoDialog.DEFAULT_MAX_CONTENT_WIDTH } ); super( descriptions, { title: titleNode, gameLevels: NumberPlayQueryParameters.gameLevels, - descriptionTextOptions: { - font: new PhetFont( 24 ) - }, - vBoxOptions: { - align: 'left', - spacing: 20, - maxWidth: MAX_CONTENT_WIDTH // scale all descriptions uniformly - }, ySpacing: 30, bottomMargin: 30 } ); Index: equality-explorer/js/solveit/view/SolveItInfoDialog.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/equality-explorer/js/solveit/view/SolveItInfoDialog.js b/equality-explorer/js/solveit/view/SolveItInfoDialog.js --- a/equality-explorer/js/solveit/view/SolveItInfoDialog.js (revision 4ca498a73dca75edd1414bcc43e6205988ddecdf) +++ b/equality-explorer/js/solveit/view/SolveItInfoDialog.js (date 1657664018326) @@ -14,8 +14,6 @@ import equalityExplorer from '../../equalityExplorer.js'; import equalityExplorerStrings from '../../equalityExplorerStrings.js'; -const MAX_CONTENT_WIDTH = 600; - class SolveItInfoDialog extends GameInfoDialog { /** @@ -27,20 +25,12 @@ const titleNode = new Text( equalityExplorerStrings.levels, { font: new PhetFont( 32 ), - maxWidth: 0.75 * MAX_CONTENT_WIDTH + maxWidth: 0.75 * GameInfoDialog.DEFAULT_MAX_CONTENT_WIDTH } ); super( descriptions, { gameLevels: EqualityExplorerQueryParameters.gameLevels, title: titleNode, - vBoxOptions: { - align: 'left', - spacing: 20, - maxWidth: MAX_CONTENT_WIDTH // scale all descriptions uniformly - }, - descriptionTextOptions: { - font: new PhetFont( 24 ) - }, ySpacing: 20, bottomMargin: 20 } ); ```

Removing the blocks-publication label. Back to @pixelzoom for any further changes if desired.

chrisklus commented 2 years ago

Another possibility for that second bullet could be to remove title from GameInfoDialog options, add titleString instead, and have GameInfoDialog be responsible for creating the titleNode, since those usages largely look the same. May be more trouble than it's worth though if we need the flexibility of exposing the Text options for the titleNode. However, this could also be an opportunity unify the phetio API for the title.

pixelzoom commented 2 years ago

Thanks for the review, I'll have a look at the proposed patch.

Another possibility for that second bullet could be to remove title from GameInfoDialog options, add titleString instead, and have GameInfoDialog be responsible for creating the titleNode ...

We'd need to also add titleOptions, for styling the Text created by GameInfoDialog. And someone will eventually want RichText instead of Text. And a useRichText option to choose between Text and RichText, like we've been saddled with in NumberDisplay. And then that complicates titleOptions -- what type do we give it? And then someone wants to use an icon in their title. And then... You see where I'm going here? title: Node is general and future-proof. Dependency injection is a better fit for the title, at the expense of a tiny bit of duplicated work for (most?) callers. (And I wish we'd done this in most UI components that take a title: string.)

pixelzoom commented 2 years ago
  • All usages of descriptionTextOptions are providing the same font size, could we make that the default?

Great suggestion. Done in the above commits.

pixelzoom commented 2 years ago
  • All usages of vBoxOptions are the same, and all are duplicating the two defaults in GameInfoDialog because maxWidth needs to be included with them. Since the maxWidth used is the same value for all usages, could we add it as a static default to GameInfoDialog (so it can still be used for the titleNode max width) and then use it in the default options?

Adding GameInfoDialog.DEFAULT_MAX_CONTENT_WIDTH (as in the patch) still requires the caller to set maxWidth for both their title and vBoxOptions (content). I decided to try a different approach, where GameInfoDialog is responsible for constraining its width, and were the caller (in most cases) never needs to deal with maxWidth.

Here's a summary of what I did in the above commits:

@chrisklus ready for your review. Let me know if you think this is an acceptable solution. And feel free to close.

screenshot_1784
chrisklus commented 2 years ago

Commits look great, thanks. One note - In the above commits I removed all the duplicated defaults for vBoxOptions, as that was part of my reasoning for creating a default for maxWidth separate from vBoxOptions, so those defaults no longer needed to be duplicated. Closing.