From fe926f98f82401f945b17f724c7732d296d2e72d Mon Sep 17 00:00:00 2001 From: Tim Kurvers Date: Wed, 8 Oct 2025 23:41:04 +0200 Subject: [PATCH] feat: implement Button enable --- src/ui/components/simple/Button.script.ts | 20 ++++++- src/ui/components/simple/Button.ts | 67 ++++++++++++++++++++++- src/ui/components/simple/Frame.ts | 14 +++++ src/ui/components/simple/FrameFlag.ts | 2 + src/ui/scripting/FrameScriptObject.ts | 36 ++++++++++-- vendor/fengari.d.ts | 4 +- 6 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/ui/components/simple/Button.script.ts b/src/ui/components/simple/Button.script.ts index 7db0385..144fd3d 100644 --- a/src/ui/components/simple/Button.script.ts +++ b/src/ui/components/simple/Button.script.ts @@ -12,11 +12,27 @@ import { import Button from './Button'; -export const Enable = () => { +export const Enable = (L: lua_State) => { + const button = Button.getObjectFromStack(L); + + if (button.protectedFunctionsAllowed) { + button.enable(true); + } else { + // TODO: Disallowed logic + } + return 0; }; -export const Disable = () => { +export const Disable = (L: lua_State) => { + const button = Button.getObjectFromStack(L); + + if (button.protectedFunctionsAllowed) { + button.enable(false); + } else { + // TODO: Disallowed logic + } + return 0; }; diff --git a/src/ui/components/simple/Button.ts b/src/ui/components/simple/Button.ts index fe74ec6..7fb25db 100644 --- a/src/ui/components/simple/Button.ts +++ b/src/ui/components/simple/Button.ts @@ -7,7 +7,7 @@ import { Status } from '../../../utils'; import ButtonState from './ButtonState'; import FontString from './FontString'; -import Frame from './Frame'; +import Frame, { FrameFlag } from './Frame'; import Texture from './Texture'; import * as scriptFunctions from './Button.script'; @@ -28,6 +28,7 @@ class Button extends Frame { fontString: FontString | null; state: ButtonState; + isStateLocked: boolean; constructor(parent: Frame | null) { super(parent); @@ -51,6 +52,11 @@ class Button extends Frame { this.fontString = null; this.state = ButtonState.DISABLED; + this.isStateLocked = false; + + this.enable(true); + // TODO: Enable input events + this.setFrameFlag(FrameFlag.Ox10000, true); } loadXML(node: XMLNode, status: Status) { @@ -93,6 +99,39 @@ class Button extends Frame { // TODO: Text, click registration and motion scripts } + enable(enabled: boolean) { + if (enabled) { + if (this.state !== ButtonState.DISABLED) { + return; + } + + this.setState(ButtonState.NORMAL, false); + + // TODO: Mouse focus + + if (this.isHighlightLocked) { + this.enableDrawLayer(DrawLayerType.HIGHLIGHT); + } + } else { + if (this.state === ButtonState.DISABLED) { + return; + } + + // TODO: Mouse focus + + this.disableDrawLayer(DrawLayerType.HIGHLIGHT); + this.setState(ButtonState.DISABLED, false); + } + + this.setFrameFlag(FrameFlag.Ox400, !enabled); + + const script = enabled ? this.scripts.get('OnEnable') : this.scripts.get('OnDisable'); + + if (script && script.luaRef !== null && !this.loading) { + this.runScript(script); + } + } + setHighlight(texture: Texture | null, _blendMode: BlendMode | null) { if (this.highlightTexture === texture) { return; @@ -110,6 +149,28 @@ class Button extends Frame { this.highlightTexture = texture; } + setState(state: ButtonState, locked: boolean) { + this.isStateLocked = locked; + + if (state == this.state) { + return; + } + + if (this.activeTexture && (this.textures[state] || state == ButtonState.NORMAL)) { + this.activeTexture.hide(); + this.activeTexture = null; + } + + if (this.textures[state]) { + this.activeTexture = this.textures[state]; + this.activeTexture.show(); + } + + this.updateTextState(state); + + this.state = state; + } + setStateTexture(state: ButtonState, texture: Texture | null) { const stored = this.textures[state]; if (stored === texture) { @@ -135,6 +196,10 @@ class Button extends Frame { texture.show(); } } + + updateTextState(_state: ButtonState) { + // TODO + } } export default Button; diff --git a/src/ui/components/simple/Frame.ts b/src/ui/components/simple/Frame.ts index 02e39c0..f9cda22 100644 --- a/src/ui/components/simple/Frame.ts +++ b/src/ui/components/simple/Frame.ts @@ -56,6 +56,8 @@ class Frame extends ScriptRegion { level: number; frameScale: number; + isHighlightLocked: boolean; + layersEnabled: EnumRecord; backdrop: Backdrop | null; @@ -81,6 +83,8 @@ class Frame extends ScriptRegion { this.level = 0; this.frameScale = 1.0; + this.isHighlightLocked = false; + this.layersEnabled = enumRecordFor(DrawLayerType, (type) => type !== DrawLayerType.HIGHLIGHT); this.backdrop = null; @@ -456,6 +460,16 @@ class Frame extends ScriptRegion { } } + disableDrawLayer(drawlayer: DrawLayerType) { + this.layersEnabled[drawlayer] = false; + this.notifyDrawLayerChanged(drawlayer); + } + + enableDrawLayer(drawlayer: DrawLayerType) { + this.layersEnabled[drawlayer] = true; + this.notifyDrawLayerChanged(drawlayer); + } + setBackdrop(backdrop: Backdrop | null) { if (this.backdrop) { // TODO: Destructor diff --git a/src/ui/components/simple/FrameFlag.ts b/src/ui/components/simple/FrameFlag.ts index 6852fa3..bcf66ef 100644 --- a/src/ui/components/simple/FrameFlag.ts +++ b/src/ui/components/simple/FrameFlag.ts @@ -4,5 +4,7 @@ export default { OCCLUDED: 0x10, MOVABLE: 0x100, RESIZABLE: 0x200, + Ox400: 0x400, + Ox10000: 0x10000, DONT_SAVE_POSITION: 0x80000, }; diff --git a/src/ui/scripting/FrameScriptObject.ts b/src/ui/scripting/FrameScriptObject.ts index 36d25d0..2507262 100644 --- a/src/ui/scripting/FrameScriptObject.ts +++ b/src/ui/scripting/FrameScriptObject.ts @@ -9,6 +9,7 @@ import { lua_State, lua_createtable, lua_getglobal, + lua_pushboolean, lua_pushcclosure, lua_pushlightuserdata, lua_pushnumber, @@ -29,6 +30,8 @@ import { This, ThisConstructor } from '../../utils'; const scriptMetaTables = new Map(); const objectTypes = new Map(); +type ScriptArg = string | number | boolean; + class FrameScriptObject { luaRef: lua_Ref | null; scripts: ScriptRegistry; @@ -112,12 +115,37 @@ class FrameScriptObject { return true; } - runScript(name: string, argsCount = 0) { + runScript(script: Script, ...args: ScriptArg[]): void + runScript(name: string, ...args: ScriptArg[]): void + runScript(nameOrScript: string | Script, ...args: ScriptArg[]) { // TODO: This needs to be moved to the caller - const script = this.scripts.get(name); + let script: Script | undefined = nameOrScript as Script; + if (typeof nameOrScript === 'string') { + script = this.scripts.get(nameOrScript); + } + if (script && script.luaRef !== null) { - // TODO: Pass in remaining arguments - ScriptingContext.instance.executeFunction(script.luaRef, this, argsCount); + const scripting = ScriptingContext.instance; + const L = scripting.state; + + const argsCount = args.length; + for (const arg of args) { + switch (typeof arg) { + case 'string': + lua_pushstring(L, arg); + break; + case 'number': + lua_pushnumber(L, arg); + break; + case 'boolean': + lua_pushboolean(L, arg); + break; + default: + throw new Error(`invalid argument ${arg} for script ${name}`); + } + } + + scripting.executeFunction(script.luaRef, this, argsCount); } } diff --git a/vendor/fengari.d.ts b/vendor/fengari.d.ts index cb1a59a..b898a76 100644 --- a/vendor/fengari.d.ts +++ b/vendor/fengari.d.ts @@ -14,7 +14,7 @@ declare module 'fengari' { type lua_String = Uint8Array; type lua_InputString = Uint8Array | string; - type lua_State = unknown + type lua_State = object & { __brand: 'lua_State' } function to_luastring(s: string): lua_String; function to_jsstring(s: lua_String): string; @@ -214,7 +214,7 @@ declare module 'fengari' { } namespace lauxlib { - type luaL_Buffer = unknown + type luaL_Buffer = object & { __brand: 'luaL_Buffer' } function luaL_addchar(B: luaL_Buffer, c: number): void; function luaL_addlstring(B: luaL_Buffer, s: string, l: number): void;