@@ -317,4 +317,151 @@ function M.DrawCalcsTooltip(tooltip, primaryBuild, primaryLabel, colData, rowLab
317317 SetDrawLayer (nil , 0 )
318318end
319319
320+ -- Resolve a modifier's source name for breakdown panel display
321+ local function resolveModSource (mod , build )
322+ local sourceType = mod .source and mod .source :match (" [^:]+" ) or " ?"
323+ local sourceName = " "
324+ if sourceType == " Item" then
325+ local itemId = mod .source :match (" Item:(%d+):.+" )
326+ local item = build .itemsTab and build .itemsTab .items [tonumber (itemId )]
327+ if item then
328+ sourceName = colorCodes [item .rarity ] .. item .name
329+ end
330+ elseif sourceType == " Tree" then
331+ local nodeId = mod .source :match (" Tree:(%d+)" )
332+ if nodeId then
333+ local nodeIdNum = tonumber (nodeId )
334+ local node = (build .spec and build .spec .nodes [nodeIdNum ])
335+ or (build .spec and build .spec .tree and build .spec .tree .nodes [nodeIdNum ])
336+ or (build .latestTree and build .latestTree .nodes [nodeIdNum ])
337+ if node then
338+ sourceName = node .dn or node .name or " "
339+ end
340+ end
341+ elseif sourceType == " Skill" then
342+ local skillId = mod .source :match (" Skill:(.+)" )
343+ if skillId and build .data and build .data .skills [skillId ] then
344+ sourceName = build .data .skills [skillId ].name
345+ end
346+ elseif sourceType == " Pantheon" then
347+ sourceName = mod .source :match (" Pantheon:(.+)" ) or " "
348+ elseif sourceType == " Spectre" then
349+ sourceName = mod .source :match (" Spectre:(.+)" ) or " "
350+ end
351+ return sourceType , sourceName
352+ end
353+
354+ -- Draw a breakdown panel for a single build's SkillBuffs or SkillDebuffs,
355+ function M .DrawSkillBreakdownPanel (build , breakdownKey , label , cellX , cellY , cellW , cellH , vp )
356+ local player = build .calcsTab and build .calcsTab .calcsEnv
357+ and build .calcsTab .calcsEnv .player
358+ if not player or not player .breakdown then return end
359+
360+ local breakdown = player .breakdown [breakdownKey ]
361+ if not breakdown or not breakdown .modList or # breakdown .modList == 0 then return end
362+
363+ local modList = breakdown .modList
364+
365+ -- Sort by mod name then value
366+ local rowList = {}
367+ for _ , entry in ipairs (modList ) do
368+ t_insert (rowList , entry )
369+ end
370+ table.sort (rowList , function (a , b )
371+ return a .mod .name > b .mod .name or (a .mod .name == b .mod .name
372+ and type (a .value ) == " number" and type (b .value ) == " number"
373+ and a .value > b .value )
374+ end )
375+
376+ -- Process rows: compute display strings and measure column widths
377+ local colDefs = {
378+ { label = " Value" , key = " displayValue" },
379+ { label = " Stat" , key = " name" },
380+ { label = " Source" , key = " source" },
381+ { label = " Source Name" , key = " sourceName" },
382+ }
383+
384+ local rows = {}
385+ for _ , entry in ipairs (rowList ) do
386+ local mod = entry .mod
387+ local row = {}
388+ row .displayValue = M .FormatCalcModValue (entry .value , mod .type )
389+ row .name = M .FormatCalcModName (mod .name or " " )
390+ local sourceType , sourceName = resolveModSource (mod , build )
391+ row .source = sourceType
392+ row .sourceName = sourceName
393+ t_insert (rows , row )
394+ end
395+
396+ -- Measure column widths
397+ for _ , col in ipairs (colDefs ) do
398+ col .width = DrawStringWidth (16 , " VAR" , col .label ) + 6
399+ for _ , row in ipairs (rows ) do
400+ if row [col .key ] then
401+ col .width = math.max (col .width , DrawStringWidth (12 , " VAR" , row [col .key ]) + 6 )
402+ end
403+ end
404+ end
405+
406+ -- Calculate panel size
407+ local panelPadding = 4
408+ local headerRowH = 20
409+ local dataRowH = 14
410+ local panelW = panelPadding
411+ for _ , col in ipairs (colDefs ) do
412+ panelW = panelW + col .width
413+ end
414+ local panelH = headerRowH + # rows * dataRowH + 4
415+
416+ -- Position panel next to the hovered cell (right side, or left if no room)
417+ local panelX = cellX + cellW + 5
418+ if panelX + panelW > vp .x + vp .width then
419+ panelX = math.max (vp .x , cellX - 5 - panelW )
420+ end
421+ local panelY = math.min (cellY , vp .y + vp .height - panelH )
422+
423+ -- Draw background
424+ SetDrawLayer (nil , 10 )
425+ SetDrawColor (0 , 0 , 0 , 0.9 )
426+ DrawImage (nil , panelX + 2 , panelY + 2 , panelW - 4 , panelH - 4 )
427+
428+ -- Draw border
429+ SetDrawLayer (nil , 11 )
430+ SetDrawColor (0.33 , 0.66 , 0.33 )
431+ DrawImage (nil , panelX , panelY , panelW , 2 )
432+ DrawImage (nil , panelX , panelY + panelH - 2 , panelW , 2 )
433+ DrawImage (nil , panelX , panelY , 2 , panelH )
434+ DrawImage (nil , panelX + panelW - 2 , panelY , 2 , panelH )
435+ SetDrawLayer (nil , 10 )
436+
437+ -- Draw column headers and separators
438+ local colX = panelX + panelPadding
439+ for i , col in ipairs (colDefs ) do
440+ col .x = colX
441+ if i > 1 then
442+ SetDrawColor (0.5 , 0.5 , 0.5 )
443+ DrawImage (nil , colX - 2 , panelY + 2 , 1 , panelH - 4 )
444+ end
445+ SetDrawColor (1 , 1 , 1 )
446+ DrawString (colX , panelY + 2 , " LEFT" , 16 , " VAR" , col .label )
447+ colX = colX + col .width
448+ end
449+
450+ -- Draw rows
451+ local rowY = panelY + headerRowH
452+ for _ , row in ipairs (rows ) do
453+ -- Row separator
454+ SetDrawColor (0.5 , 0.5 , 0.5 )
455+ DrawImage (nil , panelX + 2 , rowY - 1 , panelW - 4 , 1 )
456+ for _ , col in ipairs (colDefs ) do
457+ if row [col .key ] and row [col .key ] ~= " " then
458+ DrawString (col .x , rowY + 1 , " LEFT" , 12 , " VAR" , " ^7" .. row [col .key ])
459+ end
460+ end
461+ rowY = rowY + dataRowH
462+ end
463+
464+ SetDrawLayer (nil , 0 )
465+ end
466+
320467return M
0 commit comments