pokerogue/src/ui/modal-ui-handler.ts
NightKev 0107b1d47e
[Refactor] Create global scene variable (#4766)
* Replace various `scene` pass-arounds with global scene variable

* Modify tests

* Add scene back to `fade[in|out]()` calls

Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>

* Fix Bug Superfan ME test

Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>

* Re-enable fixed test

Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>

* Rename `gScene` to `globalScene`

* Move `globalScene` to its own file to fix import/async issues

* Fix `SelectModifierPhase` tests

* Fix ME tests by removing `scene` from `expect()`s

* Resolve merge issues

* Remove tsdocs referencing `scene` params

Remove missed instances of `.scene`

* Remove unnecessary `globalScene` usage in `loading-scene.ts`

* Fix merge conflicts

* Attempt to fix circular import issue

* Found the source of the import issue

* Fix merge issues

---------

Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>
2025-01-12 15:33:05 -08:00

183 lines
5.7 KiB
TypeScript

import { TextStyle, addTextObject } from "./text";
import type { Mode } from "./ui";
import UiHandler from "./ui-handler";
import { WindowVariant, addWindow } from "./ui-theme";
import type { Button } from "#enums/buttons";
import { globalScene } from "#app/global-scene";
export interface ModalConfig {
buttonActions: Function[];
}
export abstract class ModalUiHandler extends UiHandler {
protected modalContainer: Phaser.GameObjects.Container;
protected modalBg: Phaser.GameObjects.NineSlice;
protected titleText: Phaser.GameObjects.Text;
protected buttonContainers: Phaser.GameObjects.Container[];
protected buttonBgs: Phaser.GameObjects.NineSlice[];
protected buttonLabels: Phaser.GameObjects.Text[];
constructor(mode: Mode | null = null) {
super(mode);
this.buttonContainers = [];
this.buttonBgs = [];
this.buttonLabels = [];
}
abstract getModalTitle(config?: ModalConfig): string;
abstract getWidth(config?: ModalConfig): number;
abstract getHeight(config?: ModalConfig): number;
abstract getMargin(config?: ModalConfig): [number, number, number, number];
abstract getButtonLabels(config?: ModalConfig): string[];
getButtonTopMargin(): number {
return 0;
}
setup() {
const ui = this.getUi();
this.modalContainer = globalScene.add.container(0, 0);
this.modalContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width / 6, globalScene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
this.modalBg = addWindow(0, 0, 0, 0);
this.modalContainer.add(this.modalBg);
this.titleText = addTextObject(0, 4, "", TextStyle.SETTINGS_LABEL);
this.titleText.setOrigin(0.5, 0);
this.modalContainer.add(this.titleText);
ui.add(this.modalContainer);
const buttonLabels = this.getButtonLabels();
for (const label of buttonLabels) {
this.addButton(label);
}
this.modalContainer.setVisible(false);
}
private addButton(label: string) {
const buttonTopMargin = this.getButtonTopMargin();
const buttonLabel = addTextObject(0, 8, label, TextStyle.TOOLTIP_CONTENT);
buttonLabel.setOrigin(0.5, 0.5);
const buttonBg = addWindow(0, 0, buttonLabel.getBounds().width + 8, 16, false, false, 0, 0, WindowVariant.THIN);
buttonBg.setOrigin(0.5, 0);
buttonBg.setInteractive(new Phaser.Geom.Rectangle(0, 0, buttonBg.width, buttonBg.height), Phaser.Geom.Rectangle.Contains);
const buttonContainer = globalScene.add.container(0, buttonTopMargin);
this.buttonLabels.push(buttonLabel);
this.buttonBgs.push(buttonBg);
this.buttonContainers.push(buttonContainer);
buttonContainer.add(buttonBg);
buttonContainer.add(buttonLabel);
this.addInteractionHoverEffect(buttonBg);
this.modalContainer.add(buttonContainer);
}
show(args: any[]): boolean {
if (args.length >= 1 && "buttonActions" in args[0]) {
super.show(args);
if (args[0].hasOwnProperty("fadeOut") && typeof args[0].fadeOut === "function") {
const [ marginTop, marginRight, marginBottom, marginLeft ] = this.getMargin();
const overlay = globalScene.add.rectangle(( this.getWidth() + marginLeft + marginRight) / 2, (this.getHeight() + marginTop + marginBottom) / 2, globalScene.game.canvas.width / 6, globalScene.game.canvas.height / 6, 0);
overlay.setOrigin(0.5, 0.5);
overlay.setName("rect-ui-overlay-modal");
overlay.setAlpha(0);
this.modalContainer.add(overlay);
this.modalContainer.moveTo(overlay, 0);
globalScene.tweens.add({
targets: overlay,
alpha: 1,
duration: 250,
ease: "Sine.easeOut",
onComplete: args[0].fadeOut
});
}
const config = args[0] as ModalConfig;
this.updateContainer(config);
this.modalContainer.setVisible(true);
this.getUi().moveTo(this.modalContainer, this.getUi().length - 1);
for (let a = 0; a < this.buttonBgs.length; a++) {
if (a < this.buttonBgs.length) {
this.buttonBgs[a].on("pointerdown", (_) => config.buttonActions[a]());
}
}
return true;
}
return false;
}
updateContainer(config?: ModalConfig): void {
const [ marginTop, marginRight, marginBottom, marginLeft ] = this.getMargin(config);
const [ width, height ] = [ this.getWidth(config), this.getHeight(config) ];
this.modalContainer.setPosition((((globalScene.game.canvas.width / 6) - (width + (marginRight - marginLeft))) / 2), (((-globalScene.game.canvas.height / 6) - (height + (marginBottom - marginTop))) / 2));
this.modalBg.setSize(width, height);
const title = this.getModalTitle(config);
this.titleText.setText(title);
this.titleText.setX(width / 2);
this.titleText.setVisible(!!title);
for (let b = 0; b < this.buttonContainers.length; b++) {
const sliceWidth = width / (this.buttonContainers.length + 1);
this.buttonContainers[b].setPosition(sliceWidth * (b + 1), this.modalBg.height - (this.buttonBgs[b].height + 8));
}
}
processInput(button: Button): boolean {
return false;
}
clear() {
super.clear();
this.modalContainer.setVisible(false);
this.buttonBgs.map(bg => bg.off("pointerdown"));
}
/**
* Adds a hover effect to a game object which changes the cursor to a `pointer` and tints it slighly
* @param gameObject the game object to add hover events/effects to
*/
protected addInteractionHoverEffect(gameObject: Phaser.GameObjects.Image | Phaser.GameObjects.NineSlice | Phaser.GameObjects.Sprite) {
gameObject.on("pointerover", () => {
this.setMouseCursorStyle("pointer");
gameObject.setTint(0xbbbbbb);
});
gameObject.on("pointerout", () => {
this.setMouseCursorStyle("default");
gameObject.clearTint();
});
}
}