From 9222cc1491281ec01e48de359d7d1f873c440ab0 Mon Sep 17 00:00:00 2001 From: Tercio Jose Date: Sat, 29 Apr 2023 22:57:02 -0300 Subject: [PATCH] Added Targets, Added Options --- Definitions.lua | 52 +- Details.toc | 1 + Details_Wrath.toc | 1 + Libs/DF/header.lua | 3 +- classes/class_damage.lua | 27 + classes/class_heal.lua | 52 ++ frames/window_playerbreakdown.lua | 15 +- frames/window_playerbreakdown_spells.lua | 619 +++++++++++++++--- .../window_playerbreakdown_spells_options.lua | 278 ++++++++ functions/mixin.lua | 18 +- functions/profiles.lua | 9 +- 11 files changed, 958 insertions(+), 117 deletions(-) create mode 100644 frames/window_playerbreakdown_spells_options.lua diff --git a/Definitions.lua b/Definitions.lua index 1756c70b..cc2317e5 100644 --- a/Definitions.lua +++ b/Definitions.lua @@ -291,6 +291,7 @@ ---@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 @@ -301,21 +302,21 @@ ---@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) : table 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 ---@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 @@ -364,6 +365,7 @@ ---@field overheal number ---@field totaldenied number +---@class targettable : {[string]: number} ---@class actor : table ---@field GetSpellContainer fun(actor: actor, containerType: string) @@ -389,6 +391,7 @@ ---@field total number ---@field spell_cast table ---@field pets table +---@field targets targettable ---@class segmentid : number ---@class instanceid : number @@ -438,8 +441,21 @@ ---@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 bkTargetData breakdowntargettable +---@field Icon texture +---@field InLineTexts fontstring[] +---@field statusBar breakdownspellbarstatusbar ---@class breakdownspellbar : button, df_headerfunctions ---@field index number @@ -484,6 +500,7 @@ ---@field bCanExpand boolean ---@field expandedIndex number ---@field bIsExpanded boolean +---@field statusBarValue number ---@class breakdowntargetframe : frame ---@field spellId number @@ -492,6 +509,18 @@ ---@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 @@ -514,6 +543,7 @@ ---@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 diff --git a/Details.toc b/Details.toc index 36fbc7f7..b47178bc 100644 --- a/Details.toc +++ b/Details.toc @@ -88,6 +88,7 @@ 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/Details_Wrath.toc b/Details_Wrath.toc index 6ef3fc4f..47c42a78 100644 --- a/Details_Wrath.toc +++ b/Details_Wrath.toc @@ -81,6 +81,7 @@ 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/header.lua b/Libs/DF/header.lua index a6ae5887..922360ad 100644 --- a/Libs/DF/header.lua +++ b/Libs/DF/header.lua @@ -546,7 +546,8 @@ detailsFramework.HeaderMixin = { resizerButton.texture:SetAllPoints() resizerButton.texture:SetColorTexture(1, 1, 1, 1) - columnHeader.Arrow:SetPoint("right", columnHeader, "right", -1, 0) + local xOffset = self.options.reziser_shown and -5 or -1 + columnHeader.Arrow:SetPoint("right", columnHeader, "right", xOffset, 0) columnHeader.Separator:Hide() columnHeader.Arrow:Hide() diff --git a/classes/class_damage.lua b/classes/class_damage.lua index ba613f81..2130786a 100644 --- a/classes/class_damage.lua +++ b/classes/class_damage.lua @@ -4494,6 +4494,8 @@ function atributo_damage:MontaInfoDamageDone() --I guess this fills the list of ---@type string local playerName = actorObject:Name() + local attribute, subAttribute = instance:GetDisplay() + --guild ranking on a boss --check if is a raid encounter and if is heroic or mythic do @@ -4641,6 +4643,31 @@ function atributo_damage:MontaInfoDamageDone() --I guess this fills the list of --send to the breakdown window Details222.BreakdownWindow.SendSpellData(breakdownSpellDataList, actorObject, combatObject, instance) + --targets + + ---an array of breakdowntargettable + ---@type breakdowntargettablelist + local targetList = {} + + local targetTotalValue = 0 + + local targetsTable = self:GetTargets() + for targetName, amount in pairs(targetsTable) do + ---@class breakdowntargettable + local bkTargetData = { + name = targetName, + total = amount, + overheal = 0, + } + targetTotalValue = targetTotalValue + amount + tinsert(targetList, bkTargetData) + end + + targetList.totalValue = targetTotalValue + targetList.combatTime = actorCombatTime + + Details222.BreakdownWindow.SendTargetData(targetList, actorObject, combatObject, instance) + if 1 then return end --to be deprecated and removed: diff --git a/classes/class_heal.lua b/classes/class_heal.lua index 8a5ed242..f563e457 100644 --- a/classes/class_heal.lua +++ b/classes/class_heal.lua @@ -1997,6 +1997,58 @@ function atributo_heal:MontaInfoHealingDone() --send to the breakdown window Details222.BreakdownWindow.SendSpellData(actorSpellsSorted, actorObject, combatObject, instance) + --targets + + ---an array of breakdowntargettable + ---@type breakdowntargettable[] + local targetList = {} + + --get the targets table: in the class heal, an actor has two targets table, one for normal healing and one for overheal + ---@type targettable + local normalTargetsTable = self:GetTargets("targets") + ---@type targettable + local overhealTargetsTable = self:GetTargets("targets_overheal") + + local targetTotalValue = 0 + local targetOverhealTotalValue = 0 + + --build the data required by the breakdown window + for targetName, amount in pairs(normalTargetsTable) do + if (amount > 0) then + local overhealAmount = overhealTargetsTable[targetName] or 0 + ---@type breakdowntargettable + local bkTargetData = { + name = targetName, + total = amount, + overheal = overhealAmount, + } + targetTotalValue = targetTotalValue + amount + targetOverhealTotalValue = targetOverhealTotalValue + (overhealAmount) + tinsert(targetList, bkTargetData) + end + end + + for targetName, amount in pairs(overhealTargetsTable) do + if (amount > 0) then + if (not normalTargetsTable[targetName]) then + ---@type breakdowntargettable + local bkTargetData = { + name = targetName, + total = 0, + overheal = amount, + } + targetOverhealTotalValue = targetOverhealTotalValue + (amount) + tinsert(targetList, bkTargetData) + end + end + end + + targetList.totalValue = targetTotalValue + targetList.totalValueOverheal = targetOverhealTotalValue + targetList.combatTime = actorCombatTime + + Details222.BreakdownWindow.SendTargetData(targetList, actorObject, combatObject, instance) + if 1 then return end local instancia = info.instancia diff --git a/frames/window_playerbreakdown.lua b/frames/window_playerbreakdown.lua index 2d8b5a3e..5aeaef97 100644 --- a/frames/window_playerbreakdown.lua +++ b/frames/window_playerbreakdown.lua @@ -145,7 +145,7 @@ function Details:OpenBreakdownWindow(instanceObject, actorObject, bFromAttribute end if (not breakdownWindow.RightSideBar) then - breakdownWindow:CreateRightSideBar() + --breakdownWindow:CreateRightSideBar() end --todo: all portuguese keys to english @@ -223,7 +223,7 @@ function Details:OpenBreakdownWindow(instanceObject, actorObject, bFromAttribute --spellsTab.ResetBars() --to be implemented ---@type string - local actorClass = actorObject.classe --classe not registered because it should be renamed to english + local actorClass = actorObject.classe --classe not registered because it should be renamed to english 'class' if (not actorClass) then actorClass = "monster" @@ -422,6 +422,17 @@ function Details222.BreakdownWindow.SendSpellData(data, actorObject, combatObjec end end +function Details222.BreakdownWindow.SendTargetData(targetList, actorObject, combatObject, instance) + --need to get the tab showing the summary and transmit the data to it + local tab = Details222.BreakdownWindow.CurrentDefaultTab + if (tab) then + --tab is the tab button + if (tab.OnReceiveTargetData) then + tab.OnReceiveTargetData(targetList, actorObject, combatObject, instance) + end + end +end + function breakdownWindow.SetClassIcon(jogador, classe) if (classe ~= "UNKNOW" and classe ~= "UNGROUPPLAYER") then breakdownWindow.classIcon:SetTexCoord(Details.class_coords [classe][1], Details.class_coords [classe][2], Details.class_coords [classe][3], Details.class_coords [classe][4]) diff --git a/frames/window_playerbreakdown_spells.lua b/frames/window_playerbreakdown_spells.lua index 0e5fb01c..e12b8c4d 100644 --- a/frames/window_playerbreakdown_spells.lua +++ b/frames/window_playerbreakdown_spells.lua @@ -32,13 +32,17 @@ local spellBlockContainerSettings = { local spellBreakdownSettings = {} -local CONST_BAR_HEIGHT = 20 local CONST_TARGET_HEIGHT = 18 - local CONST_SPELLSCROLL_WIDTH = 535 local CONST_SPELLSCROLL_HEIGHT = 311 local CONST_SPELLSCROLL_AMTLINES = 14 + +local CONST_BAR_HEIGHT = 20 local CONST_SPELLSCROLL_LINEHEIGHT = 20 +local CONST_TARGET_TEXTURE = [[Interface\MINIMAP\TRACKING\Target]] +local CONST_SPELLBLOCK_DEFAULT_COLOR = {.4, .4, .4, 1} +local CONST_SPELLBLOCK_HEADERTEXT_COLOR = {.9, .8, 0, 1} +local CONST_SPELLBLOCK_HEADERTEXT_SIZE = 11 Details.SpellGroups = { [193473] = 15407, --mind flay @@ -65,29 +69,46 @@ function spellsTab.GetSpellScrollFrame() return spellsTab.TabFrame.SpellScrollFrame end ----@return df_framecontainer -function spellsTab.GetSpellScrollContainer() - return spellsTab.SpellContainerFrame -end - ---return the breakdownspellblockframe object, there's only one of this in the breakdown window ---@return breakdownspellblockframe function spellsTab.GetSpellBlockFrame() return spellsTab.TabFrame.SpellBlockFrame end +---@return breakdowntargetscrollframe +function spellsTab.GetTargetScrollFrame() + return spellsTab.TargetScrollFrame +end + +---@return df_framecontainer +function spellsTab.GetSpellScrollContainer() + return spellsTab.SpellContainerFrame +end + ---@return df_framecontainer function spellsTab.GetSpellBlockContainer() return spellsTab.BlocksContainerFrame end +---@return df_framecontainer +function spellsTab.GetTargetScrollContainer() + return spellsTab.TargetsContainerFrame +end + + function spellsTab.OnProfileChange() --no need to cache, just call the db from there spellsTab.spellcontainer_header_settings = Details.breakdown_spell_tab.spellcontainer_headers + spellsTab.targetcontainer_header_settings = Details.breakdown_spell_tab.targetcontainer_headers spellsTab.UpdateHeadersSettings("spells") + spellsTab.UpdateHeadersSettings("targets") end ----@type table +------------------------------------------------------------------------------------------------------------------------------------------------ +--Header + +---store the header object has key and its type as value, the header type can be 'spell' or 'target' +---@type table local headerContainerType = {} ---@type number @@ -108,10 +129,11 @@ local settingsPrototype = { ---default settings for the header of the spells container, label is a localized string, name is a string used to save the column settings, key is the key used to get the value from the spell table, width is the width of the column, align is the alignment of the text, enabled is if the column is enabled, canSort is if the column can be sorted, sortKey is the key used to sort the column, dataType is the type of data the column is sorting, order is the order of the sorting, offset is the offset of the column ---@type columndata[] -local spellContainerColumnInfo = { - {name = "icon", width = 22, label = "", align = "center", enabled = true, offset = columnOffset}, - {name = "target", width = 22, label = "", align = "center", enabled = true, offset = columnOffset}, - {name = "rank", label = "#", width = 16, align = "center", enabled = true, offset = columnOffset, dataType = "number"}, +local spellContainerColumnData = { + --the align seems to be bugged as the left is aligning in the center and center is on the left side + {name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset}, + {name = "target", width = 22, label = "", align = "left", enabled = true, offset = columnOffset}, + {name = "rank", label = "#", width = 16, align = "left", enabled = true, offset = columnOffset, dataType = "number"}, {name = "expand", label = "^", width = 16, align = "center", enabled = true, offset = columnOffset}, {name = "name", label = "spell name", width = 246, align = "left", enabled = true, offset = columnOffset}, {name = "amount", label = "total", key = "total", selected = true, width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset}, @@ -126,13 +148,22 @@ local spellContainerColumnInfo = { {name = "absorbed", label = "absorbed", key = "healabsorbed", width = 55, align = "left", enabled = false, canSort = true, order = "DESC", dataType = "number", attribute = DETAILS_ATTRIBUTE_HEAL, offset = columnOffset}, } +local targetContainerColumnData = { + {name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset}, + {name = "rank", label = "#", width = 20, align = "left", enabled = true, offset = columnOffset}, + {name = "name", label = "name", width = 200, align = "left", enabled = true, offset = columnOffset}, + {name = "amount", label = "total", key = "total", selected = true, width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset}, + {name = "overheal", label = "overheal", key = "overheal", width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset, attribute = DETAILS_ATTRIBUTE_HEAL}, + {name = "percent", label = "%", key = "total", width = 50, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"}, +} + ---callback for when the user resizes a column on the header ---@param headerFrame df_headerframe ---@param optionName string ---@param columnName string ---@param value any local onHeaderColumnOptionChanged = function(headerFrame, optionName, columnName, value) - ---@type string + ---@type "spells"|"targets" local containerType = headerContainerType[headerFrame] ---@type table local settings @@ -141,7 +172,7 @@ local onHeaderColumnOptionChanged = function(headerFrame, optionName, columnName settings = spellsTab.spellcontainer_header_settings elseif (containerType == "targets") then - + settings = spellsTab.targetcontainer_header_settings end settings[columnName][optionName] = value @@ -158,6 +189,9 @@ local onColumnHeaderClickCallback = function(headerFrame, columnHeader) if (containerType == "spells") then spellsTab.GetSpellScrollFrame():Refresh() + + elseif (containerType == "targets") then + spellsTab.GetTargetScrollFrame():Refresh() end end @@ -169,19 +203,21 @@ function spellsTab.UpdateHeadersSettings(containerType) ---@type table local settings ---@type table - local containerInfo + local containerColumnData + if (containerType == "spells") then settings = spellsTab.spellcontainer_header_settings - containerInfo = spellContainerColumnInfo + containerColumnData = spellContainerColumnData elseif (containerType == "targets") then - + settings = spellsTab.targetcontainer_header_settings + containerColumnData = targetContainerColumnData end --do a loop and check if the column data from columnInfo exists in the details profile settings, if not, add it - for i = 1, #containerInfo do + for i = 1, #containerColumnData do --default column settings - local columnData = containerInfo[i] + local columnData = containerColumnData[i] ---@type string local columnName = columnData.name @@ -207,11 +243,13 @@ function spellsTab.UpdateHeadersSettings(containerType) spellsTab.GetSpellScrollFrame().Header:SetHeaderTable(spellsTab.spellsHeaderData) elseif (containerType == "targets") then - spellsTab.spellsHeaderData = spellsTab.BuildHeaderTable("targets") + spellsTab.targetsHeaderData = spellsTab.BuildHeaderTable("targets") + spellsTab.GetTargetScrollFrame().Header:SetHeaderTable(spellsTab.targetsHeaderData) end end ----parse the data from details profile and build a table with the data to be used by the header +---get the header settings from details profile and build a header table using the table which store all headers columns information +---the data for each header is stored on 'spellContainerColumnInfo' and 'targetContainerColumnInfo' variables ---@param containerType "spells"|"targets" ---@return {name: string, width: number, text: string, align: string}[] function spellsTab.BuildHeaderTable(containerType) @@ -228,18 +266,19 @@ function spellsTab.BuildHeaderTable(containerType) local settings ---@type table - local containerInfo + local containerColumnData if (containerType == "spells") then settings = spellsTab.spellcontainer_header_settings - containerInfo = spellContainerColumnInfo + containerColumnData = spellContainerColumnData elseif (containerType == "targets") then - + settings = spellsTab.targetcontainer_header_settings + containerColumnData = targetContainerColumnData end - for i = 1, #containerInfo do - local columnData = containerInfo[i] + for i = 1, #containerColumnData do + local columnData = containerColumnData[i] ---@type {enabled: boolean, width: number, align: string} local columnSettings = settings[columnData.name] @@ -270,14 +309,15 @@ function spellsTab.BuildHeaderTable(containerType) headerTable[#headerTable+1] = headerColumnData end - else - --targets end end return headerTable end +------------------------------------------------------------------------------------------------------------------------------------------------ +--Bar Selection + --store the current spellbar selected, this is used to lock the spellblock container to the spellbar selected spellsTab.selectedSpellBar = nil @@ -334,40 +374,38 @@ function spellsTab.OnShownTab() spellsTab.UnSelectSpellBar() --reset the spell blocks spellsTab.GetSpellBlockFrame():ClearBlocks() - --update spells header frame (for the used spells frame) + --update spells and target header frame (spellscroll and targetscroll) spellsTab.UpdateHeadersSettings("spells") + spellsTab.UpdateHeadersSettings("targets") end --called when the tab is getting created, run only once function spellsTab.OnCreateTabCallback(tabButton, tabFrame) --~init + --get the saved variables settings for the headers spellsTab.spellcontainer_header_settings = Details.breakdown_spell_tab.spellcontainer_headers + spellsTab.targetcontainer_header_settings = Details.breakdown_spell_tab.targetcontainer_headers spellBreakdownSettings = Details.breakdown_spell_tab DetailsFramework:ApplyStandardBackdrop(tabFrame) --create the scrollbar to show the spells in the breakdown window - ---@type breakdownspellscrollframe - local spellScrollContainer = spellsTab.CreateSpellScrollContainer(tabFrame) --finished - - --create the 6 spell blocks in the right side of the breakdown window - --these blocks show the spell info like normal hits, critical hits, average, etc - ---@type breakdownspellblockframe - local spellBlockContainer = spellsTab.CreateSpellBlockContainer(tabFrame) - + spellsTab.CreateSpellScrollContainer(tabFrame) --finished + --create the 6 spell blocks in the right side of the breakdown window, these blocks show the spell info like normal hits, critical hits, average, etc + spellsTab.CreateSpellBlockContainer(tabFrame) --create the targets container spellsTab.CreateTargetContainer(tabFrame) --create the report buttons for each container --spellsTab.CreateReportButtons(tabFrame) - --these bars table are kinda deprecated now: - --store the spell bars for the spell container - tabFrame.barras1 = {} --deprecated - --store the special bars shown in the right side of the breakdown window, this is only shown when spellBlocks aren't in use - tabFrame.barras3 = {} --deprecated - spellsTab.TabFrame = tabFrame + --create a button in the breakdown window to open the options for this tab + local optionsButton = DF:CreateButton(Details.playerDetailWindow, Details.OpenSpellBreakdownOptions, 130, 20, "Open Options", 10, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) + optionsButton:SetPoint("topleft", Details.playerDetailWindow, "topleft", 210, -45) + optionsButton.textsize = 15 + optionsButton.textcolor = "white" + --open the breakdown window at startup for testing --[= debug C_Timer.After(1, function() @@ -380,28 +418,28 @@ function spellsTab.OnCreateTabCallback(tabButton, tabFrame) --~init --]=] end ----------------------------------------------------------------------- ---> scripts +--------------------------------------------------------------------------------------------------- +--Scripts --create a details bar on the right side of the window local onEnterSpellBlock = function(spellBlock) --info background is the 6 bars in the right side of the window? - Details.FadeHandler.Fader(spellBlock.overlay, "OUT") - Details.FadeHandler.Fader(spellBlock.reportButton, "OUT") + spellBlock.overlay:Show() + spellBlock.reportButton:Show() end local onLeaveSpellBlock = function(spellBlock) - Details.FadeHandler.Fader(spellBlock.overlay, "IN") - Details.FadeHandler.Fader(spellBlock.reportButton, "IN") + spellBlock.overlay:Hide() + spellBlock.reportButton:Hide() end local onEnterInfoReport = function(self) - Details.FadeHandler.Fader(self:GetParent().overlay, "OUT") - Details.FadeHandler.Fader(self, "OUT") + Details.FadeHandler.Fader(self:GetParent().overlay, 0) + Details.FadeHandler.Fader(self, 0) end local onLeaveInfoReport = function(self) - Details.FadeHandler.Fader(self:GetParent().overlay, "IN") - Details.FadeHandler.Fader(self, "IN") + Details.FadeHandler.Fader(self:GetParent().overlay, 1) + Details.FadeHandler.Fader(self, 1) end ---run this function when the mouse hover over a breakdownspellbar @@ -460,7 +498,7 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis summaryBlock:SetValue(50) summaryBlock:SetValue(100) - if (mainAttribute == DETAILS_ATTRIBUTE_DAMAGE) then --this should run within the damage class + if (mainAttribute == DETAILS_ATTRIBUTE_DAMAGE) then --this should run within the damage class ~damage local bShowDamageDone = subAttribute == DETAILS_SUBATTRIBUTE_DAMAGEDONE or subAttribute == DETAILS_SUBATTRIBUTE_DPS ---@type number @@ -472,7 +510,9 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis do --update the texts in the summary block local blockLine1, blockLine2, blockLine3 = summaryBlock:GetLines() - blockLine1.leftText:SetText(Loc ["STRING_CAST"] .. ": " .. spellBar.amountCasts) --total amount of casts + local totalCasts = spellBar.amountCasts > 0 and spellBar.amountCasts or "(?)" + + blockLine1.leftText:SetText(Loc ["STRING_CAST"] .. ": " .. totalCasts) --total amount of casts blockLine1.rightText:SetText(Loc ["STRING_HITS"]..": " .. totalHits) --hits and uptime blockLine2.leftText:SetText(Loc ["STRING_DAMAGE"]..": " .. Details:Format(spellTable.total)) --total damage @@ -494,7 +534,7 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis local percent = normalHitsAmt / math.max(totalHits, 0.0001) * 100 normalHitsBlock:SetValue(percent) - normalHitsBlock.sparkTexture:SetPoint("left", normalHitsBlock, "left", percent / 100 * normalHitsBlock:GetWidth() + spellBreakdownSettings.blockspell_spark_offset, 0) + normalHitsBlock.sparkTexture:SetPoint("left", normalHitsBlock, "left", percent / 100 * normalHitsBlock:GetWidth() + Details.breakdown_spell_tab.blockspell_spark_offset, 0) local blockLine1, blockLine2, blockLine3 = normalHitsBlock:GetLines() blockLine1.leftText:SetText(Loc ["STRING_NORMAL_HITS"]) @@ -540,7 +580,7 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis blockLine3.rightText:SetText(Loc ["STRING_DPS"] .. ": " .. Details:CommaValue(spellTable.c_total / critTempoPercent)) end - elseif (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then --this should run within the heal class + elseif (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then --this should run within the heal class ~healing ---@type number local totalHits = spellTable.counter @@ -550,7 +590,8 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis do --update the texts in the summary block local blockLine1, blockLine2, blockLine3 = summaryBlock:GetLines() - blockLine1.leftText:SetText(Loc ["STRING_CAST"] .. ": " .. spellBar.amountCasts) --total amount of casts + local totalCasts = spellBar.amountCasts > 0 and spellBar.amountCasts or "(?)" + blockLine1.leftText:SetText(Loc ["STRING_CAST"] .. ": " .. totalCasts) --total amount of casts blockLine1.rightText:SetText(Loc ["STRING_HITS"]..": " .. totalHits) --hits and uptime blockLine2.leftText:SetText(Loc ["STRING_HEAL"]..": " .. Details:Format(spellTable.total)) --total damage @@ -621,10 +662,10 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis ---@type number local overheal = spellTable.overheal or 0 if (overheal > 0) then - blockIndex = blockIndex + 1 --skip one block + --blockIndex = blockIndex + 1 --skip one block ---@type breakdownspellblock - local critHitsBlock = spellBlockContainer:GetBlock(blockIndex) - critHitsBlock:Show() + local overhealBlock = spellBlockContainer:GetBlock(blockIndex) + overhealBlock:Show() blockIndex = blockIndex + 1 local blockName @@ -635,10 +676,12 @@ local onEnterBreakdownSpellBar = function(spellBar, motion) --parei aqui: precis end local percent = overheal / (overheal + spellTable.total) * 100 - critHitsBlock:SetValue(percent) - critHitsBlock.sparkTexture:SetPoint("left", critHitsBlock, "left", percent / 100 * critHitsBlock:GetWidth() + spellBreakdownSettings.blockspell_spark_offset, 0) + overhealBlock:SetValue(percent) + overhealBlock.sparkTexture:SetPoint("left", overhealBlock, "left", percent / 100 * overhealBlock:GetWidth() + spellBreakdownSettings.blockspell_spark_offset, 0) - local blockLine1, blockLine2, blockLine3 = critHitsBlock:GetLines() + overhealBlock:SetColor(1, 0, 0, 0.4) + + local blockLine1, blockLine2, blockLine3 = overhealBlock:GetLines() blockLine1.leftText:SetText(blockName) local overhealString = Details:CommaValue(overheal) @@ -701,7 +744,6 @@ local onMouseUpBreakdownSpellBar = function(spellBar, button) end end - local onEnterSpellIconFrame = function(self) local line = self:GetParent() if (line.spellId and type(line.spellId) == "number") then @@ -721,6 +763,7 @@ local onLeaveSpellIconFrame = function(self) end -------------------------------------------------------------------------------------------------------------------------------------------- +--Spell Blocks local spellBlockMixin = { ---get one of the three lines containing fontstrings to show data @@ -740,6 +783,12 @@ local spellBlockMixin = { GetLines = function(self) return unpack(self.Lines) end, + + ---@param self breakdownspellblock + SetColor = function(self, ...) + local r, g, b, a = DF:ParseColors(...) + self.statusBarTexture:SetColorTexture(r, g, b, a) + end, } ---create a spell block into the spellblockcontainer @@ -752,7 +801,7 @@ function spellsTab.CreateSpellBlock(spellBlockContainer, index) --~breakdownspel DetailsFramework:Mixin(spellBlock, spellBlockMixin) local statusBarTexture = spellBlock:CreateTexture("$parentTexture", "artwork") - statusBarTexture:SetColorTexture(.4, .4, .4, 1) + statusBarTexture:SetColorTexture(unpack(CONST_SPELLBLOCK_DEFAULT_COLOR)) statusBarTexture:SetPoint("topleft", spellBlock, "topleft", 1, -1) statusBarTexture:SetPoint("bottomleft", spellBlock, "bottomleft", 1, 1) spellBlock.statusBarTexture = statusBarTexture @@ -880,9 +929,18 @@ local spellBlockContainerMixin = { local spellBlock = self.SpellBlocks[i] spellBlock:Hide() + spellBlock:SetColor(unpack(CONST_SPELLBLOCK_DEFAULT_COLOR)) + --clear the text shown in their lines for o = 1, 3 do spellBlock.Lines[o].leftText:SetText("") + + --set the color of the top left text in the block, the text is used as header text + if (o == 1) then + DF:SetFontColor(spellBlock.Lines[o].leftText, CONST_SPELLBLOCK_HEADERTEXT_COLOR) + DF:SetFontSize(spellBlock.Lines[o].leftText, CONST_SPELLBLOCK_HEADERTEXT_SIZE) + end + spellBlock.Lines[o].centerText:SetText("") spellBlock.Lines[o].rightText:SetText("") end @@ -901,7 +959,7 @@ local spellBlockContainerMixin = { ---create the spell blocks which shows the critical hits, normal hits, etc ---@param tabFrame tabframe ---@return breakdownspellblockframe -function spellsTab.CreateSpellBlockContainer(tabFrame) +function spellsTab.CreateSpellBlockContainer(tabFrame) --~create --create a container for the scrollframe local options = { width = Details.breakdown_spell_tab.blockcontainer_width, @@ -983,34 +1041,301 @@ function spellsTab.CreateSpellBlockContainer(tabFrame) return spellBlockFrame end -function spellsTab.CreateTargetContainer(tabFrame) - local container_alvos_window = CreateFrame("ScrollFrame", "Details_Info_ContainerAlvosScroll", tabFrame, "BackdropTemplate") - local container_alvos = CreateFrame("Frame", "Details_Info_ContainerAlvos", container_alvos_window, "BackdropTemplate") +function spellsTab.UpdateShownSpellBlock() + if (spellsTab.currentSpellBar) then + onEnterBreakdownSpellBar(spellsTab.currentSpellBar) - container_alvos:SetAllPoints(container_alvos_window) - container_alvos:SetSize(300, 100) - container_alvos:EnableMouse(true) - container_alvos:SetMovable(true) + elseif (spellsTab.GetSelectedSpellBar()) then + onEnterBreakdownSpellBar(spellsTab.GetSelectedSpellBar()) + end - container_alvos_window:SetSize(300, 100) - container_alvos_window:SetScrollChild(container_alvos) - container_alvos_window:SetPoint("bottomleft", tabFrame, "bottomleft", 20, 6) --56 default +end - container_alvos_window:SetScript("OnSizeChanged", function(self) - container_alvos:SetSize(self:GetSize()) - end) +---get a spell bar from the scroll box, if it doesn't exist, return nil +---@param scrollFrame table +---@param lineIndex number +---@return breakdowntargetbar +local getTargetBar = function(scrollFrame, lineIndex) + ---@type breakdowntargetbar + local targetBar = scrollFrame:GetLine(lineIndex) - _detalhes.gump:NewScrollBar(container_alvos_window, container_alvos, 7, 4) - container_alvos_window.slider:Altura(88) - container_alvos_window.slider:cimaPoint(0, 1) - container_alvos_window.slider:baixoPoint(0, -3) + --reset header alignment + targetBar:ResetFramesToHeaderAlignment() - container_alvos_window.gump = container_alvos - tabFrame.container_alvos = container_alvos_window + --reset columns, hiding them + targetBar.Icon:Hide() + for inLineIndex = 1, #targetBar.InLineTexts do + targetBar.InLineTexts[inLineIndex]:SetText("") + end + + return targetBar +end + + +---update a line using the data passed +---@param targetBar breakdowntargetbar +---@param index number spell position (from best to wrost) +---@param combatObject combat +---@param scrollFrame table +---@param headerTable table +---@param bkTargetData breakdowntargettable +---@param totalValue number +---@param maxValue number +local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, headerTable, bkTargetData, totalValue, maxValue) --~target ~update ~targetbar + --scrollFrame is defined as a table which is false, scrollFrame is a frame + + local textIndex = 1 + + for headerIndex = 1, #headerTable do + ---@type number + local value + + targetBar.bkTargetData = bkTargetData + value = bkTargetData.total --hardcoded to be the total healing done or damage // has to be changed + --the maxValue received is also the max healing done or damage done // has to be changed to make the statusbar in the correct length + --when sorting by another key + + ---@type number + local combatTime = combatObject:GetCombatTime() + + targetBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha) + + --statusbar size by percent + if (maxValue > 0) then + targetBar.statusBar:SetValue(bkTargetData.statusBarValue / maxValue * 100) + else + targetBar.statusBar:SetValue(0) + end + + --statusbar color + targetBar.statusBar:SetStatusBarColor(1, 1, 1, 1) + targetBar.combatTime = combatTime + + ---@type fontstring + local text = targetBar.InLineTexts[textIndex] + local header = headerTable[headerIndex] + + if (header.name == "icon") then --ok + targetBar.Icon:Show() + targetBar.Icon:SetTexture(CONST_TARGET_TEXTURE) + targetBar:AddFrameToHeaderAlignment(targetBar.Icon) + + elseif (header.name == "rank") then --ok + text:SetText(index) + targetBar:AddFrameToHeaderAlignment(text) + targetBar.rank = index + textIndex = textIndex + 1 + + elseif (header.name == "name") then --ok + text:SetText(bkTargetData.name) + targetBar.name = bkTargetData.name + targetBar:AddFrameToHeaderAlignment(text) + textIndex = textIndex + 1 + + elseif (header.name == "amount") then --ok + text:SetText(Details:Format(value)) + targetBar:AddFrameToHeaderAlignment(text) + textIndex = textIndex + 1 + + elseif (header.name == "percent") then --ok + targetBar.percent = value / totalValue * 100 --totalValue is nil + ---@type string + local percentFormatted = string.format("%.1f", targetBar.percent) .. "%" + text:SetText(percentFormatted) + + targetBar:AddFrameToHeaderAlignment(text) + textIndex = textIndex + 1 + + elseif (header.name == "overheal") then + text:SetText(Details:Format(bkTargetData.overheal or 0)) + targetBar:AddFrameToHeaderAlignment(text) + textIndex = textIndex + 1 + + elseif (header.name == "absorbed") then + text:SetText(Details:Format(bkTargetData.absorbed or 0)) + targetBar:AddFrameToHeaderAlignment(text) + textIndex = textIndex + 1 + end + end + + targetBar:AlignWithHeader(scrollFrame.Header, "left") +end + +---refresh the data shown in the spells scroll box +---@param scrollFrame table +---@param scrollData breakdowntargettablelist +---@param offset number +---@param totalLines number +local refreshFuncTargets = function(scrollFrame, scrollData, offset, totalLines) --~refresh ~target ~refreshtargets + ---@type number + local maxValue = scrollFrame.maxValue + ---@type number + local totalValue = scrollData.totalValue + ---@type actor + local actorObject = spellsTab.GetActor() + ---@type string + local actorName = actorObject:Name() + ---@type combat + local combatObject = spellsTab.GetCombat() + ---@type instance + local instanceObject = spellsTab.GetInstance() + + local headerTable = spellsTab.targetsHeaderData + + local lineIndex = 1 + + for i = 1, totalLines do + local index = i + offset + + ---@type breakdowntargettable + local bkTargetData = scrollData[index] + if (bkTargetData) then + ---called mainSpellBar because it is the line that shows the sum of all spells merged (if any) + ---@type breakdowntargetbar + local targetBar = getTargetBar(scrollFrame, lineIndex) + do + if (targetBar) then + lineIndex = lineIndex + 1 + updateTargetBar(targetBar, index, combatObject, scrollFrame, headerTable, bkTargetData, totalValue, maxValue) + end + end + + if (lineIndex > totalLines) then + break + end + end + end +end + +--sort by overheal, the statusbar length keep using healing done +--sort by overheal, the percent keep using the healing done + +function spellsTab.CreateTargetContainer(tabFrame) --~create ~target + ---@type width + local width = Details.breakdown_spell_tab.targetcontainer_width + ---@type height + local height = Details.breakdown_spell_tab.targetcontainer_height + + local defaultAmountOfLines = 50 + + --create a container for the scrollframe + local options = { + width = Details.breakdown_spell_tab.targetcontainer_width, + height = Details.breakdown_spell_tab.targetcontainer_height, + is_locked = Details.breakdown_spell_tab.targetcontainer_islocked, + can_move = false, + can_move_children = false, + use_top_resizer = true, + use_right_resizer = true, + } + + ---@type df_framecontainer + local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "TargetScrollContainer") + container:SetPoint("topleft", spellsTab.GetSpellScrollContainer(), "bottomleft", 0, -25) + container:SetFrameLevel(tabFrame:GetFrameLevel() + 10) + spellsTab.TargetsContainerFrame = container + + local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue) + if (frameContainer:IsShown()) then + if (settingName == "height") then + ---@type number + local currentHeight = spellsTab.GetTargetScrollFrame():GetHeight() + Details.breakdown_spell_tab.targetcontainer_height = settingValue + local lineAmount = math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT) + spellsTab.GetTargetScrollFrame():SetNumFramesShown(lineAmount) + + elseif (settingName == "width") then + Details.breakdown_spell_tab.targetcontainer_width = settingValue + + elseif (settingName == "is_locked") then + Details.breakdown_spell_tab.targetcontainer_islocked = settingValue + end + end + end + container:SetSettingChangedCallback(settingChangedCallbackFunction) + + --create the scrollframe similar to scrollframe used in the spellscrollframe + --replace this with a framework scrollframe + ---@type breakdowntargetscrollframe + local targetScrollFrame = DF:CreateScrollBox(container, "$parentSpellScroll", refreshFuncTargets, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT) + DF:ReskinSlider(targetScrollFrame) + targetScrollFrame:SetBackdrop({}) + targetScrollFrame:SetAllPoints() + + container:RegisterChildForDrag(targetScrollFrame) + + targetScrollFrame.DontHideChildrenOnPreRefresh = false + tabFrame.TargetScrollFrame = targetScrollFrame + spellsTab.TargetScrollFrame = targetScrollFrame + + ---@param data breakdowntargettablelist + function targetScrollFrame:RefreshMe(data) --~refreshme (targets) + --get which column is currently selected and the sort order + local columnIndex, order, key = targetScrollFrame.Header:GetSelectedColumn() + + ---@type string + local keyToSort = key + + for i = 1, #data do + ---@type spelltableadv + local bkSpellData = data[i] + bkSpellData.statusBarValue = bkSpellData[keyToSort] + end + + if (order == "DESC") then + table.sort(data, + function(t1, t2) + return t1[keyToSort] > t2[keyToSort] + end) + targetScrollFrame.maxValue = data[1] and data[1][keyToSort] + else + table.sort(data, + function(t1, t2) + return t1[keyToSort] < t2[keyToSort] + end) + targetScrollFrame.maxValue = data[#data] and data[#data][keyToSort] + end + + if (key == "overheal") then + data.totalValue = data.totalValueOverheal + end + --default: data.totalValue + --data.totalValueOverheal + + targetScrollFrame:SetData(data) + targetScrollFrame:Refresh() + end + + --~header + local headerOptions = { + padding = 2, + header_height = 14, + + reziser_shown = true, + reziser_width = 2, + reziser_color = {.5, .5, .5, 0.7}, + reziser_max_width = 246, + } + + ---@type df_headerframe + local header = DetailsFramework:CreateHeader(container, targetContainerColumnData, headerOptions) + targetScrollFrame.Header = header + targetScrollFrame.Header:SetPoint("topleft", targetScrollFrame, "topleft", 0, 1) + targetScrollFrame.Header:SetColumnSettingChangedCallback(onHeaderColumnOptionChanged) + + --cache the type of this container + headerContainerType[targetScrollFrame.Header] = "targets" + + --create the scroll lines + for i = 1, defaultAmountOfLines do + targetScrollFrame:CreateLine(spellsTab.CreateTargetBar) + end tabFrame.targets = tabFrame:CreateFontString(nil, "OVERLAY", "QuestFont_Large") - tabFrame.targets:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 24, -273) + tabFrame.targets:SetPoint("bottomleft", container, "topleft", 2, 2) tabFrame.targets:SetText(Loc ["STRING_TARGETS"] .. ":") + + return targetScrollFrame end --logistics: class_damage build the list of spells, send it to window_playerbreakdown, which gets the current summary tab and send the data for it @@ -1119,7 +1444,7 @@ local updateSpellBar = function(spellBar, index, actorName, combatObject, scroll --statusbar size by percent if (maxValue > 0) then - spellBar.statusBar:SetValue(value / maxValue * 100) + spellBar.statusBar:SetValue(bkSpellData.statusBarValue / maxValue * 100) else spellBar.statusBar:SetValue(0) end @@ -1280,9 +1605,8 @@ end ---@param scrollData breakdownspelldatalist ---@param offset number ---@param totalLines number -local refreshFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshspells ~refresh +local refreshFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshspells ~refreshfunc ~refresh ---@type number - local maxValue = scrollData[1] and scrollData[1].total local maxValue = scrollFrame.maxValue ---@type number local totalValue = scrollData.totalValue @@ -1455,10 +1779,13 @@ function spellsTab.CreateSpellScrollContainer(tabFrame) --~scroll ~create ---set the data and refresh the scrollframe ---@param self any ---@param data breakdownspelldatalist - function scrollFrame:RefreshMe(data) --~refreshme + function scrollFrame:RefreshMe(data) --~refreshme (spells) --get which column is currently selected and the sort order local columnIndex, order, key = scrollFrame.Header:GetSelectedColumn() + ---@type string + local keyToSort = key + ---@type combat local combatObject = spellsTab.GetCombat() ---@type number, number @@ -1485,10 +1812,9 @@ function spellsTab.CreateSpellScrollContainer(tabFrame) --~scroll ~create if (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then bkSpellData.healabsorbed = bkSpellData.absorbed end - end - ---@type string - local keyToSort = key + bkSpellData.statusBarValue = bkSpellData[keyToSort] + end if (order == "DESC") then table.sort(data, @@ -1545,7 +1871,7 @@ local onEnterSpellTarget = function(targetFrame) local targetName = targetTable[1] local value = targetTable[2] cooltip:AddLine(targetIndex .. ". " .. targetName, Details:Format(value)) - GameCooltip:AddIcon([[Interface\MINIMAP\TRACKING\Target]], 1, 1, 14, 14) + GameCooltip:AddIcon(CONST_TARGET_TEXTURE, 1, 1, 14, 14) Details:AddTooltipBackgroundStatusbar(false, value / topValue * 100) end @@ -1692,6 +2018,99 @@ local onLeaveSpellTarget = function(self) self:SetAlpha(.7) end +---@param self breakdowntargetbar +local onEnterBreakdownTargetBar = function(self) + self:SetAlpha(1) +end + +---@param self breakdowntargetbar +local onLeaveBreakdownTargetBar = function(self) + self:SetAlpha(0.9) +end + +---create a targetbar within the target scroll +---@param self breakdowntargetscrollframe +---@param index number +---@return breakdowntargetbar +function spellsTab.CreateTargetBar(self, index) + ---@type breakdowntargetbar + local targetBar = CreateFrame("button", self:GetName() .. "TargetBarButton" .. index, self) + targetBar.index = index + + --size and positioning + targetBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT) + local y = (index-1) * CONST_SPELLSCROLL_LINEHEIGHT * -1 + (1 * -index) - 15 + targetBar:SetPoint("topleft", self, "topleft", 0, y) + targetBar:SetPoint("topright", self, "topright", 0, y) + + targetBar:EnableMouse(true) + + targetBar:SetAlpha(0.9) + targetBar:SetFrameStrata("HIGH") + targetBar:SetScript("OnEnter", onEnterBreakdownTargetBar) + targetBar:SetScript("OnLeave", onLeaveBreakdownTargetBar) + + DF:Mixin(targetBar, DF.HeaderFunctions) + + ---@type breakdownspellbarstatusbar + local statusBar = CreateFrame("StatusBar", "$parentStatusBar", targetBar) + statusBar:SetAllPoints() + statusBar:SetAlpha(0.5) + statusBar:SetMinMaxValues(0, 100) + statusBar:SetValue(50) + statusBar:EnableMouse(false) + statusBar:SetFrameLevel(targetBar:GetFrameLevel() - 1) + targetBar.statusBar = statusBar + + ---@type texture this is the statusbar texture + local statusBarTexture = statusBar:CreateTexture("$parentTexture", "artwork") + statusBarTexture:SetTexture(SharedMedia:Fetch("statusbar", "Details Hyanda")) + statusBar:SetStatusBarTexture(statusBarTexture) + statusBar:SetStatusBarColor(1, 1, 1, 1) + + ---@type texture shown when the mouse hoverover this bar + local hightlightTexture = statusBar:CreateTexture("$parentTextureHighlight", "highlight") + hightlightTexture:SetColorTexture(1, 1, 1, 0.2) + hightlightTexture:SetAllPoints() + statusBar.highlightTexture = hightlightTexture + + ---@type texture background texture + local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border") + backgroundTexture:SetAllPoints() + backgroundTexture:SetColorTexture(.05, .05, .05) + backgroundTexture:SetAlpha(1) + statusBar.backgroundTexture = backgroundTexture + + --create an icon + ---@type texture + local icon = statusBar:CreateTexture("$parentTexture", "overlay") + icon:SetPoint("left", statusBar, "left", 0, 0) + icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2) + icon:SetTexCoord(.1, .9, .1, .9) + targetBar.Icon = icon + + targetBar:AddFrameToHeaderAlignment(icon) + + targetBar.InLineTexts = {} + + for i = 1, 5 do + ---@type fontstring + local fontString = targetBar:CreateFontString("$parentFontString" .. i, "overlay", "GameFontHighlightSmall") + fontString:SetJustifyH("left") + fontString:SetTextColor(1, 1, 1, 1) + fontString:SetNonSpaceWrap(true) + fontString:SetWordWrap(false) + targetBar["lineText" .. i] = fontString + targetBar.InLineTexts[i] = fontString + fontString:SetTextColor(1, 1, 1, 1) + targetBar:AddFrameToHeaderAlignment(fontString) + end + + targetBar:AlignWithHeader(self.Header, "left") + + return targetBar +end + ---create a spellbar within the spell scroll ---@param self breakdownspellscrollframe ---@param index number @@ -1798,7 +2217,7 @@ function spellsTab.CreateSpellBar(self, index) --~spellbar ~spellline ~spell ~cr ---@type texture local targetTexture = targetsSquareFrame:CreateTexture("$parentTexture", "overlay") - targetTexture:SetTexture([[Interface\MINIMAP\TRACKING\Target]]) + targetTexture:SetTexture(CONST_TARGET_TEXTURE) targetTexture:SetAllPoints() targetTexture:SetDesaturated(true) spellBar.targetsSquareTexture = targetTexture @@ -1871,6 +2290,14 @@ function Details.InitializeSpellBreakdownTab() spellsTab.GetSpellScrollFrame():RefreshMe(data) end + ---@param data breakdowntargettablelist + ---@param actorObject actor + ---@param combatObject combat + ---@param instance instance + function tabButton.OnReceiveTargetData(data, actorObject, combatObject, instance) + spellsTab.GetTargetScrollFrame():RefreshMe(data) + end + ---@type detailseventlistener local eventListener = Details:CreateEventListener() eventListener:RegisterEvent("DETAILS_PROFILE_APPLYED", function() diff --git a/frames/window_playerbreakdown_spells_options.lua b/frames/window_playerbreakdown_spells_options.lua new file mode 100644 index 00000000..c96651d5 --- /dev/null +++ b/frames/window_playerbreakdown_spells_options.lua @@ -0,0 +1,278 @@ + +local Details = Details +local DF = DetailsFramework + +--create the main frame for the options panel + +local createOptionsPanel = function() + local startX = 5 + local startY = -24 + local heightSize = 540 + + local DetailsSpellBreakdownTab = DetailsSpellBreakdownTab + local UIParent = UIParent + + local options_text_template = DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE") + local options_dropdown_template = DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE") + local options_switch_template = DF:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE") + local options_slider_template = DF:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE") + local options_button_template = DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE") + + local optionsFrame = DF:CreateSimplePanel(UIParent, 550, 500, "Details! Breakdown Options", "DetailsSpellBreakdownOptionsPanel") + optionsFrame:SetFrameStrata("HIGH") + optionsFrame:SetPoint("topleft", UIParent, "topleft", 2, -40) + optionsFrame:Show() + + local subSectionTitleTextTemplate = DF:GetTemplate("font", "ORANGE_FONT_TEMPLATE") + + local optionsTable = { + {type = "label", get = function() return "Spell Details Block" end, text_template = subSectionTitleTextTemplate}, + {--width + type = "range", + get = function() return Details.breakdown_spell_tab.blockcontainer_width end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockcontainer_width = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + min = 150, + max = 450, + step = 1, + name = "Width", + desc = "Width", + hidden = true, + }, + {--height + type = "range", + get = function() return Details.breakdown_spell_tab.blockcontainer_height end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockcontainer_height = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + min = 150, + max = 450, + step = 1, + name = "Height", + desc = "Height", + hidden = true, + }, + {--block height + type = "range", + get = function() return Details.breakdown_spell_tab.blockspell_height end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockspell_height = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + min = 50, + max = 80, + step = 1, + name = "Block Height", + desc = "Block Height", + }, + {--line height + type = "range", + get = function() return Details.breakdown_spell_tab.blockspellline_height end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockspellline_height = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + min = 10, + max = 30, + step = 1, + name = "Line Height", + desc = "Line Height", + }, + {--show spark + type = "toggle", + get = function() return Details.breakdown_spell_tab.blockspell_spark_show end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockspell_spark_show = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + name = "Show Spark", + desc = "Show Spark", + }, + {--spark width + type = "range", + get = function() return Details.breakdown_spell_tab.blockspell_spark_width end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockspell_spark_width = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + min = 1, + max = 24, + step = 1, + name = "Spark Width", + desc = "Spark Width", + }, + {--spark offset + type = "range", + get = function() return Details.breakdown_spell_tab.blockspell_spark_offset end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.blockspell_spark_offset = value + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + DetailsSpellBreakdownTab.UpdateShownSpellBlock() + end, + min = -12, + max = 12, + step = 1, + name = "Spark Offset", + desc = "Spark Offset", + }, + {--spark color + type = "color", + get = function() + return Details.breakdown_spell_tab.blockspell_spark_color + end, + set = function(self, r, g, b, a) + Details.breakdown_spell_tab.blockspell_spark_color[1] = r + Details.breakdown_spell_tab.blockspell_spark_color[2] = g + Details.breakdown_spell_tab.blockspell_spark_color[3] = b + Details.breakdown_spell_tab.blockspell_spark_color[4] = a + DetailsSpellBreakdownTab.GetSpellBlockFrame():UpdateBlocks() + end, + name = "Spark Color", + desc = "Spark Color", + }, + + {type = "blank"}, + {type = "blank"}, + + {type = "label", get = function() return "Spell Header Options" end, text_template = subSectionTitleTextTemplate}, + { --per second + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["persecond"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["persecond"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Per Second", + desc = "Per Second", + }, + + { --amount of casts + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["casts"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["casts"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Casts", + desc = "Casts", + }, + + { --critical hits percent + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["critpercent"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["critpercent"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Critical Hits Percent", + desc = "Critical Hits Percent", + }, + + { --amount of hits + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["hits"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["hits"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Hits Amount", + desc = "Hits Amount", + }, + + { --average damage of healing per cast amount + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["castavg"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["castavg"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Cast Average", + desc = "Cast Average", + }, + + { --debuff uptime + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["uptime"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["uptime"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Uptime", + desc = "Uptime", + }, + + { --overheal + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["overheal"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["overheal"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Overheal", + desc = "Overheal", + }, + + { --absorbed + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_headers["absorbed"].enabled end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellcontainer_headers["absorbed"].enabled = value + DetailsSpellBreakdownTab.UpdateHeadersSettings("spells") + end, + name = "Heal Absorbed", + desc = "Heal Absorbed", + }, + + {type = "breakline"}, + {type = "label", get = function() return "Scroll Options" end, text_template = subSectionTitleTextTemplate}, + + { --locked + type = "toggle", + get = function() return Details.breakdown_spell_tab.spellcontainer_islocked end, + set = function(self, fixedparam, value) + ---@type df_framecontainer + local container = DetailsSpellBreakdownTab.GetSpellScrollContainer() + container:SetResizeLocked(value) + + local container = DetailsSpellBreakdownTab.GetTargetScrollContainer() + container:SetResizeLocked(value) + end, + name = "Is Locked", + desc = "Is Locked", + }, + + {--background alpha + type = "range", + get = function() return Details.breakdown_spell_tab.spellbar_background_alpha end, + set = function(self, fixedparam, value) + Details.breakdown_spell_tab.spellbar_background_alpha = value + DetailsSpellBreakdownTab.GetSpellScrollFrame():Refresh() + end, + min = 0, + max = 1, + step = 0.1, + usedecimals = true, + name = "Background Alpha", + desc = "Background Alpha", + }, + + } + + --build the menu + optionsTable.always_boxfirst = true + DF:BuildMenu(optionsFrame, optionsTable, startX, startY, heightSize, false, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template) +end + + +function Details.OpenSpellBreakdownOptions() + if (DetailsSpellBreakdownOptionsPanel) then + DetailsSpellBreakdownOptionsPanel:RefreshOptions() + DetailsSpellBreakdownOptionsPanel:Show() + return + end + + createOptionsPanel() +end \ No newline at end of file diff --git a/functions/mixin.lua b/functions/mixin.lua index 126c8af7..f0fc22a7 100644 --- a/functions/mixin.lua +++ b/functions/mixin.lua @@ -46,6 +46,14 @@ Details222.Mixins.ActorMixin = { return actor.pets end, + ---return a table containing the targets of the actor + ---@param actor actor + ---@param key string optional, if not provided, will use the default target table: 'targets' + ---@return targettable + GetTargets = function(actor, key) + return actor[key or "targets"] + end, + ---return a table containing spellTables ---@param actor actor ---@return table @@ -92,19 +100,19 @@ Details222.Mixins.ActorMixin = { return result end, - ---this function receives a target table name and return a table containing the targets and the damage done in order of bigger to lower value + ---this function receives a key for the name of the target table (usually is 'targets') and return a table containing the targets and the damage done in order of bigger to lower value ---@param actor actor ---@param spellTable spelltable - ---@param targetTableName string + ---@param targetKey string ---@return table - BuildSpellTargetFromSpellTable = function(actor, spellTable, targetTableName) - targetTableName = targetTableName or "targets" + BuildSpellTargetFromSpellTable = function(actor, spellTable, targetKey) + targetKey = targetKey or "targets" ---@type table[] store the result which is returned by this function local result = {} ---@type table - local targets = spellTable[targetTableName] + local targets = spellTable[targetKey] for targetName, value in pairs(targets) do ---@cast targetName string diff --git a/functions/profiles.lua b/functions/profiles.lua index 15cbf572..43c19b7c 100644 --- a/functions/profiles.lua +++ b/functions/profiles.lua @@ -1424,13 +1424,18 @@ local default_global_data = { blockspellline_height = 13, - spellcontainer_width = 535, + spellcontainer_width = 429, spellcontainer_height = 311, spellcontainer_islocked = true, + targetcontainer_width = 429, + targetcontainer_height = 140, + targetcontainer_islocked = true, + spellbar_background_alpha = 0.92, - spellcontainer_headers = {}, --store information about active headers and their sizes + spellcontainer_headers = {}, --store information about active headers and their sizes (spells) + targetcontainer_headers = {}, --store information about active headers and their sizes (target) spellcontainer_header_height = 20, spellcontainer_header_fontsize = 10, spellcontainer_header_fontcolor = {1, 1, 1, 1},