Skip to content

Commit

Permalink
Add Content Fitting Mode Option on Fancy Button (#202)
Browse files Browse the repository at this point in the history
* Add Content Fitting Mode Option on Fancy Button

* Example lint fixes

---------

Co-authored-by: Dmytro Soldatov <[email protected]>
  • Loading branch information
bbazukun123 and CyberDex authored Nov 27, 2024
1 parent f0c3a99 commit 9ce9e96
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 8 deletions.
80 changes: 73 additions & 7 deletions src/FancyButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ type ViewsInput = BasicViewsInput & {
icon?: GetViewSettings;
};

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;
Expand All @@ -74,6 +82,9 @@ export type ButtonOptions = ViewsInput & {
defaultIconAnchor?: Pos | number;
animations?: StateAnimations;
nineSliceSprite?: [number, number, number, number];
contentFittingMode?: ContentFittingMode;

/** @deprecated refer to contentFittingMode instead */
ignoreRefitting?: boolean;
};

Expand Down Expand Up @@ -401,13 +412,34 @@ export class FancyButton extends ButtonContainer {

if (activeView) {
if (!this.options?.ignoreRefitting) {
if (activeView)
{
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.x = activeView.x + activeView.width / 2;
this._views.textView.y = activeView.y + activeView.height / 2;
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);
}

this._views.textView.anchor.set(anchorX, anchorY);
Expand All @@ -430,15 +462,34 @@ 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);

fitToView(activeView, this._views.iconView, this.padding, false);
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);

if ('anchor' in this._views.iconView) {
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)
{
(this._views.iconView.anchor as ObservablePoint).set(anchorX, anchorY);
} else {
this._views.iconView.pivot.set(
Expand Down Expand Up @@ -490,6 +541,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof args> = (
export const UseNineSliceSprite: StoryFn<typeof args & { contentFittingMode: 'default' | 'fill' | 'none' }> = (
{
text,
textColor,
Expand All @@ -45,6 +46,7 @@ export const UseNineSliceSprite: StoryFn<typeof args> = (
defaultTextAnchorY,
defaultIconAnchorX,
defaultIconAnchorY,
contentFittingMode,
},
context,
) =>
Expand Down Expand Up @@ -104,6 +106,7 @@ export const UseNineSliceSprite: StoryFn<typeof args> = (
duration: animationDuration,
},
},
contentFittingMode,
});

button.iconView = new MaskedFrame({
Expand Down

0 comments on commit 9ce9e96

Please sign in to comment.