diff --git a/src/FancyButton.ts b/src/FancyButton.ts index 26ba63b8..da998dc4 100644 --- a/src/FancyButton.ts +++ b/src/FancyButton.ts @@ -61,8 +61,11 @@ export type ButtonOptions = ViewsInput & { offset?: Offset; textOffset?: Offset; iconOffset?: Offset; + defaultTextScale?: Pos | number; + defaultIconScale?: Pos | number; animations?: StateAnimations; nineSliceSprite?: [number, number, number, number]; + ignoreRefitting?: boolean; }; /** @@ -135,6 +138,12 @@ export class FancyButton extends ButtonContainer /** Anchor point of the button. */ anchor: ObservablePoint; + /** Base text scaling to take into account when fitting inside the button */ + protected _defaultTextScale: Pos = { x: 1, y: 1 }; + + /** Base icon scaling to take into account when fitting inside the button */ + protected _defaultIconScale: Pos = { x: 1, y: 1 }; + /** * Creates a button with a lot of tweaks. * @param {object} options - Button options. @@ -151,6 +160,8 @@ export class FancyButton extends ButtonContainer * @param {Point} options.iconOffset - Offset of the icon view. * @param {number} options.scale - Scale of the button. Scale will be applied to a main container, * when all animations scales will be applied to the inner view. + * @param {number} options.defaultTextScale - Base text scaling to take into account when fitting inside the button. + * @param {number} options.defaultIconScale - Base icon scaling to take into account when fitting inside the button. * @param {number} options.anchor - Anchor point of the button. * @param {number} options.anchorX - Horizontal anchor point of the button. * @param {number} options.anchorY - Vertical anchor point of the button. @@ -160,7 +171,7 @@ export class FancyButton extends ButtonContainer { super(); - this.options = options; + this.options = options ?? {}; const { defaultView, @@ -172,6 +183,8 @@ export class FancyButton extends ButtonContainer offset, textOffset, iconOffset, + defaultTextScale: textScale, + defaultIconScale: iconScale, scale, anchor, anchorX, @@ -191,6 +204,8 @@ export class FancyButton extends ButtonContainer this.offset = offset; this.textOffset = textOffset; this.iconOffset = iconOffset; + this.defaultTextScale = textScale; + this.defaultIconScale = iconScale; this.scale.set(scale ?? 1); if (animations) @@ -299,6 +314,15 @@ export class FancyButton extends ButtonContainer protected createTextView(text: AnyText) { this._views.textView = getTextView(text); + + // If text scale has not manually been set, we will overwrite the base scale with the new text view scale. + if (this.options?.defaultTextScale === undefined) + { + const { x, y } = this._views.textView.scale; + + this._defaultTextScale = { x, y }; + } + this._views.textView.anchor.set(0); this.innerView.addChild(this._views.textView); @@ -374,7 +398,12 @@ export class FancyButton extends ButtonContainer if (activeView) { - fitToView(activeView, this._views.textView, this.padding); + if (!this.options?.ignoreRefitting) + { + this._views.textView.scale.set(this._defaultTextScale.x, this._defaultTextScale.y); + } + + fitToView(activeView, this._views.textView, this.padding, false); this._views.textView.x = activeView.x + (activeView.width / 2); this._views.textView.y = activeView.y + (activeView.height / 2); @@ -403,7 +432,12 @@ export class FancyButton extends ButtonContainer return; } - fitToView(activeView, this._views.iconView, this.padding); + if (!this.options?.ignoreRefitting) + { + this._views.iconView.scale.set(this._defaultIconScale.x, this._defaultIconScale.y); + } + + fitToView(activeView, this._views.iconView, this.padding, false); (this._views.iconView as Sprite).anchor?.set(0); @@ -634,6 +668,14 @@ export class FancyButton extends ButtonContainer this._views.iconView = getView(view); + // If icon scale has not manually been set, we will overwrite the base scale with the new icon view scale. + if (this.options?.defaultIconScale === undefined) + { + const { x, y } = this._views.iconView.scale; + + this._defaultIconScale = { x, y }; + } + if (!this._views.iconView.parent) { this.innerView.addChild(this._views.iconView); @@ -802,6 +844,50 @@ export class FancyButton extends ButtonContainer return this._textOffset; } + /** + * Sets the base scale for the text view to take into account when fitting inside the button. + * @param {Pos | number} scale - base scale of the text view. + */ + set defaultTextScale(scale: Pos | number) + { + if (scale === undefined) return; + // Apply to the options so that the manual scale is prioritized. + this.options.defaultTextScale = scale; + const isNumber = typeof scale === 'number'; + + this._defaultTextScale.x = isNumber ? scale : scale.x ?? 1; + this._defaultTextScale.y = isNumber ? scale : scale.y ?? 1; + this.adjustTextView(this.state); + } + + /** Returns the text view base scale. */ + get defaultTextScale(): Pos + { + return this.defaultTextScale; + } + + /** + * Sets the base scale for the icon view to take into account when fitting inside the button. + * @param {Pos | number} scale - base scale of the icon view. + */ + set defaultIconScale(scale: Pos | number) + { + if (scale === undefined) return; + // Apply to the options so that the manual scale is prioritized. + this.options.defaultIconScale = scale; + const isNumber = typeof scale === 'number'; + + this._defaultIconScale.x = isNumber ? scale : scale.x ?? 1; + this._defaultIconScale.y = isNumber ? scale : scale.y ?? 1; + this.adjustIconView(this.state); + } + + /** Returns the icon view base scale. */ + get defaultIconScale(): Pos + { + return this.defaultIconScale; + } + /** * Sets width of a FancyButtons state views. * If nineSliceSprite is set, then width will be set to nineSliceSprites of a views. diff --git a/src/stories/fancyButton/FancyButtonBitmapText.stories.ts b/src/stories/fancyButton/FancyButtonBitmapText.stories.ts index 60c7a089..9674bee4 100644 --- a/src/stories/fancyButton/FancyButtonBitmapText.stories.ts +++ b/src/stories/fancyButton/FancyButtonBitmapText.stories.ts @@ -13,6 +13,7 @@ const args = { padding: 11, textOffsetX: 0, textOffsetY: -7, + defaultTextScale: 0.99, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -21,7 +22,19 @@ const args = { }; export const UsingSpriteAndBitmapText: StoryFn = ( - { text, textColor, disabled, onPress, padding, textOffsetX, textOffsetY, anchorX, anchorY, animationDuration }, + { + text, + textColor, + disabled, + onPress, + padding, + textOffsetX, + textOffsetY, + defaultTextScale, + anchorX, + anchorY, + animationDuration + }, context ) => new PixiStory({ @@ -60,6 +73,7 @@ export const UsingSpriteAndBitmapText: StoryFn = ( text: title, padding, textOffset: { x: textOffsetX, y: textOffsetY }, + defaultTextScale, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts b/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts index d4428670..fea13287 100644 --- a/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts +++ b/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts @@ -11,6 +11,8 @@ import { action } from '@storybook/addon-actions'; const args = { text: 'Click me!', textColor: '#FFFFFF', + defaultTextScale: 0.99, + defaultIconScale: 0.2, padding: 11, anchorX: 0.5, anchorY: 0.5, @@ -21,6 +23,8 @@ const args = { export const DynamicUpdate: StoryFn = ({ text, textColor, + defaultTextScale, + defaultIconScale, disabled, onPress, padding, @@ -45,7 +49,7 @@ export const DynamicUpdate: StoryFn = ({ let icon = avatars[0]; button.iconView = Sprite.from(icon); - button.iconView.scale.set(0.2); + button.defaultIconScale = defaultIconScale; button.iconOffset = { x: -100, y: -7 }; button.textView = new Text({ @@ -54,6 +58,7 @@ export const DynamicUpdate: StoryFn = ({ fill: textColor || defaultTextStyle.fill } }); + button.defaultTextScale = defaultTextScale; button.textOffset = { x: 30, y: -7 }; button.padding = padding; diff --git a/src/stories/fancyButton/FancyButtonGraphics.stories.ts b/src/stories/fancyButton/FancyButtonGraphics.stories.ts index 31854828..8b67596b 100644 --- a/src/stories/fancyButton/FancyButtonGraphics.stories.ts +++ b/src/stories/fancyButton/FancyButtonGraphics.stories.ts @@ -24,6 +24,8 @@ const args = { iconOffsetY: -30, textOffsetX: 0, textOffsetY: 140, + defaultTextScale: 0.99, + defaultIconScale: 0.99, defaultOffsetY: 0, hoverOffsetY: -1, pressedOffsetY: 5, @@ -53,6 +55,8 @@ export const UseGraphics: StoryFn = ({ iconOffsetY, textOffsetX, textOffsetY, + defaultTextScale, + defaultIconScale, defaultOffsetY, hoverOffsetY, pressedOffsetY, @@ -107,6 +111,8 @@ export const UseGraphics: StoryFn = ({ x: iconOffsetX, y: iconOffsetY }, + defaultTextScale, + defaultIconScale, animations: { default: { props: { diff --git a/src/stories/fancyButton/FancyButtonHTMLText.stories.ts b/src/stories/fancyButton/FancyButtonHTMLText.stories.ts index 3a056217..b6674f3b 100644 --- a/src/stories/fancyButton/FancyButtonHTMLText.stories.ts +++ b/src/stories/fancyButton/FancyButtonHTMLText.stories.ts @@ -13,6 +13,7 @@ const args = { padding: 11, textOffsetX: 0, textOffsetY: -7, + defaultTextScale: 0.99, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -21,7 +22,19 @@ const args = { }; export const UsingSpriteAndHTMLText: StoryFn = ( - { text, textColor, disabled, onPress, padding, textOffsetX, textOffsetY, anchorX, anchorY, animationDuration }, + { + text, + textColor, + disabled, + onPress, + padding, + textOffsetX, + textOffsetY, + defaultTextScale, + anchorX, + anchorY, + animationDuration + }, context, ) => new PixiStory({ @@ -54,6 +67,7 @@ export const UsingSpriteAndHTMLText: StoryFn = ( text: title, padding, textOffset: { x: textOffsetX, y: textOffsetY }, + defaultTextScale, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonIcon.stories.ts b/src/stories/fancyButton/FancyButtonIcon.stories.ts index d8f073ca..5c175a10 100644 --- a/src/stories/fancyButton/FancyButtonIcon.stories.ts +++ b/src/stories/fancyButton/FancyButtonIcon.stories.ts @@ -18,6 +18,7 @@ const args = { radius: 200, iconOffsetX: 0, iconOffsetY: 0, + defaultIconScale: 0.99, defaultOffset: 0, hoverOffset: -1, pressedOffset: 5, @@ -41,6 +42,7 @@ export const UseIcon: StoryFn = ({ padding, iconOffsetX, iconOffsetY, + defaultIconScale, defaultOffset, hoverOffset, pressedOffset, @@ -83,6 +85,7 @@ export const UseIcon: StoryFn = ({ x: iconOffsetX, y: iconOffsetY }, + defaultIconScale, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts index b4cf3f0d..362158e2 100644 --- a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts +++ b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts @@ -14,6 +14,8 @@ const args = { padding: 11, width: 300, height: 137, + defaultTextScale: 0.99, + defaultIconScale: 0.2, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -31,7 +33,9 @@ export const UseNineSliceSprite: StoryFn = ({ anchorY, animationDuration, width, - height + height, + defaultTextScale, + defaultIconScale, }, context) => new PixiStory({ context, @@ -65,6 +69,7 @@ export const UseNineSliceSprite: StoryFn = ({ }), padding, textOffset: { x: 30, y: -5 }, + defaultTextScale, animations: { hover: { props: { @@ -89,7 +94,7 @@ export const UseNineSliceSprite: StoryFn = ({ borderWidth: 10, borderColor: 0xFFFFFF }); - button.iconView.scale.set(0.2); + button.defaultIconScale = defaultIconScale; button.iconOffset = { x: -100, y: -7 }; button.anchor.set(anchorX, anchorY); diff --git a/src/stories/fancyButton/FancyButtonSprite.stories.ts b/src/stories/fancyButton/FancyButtonSprite.stories.ts index c75b9078..8cf14399 100644 --- a/src/stories/fancyButton/FancyButtonSprite.stories.ts +++ b/src/stories/fancyButton/FancyButtonSprite.stories.ts @@ -13,6 +13,7 @@ const args = { padding: 11, textOffsetX: 0, textOffsetY: -7, + defaultTextScale: 0.99, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -28,6 +29,7 @@ export const UseSprite: StoryFn = ({ padding, textOffsetX, textOffsetY, + defaultTextScale, anchorX, anchorY, animationDuration @@ -54,6 +56,7 @@ export const UseSprite: StoryFn = ({ }), padding, textOffset: { x: textOffsetX, y: textOffsetY }, + defaultTextScale, animations: { hover: { props: { diff --git a/src/utils/helpers/fit.ts b/src/utils/helpers/fit.ts index 56ec0d80..6574dccf 100644 --- a/src/utils/helpers/fit.ts +++ b/src/utils/helpers/fit.ts @@ -1,6 +1,6 @@ import { Container } from 'pixi.js'; -export function fitToView(parent: Container, child: Container, padding = 0) +export function fitToView(parent: Container, child: Container, padding = 0, uniformScaling = true) { let scaleX = child.scale.x; let scaleY = child.scale.y; @@ -18,18 +18,38 @@ export function fitToView(parent: Container, child: Container, padding = 0) if (widthOverflow < 0) { - scaleX = maxWidth / (child.width * scaleX); + scaleX = maxWidth / (child.width / scaleX); } if (heightOverflow < 0) { - scaleY = maxHeight / (child.height * scaleY); + scaleY = maxHeight / (child.height / scaleY); } if (scaleX <= 0 || scaleY <= 0) { - child.visible = false; + child.scale.set(0); + + return; } - child.scale.set(Math.min(scaleX, scaleY)); + if (uniformScaling || child.scale.x === child.scale.y) + { + const scale = Math.min(scaleX, scaleY); + + child.scale.set(scale, scale); + } + else + { + const ratio = child.scale.x / child.scale.y; + + if (widthOverflow < heightOverflow) + { + child.scale.set(scaleX, scaleX / ratio); + } + else + { + child.scale.set(scaleY * ratio, scaleY); + } + } }