diff --git a/js/buttons/ButtonNode.ts b/js/buttons/ButtonNode.ts index e43efa37..90582f32 100644 --- a/js/buttons/ButtonNode.ts +++ b/js/buttons/ButtonNode.ts @@ -93,6 +93,7 @@ export default class ButtonNode extends Sizable( Voicing( Node ) ) { private readonly _pressListener: PressListener; private readonly disposeButtonNode: () => void; protected readonly content: Node | null; + public readonly contentContainer: Node | null = null; // (sun-only) protected readonly layoutSizeProperty: TinyProperty = new TinyProperty( new Dimension2( 0, 0 ) ); // The maximum lineWidth our buttonBackground can have. We'll lay things out so that if we adjust our lineWidth below @@ -205,14 +206,19 @@ export default class ButtonNode extends Sizable( Voicing( Node ) ) { let updateAlignBounds: UnknownMultilink | null = null; if ( options.content ) { - const content = options.content; - - // For performance, in case content is a complicated icon or shape. - // See https://github.com/phetsims/sun/issues/654#issuecomment-718944669 - content.pickable = false; + // Container here that can get scaled/positioned/pickable-modified, without affecting the provided content. + this.contentContainer = new Node( { + children: [ + options.content + ], + + // For performance, in case content is a complicated icon or shape. + // See https://github.com/phetsims/sun/issues/654#issuecomment-718944669 + pickable: false + } ); // Align content in the button rectangle. Must be disposed since it adds listener to content bounds. - alignBox = new AlignBox( content, { + alignBox = new AlignBox( this.contentContainer, { xAlign: options.xAlign, yAlign: options.yAlign, diff --git a/js/buttons/RectangularButton.ts b/js/buttons/RectangularButton.ts index c164aad3..d60c3968 100644 --- a/js/buttons/RectangularButton.ts +++ b/js/buttons/RectangularButton.ts @@ -147,19 +147,6 @@ export default class RectangularButton extends ButtonNode { super( buttonModel, buttonBackground, interactionStateProperty, options ); - // TODO: get this to work dynamically? Or do we always want things scaled down? - if ( options.size && options.content ) { - const previousContent = options.content; - const minScale = Math.min( - ( options.size.width - options.xMargin * 2 ) / previousContent.width, - ( options.size.height - options.yMargin * 2 ) / previousContent.height ); - - options.content = new Node( { - children: [ previousContent ], - scale: minScale - } ); - } - this.buttonNodeConstraint = new RectangularButtonNodeConstraint( this, this.layoutSizeProperty, { content: options.content ?? null, size: options.size, @@ -498,14 +485,19 @@ class RectangularButtonNodeConstraint extends LayoutConstraint { const contentWidthSizable = !!content && isWidthSizable( content ); const contentHeightSizable = !!content && isHeightSizable( content ); - let contentMinimumWidthWithMargins = Math.max( this.minWidth, content ? ( contentWidthSizable ? content.minimumWidth ?? 0 : content.width ) + this.xMargin * 2 : 0 ); - let contentMinimumHeightWithMargins = Math.max( this.minHeight, content ? ( contentHeightSizable ? content.minimumHeight ?? 0 : content.height ) + this.yMargin * 2 : 0 ); + let contentMinimumWidthWithMargins = content ? ( contentWidthSizable ? content.minimumWidth ?? 0 : content.width ) + this.xMargin * 2 : 0; + let contentMinimumHeightWithMargins = content ? ( contentHeightSizable ? content.minimumHeight ?? 0 : content.height ) + this.yMargin * 2 : 0; + // If a initial (minimum) size is specified, use this as an override (and we will scale the content down to fit) if ( this.size ) { - contentMinimumWidthWithMargins = Math.max( contentMinimumWidthWithMargins, this.size.width ); - contentMinimumHeightWithMargins = Math.max( contentMinimumHeightWithMargins, this.size.height ); + contentMinimumWidthWithMargins = this.size.width; + contentMinimumHeightWithMargins = this.size.height; } + // Apply minWidth/minHeight + contentMinimumWidthWithMargins = Math.max( this.minWidth, contentMinimumWidthWithMargins ); + contentMinimumHeightWithMargins = Math.max( this.minHeight, contentMinimumHeightWithMargins ); + // Only allow an initial update if we are not sizable in that dimension let minimumWidth = ( this.isFirstLayout || widthSizable ) @@ -550,6 +542,27 @@ class RectangularButtonNodeConstraint extends LayoutConstraint { .shiftedXY( this.mouseAreaXShift, this.mouseAreaYShift ); } + const preferredContentWidth = this.lastLocalWidth - this.xMargin * 2; + const preferredContentHeight = this.lastLocalHeight - this.yMargin * 2; + + assert && assert( preferredContentWidth > 0 ); + assert && assert( preferredContentHeight > 0 ); + + if ( this.content ) { + if ( contentWidthSizable ) { + content.preferredWidth = Math.max( preferredContentWidth, content.minimumWidth ?? 0 ); + } + if ( contentHeightSizable ) { + content.preferredHeight = Math.max( preferredContentHeight, content.minimumHeight ?? 0 ); + } + + const contentContainer = this.buttonNode.contentContainer!; + assert && assert( contentContainer ); + + contentContainer.maxWidth = preferredContentWidth; + contentContainer.maxHeight = preferredContentHeight; + } + this.isFirstLayout = false; this.layoutSizeProperty.value = new Dimension2( this.lastLocalWidth, this.lastLocalHeight );