local addonName , Details222 = ...
local breakdownWindow = Details.BreakdownWindow
local Loc = LibStub ( " AceLocale-3.0 " ) : GetLocale ( " Details " )
local SharedMedia = LibStub : GetLibrary ( " LibSharedMedia-3.0 " )
local unpack = unpack
local GetTime = GetTime
local CreateFrame = CreateFrame
local GetSpellLink = GetSpellLink or C_Spell.GetSpellLink --api local
local GetSpellInfo = Details222.GetSpellInfo
local _GetSpellInfo = Details.GetSpellInfo
local GameTooltip = GameTooltip
local IsShiftKeyDown = IsShiftKeyDown
local tinsert = table.insert
---@type detailsframework
local DF = DetailsFramework
---@type detailsframework
local detailsFramework = DetailsFramework
local spellsTab = DetailsSpellBreakdownTab
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
local spellBlockContainerSettings = {
amount = 6 , --amount of block the container have
lineAmount = 3 , --amount of line each block have
}
local headerContainerType = spellsTab.headerContainerType
local formatPetName = function ( petName , spellName , ownerName )
--remove the owner name from the pet name
local petNameWithoutOwner = petName : gsub ( ( " <.* " ) , " " )
local texture = [[Interface\AddOns\Details\images\classes_small]]
local bUseAlphaIcons = true
local specIcon = nil
local iconSize = 14
if ( petName : len ( ) == 0 ) then
return Details : AddClassOrSpecIcon ( spellName , " PET " , specIcon , iconSize , bUseAlphaIcons )
end
petNameWithoutOwner = Details : AddClassOrSpecIcon ( petNameWithoutOwner , " PET " , specIcon , iconSize , bUseAlphaIcons )
return spellName .. " |cFFCCBBBB " .. petNameWithoutOwner .. " |r "
end
---some values required by the header sort key is not available in the spellTable, so they need to be calculated
---@param combatObject combat
---@param spellData spelltable|spelltableadv
---@param key string
---@return any
local getValueForHeaderSortKey = function ( combatObject , spellData , key )
if ( key == " critpercent " ) then
return Details.SpellTableMixin . GetCritPercent ( spellData )
elseif ( key == " casts " ) then
local spellName = GetSpellInfo ( spellData.id )
local amountOfCasts = combatObject : GetSpellCastAmount ( spellsTab.GetActor ( ) : Name ( ) , spellName )
return amountOfCasts
elseif ( key == " castavg " ) then
local spellName = GetSpellInfo ( spellData.id )
local amountOfCasts = combatObject : GetSpellCastAmount ( spellsTab.GetActor ( ) : Name ( ) , spellName )
return Details.SpellTableMixin . GetCastAverage ( spellData , amountOfCasts )
elseif ( key == " uptime " ) then
return combatObject : GetSpellUptime ( spellsTab.GetActor ( ) : Name ( ) , spellData.id )
elseif ( key == " healabsorbed " ) then
return spellData.absorbed
end
end
---run when the user clicks the columnHeader
---@param headerFrame df_headerframe
---@param columnHeader df_headercolumnframe
local onColumnHeaderClickCallback = function ( headerFrame , columnHeader )
---@type string
local containerType = headerContainerType [ headerFrame ]
local scrollFrame = spellsTab.GetScrollFrameByContainerType ( containerType )
scrollFrame : Refresh ( )
local instance = spellsTab.GetInstance ( )
instance : RefreshWindow ( true )
end
---on enter function for the spell target frame
---@param targetFrame breakdowntargetframe
local onEnterSpellTarget = function ( targetFrame )
--the spell target frame is created in the statusbar which is placed above the line frame
local lineBar = targetFrame : GetParent ( ) : GetParent ( )
local spellId = targetFrame.spellId
---@type actor
local actorObject = Details : GetActorObjectFromBreakdownWindow ( )
local targets
if ( targetFrame.bIsMainLine ) then
---@type spelltableadv
local bkSpellData = targetFrame.bkSpellData
targets = actorObject : BuildSpellTargetFromBreakdownSpellData ( bkSpellData )
else
local spellTable = targetFrame.spellTable
targets = actorObject : BuildSpellTargetFromSpellTable ( spellTable )
end
---@type number the top value of targets
local topValue = math.max ( targets [ 1 ] and targets [ 1 ] [ 2 ] or 0 , 0.001 )
local cooltip = GameCooltip
cooltip : Preset ( 2 )
for targetIndex , targetTable in ipairs ( targets ) do
local targetName = targetTable [ 1 ]
local value = targetTable [ 2 ]
cooltip : AddLine ( targetIndex .. " . " .. targetName , Details : Format ( value ) )
GameCooltip : AddIcon ( CONST_TARGET_TEXTURE , 1 , 1 , 14 , 14 )
Details : AddTooltipBackgroundStatusbar ( false , value / topValue * 100 )
end
cooltip : SetOwner ( targetFrame )
cooltip : Show ( )
end
local onLeaveSpellTarget = function ( self )
GameTooltip : Hide ( )
GameCooltip : Hide ( )
self : GetParent ( ) : GetParent ( ) : GetScript ( " OnLeave " ) ( self : GetParent ( ) : GetParent ( ) )
self.texture : SetAlpha ( .7 )
self : SetAlpha ( .7 )
end
--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?
spellBlock.overlay : Show ( )
spellBlock.reportButton : Show ( )
end
local onLeaveSpellBlock = function ( spellBlock )
spellBlock.overlay : Hide ( )
spellBlock.reportButton : Hide ( )
end
local onEnterInfoReport = function ( self )
Details.FadeHandler . Fader ( self : GetParent ( ) . overlay , 0 )
Details.FadeHandler . Fader ( self , 0 )
end
local onLeaveInfoReport = function ( self )
Details.FadeHandler . Fader ( self : GetParent ( ) . overlay , 1 )
Details.FadeHandler . Fader ( self , 1 )
end
---run this function when the mouse hover over a breakdownspellbar
---@param spellBar breakdownspellbar
---@param motion boolean|nil
local onEnterSpellBar = function ( spellBar , motion ) --parei aqui: precisa por nomes nas funções e formatar as linhas das funcções
--all values from spellBar are cached values
--check if there's a spellbar selected, if there's one, ignore the mouseover
if ( spellsTab.HasSelectedSpellBar ( ) and motion ) then
return
end
spellsTab.currentSpellBar = spellBar
Details222.FocusedSpellId = spellBar.spellId
---@type instance
local instance = spellsTab.GetInstance ( )
---@type combat
local combatObject = spellsTab.GetCombat ( )
---@type number, number
local mainAttribute , subAttribute = instance : GetDisplay ( )
---@type breakdownspellblockframe
local spellBlockContainer = spellsTab.GetSpellBlockFrame ( )
spellBlockContainer : ClearBlocks ( )
---@type number
local spellId = spellBar.spellId
---@type number
local elapsedTime = spellBar.combatTime --this should be actorObject:Tempo()
---@type string
local actorName = spellsTab.GetActor ( ) : Name ( ) --attempt to index a nil value x2
---@type spelltable
local spellTable = spellBar.spellTable
if ( IsShiftKeyDown ( ) ) then
if ( type ( spellId ) == " number " ) then
GameCooltip : Preset ( 2 )
GameCooltip : SetOwner ( spellBar )
--if this is an actor header (e.g. a pet bar showing its nested spells)
if ( spellBar.bkSpellData . bIsActorHeader ) then
local petActor = combatObject : GetContainer ( mainAttribute ) : GetActor ( spellBar.bkSpellData . actorName )
local textToEditor = " "
for key , value in pairs ( petActor ) do
if ( type ( value ) ~= " function " and type ( value ) ~= " table " ) then
textToEditor = textToEditor .. key .. " = " .. tostring ( value ) .. " \n "
end
breakdownWindow.dumpDataFrame : Show ( )
breakdownWindow.dumpDataFrame . luaEditor : SetText ( textToEditor )
--hide the scroll bar
_G [ " DetailsBreakdownWindowPlayerScrollBoxDumpTableFrameCodeEditorWindowScrollBar " ] : Hide ( )
end
GameCooltip : AddLine ( " npc id: " .. petActor.aID )
GameCooltip : Show ( )
return
end
---@type actor
local thisActor = spellsTab.GetActor ( )
---@type spelltable
local thisSpellTable = thisActor : GetSpell ( spellId )
if ( not thisSpellTable ) then
local petName = spellBar.bkSpellData . actorName
local actorContainer = combatObject : GetContainer ( mainAttribute )
local petObject = actorContainer : GetActor ( petName )
if ( petObject ) then
thisSpellTable = petObject : GetSpell ( spellId )
end
end
GameCooltip : AddLine ( " spell id: " .. thisSpellTable.id )
GameCooltip : Show ( ) --add the icon for the bar bar with nested spells (place the icon of the npc or pet)
local textToEditor = " "
for key , value in pairs ( thisSpellTable ) do
if ( type ( value ) ~= " function " and type ( value ) ~= " table " ) then
textToEditor = textToEditor .. key .. " = " .. tostring ( value ) .. " \n "
end
end
breakdownWindow.dumpDataFrame : Show ( )
breakdownWindow.dumpDataFrame . luaEditor : SetText ( textToEditor )
--hide the scroll bar
_G [ " DetailsBreakdownWindowPlayerScrollBoxDumpTableFrameCodeEditorWindowScrollBar " ] : Hide ( )
end
elseif ( breakdownWindow.dumpDataFrame : IsShown ( ) ) then
breakdownWindow.dumpDataFrame : Hide ( )
end
if ( spellId == 98021 ) then --spirit link totem
GameTooltip : SetOwner ( spellBar , " ANCHOR_TOPLEFT " )
GameTooltip : AddLine ( Loc [ " STRING_SPIRIT_LINK_TOTEM_DESC " ] )
GameTooltip : Show ( )
end
---@type trinketdata
local trinketData = Details : GetTrinketData ( )
---@type number
local blockIndex = 1
--get the first spell block to use as summary
---@type breakdownspellblock
local summaryBlock = spellBlockContainer : GetBlock ( blockIndex )
summaryBlock : Show ( )
summaryBlock : SetValue ( 50 )
summaryBlock : SetValue ( 100 )
if ( mainAttribute == DETAILS_ATTRIBUTE_DAMAGE ) then
--bounce to damage class to handle the spell details
if ( subAttribute == 1 or subAttribute == 2 or subAttribute == 6 ) then
Details.atributo_damage : BuildSpellDetails ( spellBar , spellBlockContainer , blockIndex , summaryBlock , spellId , elapsedTime , actorName , spellTable , trinketData , combatObject )
end
--need to know how many blocks the damage class used
local blocksInUse = spellBlockContainer : GetBlocksInUse ( )
local maxBlocks = spellBlockContainer : GetBlocksAmount ( )
for i = blocksInUse + 1 , math.min ( maxBlocks , 4 ) do --in the current state of the breakdown, showing 5 will overlap with the phase container
spellBlockContainer : ShowEmptyBlock ( i )
end
elseif ( mainAttribute == DETAILS_ATTRIBUTE_HEAL ) then --this should run within the heal class ~healing
---@type number
local totalHits = spellTable.counter
--healing section showing healing done sub section
blockIndex = blockIndex + 1
do --update the texts in the summary block
local blockLine1 , blockLine2 , blockLine3 = summaryBlock : GetLines ( )
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
blockLine2.rightText : SetText ( Details : GetSpellSchoolFormatedName ( spellTable.spellschool ) ) --spell school
blockLine3.leftText : SetText ( Loc [ " STRING_AVERAGE " ] .. " : " .. Details : Format ( spellBar.average ) ) --average damage
blockLine3.rightText : SetText ( Loc [ " STRING_HPS " ] .. " : " .. Details : CommaValue ( spellBar.perSecond ) ) --dps
end
--check if there's normal hits and build the block
---@type number
local normalHitsAmt = spellTable.n_amt
if ( normalHitsAmt > 0 ) then
---@type breakdownspellblock
local normalHitsBlock = spellBlockContainer : GetBlock ( blockIndex )
normalHitsBlock : Show ( )
blockIndex = blockIndex + 1
local percent = normalHitsAmt / math.max ( totalHits , 0.0001 ) * 100
normalHitsBlock : SetValue ( percent )
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 " ] )
blockLine1.rightText : SetText ( normalHitsAmt .. " [|cFFC0C0C0 " .. string.format ( " %.1f " , normalHitsAmt / math.max ( totalHits , 0.0001 ) * 100 ) .. " %|r] " )
blockLine2.leftText : SetText ( Loc [ " STRING_MINIMUM_SHORT " ] .. " : " .. Details : CommaValue ( spellTable.n_min ) )
blockLine2.rightText : SetText ( Loc [ " STRING_MAXIMUM_SHORT " ] .. " : " .. Details : CommaValue ( spellTable.n_max ) )
local normalAverage = spellTable.n_total / math.max ( normalHitsAmt , 0.0001 )
blockLine3.leftText : SetText ( Loc [ " STRING_AVERAGE " ] .. " : " .. Details : CommaValue ( normalAverage ) )
local normalHPS = 0
if ( spellTable.n_total > 0 ) then
local tempo = ( elapsedTime * spellTable.n_total ) / math.max ( spellTable.total , 0.001 )
local normalAveragePercent = spellBar.average / normalAverage * 100
local normalTempoPercent = normalAveragePercent * tempo / 100
normalHPS = spellTable.n_total / normalTempoPercent
end
blockLine3.rightText : SetText ( Loc [ " STRING_HPS " ] .. " : " .. Details : CommaValue ( normalHPS ) )
end
---@type number
local criticalHitsAmt = spellTable.c_amt
if ( criticalHitsAmt > 0 ) then
---@type breakdownspellblock
local critHitsBlock = spellBlockContainer : GetBlock ( blockIndex )
critHitsBlock : Show ( )
blockIndex = blockIndex + 1
local percent = criticalHitsAmt / math.max ( totalHits , 0.0001 ) * 100
critHitsBlock : SetValue ( percent )
critHitsBlock.sparkTexture : SetPoint ( " left " , critHitsBlock , " left " , percent / 100 * critHitsBlock : GetWidth ( ) + Details.breakdown_spell_tab . blockspell_spark_offset , 0 )
local blockLine1 , blockLine2 , blockLine3 = critHitsBlock : GetLines ( )
blockLine1.leftText : SetText ( Loc [ " STRING_CRITICAL_HITS " ] )
blockLine1.rightText : SetText ( criticalHitsAmt .. " [|cFFC0C0C0 " .. string.format ( " %.1f " , criticalHitsAmt / math.max ( totalHits , 0.0001 ) * 100 ) .. " %|r] " )
blockLine2.leftText : SetText ( Loc [ " STRING_MINIMUM_SHORT " ] .. " : " .. Details : CommaValue ( spellTable.c_min ) )
blockLine2.rightText : SetText ( Loc [ " STRING_MAXIMUM_SHORT " ] .. " : " .. Details : CommaValue ( spellTable.c_max ) )
local critAverage = spellTable.c_total / math.max ( criticalHitsAmt , 0.0001 )
blockLine3.leftText : SetText ( Loc [ " STRING_AVERAGE " ] .. " : " .. Details : CommaValue ( critAverage ) )
local critHPS = 0
if ( spellTable.c_total > 0 ) then
local tempo = ( elapsedTime * spellTable.c_total ) / math.max ( spellTable.total , 0.001 )
local critAveragePercent = spellBar.average / critAverage * 100
local critTempoPercent = critAveragePercent * tempo / 100
critHPS = spellTable.c_total / critTempoPercent
end
blockLine3.rightText : SetText ( Loc [ " STRING_HPS " ] .. " : " .. Details : CommaValue ( critHPS ) )
end
---@type number
local overheal = spellTable.overheal or 0
if ( overheal > 0 ) then
--blockIndex = blockIndex + 1 --skip one block
---@type breakdownspellblock
local overhealBlock = spellBlockContainer : GetBlock ( blockIndex )
overhealBlock : Show ( )
blockIndex = blockIndex + 1
local blockName
if ( spellTable.is_shield ) then
blockName = Loc [ " STRING_SHIELD_OVERHEAL " ]
else
blockName = Loc [ " STRING_OVERHEAL " ]
end
local percent = overheal / ( overheal + spellTable.total ) * 100
overhealBlock : SetValue ( percent )
overhealBlock.sparkTexture : SetPoint ( " left " , overhealBlock , " left " , percent / 100 * overhealBlock : GetWidth ( ) + Details.breakdown_spell_tab . blockspell_spark_offset , 0 )
overhealBlock : SetColor ( 1 , 0 , 0 , 0.4 )
local blockLine1 , blockLine2 , blockLine3 = overhealBlock : GetLines ( )
blockLine1.leftText : SetText ( blockName )
local overhealString = Details : CommaValue ( overheal )
local overhealText = overhealString .. " / " .. string.format ( " %.1f " , percent ) .. " % "
blockLine1.rightText : SetText ( overhealText )
end
end
--effects on entering the bar line
spellBar : SetHeight ( CONST_SPELLSCROLL_LINEHEIGHT + 1 )
spellBar : SetAlpha ( 1 )
spellBar.spellIcon : SetSize ( CONST_SPELLSCROLL_LINEHEIGHT + 2 , CONST_SPELLSCROLL_LINEHEIGHT + 2 )
spellBar.spellIcon : SetAlpha ( 1 )
end
---run this function when the mouse leaves a breakdownspellbar
---@param spellBar breakdownspellbar
local onLeaveSpellBar = function ( spellBar )
spellsTab.currentSpellBar = nil
--remove effects on entering the bar line
spellBar : SetHeight ( CONST_SPELLSCROLL_LINEHEIGHT )
spellBar : SetAlpha ( 0.9 )
GameTooltip : Hide ( )
GameCooltip : Hide ( )
--clear spell blocks
if ( not spellsTab.HasSelectedSpellBar ( ) ) then
spellsTab.GetSpellBlockFrame ( ) : ClearBlocks ( )
end
if ( breakdownWindow.dumpDataFrame : IsShown ( ) ) then
breakdownWindow.dumpDataFrame : Hide ( )
end
end
---on mouse down a breakdownspellbar in the breakdown window
---@param spellBar breakdownspellbar
---@param button string
local onMouseDownBreakdownSpellBar = function ( spellBar , button )
local x , y = _G.GetCursorPosition ( )
spellBar.cursorPosX = math.floor ( x )
spellBar.cursorPosY = math.floor ( y )
end
---on mouse up a breakdownspellbar in the breakdown window
---@param spellBar breakdownspellbar
---@param button string
local onMouseUpBreakdownSpellBar = function ( spellBar , button )
spellBar.onMouseUpTime = GetTime ( )
---@type number, number
local x , y = _G.GetCursorPosition ( )
x = math.floor ( x )
y = math.floor ( y )
---@type boolean
local bIsMouseInTheSamePosition = ( x == spellBar.cursorPosX ) and ( y == spellBar.cursorPosY )
--if the mouse is in the same position, then the user clicked the bar
if ( bIsMouseInTheSamePosition ) then
spellsTab.SelectSpellBar ( spellBar )
end
end
local onEnterSpellIconFrame = function ( self )
local line = self : GetParent ( )
if ( line.spellId and type ( line.spellId ) == " number " ) then
local spellName = _GetSpellInfo ( line.spellId )
if ( spellName ) then
GameTooltip : SetOwner ( self , " ANCHOR_TOPLEFT " )
Details : GameTooltipSetSpellByID ( line.spellId )
GameTooltip : Show ( )
end
end
line : GetScript ( " OnEnter " ) ( line )
end
local onLeaveSpellIconFrame = function ( self )
GameTooltip : Hide ( )
self : GetParent ( ) : GetScript ( " OnLeave " ) ( self : GetParent ( ) )
end
--------------------------------------------------------------------------------------------------------------------------------------------
--Spell Blocks
local spellBlockMixin = {
---get one of the three lines containing fontstrings to show data
---line 1 is the top line, line 2 is the middle line and line 3 is the bottom line
---@param self breakdownspellblock
---@param lineIndex number
---@return breakdownspellblockline
GetLine = function ( self , lineIndex )
---@type breakdownspellblockline
local line = self.Lines [ lineIndex ]
return line
end ,
---return all lines in the spell block, all spell block have 3 lines
---@param self breakdownspellblock
---@return breakdownspellblockline, breakdownspellblockline, breakdownspellblockline
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
---@param spellBlockContainer breakdownspellblockframe
---@param index number
---@return breakdownspellblock
function spellsTab . CreateSpellBlock ( spellBlockContainer , index ) --~breakdownspellblock ~create ~spellblocks
---@type breakdownspellblock
local spellBlock = CreateFrame ( " statusbar " , " $parentBlock " .. index , spellBlockContainer , " BackdropTemplate " )
detailsFramework : Mixin ( spellBlock , spellBlockMixin )
local statusBarTexture = spellBlock : CreateTexture ( " $parentTexture " , " artwork " )
statusBarTexture : SetColorTexture ( unpack ( CONST_SPELLBLOCK_DEFAULT_COLOR ) )
statusBarTexture : SetPoint ( " topleft " , spellBlock , " topleft " , 1 , - 1 )
statusBarTexture : SetPoint ( " bottomleft " , spellBlock , " bottomleft " , 1 , 1 )
spellBlock.statusBarTexture = statusBarTexture
spellBlock : SetScript ( " OnEnter " , onEnterSpellBlock )
spellBlock : SetScript ( " OnLeave " , onLeaveSpellBlock )
spellBlock : SetScript ( " OnValueChanged " , function ( )
statusBarTexture : SetWidth ( spellBlock : GetValue ( ) / 100 * spellBlock : GetWidth ( ) )
end )
spellBlock : SetMinMaxValues ( 0 , 100 )
spellBlock : SetValue ( 100 )
--set the backdrop to have a 8x8 edge file
spellsTab.ApplyStandardBackdrop ( spellBlock )
--create the lines which will host the texts
spellBlock.Lines = { }
for i = 1 , spellBlockContainerSettings.lineAmount do
---@type breakdownspellblockline
local line = CreateFrame ( " frame " , " $parentLine " .. i , spellBlock )
spellBlock.Lines [ i ] = line
line.leftText = line : CreateFontString ( " $parentLeftText " , " overlay " , " GameFontHighlightSmall " )
line.centerText = line : CreateFontString ( " $parentLeftText " , " overlay " , " GameFontHighlightSmall " )
line.rightText = line : CreateFontString ( " $parentLeftText " , " overlay " , " GameFontHighlightSmall " )
line.leftText : SetPoint ( " left " , line , " left " , 2 , 0 )
line.leftText : SetJustifyH ( " left " )
line.centerText : SetPoint ( " center " , line , " center " , 0 , 0 )
line.centerText : SetJustifyH ( " center " )
line.rightText : SetPoint ( " right " , line , " right " , - 2 , 0 )
line.rightText : SetJustifyH ( " right " )
end
--overlay texture which fade in and out when the spell block is hovered over
--is only possible to hover over a spell block when the spellbar is selected
spellBlock.overlay = spellBlock : CreateTexture ( " $parentOverlay " , " artwork " )
spellBlock.overlay : SetTexture ( " Interface \\ AddOns \\ Details \\ images \\ overlay_detalhes " )
spellBlock.overlay : SetPoint ( " topleft " , spellBlock , " topleft " , - 8 , 8 )
spellBlock.overlay : SetPoint ( " bottomright " , spellBlock , " bottomright " , 26 , - 14 )
Details.FadeHandler . Fader ( spellBlock.overlay , 1 ) --hide
--report button, also only shown when the spell block is hovered over
spellBlock.reportButton = Details.gump : NewDetailsButton ( spellBlock , nil , nil , Details.Reportar , Details.BreakdownWindowFrame , 10 + index , 16 , 16 ,
" Interface \\ COMMON \\ VOICECHAT-ON " , " Interface \\ COMMON \\ VOICECHAT-ON " , " Interface \\ COMMON \\ VOICECHAT-ON " , " Interface \\ COMMON \\ VOICECHAT-ON " , nil , " DetailsJanelaInfoReport1 " )
Details.FadeHandler . Fader ( spellBlock.reportButton , 1 ) --hide
spellBlock.reportButton : SetScript ( " OnEnter " , onEnterInfoReport )
spellBlock.reportButton : SetScript ( " OnLeave " , onLeaveInfoReport )
--spark texture
spellBlock.sparkTexture = spellBlock : CreateTexture ( " $parentOverlaySparkTexture " , " overlay " )
spellBlock.sparkTexture : SetTexture ( " Interface \\ AddOns \\ Details \\ images \\ bar_detalhes2_end " )
spellBlock.sparkTexture : SetBlendMode ( " ADD " )
local gradientDown = detailsFramework : CreateTexture ( spellBlock , { gradient = " vertical " , fromColor = { 0 , 0 , 0 , 0.1 } , toColor = " transparent " } , 1 , spellBlock : GetHeight ( ) , " background " , { 0 , 1 , 0 , 1 } )
gradientDown : SetPoint ( " bottoms " )
spellBlock.gradientTexture = gradientDown
spellBlock.gradientTexture : Hide ( )
return spellBlock
end
local spellBlockContainerMixin = {
---refresh all the spellblocks in the container ~UpdateBlocks
---this function adjust the frame properties, does not update the data shown on them
---@param self breakdownspellblockframe
UpdateBlocks = function ( self ) --~update
---@type number, number
local width , height = Details.breakdown_spell_tab . blockcontainer_width , Details.breakdown_spell_tab . blockcontainer_height
local blockHeight = Details.breakdown_spell_tab . blockspell_height
local backgroundColor = Details.breakdown_spell_tab . blockspell_backgroundcolor
local borderColor = Details.breakdown_spell_tab . blockspell_bordercolor
local padding = Details.breakdown_spell_tab . blockspell_padding * - 1
local color = Details.breakdown_spell_tab . blockspell_color
self : SetSize ( width , height )
backgroundColor [ 1 ] , backgroundColor [ 2 ] , backgroundColor [ 3 ] , backgroundColor [ 4 ] = 0.05 , 0.05 , 0.05 , 0.2
color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] = 0.6 , 0.6 , 0.6 , 0.55
for i = 1 , # self.SpellBlocks do
---@type breakdownspellblock
local spellBlock = self.SpellBlocks [ i ]
spellBlock : SetSize ( width - 2 , blockHeight )
spellBlock : SetPoint ( " topleft " , self , " topleft " , 1 , ( blockHeight * ( i - 1 ) - i ) * - 1 - ( i * 2 ) + ( ( i - 1 ) * padding ) )
spellBlock : SetPoint ( " topright " , self , " topright " , 1 , ( blockHeight * ( i - 1 ) - i ) * - 1 - ( i * 2 ) + ( ( i - 1 ) * padding ) )
spellBlock.sparkTexture : SetSize ( Details.breakdown_spell_tab . blockspell_spark_width , blockHeight )
spellBlock.sparkTexture : SetShown ( Details.breakdown_spell_tab . blockspell_spark_show )
spellBlock.sparkTexture : SetVertexColor ( unpack ( Details.breakdown_spell_tab . blockspell_spark_color ) )
spellBlock.reportButton : SetPoint ( " bottomright " , spellBlock.overlay , " bottomright " , - 2 , 2 )
spellBlock.gradientTexture : SetHeight ( blockHeight )
spellBlock : SetBackdropBorderColor ( unpack ( borderColor ) ) --border color
spellBlock.statusBarTexture : SetVertexColor ( unpack ( Details.breakdown_spell_tab . blockspell_color ) ) --bar color
local lineHeight = blockHeight * 0.2687
--update the lines
local previousLine
for o = 1 , spellBlockContainerSettings.lineAmount do
---@type breakdownspellblockline
local line = spellBlock.Lines [ o ]
line : SetSize ( width - 2 , lineHeight )
if ( previousLine ) then
line : SetPoint ( " topleft " , previousLine , " bottomleft " , 0 , - 2 )
else
line : SetPoint ( " topleft " , spellBlock , " topleft " , 1 , - 2 )
end
previousLine = line
end
end
end ,
---@param self breakdownspellblockframe
ClearBlocks = function ( self )
for i = 1 , self : GetBlocksAmount ( ) do
---@type breakdownspellblock
local spellBlock = self.SpellBlocks [ i ]
spellBlock : Hide ( )
spellBlock : SetColor ( unpack ( CONST_SPELLBLOCK_DEFAULT_COLOR ) )
--set the status bar value to zero
spellBlock : SetValue ( 0 )
spellBlock.statusBarTexture : Show ( )
spellBlock.sparkTexture : Show ( )
--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
end
for i = 1 , math.min ( self : GetBlocksAmount ( ) , 4 ) do
self : ShowEmptyBlock ( i )
end
self.blocksInUse = 0
end ,
---show the empty block in the container, this is done to preview where the rectangle will be
---@param self breakdownspellblockframe
---@param index number
ShowEmptyBlock = function ( self , index )
local spellBlock = self.SpellBlocks [ index ]
spellBlock : Show ( )
spellBlock : SetValue ( 0 )
spellBlock.statusBarTexture : Hide ( )
spellBlock.sparkTexture : Hide ( )
end ,
---get a breakdownspellblock from the container
---@param self breakdownspellblockframe
---@param index number
---@return breakdownspellblock
GetBlock = function ( self , index )
self.blocksInUse = self.blocksInUse + 1
local spellBlock = self.SpellBlocks [ index ]
spellBlock.statusBarTexture : Show ( )
spellBlock.sparkTexture : Show ( )
return self.SpellBlocks [ index ]
end ,
---get the amount of blocks in use
---@param self breakdownspellblockframe
---@return number
GetBlocksInUse = function ( self )
return self.blocksInUse
end ,
---get the total blocks created
---@param self breakdownspellblockframe
---@return number
GetBlocksAmount = function ( self )
return # self.SpellBlocks
end ,
}
---create the spell blocks which shows the critical hits, normal hits, etc
---@param tabFrame tabframe
---@return breakdownspellblockframe
function spellsTab . CreateSpellBlockContainer ( tabFrame ) --~create ~createblock ~spellblock ~block ~container
--create a container for the scrollframe
local options = {
width = Details.breakdown_spell_tab . blockcontainer_width ,
height = Details.breakdown_spell_tab . blockcontainer_height ,
is_locked = Details.breakdown_spell_tab . blockcontainer_islocked ,
can_move = false ,
can_move_children = false ,
use_bottom_resizer = true ,
use_right_resizer = true ,
}
---@type df_framecontainer
local container = DF : CreateFrameContainer ( tabFrame , options , tabFrame : GetName ( ) .. " SpellScrollContainer " )
container : SetPoint ( " topleft " , spellsTab.GetSpellScrollContainer ( ) , " topright " , 26 , 0 )
container : SetFrameLevel ( tabFrame : GetFrameLevel ( ) + 10 )
spellsTab.BlocksContainerFrame = container
local settingChangedCallbackFunction = function ( frameContainer , settingName , settingValue )
if ( frameContainer : IsShown ( ) ) then
if ( settingName == " UpdateSize " ) then
--get the tabFrame width and height
local width , height = tabFrame : GetSize ( )
local containerWidth
--get with of the container holding the spellscrollframe
if ( spellsTab.GetSpellScrollContainer ( ) : IsShown ( ) ) then
containerWidth = spellsTab.GetSpellScrollContainer ( ) : GetWidth ( )
elseif ( spellsTab.GetGenericScrollContainer ( ) : IsShown ( ) ) then
containerWidth = spellsTab.GetGenericScrollContainer ( ) : GetWidth ( )
end
--calculate the widh of the spellblockcontainer by subtracting the width of the spellscrollframe container from the tabFrame width
local spellBlockContainerWidth = width - containerWidth - 38
--set the width of the spellblockcontainer
container : SetWidth ( spellBlockContainerWidth )
elseif ( settingName == " height " ) then
---@type number
local currentHeight = spellsTab.GetSpellScrollFrame ( ) : GetHeight ( )
Details.breakdown_spell_tab . blockcontainer_height = settingValue
spellsTab.GetSpellScrollFrame ( ) : SetNumFramesShown ( math.floor ( currentHeight / CONST_SPELLSCROLL_LINEHEIGHT ) - 1 )
elseif ( settingName == " width " ) then
Details.breakdown_spell_tab . blockcontainer_width = settingValue
elseif ( settingName == " is_locked " ) then
Details.breakdown_spell_tab . blockcontainer_islocked = settingValue
end
--update the spell blocks
spellsTab.GetSpellBlockFrame ( ) : UpdateBlocks ( )
if ( spellsTab.GetSelectedSpellBar ( ) ) then
onEnterSpellBar ( spellsTab.GetSelectedSpellBar ( ) )
end
end
end
container : SetSettingChangedCallback ( settingChangedCallbackFunction )
--create the container which will hold the spell blocks
---@type breakdownspellblockframe
local spellBlockFrame = CreateFrame ( " Frame " , " $parentSpellBlockContainer " , container , " BackdropTemplate " )
spellBlockFrame : EnableMouse ( false )
spellBlockFrame : SetResizable ( false )
spellBlockFrame : SetMovable ( false )
spellBlockFrame : SetAllPoints ( )
detailsFramework : Mixin ( spellBlockFrame , spellBlockContainerMixin )
tabFrame.SpellBlockFrame = spellBlockFrame
spellsTab.SpellBlockFrame = spellBlockFrame
container : RegisterChildForDrag ( spellBlockFrame )
spellBlockFrame.SpellBlocks = { }
spellBlockFrame.blocksInUse = 0
--create the spell blocks within the spellBlockFrame
for i = 1 , spellBlockContainerSettings.amount do
---@type breakdownspellblock
local spellBlock = spellsTab.CreateSpellBlock ( spellBlockFrame , i )
table.insert ( spellBlockFrame.SpellBlocks , spellBlock )
--size and point are set on ~UpdateBlocks
end
spellBlockFrame : UpdateBlocks ( )
return spellBlockFrame
end
function spellsTab . UpdateShownSpellBlock ( )
if ( spellsTab.currentSpellBar ) then
onEnterSpellBar ( spellsTab.currentSpellBar )
elseif ( spellsTab.GetSelectedSpellBar ( ) ) then
onEnterSpellBar ( spellsTab.GetSelectedSpellBar ( ) )
end
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
--in this tab, the data is sent to the refresh function
local onClickExpandButton = function ( expandButton , button )
---@type breakdownspellbar
local spellBar = expandButton : GetParent ( )
---@type table
local scrolFrame = spellBar : GetParent ( )
---@type boolean
local bIsSpellExpaded = expandButton.bIsSpellExpaded
--check if the one of the expanded bars was a selected spellbar and deselect
--get the current selected spellbar
---@type breakdownspellbar
local selectedSpellBar = spellsTab.GetSelectedSpellBar ( )
if ( bIsSpellExpaded ) then --it's already expended, it'll close the expanded spellbars
--check if the selected spellbar is one of the expanded spellbars and deselect it
for i = 1 , # spellBar.ExpandedChildren do
---@type breakdownspellbar
local expandedSpellBar = spellBar.ExpandedChildren [ i ]
if ( expandedSpellBar == selectedSpellBar ) then
--deselect the spellbar
spellsTab.UnSelectSpellBar ( )
break
end
end
else
spellsTab.UnSelectSpellBar ( )
end
--todo: check is any other bar has expanded state true, and close the expand (or not)
--toggle this spell expand mode
Details222.BreakdownWindow . SetSpellAsExpanded ( expandButton.petName or expandButton.spellId , not bIsSpellExpaded )
--call the refresh function of the window
---@type instance
local instanceObject = spellsTab.GetInstance ( )
instanceObject : RefreshWindow ( true )
end
---update a line using the data passed
---@param spellBar breakdownspellbar
---@param index number spell position (from best to wrost)
---@param actorName string
---@param combatObject combat
---@param scrollFrame table
---@param headerTable table
---@param bkSpellData spelltableadv
---@param spellTableIndex number
---@param totalValue number
---@param topValue number
---@param bIsMainLine boolean if true this is the line which has all the values of the spell merged
---@param sortKey string
---@param spellTablesAmount number
local updateSpellBar = function ( spellBar , index , actorName , combatObject , scrollFrame , headerTable , bkSpellData , spellTableIndex , totalValue , topValue , bIsMainLine , sortKey , spellTablesAmount )
--scrollFrame is defined as a table which is false, scrollFrame is a frame
local textIndex = 1
for headerIndex = 1 , # headerTable do
---@type number
local spellId
---@type number
local value
---@type spelltable
local spellTable
spellBar.bkSpellData = bkSpellData
local petName = " "
---@type boolean @if true, this is the main line of an actor which has its spells nested in the bkSpellData.nestedData
local bIsActorHeader = bkSpellData.bIsActorHeader
if ( bIsMainLine and bIsActorHeader ) then
spellTable = bkSpellData
value = bkSpellData.total
spellId = 0
petName = actorName
elseif ( bIsMainLine ) then
spellTable = bkSpellData
value = bkSpellData.total
spellId = bkSpellData.id
petName = bkSpellData.nestedData [ spellTableIndex ] . actorName
else
spellTable = bkSpellData.nestedData [ spellTableIndex ] . spellTable
value = spellTable.total
spellId = spellTable.id
--if isn't a spell from a nested actor, then it can use the pet name in the spell name
if ( not bkSpellData.nestedData [ spellTableIndex ] . bIsActorHeader ) then
petName = bkSpellData.nestedData [ spellTableIndex ] . actorName
end
spellBar.bIsExpandedSpell = true
end
spellBar.spellId = spellId
---@cast spellTable spelltable
spellBar.spellTable = spellTable
---@type string, number, any, string?, boolean?
local spellName , _ , spellIcon , defaultName , bBreakdownCanStack = Details.GetCustomSpellInfo ( spellId )
if ( not spellName ) then
spellName = actorName
---@type npcid
local npcId = tonumber ( bkSpellData.npcId ) or 0
spellIcon = Details.NpcIdToIcon [ npcId ] or bkSpellData.actorIcon or " "
end
--if this damage was made by an item, then get the default spellName of the damaging spell
--the name from GetSpellInfo are probably modified by a custom spell name
--amount of casts does not use custom names but always the damaging spell name from combatlog
local defaultSpellName = Details.GetItemSpellInfo ( spellId )
---@type number
local amtCasts = combatObject : GetSpellCastAmount ( actorName , defaultSpellName or spellName )
spellBar.amountCasts = amtCasts
---@type number
local uptime = combatObject : GetSpellUptime ( actorName , spellId )
---@type number
local combatTime = combatObject : GetCombatTime ( )
--statusbar size by percent
if ( topValue > 0 ) then
local barValue = spellTable [ sortKey ] or getValueForHeaderSortKey ( combatObject , spellTable , sortKey )
spellBar.statusBar : SetValue ( barValue / topValue * 100 )
else
spellBar.statusBar : SetValue ( 0 )
end
if ( petName ~= " " ) then
--if is a pet spell and has more pets nested || nop, now is a pet with its spells nested
if ( spellTablesAmount > 1 and bIsMainLine ) then
spellName = formatPetName ( " " , spellName , " " ) --causing error as spellName is nil
elseif ( bIsMainLine ) then
spellName = formatPetName ( petName , spellName , actorName )
else
spellName = formatPetName ( petName , " " , " " )
end
end
spellBar.spellId = spellId
spellBar.spellIconFrame . spellId = spellId
--spellBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha)
--statusbar color by school
local r , g , b = Details : GetSpellSchoolColor ( spellTable.spellschool or 1 )
spellBar.statusBar : SetStatusBarColor ( r , g , b , 0.963 )
if ( spellTable.counter > 0 ) then
spellBar.average = value / spellTable.counter
else
spellBar.average = 0.0001
end
spellBar.combatTime = combatTime
---@type fontstring
local text = spellBar.InLineTexts [ textIndex ]
local header = headerTable [ headerIndex ]
if ( header.name == " icon " ) then
spellBar.spellIcon : Show ( )
spellBar.spellIcon : SetTexture ( spellIcon )
spellBar.spellIcon : SetAlpha ( 0.92 )
spellBar : AddFrameToHeaderAlignment ( spellBar.spellIconFrame )
elseif ( header.name == " target " ) then --the tab does not have knownledge about the targets of the spell, it must be passed over
---@type breakdowntargetframe
local targetsSquareFrame = spellBar.targetsSquareFrame
targetsSquareFrame : Show ( )
targetsSquareFrame.spellId = spellId
targetsSquareFrame.bkSpellData = spellTable
targetsSquareFrame.spellTable = spellTable
targetsSquareFrame.bIsMainLine = bIsMainLine
spellBar : AddFrameToHeaderAlignment ( targetsSquareFrame )
elseif ( header.name == " rank " ) then
text : SetText ( index )
spellBar : AddFrameToHeaderAlignment ( text )
spellBar.rank = index
textIndex = textIndex + 1
elseif ( header.name == " expand " ) then
text : SetText ( " " )
spellBar : AddFrameToHeaderAlignment ( spellBar.expandButton )
textIndex = textIndex + 1
if ( bkSpellData.bCanExpand and bIsMainLine ) then
spellBar.expandButton : Show ( )
local bIsSpellExpaded = Details222.BreakdownWindow . IsSpellExpanded ( bIsActorHeader and actorName or spellId )
spellBar.expandButton . spellId = bIsActorHeader and actorName or spellId
spellBar.expandButton . bIsSpellExpaded = bIsSpellExpaded
spellBar.expandButton : SetScript ( " OnClick " , onClickExpandButton )
--update the texture taking the state of the expanded value
if ( bIsSpellExpaded ) then
spellBar.expandButton . texture : SetTexture ( [[Interface\AddOns\Details\images\arrow_face_down]] )
--spellBar.expandButton.texture:SetTexCoord(0, 1, 0, 1)
spellBar.expandButton . texture : SetRotation ( 0 )
else
spellBar.expandButton . texture : SetTexture ( [[Interface\AddOns\Details\images\arrow_face_down]] )
--spellBar.expandButton.texture:SetTexCoord(0, 1, 0, 1)
spellBar.expandButton . texture : SetRotation ( math.pi / 2 )
end
spellBar.expandButton . texture : SetAlpha ( 0.7 )
spellBar.expandButton . texture : SetSize ( 16 , 16 )
end
elseif ( header.name == " name " ) then
text : SetText ( Details : RemoveOwnerName ( spellName ) )
spellBar.name = spellName
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " amount " ) then
text : SetText ( Details : Format ( value ) )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " persecond " ) then
spellBar.perSecond = value / combatTime
---@type string
local perSecondFormatted = Details : Format ( spellBar.perSecond )
text : SetText ( perSecondFormatted )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " percent " ) then
spellBar.percent = value / totalValue * 100
---@type string
local percentFormatted = string.format ( " %.1f " , spellBar.percent ) .. " % "
text : SetText ( percentFormatted )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " casts " ) then
text : SetText ( amtCasts )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " critpercent " ) then
text : SetText ( string.format ( " %.1f " , spellTable.c_amt / ( spellTable.counter ) * 100 ) .. " % " )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " hits " ) then
text : SetText ( spellTable.counter )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " castavg " ) then
if ( amtCasts > 0 ) then
spellBar.castAverage = value / amtCasts
text : SetText ( Details : Format ( spellBar.castAverage ) )
else
text : SetText ( " 0 " )
end
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " uptime " ) then --need to get the uptime of the spell with the biggest uptime
text : SetText ( string.format ( " %.1f " , uptime / combatTime * 100 ) .. " % " )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " overheal " and spellTable.overheal ) then
if ( spellTable.overheal > 0 ) then
local totalHeal = spellTable.overheal + value
text : SetText ( Details : ToK2 ( spellTable.overheal ) .. " ( " .. math.floor ( spellTable.overheal / totalHeal * 100 ) .. " %) " )
else
text : SetText ( " 0% " )
end
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
elseif ( header.name == " absorbed " ) then
text : SetText ( Details : Format ( spellTable.absorbed or 0 ) )
spellBar : AddFrameToHeaderAlignment ( text )
textIndex = textIndex + 1
end
end
spellBar : AlignWithHeader ( scrollFrame.Header , " left " )
end
---get a spell bar from the scroll box, if it doesn't exist, return nil
---@param scrollFrame table
---@param lineIndex number
---@return breakdownspellbar
local getSpellBar = function ( scrollFrame , lineIndex )
---@type breakdownspellbar
local spellBar = scrollFrame : GetLine ( lineIndex )
spellBar.bIsExpandedSpell = false
Details : Destroy ( spellBar.ExpandedChildren )
--reset header alignment
spellBar : ResetFramesToHeaderAlignment ( )
spellsTab.UpdateBarSettings ( spellBar )
--reset columns, hiding them
spellBar.spellIcon : Hide ( )
spellBar.expandButton : Hide ( )
spellBar.targetsSquareFrame : Hide ( )
for inLineIndex = 1 , # spellBar.InLineTexts do
spellBar.InLineTexts [ inLineIndex ] : SetText ( " " )
end
return spellBar
end
---refresh the data shown in the spells scroll box
---@param scrollFrame table
---@param scrollData breakdownspelldatalist
---@param offset number
---@param totalLines number
local refreshSpellsFunc = function ( scrollFrame , scrollData , offset , totalLines ) --~refreshspells ~refreshfunc ~refresh ~refreshs
---@type number
local topValue = scrollFrame.topValue
---@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 keyToSort = scrollFrame.SortKey
local orderToSort = scrollFrame.SortKey
local headerTable = spellsTab.spellsHeaderData
--todo: when swapping sort orders, close already expanded spells
local lineIndex = 1
for i = 1 , totalLines do
local index = i + offset
---@type spelltableadv
local bkSpellData = scrollData [ index ]
if ( bkSpellData ) then
---@type number
local spellTablesAmount = # bkSpellData.nestedData
---called mainSpellBar because it is the line that shows the sum of all spells merged (if any)
---@type breakdownspellbar
local mainSpellBar = getSpellBar ( scrollFrame , lineIndex )
do
--main line of the spell, where the sum of all spells merged is shown
if ( mainSpellBar ) then
lineIndex = lineIndex + 1
local bIsMainLine = true
local bIsActorHeader = bkSpellData.bIsActorHeader
local spellTableIndex = 1
local spellBar = mainSpellBar
local nameToUse = actorName
if ( bIsActorHeader ) then
nameToUse = bkSpellData.actorName
end
--both calls are equal but the traceback will be different in case of an error
if ( bIsActorHeader ) then
updateSpellBar ( spellBar , index , nameToUse , combatObject , scrollFrame , headerTable , bkSpellData , spellTableIndex , totalValue , topValue , bIsMainLine , keyToSort , spellTablesAmount )
else
--here
updateSpellBar ( spellBar , index , nameToUse , combatObject , scrollFrame , headerTable , bkSpellData , spellTableIndex , totalValue , topValue , bIsMainLine , keyToSort , spellTablesAmount )
end
end
end
--if the spell is expanded
--then it adds the lines for each spell merged, but it cannot use the bkSpellData, it needs the spellTable, it's kinda using bkSpellData, need to debug
if ( bkSpellData.bIsExpanded and ( spellTablesAmount > 1 ) ) then
--filling necessary information to sort the data by the selected header column
for spellTableIndex = 1 , spellTablesAmount do
---@type bknesteddata
local nestedBkSpellData = bkSpellData.nestedData [ spellTableIndex ]
---@type spelltable
local spellTable = nestedBkSpellData.spellTable
nestedBkSpellData.value = spellTable [ keyToSort ] or getValueForHeaderSortKey ( combatObject , spellTable , keyToSort )
end
--sort the nested data
if ( orderToSort == " DESC " ) then
table.sort ( bkSpellData.nestedData ,
function ( t1 , t2 )
return t1.value < t2.value
end )
else
table.sort ( bkSpellData.nestedData ,
function ( t1 , t2 )
return t1.value > t2.value
end )
end
for spellTableIndex = 1 , spellTablesAmount do
---@type breakdownspellbar
local spellBar = getSpellBar ( scrollFrame , lineIndex )
if ( spellBar ) then
---@type bknesteddata
local nestedBkSpellData = bkSpellData.nestedData [ spellTableIndex ]
lineIndex = lineIndex + 1
---@type string
local petName = nestedBkSpellData.actorName
---@type string
local nameToUse = petName ~= " " and petName or actorName
local bIsMainLine = false
bkSpellData [ keyToSort ] = nestedBkSpellData.value
updateSpellBar ( spellBar , index , nameToUse , combatObject , scrollFrame , headerTable , bkSpellData , spellTableIndex , totalValue , topValue , bIsMainLine , keyToSort , spellTablesAmount )
mainSpellBar.ExpandedChildren [ # mainSpellBar.ExpandedChildren + 1 ] = spellBar
end
end
end
if ( lineIndex > totalLines ) then
break
end
end
end
end
---creates a scrollframe which show breakdownspellbar to show the spells used by an actor
---@param tabFrame tabframe
---@return breakdownspellscrollframe
function spellsTab . CreateSpellScrollContainer ( tabFrame ) --~scroll ~create ~spell ~container ~createspellcontainer
---@type width
local width = Details.breakdown_spell_tab . spellcontainer_width
---@type height
local height = Details.breakdown_spell_tab . spellcontainer_height
local options = {
width = Details.breakdown_spell_tab . spellcontainer_width ,
height = Details.breakdown_spell_tab . spellcontainer_height ,
is_locked = Details.breakdown_spell_tab . spellcontainer_islocked ,
can_move = false ,
can_move_children = false ,
use_bottom_resizer = true ,
use_right_resizer = false ,
}
---create a container for the scrollframe
---@type df_framecontainer
local container = DF : CreateFrameContainer ( tabFrame , options , tabFrame : GetName ( ) .. " SpellScrollContainer " )
container : SetPoint ( " topleft " , tabFrame , " topleft " , 5 , - 5 )
container : SetFrameLevel ( tabFrame : GetFrameLevel ( ) + 10 )
spellsTab.SpellContainerFrame = container
--when a setting is changed in the container, it will call this function, it is registered below with SetSettingChangedCallback()
local settingChangedCallbackFunction = function ( frameContainer , settingName , settingValue ) --doing here the callback for thge settings changed in the container
if ( frameContainer : IsShown ( ) ) then
if ( settingName == " height " ) then
---@type number
local currentHeight = spellsTab.GetSpellScrollFrame ( ) : GetHeight ( )
Details.breakdown_spell_tab . spellcontainer_height = settingValue
spellsTab.GetSpellScrollFrame ( ) : SetNumFramesShown ( math.floor ( currentHeight / CONST_SPELLSCROLL_LINEHEIGHT ) - 1 )
elseif ( settingName == " width " ) then
Details.breakdown_spell_tab . spellcontainer_width = settingValue
elseif ( settingName == " is_locked " ) then
Details.breakdown_spell_tab . spellcontainer_islocked = settingValue
end
spellsTab.GetSpellBlockContainer ( ) : SendSettingChangedCallback ( " UpdateSize " , - 1 )
end
end
container : SetSettingChangedCallback ( settingChangedCallbackFunction )
--amount of lines which will be created for the scrollframe
local defaultAmountOfLines = 50
---@type breakdownspellscrollframe
local scrollFrame = DF : CreateScrollBox ( container , " $parentSpellScroll " , refreshSpellsFunc , { } , width , height , defaultAmountOfLines , CONST_SPELLSCROLL_LINEHEIGHT )
DF : ReskinSlider ( scrollFrame )
scrollFrame : SetPoint ( " topleft " , container , " topleft " , 0 , 0 ) --need to set the points
scrollFrame : SetPoint ( " bottomright " , container , " bottomright " , 0 , 0 ) --need to set the points
container : RegisterChildForDrag ( scrollFrame )
scrollFrame.DontHideChildrenOnPreRefresh = true
tabFrame.SpellScrollFrame = scrollFrame
spellsTab.SpellScrollFrame = scrollFrame
spellsTab.ApplyStandardBackdrop ( container , scrollFrame )
---@param self breakdownphasescrollframe
---@return breakdownreporttable
function scrollFrame : GetReportData ( )
local instance = spellsTab.GetInstance ( )
---@type breakdownspelldatalist
local data = self : GetData ( )
local formatFunc = Details : GetCurrentToKFunction ( )
local actorObject = spellsTab.GetActor ( )
local displayId , subDisplayId = instance : GetDisplay ( )
local subDisplayName = Details : GetSubAttributeName ( displayId , subDisplayId )
local combatName = instance : GetCombat ( ) : GetCombatName ( )
---@type breakdownreporttable
local reportData = {
title = subDisplayName .. " for " .. detailsFramework : RemoveRealmName ( actorObject : Name ( ) ) .. " | " .. combatName
}
local topValue = data [ 1 ] and data [ 1 ] . total or 0
for i = 1 , # data do
---@type spelltableadv
local bkSpellData = data [ i ]
local spellId = bkSpellData.id
local spellName = Details.GetSpellInfo ( spellId )
if ( not spellName ) then
--dumpt(bkSpellData)
if ( bkSpellData.npcId ) then
spellName = detailsFramework : CleanUpName ( bkSpellData.actorName )
end
else
spellName = detailsFramework : CleanUpName ( spellName )
end
reportData [ # reportData + 1 ] = {
name = spellName ,
amount = formatFunc ( nil , bkSpellData.total ) ,
percent = string.format ( " %.1f " , bkSpellData.total / topValue * 100 ) .. " % " ,
}
end
return reportData
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 ,
header_click_callback = onColumnHeaderClickCallback ,
header_backdrop_color = { 0.1 , 0.1 , 0.1 , 0.4 } ,
text_color = { 1 , 1 , 1 , 0.823 } ,
}
local headerTable = { }
---create the header frame, the header frame is the frame which shows the columns names to describe the data shown in the scrollframe
---@type df_headerframe
local header = DetailsFramework : CreateHeader ( container , headerTable , headerOptions )
scrollFrame.Header = header
scrollFrame.Header : SetPoint ( " topleft " , scrollFrame , " topleft " , 0 , 1 )
scrollFrame.Header : SetColumnSettingChangedCallback ( spellsTab.OnHeaderColumnOptionChanged )
--cache the containerType which this header is used for
headerContainerType [ scrollFrame.Header ] = " spells "
--create the scroll lines
for i = 1 , defaultAmountOfLines do
scrollFrame : CreateLine ( spellsTab.CreateSpellBar )
end
---set the data and refresh the scrollframe
---@param self breakdownspellscrollframe
---@param data breakdownspelldatalist
function scrollFrame : RefreshMe ( data ) --~refreshme (spells) ~refreshmes
--get which column is currently selected and the sort order
local columnIndex , order , key = scrollFrame.Header : GetSelectedColumn ( )
scrollFrame.SortKey = key
scrollFrame.SortOrder = order
---@type string
local keyToSort = key
---@type combat
local combatObject = spellsTab.GetCombat ( )
---@type number, number
local mainAttribute , subAttribute = spellsTab.GetInstance ( ) : GetDisplay ( )
--filling necessary information to sort the data by the selected header column
for i = 1 , # data do
---@type spelltableadv
local bkSpellData = data [ i ]
if ( not bkSpellData [ keyToSort ] ) then
local value = getValueForHeaderSortKey ( combatObject , bkSpellData , keyToSort )
bkSpellData [ keyToSort ] = value
end
end
if ( order == " DESC " ) then
table.sort ( data ,
---@param t1 spelltableadv
---@param t2 spelltableadv
function ( t1 , t2 )
return t1 [ keyToSort ] > t2 [ keyToSort ]
end )
self.topValue = data [ 1 ] and data [ 1 ] [ keyToSort ]
else
table.sort ( data ,
---@param t1 spelltableadv
---@param t2 spelltableadv
function ( t1 , t2 )
return t1 [ keyToSort ] < t2 [ keyToSort ]
end )
self.topValue = data [ # data ] and data [ # data ] [ keyToSort ]
end
self : SetData ( data )
self : Refresh ( )
end
return scrollFrame
end
---create a spellbar within the spell scroll
---@param self breakdownspellscrollframe
---@param index number
---@return breakdownspellbar
function spellsTab . CreateSpellBar ( self , index ) --~spellbar ~spellline ~spell ~create ~createline ~createspell ~createspellbar
---@type breakdownspellbar
local spellBar = CreateFrame ( " button " , self : GetName ( ) .. " SpellBarButton " .. index , self )
spellBar.index = index
--size and positioning
spellBar : SetHeight ( CONST_SPELLSCROLL_LINEHEIGHT )
local y = ( index - 1 ) * CONST_SPELLSCROLL_LINEHEIGHT * - 1 + ( 1 * - index ) - 15
spellBar : SetPoint ( " topleft " , self , " topleft " , 1 , y )
spellBar : SetPoint ( " topright " , self , " topright " , - 1 , y )
spellBar : EnableMouse ( true )
spellBar : RegisterForClicks ( " AnyUp " , " AnyDown " )
spellBar : SetAlpha ( 0.823 )
spellBar : SetFrameStrata ( " high " )
spellBar : SetScript ( " OnEnter " , onEnterSpellBar )
spellBar : SetScript ( " OnLeave " , onLeaveSpellBar )
spellBar : SetScript ( " OnMouseDown " , onMouseDownBreakdownSpellBar )
spellBar : SetScript ( " OnMouseUp " , onMouseUpBreakdownSpellBar )
spellBar.onMouseUpTime = 0
spellBar.ExpandedChildren = { }
DF : Mixin ( spellBar , DF.HeaderFunctions )
---@type breakdownspellbarstatusbar
local statusBar = CreateFrame ( " StatusBar " , " $parentStatusBar " , spellBar )
statusBar : SetAllPoints ( )
statusBar : SetAlpha ( 0.5 )
statusBar : SetMinMaxValues ( 0 , 100 )
statusBar : SetValue ( 50 )
statusBar : EnableMouse ( false )
statusBar : SetFrameLevel ( spellBar : GetFrameLevel ( ) - 1 )
spellBar.statusBar = statusBar
---@type texture this is the statusbar texture
local statusBarTexture = statusBar : CreateTexture ( " $parentTexture " , " artwork " )
statusBar : SetStatusBarTexture ( statusBarTexture )
statusBar : SetStatusBarColor ( 1 , 1 , 1 , 1 )
---@type texture background texture
local backgroundTexture = statusBar : CreateTexture ( " $parentTextureBackground " , " border " )
backgroundTexture : SetAllPoints ( )
statusBar.backgroundTexture = backgroundTexture
---@type texture overlay texture to use when the spellbar is selected
local statusBarOverlayTexture = statusBar : CreateTexture ( " $parentTextureOverlay " , " overlay " , nil , 7 )
statusBarOverlayTexture : SetTexture ( [[Interface/AddOns/Details/images/overlay_indicator_1]] )
statusBarOverlayTexture : SetVertexColor ( 1 , 1 , 1 , 0.2 )
statusBarOverlayTexture : SetAllPoints ( )
statusBarOverlayTexture : Hide ( )
spellBar.overlayTexture = statusBarOverlayTexture
statusBar.overlayTexture = statusBarOverlayTexture
---@type texture shown when the mouse hoverover this spellbar
local hightlightTexture = statusBar : CreateTexture ( " $parentTextureHighlight " , " highlight " )
hightlightTexture : SetColorTexture ( 1 , 1 , 1 , 0.2 )
hightlightTexture : SetAllPoints ( )
statusBar.highlightTexture = hightlightTexture
--button to expand the bar when there's spells merged
---@type breakdownexpandbutton
local expandButton = CreateFrame ( " button " , " $parentExpandButton " , spellBar , " BackdropTemplate " )
expandButton : SetSize ( CONST_BAR_HEIGHT , CONST_BAR_HEIGHT )
expandButton : RegisterForClicks ( " LeftButtonDown " )
spellBar.expandButton = expandButton
---@type texture
local expandButtonTexture = expandButton : CreateTexture ( " $parentTexture " , " artwork " )
expandButtonTexture : SetPoint ( " center " , expandButton , " center " , 0 , 0 )
expandButtonTexture : SetSize ( CONST_BAR_HEIGHT - 2 , CONST_BAR_HEIGHT - 2 )
expandButton.texture = expandButtonTexture
--frame which will show the spell tooltip
---@type frame
local spellIconFrame = CreateFrame ( " frame " , " $parentIconFrame " , spellBar , " BackdropTemplate " )
spellIconFrame : SetSize ( CONST_BAR_HEIGHT - 2 , CONST_BAR_HEIGHT - 2 )
spellIconFrame : SetScript ( " OnEnter " , onEnterSpellIconFrame )
spellIconFrame : SetScript ( " OnLeave " , onLeaveSpellIconFrame )
spellBar.spellIconFrame = spellIconFrame
--create the icon to show the spell texture
---@type texture
local spellIcon = spellIconFrame : CreateTexture ( " $parentTexture " , " overlay " )
spellIcon : SetAllPoints ( )
spellIcon : SetTexCoord ( .1 , .9 , .1 , .9 )
detailsFramework : SetMask ( spellIcon , Details : GetTextureAtlas ( " iconmask " ) )
spellBar.spellIcon = spellIcon
--create a square frame which is placed at the right side of the line to show which targets for damaged by the spell
---@type breakdowntargetframe
local targetsSquareFrame = CreateFrame ( " frame " , " $parentTargetsFrame " , statusBar , " BackdropTemplate " )
targetsSquareFrame : SetSize ( CONST_SPELLSCROLL_LINEHEIGHT , CONST_SPELLSCROLL_LINEHEIGHT )
targetsSquareFrame : SetAlpha ( .7 )
targetsSquareFrame : SetScript ( " OnEnter " , onEnterSpellTarget )
targetsSquareFrame : SetScript ( " OnLeave " , onLeaveSpellTarget )
targetsSquareFrame : SetFrameLevel ( statusBar : GetFrameLevel ( ) + 2 )
spellBar.targetsSquareFrame = targetsSquareFrame
---@type texture
local targetTexture = targetsSquareFrame : CreateTexture ( " $parentTexture " , " overlay " )
targetTexture : SetTexture ( CONST_TARGET_TEXTURE )
targetTexture : SetAllPoints ( )
targetTexture : SetDesaturated ( true )
spellBar.targetsSquareTexture = targetTexture
targetsSquareFrame.texture = targetTexture
spellBar : AddFrameToHeaderAlignment ( spellIconFrame )
spellBar : AddFrameToHeaderAlignment ( targetsSquareFrame )
--create texts
---@type fontstring[]
spellBar.InLineTexts = { }
for i = 1 , 16 do
---@type fontstring
local fontString = spellBar : CreateFontString ( " $parentFontString " .. i , " overlay " , " GameFontHighlightSmall " )
fontString : SetJustifyH ( " left " )
fontString : SetTextColor ( 1 , 1 , 1 , 1 )
fontString : SetNonSpaceWrap ( true )
fontString : SetWordWrap ( false )
spellBar [ " lineText " .. i ] = fontString
spellBar.InLineTexts [ i ] = fontString
fontString : SetTextColor ( 1 , 1 , 1 , 1 )
spellBar : AddFrameToHeaderAlignment ( fontString )
end
spellBar : AlignWithHeader ( self.Header , " left " )
return spellBar
end