diff --git a/src/ui/Frame.ts b/src/ui/Frame.ts index 54863a77a..3913218b2 100644 --- a/src/ui/Frame.ts +++ b/src/ui/Frame.ts @@ -27,7 +27,7 @@ import { UITexture, } from "@wowts/wow-mock"; import { huge } from "@wowts/math"; -import { AceGUIRegisterAsContainer } from "./acegui-helpers"; +import { WidgetContainer } from "./acegui-helpers"; import { OvaleFutureClass } from "../states/Future"; import { BaseState } from "../states/BaseState"; import { AstIconNode, AstNodeSnapshot } from "../engine/ast"; @@ -52,7 +52,7 @@ import { OvaleActionBarClass } from "../engine/action-bar"; const strmatch = match; const INFINITY = huge; -const BARRE = 8; +const DRAG_HANDLER_HEIGHT = 8; interface Action { icons: OvaleIcon; @@ -65,7 +65,7 @@ interface Action { dy: number; } -class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { +class OvaleFrame extends WidgetContainer implements IconParent { checkBoxWidget: LuaObj = {}; listWidget: LuaObj = {}; visible = true; @@ -93,23 +93,23 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { OnRelease() {} - OnWidthSet(width: number) { + OnWidthSet = (width: number) => { const content = this.content; let contentwidth = width - 34; if (contentwidth < 0) { contentwidth = 0; } content.SetWidth(contentwidth); - } + }; - OnHeightSet(height: number) { + OnHeightSet = (height: number) => { const content = this.content; let contentheight = height - 57; if (contentheight < 0) { contentheight = 0; } content.SetHeight(contentheight); - } + }; OnLayoutFinished(width: number, height: number) { if (!width) { @@ -146,27 +146,28 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { private goNextIcon( action: Action, left: number, - top: number - ): [left: number, top: number] { - const BARRE = 8; + top: number, + maxWidth: number, + maxHeight: number + ): [left: number, top: number, maxWidth: number, maxHeight: number] { const profile = this.ovaleOptions.db.profile; const margin = profile.apparence.margin; const width = action.scale * 36 + margin; const height = action.scale * 36 + margin; + action.left = left; + action.top = top; if (profile.apparence.vertical) { - action.left = top; - action.top = -left - BARRE - margin; + action.dx = 0; + action.dy = -height; + } else { action.dx = width; action.dy = 0; - } else { - action.left = left; - action.top = -top - BARRE - margin; - action.dx = 0; - action.dy = height; } - // top = top + height; - left = left + width; - return [left, top]; + if (left + width > maxWidth) maxWidth = left + width; + if (height - top > maxHeight) maxHeight = height - top; + left = left + action.dx; + top = top + action.dy; + return [left, top, maxWidth, maxHeight]; } UpdateVisibility() { @@ -174,7 +175,7 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { const profile = this.ovaleOptions.db.profile; if (!profile.apparence.enableIcons) { this.visible = false; - } else if (!this.hider.IsVisible()) { + } else if (!this.frame.IsVisible()) { this.visible = false; } else { if (profile.apparence.hideVehicule && UnitHasVehicleUI("player")) { @@ -242,7 +243,8 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { const iconNodes = this.ovaleCompile.GetIconNodes(); let left = 0; let top = 0; - const maxHeight = 0; + let maxHeight = 0; + let maxWidth = 0; for (const [k, node] of ipairs(iconNodes)) { const icon = this.actions[k]; @@ -251,7 +253,13 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { const [element, atTime] = this.getIconAction(node); if (element && atTime) { - [left, top] = this.goNextIcon(icon, left, top); + [left, top, maxWidth, maxHeight] = this.goNextIcon( + icon, + left, + top, + maxWidth, + maxHeight + ); icon.icons.Show(); let start; if (element.type === "action" && element.offgcd) { @@ -278,7 +286,7 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { icon.icons.Hide(); } } - this.updateBarSize(left, maxHeight); + this.updateDragHandle(maxWidth, maxHeight); wipe(this.ovale.refreshNeeded); this.ovaleDebug.UpdateTrace(); PrintOneTimeMessages(); @@ -364,21 +372,21 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { icons.cooldownStart && icons.cooldownEnd ) { - let top = + let ratio = 1 - (now - icons.cooldownStart) / (icons.cooldownEnd - icons.cooldownStart); - if (top < 0) { - top = 0; - } else if (top > 1) { - top = 1; + if (ratio < 0) { + ratio = 0; + } else if (ratio > 1) { + ratio = 1; } icons.SetPoint( "TOPLEFT", this.frame, "TOPLEFT", - (action.left + top * action.dx) / action.scale, - (action.top - top * action.dy) / action.scale + (action.left + ratio * action.dx) / action.scale, + (action.top + ratio * action.dy) / action.scale ); } } @@ -389,18 +397,18 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { this.frame, "TOPLEFT", action.left / action.scale, - action.top / action.scale + action.top / action.scale - + DRAG_HANDLER_HEIGHT - + profile.apparence.margin ); } } UpdateFrame() { const profile = this.ovaleOptions.db.profile; - if (this.hider.IsVisible()) { + if (this.frame.IsVisible()) { this.frame.ClearAllPoints(); this.frame.SetPoint( - "CENTER", - this.hider, "CENTER", profile.apparence.offsetX, profile.apparence.offsetY @@ -556,11 +564,7 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { } const profile = this.ovaleOptions.db.profile; this.frame.EnableMouse(!profile.apparence.clickThru); - let left = 0; - let maxHeight = 0; - let maxWidth = 0; - let top = 0; - const margin = profile.apparence.margin; + const iconNodes = this.ovaleCompile.GetIconNodes(); for (const [k, node] of ipairs(iconNodes)) { if (!this.actions[k]) { @@ -582,36 +586,19 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { }; } const action = this.actions[k]; - let width, height, newScale; + let newScale; if ( node.rawNamedParams.size != undefined && node.rawNamedParams.size.type === "string" && node.rawNamedParams.size.value === "small" ) { newScale = profile.apparence.smallIconScale; - width = newScale * 36 + margin; - height = newScale * 36 + margin; } else { newScale = profile.apparence.iconScale; - width = newScale * 36 + margin; - height = newScale * 36 + margin; - } - if (top + height > profile.apparence.iconScale * 36 + margin) { - top = 0; - left = maxWidth; } + action.scale = newScale; - if (profile.apparence.vertical) { - action.left = top; - action.top = -left - BARRE - margin; - action.dx = width; - action.dy = 0; - } else { - action.left = left; - action.top = -top - BARRE - margin; - action.dx = 0; - action.dy = height; - } + let icon: OvaleIcon; icon = action.icons; let scale = action.scale; @@ -633,60 +620,38 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { this.skinGroup.AddButton(icon.frame); } icon.Show(); - top = top + height; - if (top > maxHeight) { - maxHeight = top; - } - if (left + width > maxWidth) { - maxWidth = left + width; - } } this.content.SetAlpha(profile.apparence.optionsAlpha); - this.updateBarSize(maxWidth, maxHeight); } - private updateBarSize(maxWidth: number, maxHeight: number) { + private updateDragHandle(maxWidth: number, maxHeight: number) { const profile = this.ovaleOptions.db.profile; const margin = profile.apparence.margin; - if (profile.apparence.vertical) { - this.barre.SetWidth(maxHeight - margin); - this.barre.SetHeight(BARRE); - this.frame.SetWidth(maxHeight + profile.apparence.iconShiftY); - this.frame.SetHeight( - maxWidth + BARRE + margin + profile.apparence.iconShiftX - ); - this.content.SetPoint( - "TOPLEFT", - this.frame, - "TOPLEFT", - maxHeight + profile.apparence.iconShiftX, - profile.apparence.iconShiftY - ); - } else { - this.barre.SetWidth(maxWidth - margin); - this.barre.SetHeight(BARRE); - this.frame.SetWidth(maxWidth); - this.frame.SetHeight(maxHeight + BARRE + margin); - this.content.SetPoint( - "TOPLEFT", - this.frame, - "TOPLEFT", - maxWidth + profile.apparence.iconShiftX, - profile.apparence.iconShiftY - ); - } + this.dragHandleTexture.SetWidth(maxWidth - margin); + this.dragHandleTexture.SetHeight(DRAG_HANDLER_HEIGHT); + this.frame.SetWidth(maxWidth); + this.frame.SetHeight(maxHeight + DRAG_HANDLER_HEIGHT + margin); + this.content.SetPoint( + "TOPLEFT", + this.frame, + "TOPLEFT", + maxWidth + profile.apparence.iconShiftX, + profile.apparence.iconShiftY + ); } type = "Frame"; // frame: UIFrame; localstatus = {}; actions: LuaArray = {}; - hider: UIFrame; + + /** Only used to know the update interval */ updateFrame: UIFrame; - // content: UIFrame; timeSinceLastUpdate: number; - barre: UITexture; + + /** Used to drag the frame */ + dragHandleTexture: UITexture; skinGroup?: MasqueSkinGroup; private tracer: Tracer; @@ -710,46 +675,53 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { private scripts: OvaleScriptsClass, private actionBar: OvaleActionBarClass ) { - super(); + super( + CreateFrame( + "Frame", + undefined, + UIParent, + "SecureHandlerStateTemplate" + ) + ); this.traceLog = LibTextDump.New(`Ovale - ${L.icon_snapshot}`, 750, 500); - const hider = CreateFrame( - "Frame", - `${ovale.GetName()}PetBattleFrameHider`, - UIParent, - "SecureHandlerStateTemplate" - ); - const newFrame = CreateFrame("Frame", undefined, hider); - hider.SetAllPoints(UIParent); - RegisterStateDriver(hider, "visibility", "[petbattle] hide; show"); + // const hider = CreateFrame( + // "Frame", + // `${ovale.GetName()}PetBattleFrameHider`, + // UIParent, + // "SecureHandlerStateTemplate" + // ); + // const newFrame = ; + // hider.SetAllPoints(UIParent); + RegisterStateDriver(this.frame, "visibility", "[petbattle] hide; show"); this.tracer = ovaleDebug.create("OvaleFrame"); - this.frame = newFrame; - this.hider = hider; + // this.frame = newFrame; + // this.hider = hider; this.updateFrame = CreateFrame( "Frame", `${ovale.GetName()}UpdateFrame` ); - this.barre = this.frame.CreateTexture(); - this.content = CreateFrame("Frame", undefined, this.updateFrame); + this.dragHandleTexture = this.frame.CreateTexture(); if (Masque) { this.skinGroup = Masque.Group(ovale.GetName()); } this.timeSinceLastUpdate = INFINITY; - newFrame.SetWidth(100); - newFrame.SetHeight(100); - newFrame.SetMovable(true); - newFrame.SetFrameStrata("MEDIUM"); - newFrame.SetScript("OnMouseDown", () => { + const frame = this.frame; + frame.SetWidth(100); + frame.SetHeight(100); + frame.SetMovable(true); + frame.SetFrameStrata("MEDIUM"); + frame.SetScript("OnMouseDown", () => { if (!ovaleOptions.db.profile.apparence.verrouille) { - newFrame.StartMoving(); + frame.StartMoving(); AceGUI.ClearFocus(); } }); - newFrame.SetScript("OnMouseUp", () => { - newFrame.StopMovingOrSizing(); - const [x, y] = newFrame.GetCenter(); - const parent = newFrame.GetParent(); + frame.SetScript("OnMouseUp", () => { + frame.StopMovingOrSizing(); + const [x, y] = frame.GetCenter(); + const parent = frame.GetParent(); if (parent) { const profile = ovaleOptions.db.profile; const [parentX, parentY] = parent.GetCenter(); @@ -757,29 +729,28 @@ class OvaleFrame extends AceGUI.WidgetContainerBase implements IconParent { profile.apparence.offsetY = y - parentY; } }); - newFrame.SetScript("OnEnter", () => { + frame.SetScript("OnEnter", () => { const profile = ovaleOptions.db.profile; if ( !(profile.apparence.enableIcons && profile.apparence.verrouille) ) { - this.barre.Show(); + this.dragHandleTexture.Show(); } }); - newFrame.SetScript("OnLeave", () => { - this.barre.Hide(); + frame.SetScript("OnLeave", () => { + this.dragHandleTexture.Hide(); }); - newFrame.SetScript("OnHide", () => this.Hide()); + frame.SetScript("OnHide", () => this.Hide()); this.updateFrame.SetScript("OnUpdate", (updateFrame, elapsed) => this.OnUpdate(elapsed) ); - this.barre.SetColorTexture(0.8, 0.8, 0.8, 0.5); - this.barre.SetPoint("TOPLEFT", 0, 0); - this.barre.Hide(); + this.dragHandleTexture.SetColorTexture(0.8, 0.8, 0.8, 0.5); + this.dragHandleTexture.SetPoint("TOPLEFT", 0, 0); + this.dragHandleTexture.Hide(); const content = this.content; content.SetWidth(200); content.SetHeight(100); content.Hide(); - AceGUIRegisterAsContainer(this); } debugIcon(index: number): void { diff --git a/src/ui/Icon.ts b/src/ui/Icon.ts index dc6894b6d..05befa002 100644 --- a/src/ui/Icon.ts +++ b/src/ui/Icon.ts @@ -58,7 +58,7 @@ export class OvaleIcon { rangeIndicator: UIFontString; remains: UIFontString; shortcut: UIFontString; - icone: UITexture; + icon: UITexture; frame: UICheckButton; HasScriptControls() { @@ -77,23 +77,15 @@ export class OvaleIcon { private ovaleSpellBook: OvaleSpellBookClass, private actionBar: OvaleActionBarClass ) { - if (!secure) { - this.frame = CreateFrame( - "CheckButton", - name, - parent.frame, + this.frame = CreateFrame( + "CheckButton", + name, + parent.frame, + (secure && "SecureActionButtonTemplate, ActionButtonTemplate") || "ActionButtonTemplate" - ); - } else { - this.frame = CreateFrame( - "CheckButton", - name, - parent.frame, - "SecureActionButtonTemplate, ActionButtonTemplate" - ); - } + ); const profile = this.ovaleOptions.db.profile; - this.icone = _G[`${name}Icon`]; + this.icon = _G[`${name}Icon`]; this.shortcut = _G[`${name}HotKey`]; this.remains = _G[`${name}Name`]; this.rangeIndicator = _G[`${name}Count`]; @@ -120,9 +112,9 @@ export class OvaleIcon { this.actionType = undefined; this.actionId = undefined; this.actionHelp = undefined; - this.frame.SetScript("OnMouseUp", this.OvaleIcon_OnMouseUp); - this.frame.SetScript("OnEnter", () => this.OvaleIcon_OnEnter()); - this.frame.SetScript("OnLeave", () => this.OvaleIcon_OnLeave()); + this.frame.SetScript("OnMouseUp", this.onMouseUp); + this.frame.SetScript("OnEnter", this.onEnter); + this.frame.SetScript("OnLeave", this.onLeave); this.focusText.SetFontObject("GameFontNormalSmall"); this.focusText.SetAllPoints(this.frame); this.focusText.SetTextColor(1, 1, 1); @@ -134,9 +126,9 @@ export class OvaleIcon { } SetValue(value: number | undefined, actionTexture: string | undefined) { - this.icone.Show(); - this.icone.SetTexture(actionTexture); - this.icone.SetAlpha(this.ovaleOptions.db.profile.apparence.alpha); + this.icon.Show(); + this.icon.SetTexture(actionTexture); + this.icon.SetAlpha(this.ovaleOptions.db.profile.apparence.alpha); this.cd.Hide(); this.focusText.Hide(); this.rangeIndicator.Hide(); @@ -227,12 +219,12 @@ export class OvaleIcon { } else { cd.Hide(); } - this.icone.Show(); - this.icone.SetTexture(element.actionTexture); + this.icon.Show(); + this.icon.SetTexture(element.actionTexture); if (element.actionUsable) { - this.icone.SetAlpha(1); + this.icon.SetAlpha(1); } else { - this.icone.SetAlpha(0.5); + this.icon.SetAlpha(0.5); } const options = element.options; @@ -242,9 +234,9 @@ export class OvaleIcon { element.actionResourceExtend && element.actionResourceExtend > 0 ) { - this.icone.SetVertexColor(0.75, 0.2, 0.2); + this.icon.SetVertexColor(0.75, 0.2, 0.2); } else { - this.icone.SetVertexColor(1, 1, 1); + this.icon.SetVertexColor(1, 1, 1); } if (isString(options.help)) this.actionHelp = options.help; if (!(this.cooldownStart && this.cooldownEnd)) { @@ -326,7 +318,7 @@ export class OvaleIcon { } this.frame.Show(); } else { - this.icone.Hide(); + this.icon.Hide(); this.rangeIndicator.Hide(); this.shortcut.Hide(); this.remains.Hide(); @@ -406,7 +398,7 @@ export class OvaleIcon { SetRangeIndicator(text: string) { this.rangeIndicator.SetText(text); } - OvaleIcon_OnMouseUp = ( + onMouseUp = ( _: unknown, button: | "LeftButton" @@ -423,7 +415,7 @@ export class OvaleIcon { } this.frame.SetChecked(true); }; - OvaleIcon_OnEnter() { + onEnter = () => { if (this.help || this.actionType || this.HasScriptControls()) { GameTooltip.SetOwner(this.frame, "ANCHOR_BOTTOMLEFT"); if (this.help) { @@ -460,12 +452,12 @@ export class OvaleIcon { } GameTooltip.Show(); } - } - OvaleIcon_OnLeave() { + }; + onLeave = () => { if (this.help || this.HasScriptControls()) { GameTooltip.Hide(); } - } + }; SetPoint( anchor: UIPosition, reference: UIFrame, diff --git a/src/ui/acegui-helpers.ts b/src/ui/acegui-helpers.ts index 8e716a1cb..7117c258f 100644 --- a/src/ui/acegui-helpers.ts +++ b/src/ui/acegui-helpers.ts @@ -1,37 +1,74 @@ import { LuaArray, LuaObj } from "@wowts/lua"; -import { UIFrame } from "@wowts/wow-mock"; - -interface Widget { - frame: UIFrame & { obj?: T }; - children?: unknown; - userdata?: unknown; - events?: unknown; - base?: unknown; - content: UIFrame & { obj?: T }; - SetLayout(list: string): void; -} +import { CreateFrame, UIFrame } from "@wowts/wow-mock"; +import AceGUI, { AceGUIWidgetBase } from "@wowts/ace_gui-3.0"; + +export class Widget extends AceGUI.WidgetBase { + userdata: LuaObj = {}; + events: LuaObj = {}; + base = AceGUI.WidgetBase; + frame: T & { obj?: Widget }; + + protected OnWidthSet?: (width: number) => void; + protected OnHeightSet?: (height: number) => void; -export function AceGUIRegisterAsContainer, U>( - widget: T & U -) { - widget.children = {}; - widget.userdata = {}; - widget.events = {}; - // widget.base = WidgetContainerBase - widget.content.obj = widget; - widget.frame.obj = widget; - // widget.content.SetScript("OnSizeChanged", ContentResize) - // widget.frame.SetScript("OnSizeChanged", FrameResize) - widget.SetLayout("List"); + constructor(frame: T) { + super(); + this.frame = frame; + this.frame.obj = this; + this.frame.SetScript("OnSizeChanged", this.handleFrameResize); + } + + private handleFrameResize = () => { + if (this.frame.GetWidth() && this.frame.GetHeight()) { + if (this.OnWidthSet) this.OnWidthSet(this.frame.GetWidth()); + if (this.OnHeightSet) this.OnHeightSet(this.frame.GetHeight()); + } + }; } -export function AceGUIRegisterAsWidget, U>(widget: T & U) { - widget.userdata = {}; - widget.events = {}; - // widget.base = WidgetBase - widget.frame.obj = widget; - // widget.frame.SetScript("OnSizeChanged", FrameResize) - return widget; +export class WidgetContainer< + T extends UIFrame +> extends AceGUI.WidgetContainerBase { + children: LuaArray = {}; + userdata: LuaObj = {}; + events: LuaObj = {}; + + /** Where the child frames are placed */ + content: UIFrame & { obj?: WidgetContainer }; + frame: T & { obj?: WidgetContainer }; + base = AceGUI.WidgetContainerBase; + width = 0; + height = 0; + + protected OnWidthSet?: (width: number) => void; + protected OnHeightSet?: (height: number) => void; + + constructor(frame: T) { + super(); + const content = CreateFrame("Frame", undefined, frame); + content.SetScript("OnSizeChanged", this.handleFrameResize); + frame.SetScript("OnSizeChanged", this.handleContentResize); + this.content = content; + this.content.obj = this; + this.frame = frame; + this.frame.obj = this; + this.SetLayout("List"); + } + + private handleFrameResize = () => { + if (this.frame.GetWidth() && this.frame.GetHeight()) { + if (this.OnWidthSet) this.OnWidthSet(this.frame.GetWidth()); + if (this.OnHeightSet) this.OnHeightSet(this.frame.GetHeight()); + } + }; + + private handleContentResize = () => { + if (this.content.GetWidth() && this.content.GetHeight()) { + this.width = this.content.GetWidth(); + this.height = this.content.GetHeight(); + this.DoLayout(); + } + }; } interface OptionUiBase {