diff --git a/js/common/NumberPairsConstants.ts b/js/common/NumberPairsConstants.ts index a73da14..7810a8f 100644 --- a/js/common/NumberPairsConstants.ts +++ b/js/common/NumberPairsConstants.ts @@ -8,6 +8,7 @@ import numberPairs from '../numberPairs.js'; import PhetFont from '../../../scenery-phet/js/PhetFont.js'; +import Range from '../../../dot/js/Range.js'; const NumberPairsConstants = { @@ -18,7 +19,16 @@ const NumberPairsConstants = { INTRO_INITIAL_SUM_VALUE: 3, INTRO_INITIAL_LEFT_ADDEND_VALUE: 2, - COUNTING_AREA_X_MARGIN: 100 + TEN_INITIAL_SUM_VALUE: 3, + TEN_INITIAL_LEFT_ADDEND_VALUE: 2, + TWENTY_INITIAL_SUM_VALUE: 11, + TWENTY_INITIAL_LEFT_ADDEND_VALUE: 10, + SUM_INITIAL_SUM_VALUE: 3, + SUM_INITIAL_LEFT_ADDEND_VALUE: 2, + COUNTING_AREA_X_MARGIN: 100, + + TEN_SCENE_RANGE: new Range( 0, 10 ), + TWENTY_SCENE_RANGE: new Range( 11, 20 ) }; numberPairs.register( 'NumberPairsConstants', NumberPairsConstants ); diff --git a/js/common/view/NumberPairsScreenView.ts b/js/common/view/NumberPairsScreenView.ts index c652ed4..8e6004c 100644 --- a/js/common/view/NumberPairsScreenView.ts +++ b/js/common/view/NumberPairsScreenView.ts @@ -13,19 +13,23 @@ import optionize from '../../../../phet-core/js/optionize.js'; import NumberPairsConstants from '../NumberPairsConstants.js'; import ResetAllButton from '../../../../scenery-phet/js/buttons/ResetAllButton.js'; import NumberPairsModel from '../model/NumberPairsModel.js'; +import Range from '../../../../dot/js/Range.js'; +import SumRadioButtonGroup from './SumRadioButtonGroup.js'; type SelfOptions = { numberSentenceContent: Node; numberBondContent: Node; equationContent?: Node | null; + sceneRange?: Range | null; }; export type NumberPairsScreenViewOptions = SelfOptions & ScreenViewOptions; export default class NumberPairsScreenView extends ScreenView { public constructor( model: NumberPairsModel, providedOptions: NumberPairsScreenViewOptions ) { const options = optionize()( { - equationContent: null + equationContent: null, + sceneRange: null }, providedOptions ); super( options ); @@ -65,6 +69,25 @@ export default class NumberPairsScreenView extends ScreenView { tandem: options.tandem.createTandem( 'resetAllButton' ) } ); this.addChild( resetAllButton ); + + // Add the sum radio button group if the scene range is provided. Each radio button represents a sum value + // that is associated with a scene state. + if ( options.sceneRange ) { + const sumRadioButtonGroup = new SumRadioButtonGroup( model.sumProperty, { + sceneRange: options.sceneRange + } ); + + // Sum radio buttons should be center aligned vertically above the reset all button. + const sumSelectorAlignBox = new AlignBox( sumRadioButtonGroup, { + alignBounds: this.layoutBounds.withOffsets( 0, 0, 0, -resetAllButton.height - NumberPairsConstants.SCREEN_VIEW_Y_MARGIN ), + yMargin: NumberPairsConstants.SCREEN_VIEW_Y_MARGIN, + xMargin: NumberPairsConstants.SCREEN_VIEW_X_MARGIN, + yAlign: 'center', + xAlign: 'right' + } ); + + this.addChild( sumSelectorAlignBox ); + } } /** diff --git a/js/common/view/SumRadioButtonGroup.ts b/js/common/view/SumRadioButtonGroup.ts new file mode 100644 index 0000000..626961a --- /dev/null +++ b/js/common/view/SumRadioButtonGroup.ts @@ -0,0 +1,46 @@ +// Copyright 2024, University of Colorado Boulder +/** + * SumRadioButtonGroup is a RectangularRadioButtonGroup that displays the sum values that can be selected by the user. + * The sum values are displayed in descending order and are each associated with a scene that tracks its own state. + * + * @author Marla Schulz (PhET Interactive Simulations) + * + */ + +import RectangularRadioButtonGroup, { RectangularRadioButtonGroupOptions } from '../../../../sun/js/buttons/RectangularRadioButtonGroup.js'; +import Range from '../../../../dot/js/Range.js'; +import { Text } from '../../../../scenery/js/imports.js'; +import numberPairs from '../../numberPairs.js'; +import optionize from '../../../../phet-core/js/optionize.js'; +import PhetFont from '../../../../scenery-phet/js/PhetFont.js'; +import Property from '../../../../axon/js/Property.js'; +import Dimension2 from '../../../../dot/js/Dimension2.js'; + +type SelfOptions = { + sceneRange: Range; +}; +type SceneSelectionRadioButtonGroupOptions = SelfOptions & RectangularRadioButtonGroupOptions; +export default class SumRadioButtonGroup extends RectangularRadioButtonGroup { + + public constructor( sumProperty: Property, providedOptions: SceneSelectionRadioButtonGroupOptions ) { + const options = optionize()( { + radioButtonOptions: { + size: new Dimension2( 35, 35 ) + } + }, providedOptions ); + + // We want our scene values to be in descending order and include both the min and the max. + const groupItems = _.times( options.sceneRange.getLength() + 1, i => { + const sceneValue = options.sceneRange.min + i; + const sceneIcon = new Text( sceneValue.toString(), { font: new PhetFont( 20 ) } ); + return { + createNode: () => sceneIcon, + value: sceneValue, + tandem: `sum${sceneValue}RadioButton` + }; + } ).reverse(); + super( sumProperty, groupItems, options ); + } +} + +numberPairs.register( 'SumRadioButtonGroup', SumRadioButtonGroup ); \ No newline at end of file diff --git a/js/intro/view/IntroScreenView.ts b/js/intro/view/IntroScreenView.ts index 74dbd80..d5f423f 100644 --- a/js/intro/view/IntroScreenView.ts +++ b/js/intro/view/IntroScreenView.ts @@ -15,6 +15,7 @@ import NumberPairsScreenView, { NumberPairsScreenViewOptions } from '../../commo import StrictOmit from '../../../../phet-core/js/types/StrictOmit.js'; import PickRequired from '../../../../phet-core/js/types/PickRequired.js'; import NumberPairsColors from '../../common/NumberPairsColors.js'; +import NumberPairsConstants from '../../common/NumberPairsConstants.js'; type SelfOptions = { //TODO add options that are specific to IntroScreenView here @@ -38,7 +39,8 @@ export default class IntroScreenView extends NumberPairsScreenView { rightAddendColorProperty: NumberPairsColors.locationRightAddendColorProperty }, tandem: providedOptions.tandem.createTandem( 'numberBondAccordionBox' ) - } ) + } ), + sceneRange: NumberPairsConstants.TEN_SCENE_RANGE }, providedOptions ); super( model, options ); diff --git a/js/sum/model/SumModel.ts b/js/sum/model/SumModel.ts index 6fd53aa..729d2ef 100644 --- a/js/sum/model/SumModel.ts +++ b/js/sum/model/SumModel.ts @@ -25,8 +25,8 @@ export default class SumModel extends NumberPairsModel { public constructor( providedOptions: SumModelOptions ) { const options = optionize()( { - initialSumValue: NumberPairsConstants.INTRO_INITIAL_SUM_VALUE, - initialLeftAddendValue: NumberPairsConstants.INTRO_INITIAL_LEFT_ADDEND_VALUE + initialSumValue: NumberPairsConstants.SUM_INITIAL_SUM_VALUE, + initialLeftAddendValue: NumberPairsConstants.SUM_INITIAL_LEFT_ADDEND_VALUE }, providedOptions ); super( options ); diff --git a/js/ten/model/TenModel.ts b/js/ten/model/TenModel.ts index 6bb6360..c255057 100644 --- a/js/ten/model/TenModel.ts +++ b/js/ten/model/TenModel.ts @@ -25,8 +25,8 @@ export default class TenModel extends NumberPairsModel { public constructor( providedOptions: TenModelOptions ) { const options = optionize()( { - initialSumValue: NumberPairsConstants.INTRO_INITIAL_SUM_VALUE, - initialLeftAddendValue: NumberPairsConstants.INTRO_INITIAL_LEFT_ADDEND_VALUE + initialSumValue: NumberPairsConstants.TEN_INITIAL_SUM_VALUE, + initialLeftAddendValue: NumberPairsConstants.TEN_INITIAL_LEFT_ADDEND_VALUE }, providedOptions ); super( options ); } diff --git a/js/ten/view/TenScreenView.ts b/js/ten/view/TenScreenView.ts index f9a700f..3db2eaa 100644 --- a/js/ten/view/TenScreenView.ts +++ b/js/ten/view/TenScreenView.ts @@ -16,6 +16,7 @@ import NumberBondAccordionBox from '../../common/view/NumberBondAccordionBox.js' import EquationAccordionBox from '../../common/view/EquationAccordionBox.js'; import PickRequired from '../../../../phet-core/js/types/PickRequired.js'; import NumberPairsColors from '../../common/NumberPairsColors.js'; +import NumberPairsConstants from '../../common/NumberPairsConstants.js'; type SelfOptions = { //TODO add options that are specific to TenScreenView here @@ -45,7 +46,8 @@ export default class TenScreenView extends NumberPairsScreenView { leftAddendColorProperty: NumberPairsColors.attributeLeftAddendColorProperty, rightAddendColorProperty: NumberPairsColors.attributeRightAddendColorProperty, tandem: providedOptions.tandem.createTandem( 'equationAccordionBox' ) - } ) + } ), + sceneRange: NumberPairsConstants.TEN_SCENE_RANGE }, providedOptions ); super( model, options ); diff --git a/js/twenty/model/TwentyModel.ts b/js/twenty/model/TwentyModel.ts index 3577fb1..811752e 100644 --- a/js/twenty/model/TwentyModel.ts +++ b/js/twenty/model/TwentyModel.ts @@ -25,8 +25,8 @@ export default class TwentyModel extends NumberPairsModel { public constructor( providedOptions: TwentyModelOptions ) { const options = optionize()( { - initialSumValue: NumberPairsConstants.INTRO_INITIAL_SUM_VALUE, - initialLeftAddendValue: NumberPairsConstants.INTRO_INITIAL_LEFT_ADDEND_VALUE + initialSumValue: NumberPairsConstants.TWENTY_INITIAL_SUM_VALUE, + initialLeftAddendValue: NumberPairsConstants.TWENTY_INITIAL_LEFT_ADDEND_VALUE }, providedOptions ); super( options ); } diff --git a/js/twenty/view/TwentyScreenView.ts b/js/twenty/view/TwentyScreenView.ts index f9af7e7..9746742 100644 --- a/js/twenty/view/TwentyScreenView.ts +++ b/js/twenty/view/TwentyScreenView.ts @@ -16,6 +16,7 @@ import NumberBondAccordionBox from '../../common/view/NumberBondAccordionBox.js' import EquationAccordionBox from '../../common/view/EquationAccordionBox.js'; import PickRequired from '../../../../phet-core/js/types/PickRequired.js'; import NumberPairsColors from '../../common/NumberPairsColors.js'; +import NumberPairsConstants from '../../common/NumberPairsConstants.js'; type SelfOptions = { //TODO add options that are specific to TwentyScreenView here @@ -45,7 +46,8 @@ export default class TwentyScreenView extends NumberPairsScreenView { leftAddendColorProperty: NumberPairsColors.numberLineLeftAddendColorProperty, rightAddendColorProperty: NumberPairsColors.numberLineRightAddendColorProperty, tandem: providedOptions.tandem.createTandem( 'equationAccordionBox' ) - } ) + } ), + sceneRange: NumberPairsConstants.TWENTY_SCENE_RANGE }, providedOptions ); super( model, options );