diff --git a/API.lua b/API.lua index ecaeaa6d..b2c4ad0e 100644 --- a/API.lua +++ b/API.lua @@ -382,11 +382,11 @@ spell.successful_casted = how many times this spell has been casted successfully spell.n_min = minimal damage made on a normal hit. spell.n_max = max damage made on a normal hit. spell.n_amt = amount of normal hits. -spell.n_dmg = total amount made doing only normal hits. +spell.n_total = total amount made doing only normal hits. spell.c_min = minimal damage made on a critical hit. spell.c_max = max damage made on a critical hit. spell.c_amt = how many times this spell got a critical hit. -spell.c_dmg = total amount made doing only normal hits. +spell.c_total = total amount made doing only normal hits. spell.g_amt = how many glancing blows this spell has. spell.g_dmg = total damage made by glancing blows. spell.r_amt = total of times this spell got resisted by the target. @@ -438,11 +438,11 @@ spell.overheal = amount of overheal made by this spell. spell.n_min = minimal heal made on a normal hit. spell.n_max = max heal made on a normal hit. spell.n_amt = amount of normal hits. -spell.n_curado = total amount made doing only normal hits (weird name I know). +spell.n_total = total amount made doing only normal hits (weird name I know). spell.c_min = minimal heal made on a critical hit. spell.c_max = max heal made on a critical hit. spell.c_amt = how many times this spell got a critical hit. -spell.c_curado = total amount made doing only normal hits. +spell.c_total = total amount made doing only normal hits. spell.targets = hash table containing {["targetname"] = total healing done by this spell on this target} spell.targets_overheal = hash table containing {["targetname"] = total overhealing by this spell on this target} diff --git a/API.txt b/API.txt index dcad0775..b685f0dc 100644 --- a/API.txt +++ b/API.txt @@ -385,11 +385,11 @@ spell.successful_casted = how many times this spell has been casted successfully spell.n_min = minimal damage made on a normal hit. spell.n_max = max damage made on a normal hit. spell.n_amt = amount of normal hits. -spell.n_dmg = total amount made doing only normal hits. +spell.n_total = total amount made doing only normal hits. spell.c_min = minimal damage made on a critical hit. spell.c_max = max damage made on a critical hit. spell.c_amt = how many times this spell got a critical hit. -spell.c_dmg = total amount made doing only normal hits. +spell.c_total = total amount made doing only normal hits. spell.g_amt = how many glancing blows this spell has. spell.g_dmg = total damage made by glancing blows. spell.r_amt = total of times this spell got resisted by the target. @@ -442,11 +442,11 @@ spell.overheal = amount of overheal made by this spell. spell.n_min = minimal heal made on a normal hit. spell.n_max = max heal made on a normal hit. spell.n_amt = amount of normal hits. -spell.n_curado = total amount made doing only normal hits (weird name I know). +spell.n_total = total amount made doing only normal hits (weird name I know). spell.c_min = minimal heal made on a critical hit. spell.c_max = max heal made on a critical hit. spell.c_amt = how many times this spell got a critical hit. -spell.c_curado = total amount made doing only normal hits. +spell.c_total = total amount made doing only normal hits. spell.targets = hash table containing {["targetname"] = total healing done by this spell on this target} spell.targets_overheal = hash table containing {["targetname"] = total overhealing by this spell on this target} diff --git a/Definitions.lua b/Definitions.lua index 78fe596f..68b7b3da 100644 --- a/Definitions.lua +++ b/Definitions.lua @@ -1,9 +1,17 @@ +--uiobject: is an object that represents a UI element, such as a frame, a texture, or a button. UIObjects are the base class for all UI elements in the WoW API. +--3D World: is an object which is placed behind|below all UI elements, cannot be parent of any object, in the 3D World object is where the game world is rendered +--size: corresponds to the height and height of an object, it is measure in pixels, must be bigger than zero. +--scale: the size of an object is multiplied by this value, it is measure in percentage, must be between 0.65 and 2.40. +--alpha: corresponds to the transparency of an object, the bigger is the value less transparent is the object, it is measure in percentage, must be between 0 and 1, zero is fully transparent and one is fully opaque. + + ---@class _G ---@field RegisterAttributeDriver fun(statedriver: frame, attribute: string, conditional: string) ---@field RegisterStateDriver fun(statedriver: frame, attribute: string, conditional: string) ---@field UnitGUID fun(unit: unit): string ---@field UnitName fun(unit: unit): string +---@field GetCursorPosition fun(): number, number return the position of the cursor on the screen, in pixels, relative to the bottom left corner of the screen. ---@class unixtime : number const @@ -16,6 +24,9 @@ ---@field NewTimer fun(delay: number, func: function): timer ---@field NewTicker fun(interval: number, func: function, iterations: number|nil): timer +---@class tablesize : {H: number, W: number} +---@class tablecoords : {L: number, R: number, T: number, B: number} + ---@class red : number color value representing the red component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color) ---@class green : number color value representing the green component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color) ---@class blue : number color value representing the blue component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color) @@ -23,9 +34,9 @@ ---@class color : table, string @table(r: red|number, g: green|number, b: blue|number, a: alpha|number) @string(color name) @hex (000000-ffffff) value representing a color, the value must be a table with the following fields: r, g, b, a. r, g, b are numbers between 0 and 1, a is a number between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color) ---@class scale : number @number(0.65-2.40) value representing the scale factor of the UIObject, the value must be between 0.65 and 2.40, the width and height of the UIObject will be multiplied by this value. ---@class texture : string, number is an object that represents a graphical image. Textures are used to display visual elements such as icons, backgrounds, borders, and more. ----@class frame : UIObject represents a container for other UI elements, such as textures, buttons, text, and more. +---@class frame : uiobject represents a container for other UI elements, such as textures, buttons, text, and more. Gotten from the first result of GetWidth() or from the first result of GetSize(). It is expected a GetWidth() or GetSize() when the type 'width' is used. ---@class width : number property that represents the horizontal size of a UI element, such as a frame or a texture. ----@class height : number property that represents the vertical size of a UI element, such as a frame or a texture. +---@class height : number property that represents the vertical size of a UI element, such as a frame or a texture. Gotten from the first result of GetHeight() or from the second result of GetSize(). It is expected a GetHeight() or GetSize() when the type 'height' is used. ---@class script : string, function is a piece of code that is executed in response to a specific event, such as a button click or a frame update. Scripts can be used to implement behavior and logic for UI elements. ---@class event : string is a notification that is sent to a frame when something happens, such as a button click or a frame update. Events can be used to trigger scripts. ---@class framestrata : string @string(BACKGROUND, LOW, MEDIUM, HIGH, DIALOG, FULLSCREEN, FULLSCREEN_DIALOG, TOOLTIP) property that determines the stacking order of frames. Higher strata values indicate frames that should be displayed on top of frames with lower strata values. @@ -33,31 +44,33 @@ ---@class unit : string string that represents a unit in the game, such as the player, a party member, or a raid member. ---@class health : number amount of hit points (health) of a unit. This value can be changed by taking damage or healing. ---@class role : string @string(TANK, HEALER, DAMAGER, NONE) is a string that represents the role of a unit, such as tank, healer, or damage dealer. +---@class point : string @string(topleft, topright, bottomleft, bottomright, top, bottom, left, right, center) is a string that represents a point on a frame. Points are used to position frames relative to each other. ----@class UIObject ----@field Show fun(self: UIObject) ----@field Hide fun(self: UIObject) ----@field SetShown fun(self: UIObject, state: boolean) ----@field IsShown fun(self: UIObject) : boolean ----@field SetAllPoints fun(self: UIObject) ----@field SetParent fun(self: UIObject, parent: frame) ----@field SetSize fun(self: UIObject, width: width|number, height: height|number) ----@field SetWidth fun(self: UIObject, width: width|number) ----@field SetHeight fun(self: UIObject, height: height|number) ----@field SetAlpha fun(self: UIObject, alpha: alpha|number) ----@field SetScale fun(self: UIObject, scale: scale|number) ----@field GetWidth fun(self: UIObject) : width|number ----@field GetHeight fun(self: UIObject) : height|number ----@field GetScale fun(self: UIObject) : scale|number ----@field GetAlpha fun(self: UIObject) : alpha|number ----@field GetSize fun(self: UIObject) : width|number, height|number ----@field GetParent fun(self: UIObject) : frame ----@field GetPoint fun(self: UIObject, index: number): string, frame, string, number, number ----@field SetPoint fun(self: UIObject, point: string, relativeFrame: frame, relativePoint: string, xOffset: number, yOffset: number) ----@field ClearAllPoints fun(self: UIObject) ----@field CreateAnimationGroup fun(self: UIObject, name: string|nil, templateName: string|nil) : animationgroup +---@class uiobject +---@field Show fun(self: uiobject) make the object be shown on the user screen +---@field Hide fun(self: uiobject) make the object be hidden from the user screen +---@field SetShown fun(self: uiobject, state: boolean) show or hide the object +---@field IsShown fun(self: uiobject) : boolean return if the object is shown or not +---@field SetAllPoints fun(self: uiobject) set the object to be the same size as its parent +---@field SetParent fun(self: uiobject, parent: frame) set the parent object of the object +---@field SetSize fun(self: uiobject, width: width|number, height: height|number) set the width and height of the object +---@field SetWidth fun(self: uiobject, width: width|number) set only the width of the object +---@field SetHeight fun(self: uiobject, height: height|number) set only the height of the object +---@field SetAlpha fun(self: uiobject, alpha: alpha|number) set the transparency of the object +---@field SetScale fun(self: uiobject, scale: scale|number) +---@field GetWidth fun(self: uiobject) : width|number +---@field GetHeight fun(self: uiobject) : height|number +---@field GetScale fun(self: uiobject) : scale|number +---@field GetAlpha fun(self: uiobject) : alpha|number +---@field GetSize fun(self: uiobject) : width|number, height|number +---@field GetParent fun(self: uiobject) : frame +---@field GetPoint fun(self: uiobject, index: number): string, frame, string, number, number +---@field GetCenter fun(self: uiobject): number, number +---@field SetPoint fun(self: uiobject, point: "topleft"|"topright"|"bottomleft"|"bottomright"|"top"|"bottom"|"left"|"right"|"center", relativeFrame: uiobject, relativePoint: "topleft"|"topright"|"bottomleft"|"bottomright"|"top"|"bottom"|"left"|"right"|"center", xOffset: number, yOffset: number) +---@field ClearAllPoints fun(self: uiobject) +---@field CreateAnimationGroup fun(self: uiobject, name: string|nil, templateName: string|nil) : animationgroup ----@class animationgroup : UIObject +---@class animationgroup : uiobject ---@field CreateAnimation fun(self: animationgroup, animationType: string, name: string|nil, inheritsFrom: string|nil) : animation ---@field GetAnimation fun(self: animationgroup, name: string) : animation ---@field GetAnimations fun(self: animationgroup) : table @@ -75,11 +88,11 @@ ---@field SetDuration fun(self: animationgroup, duration: number) ---@field SetEndDelay fun(self: animationgroup, delay: number) ---@field SetLooping fun(self: animationgroup, loop: boolean) ----@field SetScript fun(self: animationgroup, event: string, handler: function) +---@field SetScript fun(self: animationgroup, event: string, handler: function|nil) "OnEvent"|"OnShow" ---@field SetSmoothProgress fun(self: animationgroup, smooth: boolean) ---@field Stop fun(self: animationgroup) ----@class animation : UIObject +---@class animation : uiobject ---@field GetDuration fun(self: animation) : number ---@field GetEndDelay fun(self: animation) : number ---@field GetOrder fun(self: animation) : number @@ -94,15 +107,15 @@ ---@field SetDuration fun(self: animation, duration: number) ---@field SetEndDelay fun(self: animation, delay: number) ---@field SetOrder fun(self: animation, order: number) ----@field SetScript fun(self: animation, event: string, handler: function) +---@field SetScript fun(self: animation, event: string, handler: function|nil) ---@field SetSmoothing fun(self: animation, smoothing: string) ---@field Stop fun(self: animation) ----@class frame : UIObject +---@class frame : uiobject ---@field SetAttribute fun(self: frame, name: string, value: any) ----@field SetScript fun(self: frame, event: string, handler: function) +---@field SetScript fun(self: frame, event: string, handler: function|nil) ---@field GetScript fun(self: frame, event: string) : function ----@field SetFrameStrata fun(self: frame, strata: framestrata|string) +---@field SetFrameStrata fun(self: frame, strata: framestrata|"background"|"low"|"medium"|"high"|"dialog"|"fullscreen"|"fullscreen_dialog"|"tooltip") ---@field SetFrameLevel fun(self: frame, level: number) ---@field SetClampedToScreen fun(self: frame, clamped: boolean) ---@field SetClampRectInsets fun(self: frame, left: number, right: number, top: number, bottom: number) @@ -115,6 +128,9 @@ ---@field SetToplevel fun(self: frame, toplevel: boolean) ---@field SetPropagateKeyboardInput fun(self: frame, propagate: boolean) ---@field SetPropagateGamepadInput fun(self: frame, propagate: boolean) +---@field StartMoving fun(self: frame) +---@field StartSizing fun(self: frame, point: "top"|"topright"|"right"|"bottomright"|"bottom"|"bottomleft"|"left"|"topleft") +---@field StopMovingOrSizing fun(self: frame) ---@field GetAttribute fun(self: frame, name: string) : any ---@field GetFrameLevel fun(self: frame) : number ---@field GetFrameStrata fun(self: frame) : framestrata|string @@ -125,9 +141,13 @@ ---@field GetObjectType fun(self: frame) : string ---@field GetChildren fun(self: frame) : frame[] ---@field GetRegions fun(self: frame) : region[] ----@field CreateTexture fun(self: frame, name: string|nil, layer: string, inherits: string|nil, subLayer: number|nil) : texture ----@field CreateFontString fun(self: frame, name: string|nil, layer: string, inherits: string|nil, subLayer: number|nil) : fontstring +---@field CreateTexture fun(self: frame, name: string|nil, layer: "background"|"border"|"artwork"|"overlay"|"highlight", inherits: string|nil, subLayer: number|nil) : texture +---@field CreateFontString fun(self: frame, name: string|nil, layer: "background"|"border"|"artwork"|"overlay"|"highlight", inherits: string|nil, subLayer: number|nil) : fontstring ---@field EnableMouse fun(self: frame, enable: boolean) +---@field SetResizable fun(self: frame, enable: boolean) +---@field EnableMouseWheel fun(self: frame, enable: boolean) +---@field RegisterForDrag fun(self: frame, button: string) +---@field SetResizeBounds fun(self: frame, minWidth: number, minHeight: number, maxWidth: number, maxHeight: number) ---@class button : frame ---@field SetNormalTexture fun(self: button, texture: texture) @@ -148,14 +168,45 @@ ---@field GetFontString fun(self: button) : fontstring ---@field SetButtonState fun(self: button, state: string, enable: boolean) ---@field GetButtonState fun(self: button, state: string) : boolean ----@field RegisterForClicks fun(self: button, button1: string|nil, button2: string|nil) +---@field RegisterForClicks fun(self: button, button1: nil|"AnyUp"|"AnyDown"|"LeftButtonDown"|"LeftButtonUp"|"MiddleButtonUp"|"MiddleButtonDown"|"RightButtonDown"|"RightButtonUp"|"Button4Up"|"Button4Down"|"Button5Up"|"Button5Down", button2: nil|"AnyUp"|"AnyDown"|"LeftButtonDown"|"LeftButtonUp"|"MiddleButtonUp"|"MiddleButtonDown"|"RightButtonDown"|"RightButtonUp"|"Button4Up"|"Button4Down"|"Button5Up"|"Button5Down") +---@field GetNormalTexture fun(self: button) : texture +---@field GetPushedTexture fun(self: button) : texture +---@field GetHighlightTexture fun(self: button) : texture +---@field GetDisabledTexture fun(self: button) : texture ----@class fontstring : UIObject ----@field SetDrawLayer fun(self: fontstring, layer: string, subLayer: number|nil) +---@class statusbar : frame +---@field SetStatusBarColor fun(self: statusbar, r: red|number, g: green|number, b: blue|number, a: alpha|number) +---@field SetStatusBarTexture fun(self: statusbar, path: string) +---@field SetMinMaxValues fun(self: statusbar, minValue: number, maxValue: number) +---@field SetValue fun(self: statusbar, value: number) +---@field SetValueStep fun(self: statusbar, valueStep: number) +---@field SetOrientation fun(self: statusbar, orientation: string) +---@field SetReverseFill fun(self: statusbar, reverseFill: boolean) +---@field GetMinMaxValues fun(self: statusbar) : number, number +---@field GetValue fun(self: statusbar) : number +---@field GetValueStep fun(self: statusbar) : number +---@field GetOrientation fun(self: statusbar) : string +---@field GetReverseFill fun(self: statusbar) : boolean + +---@class scrollframe : frame +---@field SetScrollChild fun(self: scrollframe, child: frame) +---@field GetScrollChild fun(self: scrollframe) : frame +---@field SetHorizontalScroll fun(self: scrollframe, offset: number) +---@field SetVerticalScroll fun(self: scrollframe, offset: number) +---@field GetHorizontalScroll fun(self: scrollframe) : number +---@field GetVerticalScroll fun(self: scrollframe) : number +---@field GetHorizontalScrollRange fun(self: scrollframe) : number +---@field GetVerticalScrollRange fun(self: scrollframe) : number + +---@class region : uiobject + +---@class fontstring : region +---@field SetDrawLayer fun(self: fontstring, layer: "background"|"border"|"artwork"|"overlay"|"highlight", subLayer: number|nil) ---@field SetFont fun(self: fontstring, font: string, size: number, flags: string) ----@field SetText fun(self: fontstring, text: string) +---@field SetText fun(self: fontstring, text: string|number) ---@field GetText fun(self: fontstring) : string ---@field GetFont fun(self: fontstring) : string, number, string +---@field GetStringWidth fun(self: fontstring) : number return the width of the string in pixels ---@field SetShadowColor fun(self: fontstring, r: red|number, g: green|number, b: blue|number, a: alpha|number) ---@field GetShadowColor fun(self: fontstring) : number, number, number, number ---@field SetShadowOffset fun(self: fontstring, offsetX: number, offsetY: number) @@ -166,10 +217,6 @@ ---@field GetJustifyH fun(self: fontstring) : string ---@field SetJustifyV fun(self: fontstring, justifyV: string) ---@field GetJustifyV fun(self: fontstring) : string ----@field SetWidth fun(self: fontstring, width: number) ----@field GetWidth fun(self: fontstring) : number ----@field SetHeight fun(self: fontstring, height: number) ----@field GetHeight fun(self: fontstring) : number ---@field SetNonSpaceWrap fun(self: fontstring, nonSpaceWrap: boolean) ---@field GetNonSpaceWrap fun(self: fontstring) : boolean ---@field SetIndentedWordWrap fun(self: fontstring, indentedWordWrap: boolean) @@ -200,41 +247,17 @@ ---@field SetTextTruncateLines fun(self: fontstring, lines: number) ---@field GetTextTruncateLines fun(self: fontstring) : number ----@class statusbar : frame ----@field SetStatusBarColor fun(self: statusbar, r: red|number, g: green|number, b: blue|number, a: alpha|number) ----@field SetStatusBarTexture fun(self: statusbar, path: string) ----@field SetMinMaxValues fun(self: statusbar, minValue: number, maxValue: number) ----@field SetValue fun(self: statusbar, value: number) ----@field SetValueStep fun(self: statusbar, valueStep: number) ----@field SetOrientation fun(self: statusbar, orientation: string) ----@field SetReverseFill fun(self: statusbar, reverseFill: boolean) ----@field GetMinMaxValues fun(self: statusbar) : number, number ----@field GetValue fun(self: statusbar) : number ----@field GetValueStep fun(self: statusbar) : number ----@field GetOrientation fun(self: statusbar) : string ----@field GetReverseFill fun(self: statusbar) : boolean - ----@class texture : UIObject ----@field SetDrawLayer fun(self: texture, layer: string, subLayer: number|nil) +---@class texture : region +---@field SetDrawLayer fun(self: texture, layer: "background"|"border"|"artwork"|"overlay"|"highlight", subLayer: number|nil) ---@field SetTexture fun(self: texture, path: string) ----@field SetColorTexture fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number) +---@field SetColorTexture fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number|nil) ---@field SetDesaturated fun(self: texture, desaturate: boolean) ----@field SetBlendMode fun(self: texture, mode: string) ----@field SetVertexColor fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number) ----@field SetAlpha fun(self: texture, alpha: number) ----@field GetAlpha fun(self: texture) : number ----@field SetWidth fun(self: texture, width: number) ----@field SetHeight fun(self: texture, height: number) ----@field GetWidth fun(self: texture) : number ----@field GetHeight fun(self: texture) : number ----@field SetPoint fun(self: texture, point: string, relativeFrame: table, relativePoint: string, xOfs: number, yOfs: number) +---@field SetBlendMode fun(self: texture, mode: "ADD"|"BLEND"|"DISABLE"|"MOD"|"MOD2X"|"OVERLAY"|"REPLACE"|"SUBTRACT") +---@field SetVertexColor fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number|nil) ---@field GetPoint fun(self: texture, index: number) : string, table, string, number, number ---@field SetShown fun(self: texture, state: boolean) ---@field IsShown fun(self: texture) : boolean ----@field SetParent fun(self: texture, parent: table) ---@field GetParent fun(self: texture) : table ----@field SetScale fun(self: texture, scale: number) ----@field GetScale fun(self: texture) : number ---@field SetTexCoord fun(self: texture, left: number, right: number, top: number, bottom: number) ---@field GetTexCoord fun(self: texture) : number, number, number, number ---@field SetRotation fun(self: texture, rotation: number) @@ -263,20 +286,40 @@ ---@field GetBlendMode fun(self: texture) : string ---@field GetVertexColor fun(self: texture) : number, number, number, number + + + + + + +---@class details +---@field GetInstance fun(self: details) : instance +---@field GetWindow fun(self: details) : instance this is an alias of GetInstance +---@field GetCombat fun(self: details) : combat +---@field GetSpellSchoolFormatedName fun(self: details, spellschool: number) : string +---@field CommaValue fun(self: details, number: number) : string +---@field CreateEventListener fun(self: details) : table + +---@class detailseventlistener : table +---@field RegisterEvent fun(self: detailseventlistener, event: "DETAILS_INSTANCE_OPEN"|"DETAILS_INSTANCE_CLOSE"|"DETAILS_INSTANCE_SIZECHANGED"|"DETAILS_INSTANCE_STARTRESIZE"|"DETAILS_INSTANCE_ENDRESIZE"|"DETAILS_INSTANCE_STARTSTRETCH"|"DETAILS_INSTANCE_ENDSTRETCH"|"DETAILS_INSTANCE_CHANGESEGMENT"|"DETAILS_INSTANCE_CHANGEATTRIBUTE"|"DETAILS_INSTANCE_CHANGEMODE"|"DETAILS_INSTANCE_NEWROW"|"DETAILS_OPTIONS_MODIFIED"|"DETAILS_DATA_RESET"|"DETAILS_DATA_SEGMENTREMOVED"|"COMBAT_ENCOUNTER_START"|"COMBAT_ENCOUNTER_END"|"COMBAT_PLAYER_ENTER"|"COMBAT_PLAYER_LEAVE"|"COMBAT_PLAYER_TIMESTARTED"|"COMBAT_BOSS_WIPE"|"COMBAT_BOSS_DEFEATED"|"COMBAT_BOSS_FOUND"|"COMBAT_INVALID"|"COMBAT_PREPOTION_UPDATED"|"COMBAT_CHARTTABLES_CREATING"|"COMBAT_CHARTTABLES_CREATED"|"COMBAT_ENCOUNTER_PHASE_CHANGED"|"COMBAT_ARENA_START"|"COMBAT_ARENA_END"|"COMBAT_MYTHICDUNGEON_START"|"COMBAT_MYTHICDUNGEON_END"|"GROUP_ONENTER"|"GROUP_ONLEAVE"|"ZONE_TYPE_CHANGED"|"REALM_CHANNEL_ENTER"|"REALM_CHANNEL_LEAVE"|"COMM_EVENT_RECEIVED"|"COMM_EVENT_SENT"|"UNIT_SPEC"|"UNIT_TALENTS"|"PLAYER_TARGET"|"DETAILS_PROFILE_APPLYED", callback: function) +---@field UnregisterEvent fun(self: detailseventlistener, event: "DETAILS_INSTANCE_OPEN"|"DETAILS_INSTANCE_CLOSE"|"DETAILS_INSTANCE_SIZECHANGED"|"DETAILS_INSTANCE_STARTRESIZE"|"DETAILS_INSTANCE_ENDRESIZE"|"DETAILS_INSTANCE_STARTSTRETCH"|"DETAILS_INSTANCE_ENDSTRETCH"|"DETAILS_INSTANCE_CHANGESEGMENT"|"DETAILS_INSTANCE_CHANGEATTRIBUTE"|"DETAILS_INSTANCE_CHANGEMODE"|"DETAILS_INSTANCE_NEWROW"|"DETAILS_OPTIONS_MODIFIED"|"DETAILS_DATA_RESET"|"DETAILS_DATA_SEGMENTREMOVED"|"COMBAT_ENCOUNTER_START"|"COMBAT_ENCOUNTER_END"|"COMBAT_PLAYER_ENTER"|"COMBAT_PLAYER_LEAVE"|"COMBAT_PLAYER_TIMESTARTED"|"COMBAT_BOSS_WIPE"|"COMBAT_BOSS_DEFEATED"|"COMBAT_BOSS_FOUND"|"COMBAT_INVALID"|"COMBAT_PREPOTION_UPDATED"|"COMBAT_CHARTTABLES_CREATING"|"COMBAT_CHARTTABLES_CREATED"|"COMBAT_ENCOUNTER_PHASE_CHANGED"|"COMBAT_ARENA_START"|"COMBAT_ARENA_END"|"COMBAT_MYTHICDUNGEON_START"|"COMBAT_MYTHICDUNGEON_END"|"GROUP_ONENTER"|"GROUP_ONLEAVE"|"ZONE_TYPE_CHANGED"|"REALM_CHANNEL_ENTER"|"REALM_CHANNEL_LEAVE"|"COMM_EVENT_RECEIVED"|"COMM_EVENT_SENT"|"UNIT_SPEC"|"UNIT_TALENTS"|"PLAYER_TARGET"|"DETAILS_PROFILE_APPLYED") + ---@class combat : table ----@field GetCombatTime fun(combat) ----@field GetDeaths fun(combat) --get the table which contains the deaths of the combat ---@field end_time number ---@field start_time number ----@field GetStartTime fun(combat: combat, time: number) ----@field SetStartTime fun(combat: combat, time: number) ----@field GetEndTime fun(combat: combat, time: number) ----@field SetEndTime fun(combat: combat, time: number) ----@field CopyDeathsFrom fun(combat1: combat, combat2: combat, bMythicPlus: boolean) copy the deaths from combat2 to combat1, use true on bMythicPlus if the combat is from a mythic plus run ----@field GetContainer fun(combat: combat, containerType: number) get an actor container, containerType can be 1 for damage, 2 heal, 3 energy, 4 utility ---@field is_mythic_dungeon_trash boolean ---@field is_mythic_dungeon_run_id number ---@field is_mythic_dungeon_segment boolean +---@field GetCombatTime fun(combat) : number +---@field GetDeaths fun(combat) : table --get the table which contains the deaths of the combat +---@field GetStartTime fun(combat: combat) : number +---@field SetStartTime fun(combat: combat, time: number) +---@field GetEndTime fun(combat: combat) : number +---@field SetEndTime fun(combat: combat, time: number) +---@field CopyDeathsFrom fun(combat1: combat, combat2: combat, bMythicPlus: boolean) copy the deaths from combat2 to combat1, use true on bMythicPlus if the combat is from a mythic plus run +---@field GetContainer fun(combat: combat, containerType: number) : actorcontainer get an actor container, containerType can be 1 for damage, 2 heal, 3 energy, 4 utility +---@field GetSpellCastAmount fun(combat: combat, actorName: string, spellId: number) : number get the amount of times a spell was casted +---@field GetSpellUptime fun(combat: combat, actorName: string, spellId: number, auraType: string|nil) : number get the uptime of a buff or debuff ---@class actorcontainer : table ---@field _ActorTable table @@ -289,24 +332,73 @@ ---@field GetActorTable fun(container: actorcontainer) get the table which contains the actors ---@field ListActors fun(container: actorcontainer) usage: for index, actorObject in container:ListActors() do - ---@class spellcontainer : table +---@field GetSpell fun(container: spellcontainer, spellId: number) get a spell by its id +---@field ListActors fun(container: spellcontainer) : pairs usage: for spellId, spelltable in container:ListActors() do ---@field _ActorTable table ---@class spelltable : table +---@field uptime number +---@field total number +---@field spellschool number +---@field counter number amount of hits +---@field c_amt number critical hits by a damage or heal spell +---@field c_min number min damage or healing done by critical hits of the spell +---@field c_max number min damage or healing done by critical hits of the spell +---@field c_total number total damage or heal made by critical hits of the spell +---@field n_amt number normal hits by a damage or heal spell +---@field n_min number min damage or healing done by normal hits of the spell +---@field n_max number min damage or healing done by normal hits of the spell +---@field n_total number total damage or heal made by normal hits of the spell +---@field targets table store the [target name] = total value +---@field targets_overheal table +---@field targets_absorbs table +---@field id number --spellid +---@field is_shield boolean --true if the spell is a shield +---@field successful_casted number successful casted times (only for enemies) +---@field g_amt number glacing hits +---@field g_dmg number +---@field r_amt number --resisted +---@field r_dmg number +---@field b_amt number --blocked +---@field b_dmg number +---@field a_amt number --absorved +---@field a_dmg number +---@field isReflection boolean +---@field totalabsorb number healing absorbed +---@field absorbed number damage absorbed by shield | healing absorbed by buff or debuff +---@field overheal number +---@field totaldenied number + +---@class targettable : {[string]: number} ---@class actor : table +---@field GetSpellContainer fun(actor: actor, containerType: "debuff"|"buff"|"spell"|"cooldowns") : spellcontainer +---@field Name fun(actor: actor) : string get the name of the actor +---@field Tempo fun(actor: actor) : number get the activity or effective time of the actor +---@field GetPets fun(actor: actor) : table get a table with all pet names that belong to the player +---@field GetSpellList fun(actor: actor) : table +---@field BuildSpellTargetFromBreakdownSpellData fun(actor: actor, bkSpellData: spelltableadv) : table +---@field BuildSpellTargetFromSpellTable fun(actor: actor, spellTable: spelltable) : table ---@field debuff_uptime_spells table ---@field buff_uptime_spells table ---@field spells table +---@field aID number|string +---@field spellicon number|string ---@field cooldowns_defensive_spells table ---@field nome string ---@field serial string +---@field spec number ---@field grupo boolean ---@field fight_component boolean ---@field boss_fight_component boolean ---@field boss boolean ---@field last_event unixtime +---@field total_without_pet number +---@field total number +---@field spell_cast table +---@field pets table +---@field targets targettable ---@class segmentid : number ---@class instanceid : number @@ -344,7 +436,160 @@ ---@field RefreshData fun(instance: instance, force: boolean|nil) ---@field RefreshWindow fun(instance: instance, force: boolean|nil) - +---@class tabframe : frame this is the tab frame object for the breakdown window + +---@class breakdownscrolldata : table +---@field totalValue number total done by the actor +---@field combatTime number +---@field [spelltableadv] spelltableadv indexed part of the table + +---@class breakdownexpandbutton : button +---@field texture texture + +---@class breakdownspellscrollframe : df_scrollboxmixin, scrollframe +---@field Header df_headerframe +---@field RefreshMe fun(scrollFrame: breakdownspellscrollframe, data: table|nil) + +---@class breakdowntargetscrollframe : df_scrollboxmixin, scrollframe +---@field Header df_headerframe +---@field RefreshMe fun(scrollFrame: breakdowntargetscrollframe, data: table|nil) + +---@class breakdowntargetbar : button, df_headerfunctions +---@field index number +---@field rank number +---@field name string +---@field percent number +---@field amount number +---@field total number +---@field actorName string +---@field bkTargetData breakdowntargettable +---@field Icon texture +---@field InLineTexts fontstring[] +---@field statusBar breakdownspellbarstatusbar + +---@class breakdownspellbar : button, df_headerfunctions +---@field index number +---@field rank number +---@field spellId number +---@field name string +---@field combatTime number +---@field perSecond number +---@field percent number +---@field amountCasts number +---@field average number +---@field castAverage number +---@field onMouseUpTime number GetTime() of when the spellbar got OnMouseUp event +---@field cursorPosX number mouse position when the spellbar got OnMouseDown event +---@field cursorPosY number mouse position when the spellbar got OnMouseDown event +---@field spellTable spelltable +---@field bkSpellData spelltableadv +---@field statusBar breakdownspellbarstatusbar +---@field expandButton breakdownexpandbutton +---@field spellIconFrame frame +---@field spellIcon texture +---@field targetsSquareFrame breakdowntargetframe +---@field targetsSquareTexture texture +---@field overlayTexture texture +---@field bIsExpandedSpell boolean +---@field ExpandedChildren breakdownspellbar[] store the spellbars which are expanded from this spellbar (spellbars shown when the expand button is pressed) +---@field InLineTexts fontstring[] + +---@class breakdownspellbarstatusbar : statusbar +---@field backgroundTexture texture +---@field overlayTexture texture +---@field highlightTexture texture + +---spelltableadv is similar to spelltable but allow custom members, methods and any modification isn't save to saved variables +---@class spelltableadv : spelltable, spelltablemixin +---@field expanded boolean if is true the show the nested spells +---@field spellTables spelltable[] +---@field spellIds number[] +---@field petNames string[] +---@field bCanExpand boolean +---@field expandedIndex number +---@field bIsExpanded boolean +---@field statusBarValue number + +---@class breakdowntargetframe : frame +---@field spellId number +---@field bkSpellData spelltableadv +---@field spellTable spelltable +---@field texture texture +---@field bIsMainLine boolean + +---@class breakdowntargettablelist : breakdowntargettable[] +---@field totalValue number +---@field totalValueOverheal number +---@field combatTime number + +---@class breakdowntargettable : table +---@field name string +---@field total number +---@field overheal number|nil +---@field absorbed number|nil +---@field statusBarValue number + +---@class breakdownspelldatalist : spelltableadv[] +---@field totalValue number +---@field combatTime number + +---@class breakdownspellstab : tabframe +---@field SpellScrollFrame breakdownspellscrollframe +---@field SpellBlockFrame breakdownspellblockframe + +---@class breakdownspellblockframe : frame container for the spellblocks in the breakdown window +---@field SpellBlocks breakdownspellblock[] +---@field UpdateBlocks fun(self: breakdownspellblockframe) +---@field ClearBlocks fun(self: breakdownspellblockframe) +---@field GetBlock fun(self: breakdownspellblockframe, index: number) : breakdownspellblock + +---@class breakdownspellblock : statusbar breakdownspellblock object which is created inside the breakdownspellblockframe +---@field Lines breakdownspellblockline[] +---@field reportButton button +---@field overlay texture +---@field statusBarTexture texture +---@field sparkTexture texture +---@field gradientTexture texture +---@field backgroundTexture texture +---@field GetLine fun(self: breakdownspellblock, index: number) : breakdownspellblockline +---@field GetLines fun(self: breakdownspellblock) : breakdownspellblockline, breakdownspellblockline, breakdownspellblockline +---@field SetColor fun(self: breakdownspellblock, r: any, g: number|nil, b: number|nil, a: number|nil) + +---@class breakdownspellblockline : frame a line inside a breakdownspellblock, there's 3 of them in each breakdownspellblock +---@field leftText fontstring +---@field centerText fontstring +---@field rightText fontstring + +---@class breakdownspelltab +---@field selectedSpellBar breakdownspellbar +---@field TabFrame breakdownspellstab +---@field mainAttribute number +---@field subAttribute number +---@field GetActor fun() : actor +---@field GetCombat fun() : combat +---@field GetInstance fun() : instance +---@field GetSpellScrollFrame fun() : breakdownspellscrollframe +---@field GetSpellBlockFrame fun() : breakdownspellblockframe +---@field GetTargetScrollFrame fun() : breakdowntargetscrollframe +---@field GetSpellScrollContainer fun() : df_framecontainer +---@field GetSpellBlockContainer fun() : df_framecontainer +---@field GetTargetScrollContainer fun() : df_framecontainer +---@field OnProfileChange fun() +---@field UpdateHeadersSettings fun(containerType: string) +---@field BuildHeaderTable fun(containerType: string) : {name: string, width: number, text: string, align: string}[] +---@field SelectSpellBar fun(spellBar: breakdownspellbar) +---@field UnSelectSpellBar fun() +---@field GetSelectedSpellBar fun() : breakdownspellbar +---@field HasSelectedSpellBar fun() : boolean +---@field OnShownTab fun() +---@field OnCreateTabCallback fun(tabButton: button, tabFrame: frame) +---@field CreateSpellBlock fun(spellBlockContainer: breakdownspellblockframe, index: number) : breakdownspellblock +---@field CreateSpellBlockContainer fun(tabFrame: tabframe) : breakdownspellblockframe +---@field UpdateShownSpellBlock fun() +---@field CreateTargetContainer fun(tabFrame: tabframe) : breakdowntargetscrollframe +---@field CreateSpellScrollContainer fun(tabFrame: tabframe) : breakdownspellscrollframe +---@field CreateTargetBar fun(self: breakdowntargetscrollframe, index: number) : breakdowntargetbar +---@field CreateSpellBar fun(self: breakdownspellscrollframe, index: number) : breakdownspellbar diff --git a/Details.toc b/Details.toc index 5015b2ae..b47178bc 100644 --- a/Details.toc +++ b/Details.toc @@ -87,6 +87,8 @@ frames\window_playerbreakdown_list.lua frames\window_playerbreakdown_compare.lua frames\window_playerbreakdown_avoidance.lua frames\window_playerbreakdown_auras.lua +frames\window_playerbreakdown_spells.lua +frames\window_playerbreakdown_spells_options.lua frames\window_report.lua frames\window_main.lua frames\window_custom.lua @@ -113,6 +115,7 @@ frames\window_statistics.lua frames\window_aura_tracker.lua classes\class_error.lua +classes\class_spelltable.lua classes\class_combat.lua classes\class_damage.lua classes\class_spelldamage.lua diff --git a/Details_Wrath.toc b/Details_Wrath.toc index 18fd73ce..47c42a78 100644 --- a/Details_Wrath.toc +++ b/Details_Wrath.toc @@ -80,6 +80,8 @@ frames\window_playerbreakdown_list.lua frames\window_playerbreakdown_compare.lua frames\window_playerbreakdown_avoidance.lua frames\window_playerbreakdown_auras.lua +frames\window_playerbreakdown_spells.lua +frames\window_playerbreakdown_spells_options.lua frames\window_report.lua frames\window_main.lua frames\window_custom.lua diff --git a/Libs/DF/containers.lua b/Libs/DF/containers.lua new file mode 100644 index 00000000..c8fa90fd --- /dev/null +++ b/Libs/DF/containers.lua @@ -0,0 +1,559 @@ + +local detailsFramework = _G ["DetailsFramework"] +if (not detailsFramework or not DetailsFrameworkCanLoad) then + return +end + +local _ +local DF = detailsFramework + +local CreateFrame = CreateFrame +local wipe = wipe +local unpack = unpack + +---@class df_framecontainer : frame, dfframecontainermixin, df_optionsmixin +---@field bIsSizing boolean +---@field options table +---@field currentWidth number +---@field currentHeight number +---@field bottomLeftResizer framecontainerresizer +---@field bottomRightResizer framecontainerresizer +---@field topLeftResizer framecontainerresizer +---@field topRightResizer framecontainerresizer +---@field topResizer framecontainerresizer +---@field bottomResizer framecontainerresizer +---@field leftResizer framecontainerresizer +---@field rightResizer framecontainerresizer +---@field cornerResizers framecontainerresizer[] +---@field sideResizers framecontainerresizer[] +---@field components table +---@field moverFrame frame +---@field movableChildren table +---@field settingChangedCallback fun(frameContainer: df_framecontainer, settingName: string, settingValue: any) +---@field OnSizeChanged fun(frameContainer: df_framecontainer) +---@field OnResizerMouseDown fun(resizerButton: button, mouseButton: string) +---@field OnResizerMouseUp fun(resizerButton: button, mouseButton: string) +---@field HideResizer fun(frameContainer: df_framecontainer) +---@field ShowResizer fun(frameContainer: df_framecontainer) +---@field OnInitialize fun(frameContainer: df_framecontainer) +---@field SetResizeLocked fun(frameContainer: df_framecontainer, isLocked: boolean) +---@field SetMovableLocked fun(frameContainer: df_framecontainer, isLocked: boolean) +---@field CheckResizeLockedState fun(frameContainer: df_framecontainer) +---@field CheckMovableLockedState fun(frameContainer: df_framecontainer) +---@field CreateMover fun(frameContainer: df_framecontainer) +---@field CreateResizers fun(frameContainer: df_framecontainer) +---@field RegisterChildForDrag fun(frameContainer: df_framecontainer, child: frame) +---@field UnregisterChildForDrag fun(frameContainer: df_framecontainer, child: frame) +---@field RefreshChildrenState fun(frameContainer: df_framecontainer) +---@field OnChildDragStart fun(frameContainer: df_framecontainer, child: frame) +---@field OnChildDragStop fun(frameContainer: df_framecontainer, child: frame) +---@field SetSettingChangedCallback fun(frameContainer: df_framecontainer, callback: fun(frameContainer: df_framecontainer, settingName: string, settingValue: any)) +---@field SendSettingChangedCallback fun(frameContainer: df_framecontainer, settingName: string, settingValue: any) + + + +---@class framecontainerresizer : button +---@field sizingFrom string + +---@class dfframecontainermixin +detailsFramework.FrameContainerMixin = { + --methods + + ---run when the user click on the resizer + ---@param resizerButton framecontainerresizer + ---@param mouseButton string + OnResizerMouseDown = function(resizerButton, mouseButton) + if (mouseButton ~= "LeftButton") then + return + end + + ---@type df_framecontainer + local frameContainer = resizerButton:GetParent() --Cannot assign `frame` to `df_framecontainer`. .. but df_framecontainer is inherited from frame + + if (frameContainer.bIsSizing) then + return + end + + frameContainer.bIsSizing = true + frameContainer:StartSizing(resizerButton.sizingFrom) + end, + + ---run when the user click on the resizer + ---@param resizerButton framecontainerresizer + ---@param mouseButton string + OnResizerMouseUp = function(resizerButton, mouseButton) + ---@type df_framecontainer + local frameContainer = resizerButton:GetParent() --Cannot assign `frame` to `df_framecontainer`. .. but df_framecontainer is inherited from frame + + if (not frameContainer.bIsSizing) then + return + end + + frameContainer:StopMovingOrSizing() + frameContainer.bIsSizing = false + end, + + ---hide resizer + ---@param frameContainer df_framecontainer + HideResizer = function(frameContainer) + for i = 1, #frameContainer.cornerResizers do + frameContainer.cornerResizers[i]:Hide() + end + + for i = 1, #frameContainer.sideResizers do + frameContainer.sideResizers[i]:Hide() + end + end, + + ---show resizer + ---@param frameContainer df_framecontainer + ShowResizer = function(frameContainer) + --corner resizers + if (frameContainer.options.use_bottomleft_resizer) then + frameContainer.bottomLeftResizer:Show() + end + if (frameContainer.options.use_bottomright_resizer) then + frameContainer.bottomRightResizer:Show() + end + if (frameContainer.options.use_topleft_resizer) then + frameContainer.topRightResizer:Show() + end + if (frameContainer.options.use_topright_resizer) then + frameContainer.topRightResizer:Show() + end + + --side resizers + if (frameContainer.options.use_top_resizer) then + frameContainer.topResizer:Show() + end + if (frameContainer.options.use_bottom_resizer) then + frameContainer.bottomResizer:Show() + end + if (frameContainer.options.use_left_resizer) then + frameContainer.leftResizer:Show() + end + if (frameContainer.options.use_right_resizer) then + frameContainer.rightResizer:Show() + end + end, + + ---check the lock state and show or hide the resizer, set the frame as movable or not, resizeable or not + ---@param frameContainer df_framecontainer + CheckResizeLockedState = function(frameContainer) + if (frameContainer.options.is_locked) then + frameContainer:HideResizer() + frameContainer:SetResizable(false) + else + frameContainer:ShowResizer() + frameContainer:SetResizable(true) + end + end, + + ---check if the framecontainer can be moved and show or hide the mover + ---@param frameContainer df_framecontainer + CheckMovableLockedState = function(frameContainer) + if (frameContainer.options.is_movement_locked) then + frameContainer:SetMovable(false) + frameContainer:EnableMouse(false) + frameContainer.moverFrame:Hide() + else + frameContainer:SetMovable(true) + frameContainer:EnableMouse(true) + frameContainer.moverFrame:Show() + end + end, + + ---set the lock state + ---@param frameContainer df_framecontainer + ---@param isLocked boolean + SetResizeLocked = function(frameContainer, isLocked) + frameContainer.options.is_locked = isLocked + frameContainer:SendSettingChangedCallback("is_locked", isLocked) + frameContainer:CheckResizeLockedState() + end, + + ---set the state of the mover frame + ---@param frameContainer df_framecontainer + ---@param isLocked boolean + SetMovableLocked = function(frameContainer, isLocked) + frameContainer.options.is_movement_locked = isLocked + frameContainer:SendSettingChangedCallback("is_movement_locked", isLocked) + frameContainer:CheckMovableLockedState() + end, + + ---create a mover to move the frame + ---@param frameContainer df_framecontainer + CreateMover = function(frameContainer) + local mover = CreateFrame("button", nil, frameContainer) + frameContainer.moverFrame = mover + mover:SetAllPoints(frameContainer) + mover:EnableMouse(false) + mover:SetMovable(true) + mover:SetScript("OnMouseDown", function(self, mouseButton) + if (mouseButton ~= "LeftButton" or frameContainer.options.is_movement_locked) then + return + end + frameContainer:StartMoving() + end) + mover:SetScript("OnMouseUp", function(self, mouseButton) + if (mouseButton ~= "LeftButton" or frameContainer.options.is_movement_locked) then + return + end + frameContainer:StopMovingOrSizing() + end) + end, + + ---create four corner resizer and four side resizer + ---@param frameContainer df_framecontainer + CreateResizers = function(frameContainer) + local parent = frameContainer:GetParent() + --create resizers for the container corners + local bottomLeftResizer, bottomRightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "BottomLeftResizer", parent:GetName() .. "BottomRightResizer") + frameContainer.bottomLeftResizer = bottomLeftResizer + frameContainer.bottomRightResizer = bottomRightResizer + + local topLeftResizer, topRightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "TopLeftResizer", parent:GetName() .. "TopRightResizer") + frameContainer.topLeftResizer = topLeftResizer + frameContainer.topRightResizer = topRightResizer + + local topResizer, bottomResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "TopResizer", parent:GetName() .. "BottomResizer") + frameContainer.topResizer = topResizer + frameContainer.bottomResizer = bottomResizer + + local leftResizer, rightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "LeftResizer", parent:GetName() .. "RightResizer") + frameContainer.leftResizer = leftResizer + frameContainer.rightResizer = rightResizer + + frameContainer.cornerResizers = { + bottomLeftResizer, + bottomRightResizer, + topLeftResizer, + topRightResizer, + } + + frameContainer.sideResizers = { + topResizer, + bottomResizer, + leftResizer, + rightResizer, + } + + --add all resizers to the frameContainer.components table + for i = 1, #frameContainer.cornerResizers do + frameContainer.components[frameContainer.cornerResizers[i]] = true + end + for i = 1, #frameContainer.sideResizers do + frameContainer.components[frameContainer.sideResizers[i]] = true + end + + --hide all resizers + frameContainer:HideResizer() + end, + + ---run when the container is created + ---@param frameContainer df_framecontainer + OnInitialize = function(frameContainer) --õninit ~init ~oninit + --set the default members + frameContainer.bIsSizing = false + frameContainer:SetSize(frameContainer.options.width, frameContainer.options.height) + + --iterate among the corner resizers and set the mouse down and up scripts + for i = 1, #frameContainer.cornerResizers do + frameContainer.cornerResizers[i]:SetScript("OnMouseDown", frameContainer.OnResizerMouseDown) + frameContainer.cornerResizers[i]:SetScript("OnMouseUp", frameContainer.OnResizerMouseUp) + end + + local sideResizeThickness = 2 + + --iterate among the side resizers and set the mouse down and up scripts; set the texture color; clear all points; set the thickness + for i = 1, #frameContainer.sideResizers do + frameContainer.sideResizers[i]:SetScript("OnMouseDown", frameContainer.OnResizerMouseDown) + frameContainer.sideResizers[i]:SetScript("OnMouseUp", frameContainer.OnResizerMouseUp) + + frameContainer.sideResizers[i]:GetNormalTexture():SetColorTexture(1, 1, 1, 0.6) + frameContainer.sideResizers[i]:GetHighlightTexture():SetColorTexture(detailsFramework:ParseColors("aqua")) + frameContainer.sideResizers[i]:GetPushedTexture():SetColorTexture(1, 1, 1, 1) + + frameContainer.sideResizers[i]:ClearAllPoints() + + --can use SetSize here because the width or height are set by the point, e.g. 'topleft' to 'topright' overwrite the width set here + frameContainer.sideResizers[i]:SetSize(sideResizeThickness, sideResizeThickness) + end + + --flip the corner resizers texturess + frameContainer.topLeftResizer:GetNormalTexture():SetTexCoord(1, 0, 1, 0) + frameContainer.topLeftResizer:GetHighlightTexture():SetTexCoord(1, 0, 1, 0) + frameContainer.topLeftResizer:GetPushedTexture():SetTexCoord(1, 0, 1, 0) + frameContainer.topRightResizer:GetNormalTexture():SetTexCoord(0, 1, 1, 0) + frameContainer.topRightResizer:GetHighlightTexture():SetTexCoord(0, 1, 1, 0) + frameContainer.topRightResizer:GetPushedTexture():SetTexCoord(0, 1, 1, 0) + frameContainer.topLeftResizer:ClearAllPoints() + frameContainer.topLeftResizer:SetPoint("topleft", frameContainer, "topleft", 0, 0) + frameContainer.topRightResizer:ClearAllPoints() + frameContainer.topRightResizer:SetPoint("topright", frameContainer, "topright", 0, 0) + + --resize from for the corner resizers + frameContainer.bottomLeftResizer.sizingFrom = "bottomleft" + frameContainer.bottomRightResizer.sizingFrom = "bottomright" + frameContainer.topLeftResizer.sizingFrom = "topleft" + frameContainer.topRightResizer.sizingFrom = "topright" + + --resize from for the side resizers + frameContainer.topResizer.sizingFrom = "top" + frameContainer.bottomResizer.sizingFrom = "bottom" + frameContainer.leftResizer.sizingFrom = "left" + frameContainer.rightResizer.sizingFrom = "right" + + --set the side resizer points + frameContainer.topResizer:SetPoint("topleft", frameContainer, "topleft", 0, 2) + frameContainer.topResizer:SetPoint("topright", frameContainer, "topright", 0, 2) + frameContainer.bottomResizer:SetPoint("bottomleft", frameContainer, "bottomleft", 0, -2) + frameContainer.bottomResizer:SetPoint("bottomright", frameContainer, "bottomright", 0, -2) + frameContainer.leftResizer:SetPoint("topleft", frameContainer, "topleft", -2, 0) + frameContainer.leftResizer:SetPoint("bottomleft", frameContainer, "bottomleft", -2, 0) + frameContainer.rightResizer:SetPoint("topright", frameContainer, "topright", 2, 0) + frameContainer.rightResizer:SetPoint("bottomright", frameContainer, "bottomright", 2, 0) + + if (frameContainer.options.is_locked) then + frameContainer:HideResizer() + else + frameContainer:ShowResizer() + end + + frameContainer:CheckResizeLockedState() + frameContainer:CheckMovableLockedState() + frameContainer:SetResizeBounds(50, 50, 1000, 1000) + end, + + ---run when the container has its size changed + ---@param frameContainer df_framecontainer + OnSizeChanged = function(frameContainer) + ---@type frame[] + local children = {frameContainer:GetChildren()} + ---@type number + local childrenAmount = #children + + --get the container size before its size was changed and calculate the percent of the difference between the old size and the new size + --adding +1 to the width and height difference to prevent the child from shrinking to 0, so it is scaled by 1 + ---@type number + local widthDifference = 1 + (frameContainer:GetWidth() - frameContainer.currentWidth) / frameContainer.currentWidth + ---@type number + local heightDifference = 1 + (frameContainer:GetHeight() - frameContainer.currentHeight) / frameContainer.currentHeight + + for i = 1, childrenAmount do + ---@type frame + local child = children[i] + --if the child is a component, skip it + if (not frameContainer.components[child]) then + child:SetWidth(child:GetWidth() * widthDifference) + child:SetHeight(child:GetHeight() * heightDifference) + end + end + + --update the current size of the container + frameContainer.currentWidth = frameContainer:GetWidth() + frameContainer.currentHeight = frameContainer:GetHeight() + + frameContainer:SendSettingChangedCallback("width", frameContainer.currentWidth) + frameContainer:SendSettingChangedCallback("height", frameContainer.currentHeight) + end, + + OnChildDragStop = function(child) + child:StopMovingOrSizing() + child:SetScript("OnUpdate", nil) + end, + + ---@param child frame + OnChildDragStart = function(child) + ---@type df_framecontainer + local frameContainer = child:GetParent() + + ---get the coordinates for the frame container, which is called 'boundingBox' for convenience + ---@type objectcoordinates + local boundingBox = detailsFramework:GetObjectCoordinates(frameContainer) + + child:StartMoving() + + --save the current point of the child, so it can be restored if the child is dragged outside the container + local childPoints = {} + for pointIndex = 1, child:GetNumPoints() do + childPoints[pointIndex] = {child:GetPoint(pointIndex)} + end + + child:SetScript("OnUpdate", function(self) + ---@type objectcoordinates + local childPos = detailsFramework:GetObjectCoordinates(self) + --check if the borders of the rectangle 'rec' collided with the borders of the rectangle 'bbox' + if ((childPos.left < boundingBox.left or childPos.right > boundingBox.right) or (childPos.top > boundingBox.top or childPos.bottom < boundingBox.bottom)) then + child:ClearAllPoints() + for pointIndex = 1, #childPoints do + child:SetPoint(unpack(childPoints[pointIndex])) + end + else + wipe(childPoints) + for pointIndex = 1, child:GetNumPoints() do + childPoints[pointIndex] = {child:GetPoint(pointIndex)} + end + end + end) + end, + + ---check if the children can be moved and set the properties on thisFrame + ---@param frameContainer df_framecontainer + RefreshChildrenState = function(frameContainer) + frameContainer:EnableMouse(true) + if (frameContainer.options.can_move_children) then + for child, _ in pairs(frameContainer.movableChildren) do + child:EnableMouse(true) + child:SetMovable(true) + child:RegisterForDrag("LeftButton") + child:SetScript("OnDragStart", detailsFramework.FrameContainerMixin.OnChildDragStart) + child:SetScript("OnDragStop", detailsFramework.FrameContainerMixin.OnChildDragStop) + end + else + for child, _ in pairs(frameContainer.movableChildren) do + child:EnableMouse(false) + child:SetMovable(false) + child:RegisterForDrag("") + child:SetScript("OnDragStart", nil) + child:SetScript("OnDragStop", nil) + end + end + end, + + ---@param frameContainer df_framecontainer + ---@param child frame + RegisterChildForDrag = function(frameContainer, child) + frameContainer.movableChildren[child] = true + frameContainer:RefreshChildrenState() + child:SetFrameStrata(frameContainer:GetFrameStrata()) + child:SetFrameLevel(frameContainer:GetFrameLevel() + 1) + end, + + ---@param frameContainer df_framecontainer + ---@param child frame + UnregisterChildForDrag = function(frameContainer, child) + frameContainer.movableChildren[child] = nil + frameContainer:RefreshChildrenState() + end, + + ---@param frameContainer df_framecontainer + ---@param callback function + SetSettingChangedCallback = function(frameContainer, callback) + frameContainer.settingChangedCallback = callback + end, + + ---send a callback to the setting changed callback + ---@param frameContainer df_framecontainer + ---@param key string + ---@param value any + SendSettingChangedCallback = function(frameContainer, key, value) + if (type(frameContainer.settingChangedCallback) == "function") then + detailsFramework:Dispatch(frameContainer.settingChangedCallback, frameContainer, key, value) + end + end, +} + +---these are the default settings for the frame container; these keys can be accessed by df_framecontainer.options[key] +---@type table +local frameContainerOptions = { + --default settings + width = 300, + height = 150, + is_locked = true, --can or not be resized + is_movement_locked = true, --can or not be moved + can_move_children = true, + use_topleft_resizer = false, + use_topright_resizer = false, + use_bottomleft_resizer = false, + use_bottomright_resizer = false, + use_top_resizer = false, + use_bottom_resizer = false, + use_left_resizer = false, + use_right_resizer = false, +} + +---create a frame container, which is a frame that envelops another frame, and can be moved, resized, etc. +---@param parent frame +---@param options table|nil +---@param frameName string|nil +---@return df_framecontainer +function DF:CreateFrameContainer(parent, options, frameName) + ---@type df_framecontainer + local frameContainer = CreateFrame("frame", frameName or ("$parentFrameContainer" .. math.random(10000, 99999)), parent, "BackdropTemplate") + frameContainer.components = {} + frameContainer.movableChildren = {} + frameContainer:EnableMouse(false) + + detailsFramework:Mixin(frameContainer, detailsFramework.FrameContainerMixin) + detailsFramework:Mixin(frameContainer, detailsFramework.OptionsFunctions) + + frameContainer:CreateResizers() + frameContainer:CreateMover() + frameContainer:BuildOptionsTable(frameContainerOptions, options) + + frameContainer:OnInitialize() + + frameContainer.currentWidth = frameContainer:GetWidth() + frameContainer.currentHeight = frameContainer:GetHeight() + frameContainer:SetScript("OnSizeChanged", frameContainer.OnSizeChanged) + + return frameContainer +end + + + + +function DF:CreateFrameContainerTest(parent, options, frameName) + local container = DF:CreateFrameContainer(parent, options, frameName) + container:SetSize(400, 400) + container:SetPoint("center", _G.UIParent, "center", 0, 0) + + detailsFramework:ApplyStandardBackdrop(container) + + local verticalLastBox = nil + for i = 1, 4 do + local lastBox = nil + for o = 1, 4 do + local frame = CreateFrame("frame", "$parentFrame" .. i .. o, container, "BackdropTemplate") + container:RegisterChildForDrag(frame) + + frame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + frame:SetBackdropColor(0, 0, 0, 0.5) + frame:SetBackdropBorderColor(1, 1, 1, 0.5) + frame:SetSize(98, 98) + if (lastBox) then + frame:SetPoint("TOPLEFT", lastBox, "topright", 1, 0) + else + if (verticalLastBox) then + frame:SetPoint("TOPLEFT", verticalLastBox, "bottomleft", 0, -1) + verticalLastBox = frame + else + local x = 1 + (o - 1) * 99 + local y = -10 - (i - 1) * 99 + frame:SetPoint("TOPLEFT", container, "TOPLEFT", x, y) + verticalLastBox = frame + end + end + lastBox = frame + end + end + + C_Timer.After(2, function() + --container:SetResizeLocked(true) + end) +end + +--C_Timer.After(2, function() +-- DetailsFramework:CreateFrameContainerTest(UIParent) +--end) + +--[=[ + /run DetailsFramework:CreateFrameContainerTest(UIParent) + + C_Timer.After(2, function() + DetailsFramework:CreateFrameContainerTest(UIParent) + end) + + +--]=] \ No newline at end of file diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index 5196683b..0e952edb 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 421 +local dversion = 422 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -827,35 +827,34 @@ end ---@param value number ---@return string function DF:IntegerToTimer(value) --~formattime - return "" .. floor(value/60) .. ":" .. format("%02.f", value%60) + return "" .. math.floor(value/60) .. ":" .. string.format("%02.f", value%60) end ---remove the realm name from a name ---@param name string ----@return string +---@return string, number function DF:RemoveRealmName(name) return name:gsub(("%-.*"), "") end ---remove the realm name from a name ---@param name string ----@return string +---@return string, number function DF:RemoveRealName(name) return name:gsub(("%-.*"), "") end ---get the UIObject of type 'FontString' named fontString and set the font size to the maximum value of the arguments ----@param fontString FontString +---@param fontString fontstring ---@vararg number function DF:SetFontSize(fontString, ...) local font, _, flags = fontString:GetFont() - fontString:SetFont(font, max(...), flags) + fontString:SetFont(font, math.max(...), flags) end ---get the UIObject of type 'FontString' named fontString and set the font to the argument fontface ----@param fontString FontString +---@param fontString fontstring ---@param fontface string ----@return nil function DF:SetFontFace(fontString, fontface) local font = SharedMedia:Fetch("font", fontface, true) if (font) then @@ -867,26 +866,24 @@ function DF:SetFontFace(fontString, fontface) end ---get the FontString passed and set the font color ----@param fontString FontString +---@param fontString fontstring ---@param r any ---@param g number|nil ---@param b number|nil ---@param a number|nil ----@return nil function DF:SetFontColor(fontString, r, g, b, a) r, g, b, a = DF:ParseColors(r, g, b, a) fontString:SetTextColor(r, g, b, a) end ---get the FontString passed and set the font shadow color and offset ----@param fontString FontString +---@param fontString fontstring ---@param r number ---@param g number ---@param b number ---@param a number ---@param x number ---@param y number ----@return nil function DF:SetFontShadow(fontString, r, g, b, a, x, y) r, g, b, a = DF:ParseColors(r, g, b, a) fontString:SetShadowColor(r, g, b, a) @@ -899,9 +896,8 @@ function DF:SetFontShadow(fontString, r, g, b, a, x, y) end ---get the FontString object passed and set the rotation of the text shown ----@param fontString FontString +---@param fontString fontstring ---@param degrees number ----@return nil function DF:SetFontRotation(fontString, degrees) if (type(degrees) == "number") then if (not fontString.__rotationAnimation) then @@ -3343,8 +3339,11 @@ function DF:OpenInterfaceProfile() end ----------------------------- ---safe copy from blizz api -function DF:Mixin(object, ...) +---copy all members from #2 ... to #1 object +---@param object table +---@param ... any +---@return any +function DF:Mixin(object, ...) --safe copy from blizz api for i = 1, select("#", ...) do local mixin = select(i, ...) for key, value in pairs(mixin) do diff --git a/Libs/DF/header.lua b/Libs/DF/header.lua new file mode 100644 index 00000000..eceab551 --- /dev/null +++ b/Libs/DF/header.lua @@ -0,0 +1,634 @@ + +local detailsFramework = DetailsFramework + +if (not detailsFramework or not DetailsFrameworkCanLoad) then + return +end + +local unpack = unpack +local CreateFrame = CreateFrame +local geterrorhandler = geterrorhandler +local wipe = wipe + +--definitions +---@class df_headerchild : uiobject +---@field FramesToAlign table + +---@class df_headerframe : frame, df_headermixin, df_optionsmixin +---@field columnHeadersCreated df_headercolumnframe[] +---@field options table +---@field HeaderTable table +---@field columnSelected number + +---@class df_headermixin : table +---@field NextHeader number +---@field HeaderWidth number +---@field HeaderHeight number +---@field OnColumnSettingChangeCallback function +---@field GetColumnWidth fun(self: df_headerframe, columnId: number) +---@field SetHeaderTable fun(self: df_headerframe, newTable) +---@field GetSelectedColumn fun(self: df_headerframe) : number, string, string +---@field Refresh fun(self: df_headerframe) +---@field UpdateSortArrow fun(self: df_headerframe, columnHeader: df_headercolumnframe, defaultShown: boolean|nil, defaultOrder: string|nil) +---@field UpdateColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe, headerIndex) +---@field ResetColumnHeaderBackdrop fun(self: df_headerframe, columnHeader: df_headercolumnframe) +---@field SetBackdropColorForSelectedColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe) +---@field ClearColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe) +---@field GetNextHeader fun(self: df_headerframe) : df_headercolumnframe +---@field SetColumnSettingChangedCallback fun(self: df_headerframe, func: function) : boolean + +---@class df_headercolumnframe : frame +---@field Icon texture +---@field Text fontstring +---@field Arrow texture +---@field Separator texture +---@field resizerButton df_headerresizer +---@field bIsRezising boolean +---@field bInUse boolean +---@field columnData table +---@field order string +---@field columnIndex number +---@field columnAlign string +---@field XPosition number +---@field columnOffset number +---@field key string used to sort the values + +---@class df_headerresizer : button +---@field texture texture + +--mixed functions +---@class df_headerfunctions : table +detailsFramework.HeaderFunctions = { + ---comment + ---@param self df_headerchild + ---@param frame uiobject + AddFrameToHeaderAlignment = function(self, frame) + self.FramesToAlign = self.FramesToAlign or {} + table.insert(self.FramesToAlign, frame) + end, + + ---comment + ---@param self df_headerchild + ResetFramesToHeaderAlignment = function(self) + wipe(self.FramesToAlign) + end, + + SetFramesToHeaderAlignment = function(self, ...) + ---@cast self df_headerchild + wipe(self.FramesToAlign) + self.FramesToAlign = {...} + end, + + GetFramesFromHeaderAlignment = function(self, frame) + return self.FramesToAlign or {} + end, + + ---@param self uiobject + ---@param headerFrame df_headerframe + ---@param anchor string + AlignWithHeader = function(self, headerFrame, anchor) + local columnHeaderFrames = headerFrame.columnHeadersCreated + anchor = anchor or "topleft" + + ---@cast self df_headerchild + + for i = 1, #self.FramesToAlign do + local frame = self.FramesToAlign[i] + frame:ClearAllPoints() + + ---@type df_headercolumnframe + local columnHeader = columnHeaderFrames[i] + if (columnHeader) then + local offset = 0 + + if (columnHeader.columnAlign == "right") then + offset = columnHeader:GetWidth() + if (frame:GetObjectType() == "FontString") then + frame:SetJustifyH("right") + end + end + + frame:SetPoint(columnHeader.columnAlign, self, anchor, columnHeader.XPosition + columnHeader.columnOffset + offset, 0) + end + end + end, + + ---comment + ---@param columnHeader df_headercolumnframe + ---@param buttonClicked string + OnClick = function(columnHeader, buttonClicked) + --get the header main frame + ---@type df_headerframe + local headerFrame = columnHeader:GetParent() + + --if this header does not have a clickable header, just ignore + if (not headerFrame.columnSelected) then + return + end + + --check if this column has 'canSort' key, otherwise ignore the click + if (not columnHeader.columnData.canSort) then + return + end + + --get the latest column header selected + ---@type df_headercolumnframe + local previousColumnHeader = headerFrame.columnHeadersCreated[headerFrame.columnSelected] + previousColumnHeader.Arrow:Hide() + headerFrame:ResetColumnHeaderBackdrop(previousColumnHeader) + headerFrame:SetBackdropColorForSelectedColumnHeader(columnHeader) + + if (headerFrame.columnSelected == columnHeader.columnIndex) then + columnHeader.order = columnHeader.order ~= "ASC" and "ASC" or "DESC" + end + headerFrame.columnOrder = columnHeader.order + + --set the new column header selected + headerFrame.columnSelected = columnHeader.columnIndex + + headerFrame:UpdateSortArrow(columnHeader) + + if (headerFrame.options.header_click_callback) then + --callback with the main header frame, column header, column index and column order as payload + local okay, errortext = pcall(headerFrame.options.header_click_callback, headerFrame, columnHeader, columnHeader.columnIndex, columnHeader.order) + if (not okay) then + print("DF: Header onClick callback error:", errortext) + end + end + end, + + ---comment + ---@param self button + ---@param buttonClicked string + OnMouseDown = function(self, buttonClicked) + if (buttonClicked == "LeftButton") then + + end + end, + + ---comment + ---@param self button + ---@param buttonClicked string + OnMouseUp = function(self, buttonClicked) + if (buttonClicked == "LeftButton") then + + end + end, +} + +---@class df_headermixin : table +detailsFramework.HeaderMixin = { + ---@param self df_headerframe + ---@param columnId number + ---@return number + GetColumnWidth = function(self, columnId) + return self.HeaderTable[columnId].width + end, + + ---@param self df_headerframe + ---@param newTable table + SetHeaderTable = function(self, newTable) + self.columnHeadersCreated = self.columnHeadersCreated or {} + self.HeaderTable = newTable + self.NextHeader = 1 + self.HeaderWidth = 0 + self.HeaderHeight = 0 + self:Refresh() + end, + + ---@param self df_headerframe + ---@param func function + ---@return boolean + SetColumnSettingChangedCallback = function(self, func) + if (type(func) ~= "function") then + self.OnColumnSettingChangeCallback = nil + return false + end + self.OnColumnSettingChangeCallback = func + return true + end, + + --return which header is current selected and the the order ASC DESC + ---@param self df_headerframe + ---@return number, string + GetSelectedColumn = function(self) + ---@type number + local columnSelected = self.columnSelected + ---@type df_headercolumnframe + local columnHeader = self.columnHeadersCreated[columnSelected or 1] + + return columnSelected, columnHeader.order, columnHeader.key + end, + + --clean up and rebuild the header following the header options + --@self: main header frame + ---@param self df_headerframe + Refresh = function(self) + --refresh background frame + self:SetBackdrop(self.options.backdrop) + self:SetBackdropColor(unpack(self.options.backdrop_color)) + self:SetBackdropBorderColor(unpack(self.options.backdrop_border_color)) + + --reset all header frames + for i = 1, #self.columnHeadersCreated do + local columnHeader = self.columnHeadersCreated[i] + columnHeader.bInUse = false + columnHeader:Hide() + end + + local previousColumnHeader + local growDirection = string.lower(self.options.grow_direction) + + --amount of headers to be updated + local headerSize = #self.HeaderTable + + --update header frames + for i = 1, headerSize do + --get the header button, a new one is created if it doesn't exists yet + local columnHeader = self:GetNextHeader() + self:UpdateColumnHeader(columnHeader, i) + + --grow direction + if (not previousColumnHeader) then + columnHeader:SetPoint("topleft", self, "topleft", 0, 0) + + if (growDirection == "right") then + if (self.options.use_line_separators) then + columnHeader.Separator:Show() + columnHeader.Separator:SetWidth(self.options.line_separator_width) + columnHeader.Separator:SetColorTexture(unpack(self.options.line_separator_color)) + + columnHeader.Separator:ClearAllPoints() + if (self.options.line_separator_gap_align) then + columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0) + else + columnHeader.Separator:SetPoint("topright", columnHeader, "topright", 0, 0) + end + columnHeader.Separator:SetHeight(self.options.line_separator_height) + end + end + else + if (growDirection == "right") then + columnHeader:SetPoint("topleft", previousColumnHeader, "topright", self.options.padding, 0) + + if (self.options.use_line_separators) then + columnHeader.Separator:Show() + columnHeader.Separator:SetWidth(self.options.line_separator_width) + columnHeader.Separator:SetColorTexture(unpack(self.options.line_separator_color)) + + columnHeader.Separator:ClearAllPoints() + if (self.options.line_separator_gap_align) then + columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0) + else + columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0) + end + columnHeader.Separator:SetHeight(self.options.line_separator_height) + + if (headerSize == i) then + columnHeader.Separator:Hide() + end + end + + elseif (growDirection == "left") then + columnHeader:SetPoint("topright", previousColumnHeader, "topleft", -self.options.padding, 0) + + elseif (growDirection == "bottom") then + columnHeader:SetPoint("topleft", previousColumnHeader, "bottomleft", 0, -self.options.padding) + + elseif (growDirection == "top") then + columnHeader:SetPoint("bottomleft", previousColumnHeader, "topleft", 0, self.options.padding) + end + end + + previousColumnHeader = columnHeader + end + + self:SetSize(self.HeaderWidth, self.HeaderHeight) + end, + + ---@param self df_headerframe + ---@param columnHeader df_headercolumnframe + ---@param defaultShown boolean + ---@param defaultOrder string + UpdateSortArrow = function(self, columnHeader, defaultShown, defaultOrder) + local options = self.options + local order = defaultOrder or columnHeader.order + local arrowIcon = columnHeader.Arrow + + if (type(defaultShown) ~= "boolean") then + arrowIcon:Show() + else + arrowIcon:SetShown(defaultShown) + if (defaultShown) then + self:SetBackdropColorForSelectedColumnHeader(columnHeader) + end + end + + arrowIcon:SetAlpha(options.arrow_alpha) + + if (order == "ASC") then + arrowIcon:SetTexture(options.arrow_up_texture) + arrowIcon:SetTexCoord(unpack(options.arrow_up_texture_coords)) + arrowIcon:SetSize(unpack(options.arrow_up_size)) + + elseif (order == "DESC") then + arrowIcon:SetTexture(options.arrow_down_texture) + arrowIcon:SetTexCoord(unpack(options.arrow_down_texture_coords)) + arrowIcon:SetSize(unpack(options.arrow_down_size)) + end + end, + + ---@param self df_headerframe + ---@param columnHeader df_headercolumnframe + ---@param headerIndex number + UpdateColumnHeader = function(self, columnHeader, headerIndex) + --this is the data to update the columnHeader + local columnData = self.HeaderTable[headerIndex] + + columnHeader.key = columnData.key or "total" + + if (columnData.icon) then + columnHeader.Icon:SetTexture(columnData.icon) + + if (columnData.texcoord) then + columnHeader.Icon:SetTexCoord(unpack(columnData.texcoord)) + else + columnHeader.Icon:SetTexCoord(0, 1, 0, 1) + end + + columnHeader.Icon:SetPoint("left", columnHeader, "left", self.options.padding, 0) + columnHeader.Icon:Show() + end + + if (columnData.text) then + columnHeader.Text:SetText(columnData.text) + + --text options + detailsFramework:SetFontColor(columnHeader.Text, self.options.text_color) + detailsFramework:SetFontSize(columnHeader.Text, self.options.text_size) + detailsFramework:SetFontOutline(columnHeader.Text, self.options.text_shadow) + + --point + if (not columnData.icon) then + columnHeader.Text:SetPoint("left", columnHeader, "left", self.options.padding, 0) + else + columnHeader.Text:SetPoint("left", columnHeader.Icon, "right", self.options.padding, 0) + end + + columnHeader.Text:Show() + end + + --column header index + columnHeader.columnIndex = headerIndex + + if (columnData.canSort) then + columnHeader.order = "DESC" + columnHeader.Arrow:SetTexture(self.options.arrow_up_texture) + else + columnHeader.Arrow:Hide() + end + + if (columnData.selected) then + columnHeader.Arrow:Show() + columnHeader.Arrow:SetAlpha(.843) + self:UpdateSortArrow(columnHeader, true, columnHeader.order) + self.columnSelected = headerIndex + else + if (columnData.canSort) then + self:UpdateSortArrow(columnHeader, false, columnHeader.order) + end + end + + --size + if (columnData.width) then + columnHeader:SetWidth(columnData.width) + end + if (columnData.height) then + columnHeader:SetHeight(columnData.height) + end + + columnHeader.XPosition = self.HeaderWidth -- + self.options.padding + columnHeader.YPosition = self.HeaderHeight -- + self.options.padding + + columnHeader.columnAlign = columnData.align or "left" + columnHeader.columnOffset = columnData.offset or 0 + + --add the header piece size to the total header size + local growDirection = string.lower(self.options.grow_direction) + + if (growDirection == "right" or growDirection == "left") then + self.HeaderWidth = self.HeaderWidth + columnHeader:GetWidth() + self.options.padding + self.HeaderHeight = math.max(self.HeaderHeight, columnHeader:GetHeight()) + + elseif (growDirection == "top" or growDirection == "bottom") then + self.HeaderWidth = math.max(self.HeaderWidth, columnHeader:GetWidth()) + self.HeaderHeight = self.HeaderHeight + columnHeader:GetHeight() + self.options.padding + end + + local bShowColumnHeaderReziser = self.options.reziser_shown + if (bShowColumnHeaderReziser) then + local resizerButton = columnHeader.resizerButton + resizerButton:Show() + resizerButton.texture:SetVertexColor(unpack(self.options.reziser_color)) + resizerButton:SetWidth(self.options.reziser_width) + resizerButton:SetHeight(columnHeader:GetHeight()) + else + columnHeader.resizerButton:Hide() + end + + columnHeader:Show() + columnHeader.bInUse = true + columnHeader.columnData = columnData + end, + + ---reset column header backdrop + ---@param self df_headerframe + ---@param columnHeader df_headercolumnframe + ResetColumnHeaderBackdrop = function(self, columnHeader) + columnHeader:SetBackdrop(self.options.header_backdrop) + columnHeader:SetBackdropColor(unpack(self.options.header_backdrop_color)) + columnHeader:SetBackdropBorderColor(unpack(self.options.header_backdrop_border_color)) + end, + + ---@param self df_headerframe + ---@param columnHeader df_headercolumnframe + SetBackdropColorForSelectedColumnHeader = function(self, columnHeader) + columnHeader:SetBackdropColor(unpack(self.options.header_backdrop_color_selected)) + end, + + ---clear the column header + ---@param self df_headerframe + ---@param columnHeader df_headercolumnframe + ClearColumnHeader = function(self, columnHeader) + columnHeader:SetSize(self.options.header_width, self.options.header_height) + self:ResetColumnHeaderBackdrop(columnHeader) + + columnHeader:ClearAllPoints() + + columnHeader.Icon:SetTexture("") + columnHeader.Icon:Hide() + columnHeader.Text:SetText("") + columnHeader.Text:Hide() + end, + + ---get the next column header, create one if doesn't exists + ---@param self df_headerframe + GetNextHeader = function(self) + local nextHeader = self.NextHeader + local columnHeader = self.columnHeadersCreated[nextHeader] + + if (not columnHeader) then + --create a new column header + ---@type df_headercolumnframe + columnHeader = CreateFrame("button", "$parentHeaderIndex" .. nextHeader, self, "BackdropTemplate") + columnHeader:SetScript("OnClick", detailsFramework.HeaderFunctions.OnClick) + columnHeader:SetMovable(true) + columnHeader:SetResizable(true) + + --header icon + detailsFramework:CreateImage(columnHeader, "", self.options.header_height, self.options.header_height, "ARTWORK", nil, "Icon", "$parentIcon") + --header separator + detailsFramework:CreateImage(columnHeader, "", 1, 1, "ARTWORK", nil, "Separator", "$parentSeparator") + --header name text + detailsFramework:CreateLabel(columnHeader, "", self.options.text_size, self.options.text_color, "GameFontNormal", "Text", "$parentText", "ARTWORK") + --header selected and order icon + detailsFramework:CreateImage(columnHeader, self.options.arrow_up_texture, 12, 12, "ARTWORK", nil, "Arrow", "$parentArrow") + + ---rezise button + ---@type df_headerresizer + local resizerButton = CreateFrame("button", "$parentResizer", columnHeader) + resizerButton:SetWidth(4) + resizerButton:SetFrameLevel(columnHeader:GetFrameLevel()+2) + resizerButton:SetPoint("topright", columnHeader, "topright", -1, -1) + resizerButton:SetPoint("bottomright", columnHeader, "bottomright", -1, 1) + resizerButton:EnableMouse(true) + resizerButton:RegisterForClicks("LeftButtonDown", "LeftButtonUp") + columnHeader.resizerButton = resizerButton + + resizerButton:SetScript("OnEnter", function() + resizerButton.texture:SetVertexColor(1, 1, 1, 0.9) + end) + + resizerButton:SetScript("OnLeave", function() + resizerButton.texture:SetVertexColor(unpack(self.options.reziser_color)) + end) + + resizerButton:SetScript("OnMouseDown", function() --move this to a single function + if (not columnHeader.bIsRezising) then + --get the string length to know the min size + local textLength = columnHeader.Text:GetStringWidth() + 6 + columnHeader:SetResizeBounds(math.max(textLength, self.options.reziser_min_width), columnHeader:GetHeight(), self.options.reziser_max_width, columnHeader:GetHeight()) + columnHeader.bIsRezising = true + columnHeader:StartSizing("right") + end + end) + + resizerButton:SetScript("OnMouseUp", function() + if (columnHeader.bIsRezising) then + columnHeader.bIsRezising = false + columnHeader:StopMovingOrSizing() + + --callback or modify into a passed by table? + if (self.OnColumnSettingChangeCallback) then --need to get the header name + local columnName = columnHeader.columnData.name + xpcall(self.OnColumnSettingChangeCallback, geterrorhandler(), self, "width", columnName, columnHeader:GetWidth()) + end + end + end) + + resizerButton:SetScript("OnHide", function() + if (columnHeader.bIsRezising) then + columnHeader:StopMovingOrSizing() + columnHeader.bIsRezising = false + end + end) + + resizerButton.texture = resizerButton:CreateTexture(nil, "overlay") + resizerButton.texture:SetAllPoints() + resizerButton.texture:SetColorTexture(1, 1, 1, 1) + + local xOffset = self.options.reziser_shown and -5 or -1 + columnHeader.Arrow:SetPoint("right", columnHeader, "right", xOffset, 0) + + columnHeader.Separator:Hide() + columnHeader.Arrow:Hide() + + self:UpdateSortArrow(columnHeader, false, "DESC") + + table.insert(self.columnHeadersCreated, columnHeader) + columnHeader = columnHeader + end + + self:ClearColumnHeader(columnHeader) + self.NextHeader = self.NextHeader + 1 + return columnHeader + end, + + NextHeader = 1, + HeaderWidth = 0, + HeaderHeight = 0, +} + +local default_header_options = { + backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, + backdrop_color = {0, 0, 0, 0.2}, + backdrop_border_color = {0.1, 0.1, 0.1, .2}, + + text_color = {1, 1, 1, 1}, + text_size = 10, + text_shadow = false, + grow_direction = "RIGHT", + padding = 2, + + reziser_shown = false, --make sure to set the callback function with: header:SetOnColumnResizeScript(callbackFunction) + reziser_width = 2, + reziser_color = {1, 0.6, 0, 0.6}, + reziser_min_width = 16, + reziser_max_width = 200, + + --each piece of the header + header_backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, + header_backdrop_color = {0, 0, 0, 0.5}, + header_backdrop_color_selected = {0.3, 0.3, 0.3, 0.5}, + header_backdrop_border_color = {0, 0, 0, 0}, + header_width = 120, + header_height = 20, + + arrow_up_texture = [[Interface\Buttons\Arrow-Up-Down]], + arrow_up_texture_coords = {0, 1, 6/16, 1}, + arrow_up_size = {12, 11}, + arrow_down_texture = [[Interface\Buttons\Arrow-Down-Down]], + arrow_down_texture_coords = {0, 1, 0, 11/16}, + arrow_down_size = {12, 11}, + arrow_alpha = 0.659, + + use_line_separators = false, + line_separator_color = {.1, .1, .1, .6}, + line_separator_width = 1, + line_separator_height = 200, + line_separator_gap_align = false, +} + +---create a header frame +---@param parent frame +---@param headerTable table +---@param options table|nil +---@param frameName string|nil +---@return df_headerframe +function detailsFramework:CreateHeader(parent, headerTable, options, frameName) + ---@type df_headerframe + local newHeader = CreateFrame("frame", frameName or "$parentHeaderLine", parent, "BackdropTemplate") + + detailsFramework:Mixin(newHeader, detailsFramework.OptionsFunctions) + detailsFramework:Mixin(newHeader, detailsFramework.HeaderMixin) + + newHeader:BuildOptionsTable(default_header_options, options) + + newHeader:SetBackdrop(newHeader.options.backdrop) + newHeader:SetBackdropColor(unpack(newHeader.options.backdrop_color)) + newHeader:SetBackdropBorderColor(unpack(newHeader.options.backdrop_border_color)) + + newHeader:SetHeaderTable(headerTable) + + return newHeader +end \ No newline at end of file diff --git a/Libs/DF/load.xml b/Libs/DF/load.xml index 7380d8d5..fa46ad83 100644 --- a/Libs/DF/load.xml +++ b/Libs/DF/load.xml @@ -4,6 +4,8 @@