From bacd7878ce4df034634e2081aa9c2fd552b1802f Mon Sep 17 00:00:00 2001 From: Baz Utsahajit Date: Mon, 28 Oct 2024 15:33:28 +0000 Subject: [PATCH] Add Content Fitting Mode Option on Fancy Button --- src/FancyButton.ts | 70 +++++++++++++++++-- .../FancyButtonNineSliceSprite.stories.ts | 5 +- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/FancyButton.ts b/src/FancyButton.ts index 04177aa..a5817d9 100644 --- a/src/FancyButton.ts +++ b/src/FancyButton.ts @@ -53,6 +53,14 @@ type ViewsInput = BasicViewsInput & { icon?: ButtonView; }; +type ContentFittingMode = + // Fits the text/icon content inside the button. + | 'default' + // Fill the button with the text/icon content, scaling it up to fill the view space with padding accounted for. + | 'fill' + // Only apply the default scaling and anchoring, without constraining to the button view's dimensions. + | 'none'; + export type ButtonOptions = ViewsInput & { padding?: number; scale?: number; @@ -68,6 +76,9 @@ export type ButtonOptions = ViewsInput & { defaultIconAnchor?: Pos | number; animations?: StateAnimations; nineSliceSprite?: [number, number, number, number]; + contentFittingMode?: ContentFittingMode; + + /** @deprecated refer to contentFittingMode instead */ ignoreRefitting?: boolean; }; @@ -413,12 +424,29 @@ export class FancyButton extends ButtonContainer if (activeView) { - if (!this.options?.ignoreRefitting) + if (!this.options.ignoreRefitting) { this._views.textView.scale.set(this._defaultTextScale.x, this._defaultTextScale.y); } - fitToView(activeView, this._views.textView, this.padding, false); + if (this.contentFittingMode === 'default') + { + fitToView(activeView, this._views.textView, this.padding, false); + } + + if (this.contentFittingMode === 'fill') + { + // reset to base dimensions for calculations + this._views.textView.scale.set(1); + + const availableWidth = activeView.width - (this.padding * 2); + const availableHeight = activeView.height - (this.padding * 2); + const targetScaleX = availableWidth / this._views.textView.width; + const targetScaleY = availableHeight / this._views.textView.height; + const scale = Math.min(targetScaleX, targetScaleY); + + this._views.textView.scale.set(scale * this._defaultTextScale.x, scale * this._defaultTextScale.y); + } this._views.textView.x = activeView.x + (activeView.width / 2); this._views.textView.y = activeView.y + (activeView.height / 2); @@ -447,14 +475,31 @@ export class FancyButton extends ButtonContainer return; } - if (!this.options?.ignoreRefitting) + if (!this.options.ignoreRefitting) { this._views.iconView.scale.set(this._defaultIconScale.x, this._defaultIconScale.y); } - const { x: anchorX, y: anchorY } = this._defaultIconAnchor; + if (this.contentFittingMode === 'default') + { + fitToView(activeView, this._views.iconView, this.padding, false); + } + + if (this.contentFittingMode === 'fill') + { + // reset to base dimensions for calculations + this._views.iconView.scale.set(1); + + const availableWidth = activeView.width - (this.padding * 2); + const availableHeight = activeView.height - (this.padding * 2); + const targetScaleX = availableWidth / this._views.iconView.width; + const targetScaleY = availableHeight / this._views.iconView.height; + const scale = Math.min(targetScaleX, targetScaleY); - fitToView(activeView, this._views.iconView, this.padding, false); + this._views.iconView.scale.set(scale * this._defaultIconScale.x, scale * this._defaultIconScale.y); + } + + const { x: anchorX, y: anchorY } = this._defaultIconAnchor; if ('anchor' in this._views.iconView) { @@ -509,6 +554,21 @@ export class FancyButton extends ButtonContainer this.adjustTextView(this.state); } + /** + * Sets the fitting mode for the button's content. + * @param {ContentFittingMode} mode - fitting mode type. + */ + set contentFittingMode(mode: ContentFittingMode) + { + this.options.contentFittingMode = mode; + } + + /** Returns the fitting mode for the button's content, defaulting to 'default'. */ + get contentFittingMode(): ContentFittingMode + { + return this.options.contentFittingMode ?? 'default'; + } + /** * Sets the default view of the button. * @param { string | Container } view - string (path to the image) or a Container-based view diff --git a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts index 7f16343..cb752e0 100644 --- a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts +++ b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts @@ -24,10 +24,11 @@ const args = { anchorY: 0.5, animationDuration: 100, disabled: false, + contentFittingMode: ["default", "fill", "none"], onPress: action("button was pressed! (tap or click!)"), }; -export const UseNineSliceSprite: StoryFn = ( +export const UseNineSliceSprite: StoryFn = ( { text, textColor, @@ -45,6 +46,7 @@ export const UseNineSliceSprite: StoryFn = ( defaultTextAnchorY, defaultIconAnchorX, defaultIconAnchorY, + contentFittingMode, }, context, ) => @@ -98,6 +100,7 @@ export const UseNineSliceSprite: StoryFn = ( duration: animationDuration, }, }, + contentFittingMode, }); button.iconView = new MaskedFrame({