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 NumberPlayAccordionBox base type #143

Closed
chrisklus opened this issue Feb 6, 2022 · 2 comments
Closed

Add NumberPlayAccordionBox base type #143

chrisklus opened this issue Feb 6, 2022 · 2 comments
Assignees

Comments

@chrisklus
Copy link
Contributor

For adapting and factoring out the content/size management strategy used by CountingAccordionBox over in #121 and supporting work for TotalAccordionBoxes needed in #131.

@chrisklus chrisklus self-assigned this Feb 6, 2022
@chrisklus
Copy link
Contributor Author

chrisklus commented Feb 8, 2022

Patch from in progress work:

Index: js/common/view/NumberPlayAccordionBox.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/common/view/NumberPlayAccordionBox.ts b/js/common/view/NumberPlayAccordionBox.ts
new file mode 100644
--- /dev/null	(date 1644137074425)
+++ b/js/common/view/NumberPlayAccordionBox.ts	(date 1644137074425)
@@ -0,0 +1,123 @@
+// Copyright 2019-2022, University of Colorado Boulder
+
+/**
+ * Base class for all Number Play accordion boxes.
+ *
+ * @author Chris Klusendorf (PhET Interactive Simulations)
+ */
+
+import EnumerationProperty from '../../../../axon/js/EnumerationProperty.js';
+import CountingCommonConstants from '../../../../counting-common/js/common/CountingCommonConstants.js';
+import CountingObjectType from '../../../../counting-common/js/common/model/CountingObjectType.js';
+import Bounds2 from '../../../../dot/js/Bounds2.js';
+import Dimension2 from '../../../../dot/js/Dimension2.js';
+import merge from '../../../../phet-core/js/merge.js';
+import { Color, Image, Node, Rectangle, Text } from '../../../../scenery/js/imports.js';
+import AccordionBox from '../../../../sun/js/AccordionBox.js';
+import RectangularRadioButtonGroup from '../../../../sun/js/buttons/RectangularRadioButtonGroup.js';
+import numberPlay from '../../numberPlay.js';
+import numberPlayStrings from '../../numberPlayStrings.js';
+import NumberPlayConstants, { AccordionBoxOptions } from '../NumberPlayConstants.js';
+import OnesPlayAreaNode from './OnesPlayAreaNode.js';
+import OnesPlayArea from '../model/OnesPlayArea.js';
+import BaseNumberNode from '../../../../counting-common/js/common/view/BaseNumberNode.js';
+import BaseNumber from '../../../../counting-common/js/common/model/BaseNumber.js';
+import GroupAndLinkType from '../model/GroupAndLinkType.js';
+
+// constants
+const RADIO_BUTTON_SIZE = new Dimension2( 28, 28 ); // in screen coordinates
+const CONTENT_OVERFLOW_LEFT = 30; // amount of "inaccessible" space in an AccordionBox, in screen coordinates
+const CONTENT_OVERFLOW_RIGHT = 10; // amount of "inaccessible" space in an AccordionBox, in screen coordinates
+
+class NumberPlayAccordionBox extends AccordionBox {
+
+  constructor( width: number, height: number, providedOptions: any ) {
+
+    const contentNode = new Rectangle( {
+      rectWidth: width,
+      rectHeight: height
+    } );
+
+    const playAreaContentBounds = new Bounds2(
+      contentNode.left,
+      contentNode.top,
+      contentNode.right,
+      contentNode.bottom
+    );
+
+    // set the local bounds so they don't change
+    contentNode.localBounds = playAreaContentBounds;
+
+    // compensate for AccordionBox not giving access to all horizontal space
+    const playAreaViewBounds = playAreaContentBounds.withOffsets( CONTENT_OVERFLOW_LEFT, 0, CONTENT_OVERFLOW_RIGHT, 0 );
+
+    const objectsPlayAreaNode = new OnesPlayAreaNode( playArea, countingObjectTypeProperty, playAreaViewBounds );
+    contentNode.addChild( objectsPlayAreaNode );
+
+    // TODO-TS: use specific RadioButtonGroup type
+    let radioButtonGroup: Node | null = null;
+    if ( options.countingObjectTypes ) {
+
+      // create the icons for the RectangularRadioButtonGroup
+      // @ts-ignore
+      const buttons = [];
+      options.countingObjectTypes.forEach( countingObjectType => {
+        let iconNode = null;
+        if ( countingObjectType === CountingObjectType.PAPER_NUMBER ) {
+          iconNode = new BaseNumberNode( new BaseNumber( 1, 0 ), 1 );
+          iconNode.setScaleMagnitude( RADIO_BUTTON_SIZE.height / iconNode.height );
+        }
+        else {
+          iconNode = new Image( CountingCommonConstants.COUNTING_OBJECT_TYPE_TO_IMAGE.get( countingObjectType ), {
+            maxWidth: RADIO_BUTTON_SIZE.width,
+            maxHeight: RADIO_BUTTON_SIZE.height
+          } );
+        }
+
+        buttons.push( {
+          value: countingObjectType,
+          node: iconNode
+        } );
+      } );
+
+      // create and add the RectangularRadioButtonGroup, which is a control for changing the CountingObjectType of the playObjects
+      // @ts-ignore
+      radioButtonGroup = new RectangularRadioButtonGroup( countingObjectTypeProperty, buttons, {
+        baseColor: Color.WHITE,
+        orientation: 'horizontal',
+        spacing: 10
+      } );
+      radioButtonGroup.right = playAreaViewBounds.right - CountingCommonConstants.COUNTING_PLAY_AREA_MARGIN;
+      radioButtonGroup.bottom = playAreaViewBounds.bottom - CountingCommonConstants.COUNTING_PLAY_AREA_MARGIN;
+      contentNode.addChild( radioButtonGroup );
+    }
+
+    // add the linked play area
+    if ( options.linkedPlayArea && options.groupAndLinkTypeProperty ) {
+      const linkedObjectsPlayAreaNode = new OnesPlayAreaNode(
+        options.linkedPlayArea,
+        countingObjectTypeProperty,
+        playAreaViewBounds, {
+          viewHasIndependentModel: false
+        }
+      );
+      contentNode.addChild( linkedObjectsPlayAreaNode );
+
+      options.groupAndLinkTypeProperty.link( groupAndLinkType => {
+        objectsPlayAreaNode.visible = !( groupAndLinkType === GroupAndLinkType.GROUPED_AND_LINKED );
+        linkedObjectsPlayAreaNode.visible = groupAndLinkType === GroupAndLinkType.GROUPED_AND_LINKED;
+        radioButtonGroup && radioButtonGroup.moveToFront();
+      } );
+    }
+
+    super( contentNode, merge( {
+      titleNode: new Text( options.titleString, {
+        font: NumberPlayConstants.ACCORDION_BOX_TITLE_FONT,
+        maxWidth: NumberPlayConstants.LOWER_ACCORDION_BOX_TITLE_MAX_WIDTH
+      } )
+    }, options ) );
+  }
+}
+
+numberPlay.register( 'NumberPlayAccordionBox', NumberPlayAccordionBox );
+export default NumberPlayAccordionBox;
\ No newline at end of file

chrisklus added a commit that referenced this issue Feb 9, 2022
…x to extend NumberPlayAccordionBox on Ten+Twenty screens, improve their content sizing and spacing, see #143
@chrisklus
Copy link
Contributor Author

chrisklus commented Feb 9, 2022

This issue is complete. There is some work left for getting the options pattern working all correctly for this type structure, but that feels outside of scope for what I was trying to accomplish here. However, I was able to improve the existing options patterns in the process. #131 is now unblocked, closing.

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

No branches or pull requests

1 participant