--this file controls the left panel of the breakdown window, where the player list and plugins are shown ---@type details local Details = _G.Details ---@class detailsframework local detailsFramework = _G.DetailsFramework local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true) local addonName, Details222 = ... local breakdownWindowPlayerList = {} local unpack = table.unpack or unpack local C_Timer = _G.C_Timer local tinsert = table.insert local CreateFrame = CreateFrame local GetSpecializationInfoByID = GetSpecializationInfoByID local PixelUtil = PixelUtil local scrollbox_size = {215, 405} local scrollbox_lines = 20 local player_line_height = 20 local scrollbox_line_backdrop_color = {0.2, 0.2, 0.2, 0.5} local scrollbox_line_backdrop_color_selected = {1, 1, 0, 0.45} local scrollbox_line_backdrop_color_highlight = {.9, .9, .9, 0.5} local player_scroll_size = {195, 288} ---@type table local lastSelectedPlayerPerSegment = {} ---@type actorname local lastSelectedPlayerName = "" local onPlayerSelected = function(breakdownWindowFrame, playerObject) ---@type instance local instanceObject = Details:GetActiveWindowFromBreakdownWindow() Details:OpenBreakdownWindow(instanceObject, playerObject, false, true) --cache the latest selected player for this combat ---@type combat local combatObject = instanceObject:GetCombat() ---@type actorname local playerName = playerObject:Name() lastSelectedPlayerPerSegment[combatObject:GetCombatUID()] = playerName lastSelectedPlayerName = playerName breakdownWindowFrame.playerScrollBox:Refresh() end local getActorToShowInBreakdownWindow = function(combatObject) ---@type breakdownwindow local breakdownWindowFrame = Details.BreakdownWindowFrame --when the select is selected, figure out which player need to be selected in the playerScroll ---@type instance local instanceObject = Details:GetActiveWindowFromBreakdownWindow() ---@type uniquecombatid local combatUID = combatObject:GetCombatUID() local displayId, subDisplayId = instanceObject:GetDisplay() ---@type actorname local playerName = lastSelectedPlayerPerSegment[combatUID] if (playerName) then ---@type actor local playerObject = combatObject:GetActor(displayId, playerName) return playerObject else ---@type actor local playerObject = combatObject:GetActor(displayId, lastSelectedPlayerName) if (playerObject) then lastSelectedPlayerPerSegment[combatUID] = playerObject:Name() return playerObject else playerObject = combatObject:GetActor(displayId, Details.playername) if (playerObject) then lastSelectedPlayerPerSegment[combatUID] = playerObject:Name() return playerObject end --get the top player from the combat display and subDisplay and select it ---@type actor local actorObject = instanceObject:GetActorBySubDisplayAndRank(displayId, subDisplayId, 1) if (actorObject) then lastSelectedPlayerPerSegment[combatUID] = actorObject:Name() return actorObject end end end end ---this function get the list of active plugins which has a frame to show in the breakdown window and create a button for each one ---@param breakdownWindowFrame breakdownwindow ---@param pluginsFrame frame ---@param breakdownSideMenu frame ---@return number height how much space pluginsFrame is using local refreshPluginButtons = function(breakdownWindowFrame, pluginsFrame, breakdownSideMenu) local amountPluginButtons = #breakdownWindowFrame.RegisteredPluginButtons local pluginButtonHeight = 20 local spacingBetweenButtons = 1 local totalHeight = 0 for i = 1, amountPluginButtons do ---@type button local pluginButton = breakdownWindowFrame.RegisteredPluginButtons[i] pluginButton:Show() PixelUtil.SetSize(pluginButton, pluginsFrame:GetWidth() - 4, pluginButtonHeight) pluginButton:ClearAllPoints() if (i == 1) then PixelUtil.SetPoint(pluginButton, "topleft", pluginsFrame, "topleft", 2, -22) else PixelUtil.SetPoint(pluginButton, "topleft", breakdownWindowFrame.RegisteredPluginButtons[i - 1], "bottomleft", 0, -spacingBetweenButtons) end local fontString = _G[pluginButton:GetName() .. "_Text"] Details222.BreakdownWindow.ApplyFontSettings(fontString) totalHeight = totalHeight + pluginButtonHeight + spacingBetweenButtons end --add the height of the header and the spacing between the header and the first button and the last button and the bottom of the frame totalHeight = totalHeight + 20 + 2 pluginsFrame:SetPoint("topleft", breakdownSideMenu, "topleft", 0, 0) pluginsFrame:SetWidth(breakdownSideMenu:GetWidth()) pluginsFrame:SetHeight(amountPluginButtons * pluginButtonHeight + 22 + (amountPluginButtons * 1)) return totalHeight end local createPlayerScrollBox = function(breakdownWindowFrame, breakdownSideMenu, playerSelectionHeaderFrame) local refreshPlayerScrollFunc = function(self, data, offset, totalLines) local topResult = data[1] if (topResult) then topResult = topResult.total end ---@type combat local combatObject = Details:GetCombatFromBreakdownWindow() local encounterId = combatObject:GetEncounterCleuID() local difficultyId = combatObject:GetDifficulty() for i = 1, totalLines do --~refresh local index = i + offset local playerObject = data[index] if (playerObject) then local line = self:GetLine(i) if (line) then line.playerObject = playerObject line.combatObject = combatObject line.index = index line:UpdateLine(topResult, encounterId, difficultyId) end end end end local lineOnClick = function(self) if (self.playerObject ~= Details:GetActorObjectFromBreakdownWindow() or breakdownWindowFrame.shownPluginObject) then onPlayerSelected(breakdownWindowFrame, self.playerObject) end end local lineOnEnter = function(self) self:SetBackdropColor(unpack(scrollbox_line_backdrop_color_highlight)) self.specIcon:SetBlendMode("ADD") self.roleIcon:SetBlendMode("ADD") end local lineOnLeave = function(self) if (self.isSelected) then self:SetBackdropColor(unpack(scrollbox_line_backdrop_color_selected)) else self:SetBackdropColor(unpack(scrollbox_line_backdrop_color)) end self.specIcon:SetBlendMode("BLEND") self.roleIcon:SetBlendMode("BLEND") end local updatePlayerLine = function(self, topResult, encounterId, difficultyId) --~update local playerSelected = lastSelectedPlayerName if (playerSelected == self.playerObject:Name()) then self:SetBackdropColor(unpack(scrollbox_line_backdrop_color_selected)) self.isSelected = true else self:SetBackdropColor(unpack(scrollbox_line_backdrop_color)) self.isSelected = nil end local specRole --adjust the player icon if (self.playerObject.spellicon) then self.specIcon:SetTexture(self.playerObject.spellicon) self.specIcon:SetTexCoord(.1, .9, .1, .9) else local specIcon, L, R, T, B = Details:GetSpecIcon(self.playerObject.spec, false) if (specIcon) then self.specIcon:SetTexture(specIcon) self.specIcon:SetTexCoord(L, R, T, B) specRole = "NONE" else self.specIcon:SetTexture("") end end --adjust the role icon if (specRole) then local roleIcon, L, R, T, B = Details:GetRoleIcon(specRole) if (roleIcon) then self.roleIcon:SetTexture(roleIcon) self.roleIcon:SetTexCoord(L, R, T, B) else self.roleIcon:SetTexture("") end else self.roleIcon:SetTexture("") end local playerGear = openRaidLib and openRaidLib.GetUnitGear(self.playerObject.nome) --do not show the role icon self.roleIcon:SetTexture("") --not in use --set the player name self.playerName:SetText(Details:GetOnlyName(self.playerObject.nome)) self.rankText:SetText(self.index) --not in use --item level local itemLevel = Details.ilevel:GetIlvl(self.playerObject.serial) self.itemLevelText:SetText((itemLevel and itemLevel.ilvl and math.floor(itemLevel.ilvl)) or (self.playerObject.ilvl) or (playerGear and playerGear.ilevel) or "0") local actorSpecId = self.playerObject.spec local actorTotal = self.playerObject.total local combatObject = self.combatObject -- we dont have warcraft logs or any percentile stuff. self.percentileText:SetText("N/A") self.percentileText:SetAlpha(0.25) Details222.BreakdownWindow.ApplyFontSettings(self.playerName) Details222.BreakdownWindow.ApplyFontSettings(self.itemLevelText) Details222.BreakdownWindow.ApplyFontSettings(self.percentileText) Details222.BreakdownWindow.ApplyTextureSettings(self.totalStatusBar) --set the statusbar local r, g, b = self.playerObject:GetClassColor() self.totalStatusBar:SetStatusBarColor(r, g, b, 1) self.totalStatusBar:SetMinMaxValues(0, topResult) self.totalStatusBar:SetValue(actorTotal) end --get a Details! window local lowerInstanceId = Details:GetLowerInstanceNumber() local fontFile local fontSize local fontOutline --header setup local headerTable = { {text = "", width = 20}, {text = "Player Name", width = 100}, {text = "iLvL", width = 30}, {text = "WCL Parse", width = 60}, } local headerOptions = { padding = 2, } if (lowerInstanceId) then local instance = Details:GetInstance(lowerInstanceId) if (instance) then fontFile = instance.row_info.font_face fontSize = instance.row_info.font_size fontOutline = instance.row_info.textL_outline end end local createPlayerLine = function(self, index) --create a new line local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate") detailsFramework:SetTemplate(line, "STANDARD_GRAY") detailsFramework:Mixin(line, detailsFramework.HeaderFunctions) ---@type frame local OTTFrame = CreateFrame("frame", nil, line) OTTFrame:SetFrameLevel(line:GetFrameLevel()+2) OTTFrame:SetAllPoints() line.OTTFrame = OTTFrame PixelUtil.SetPoint(line, "topleft", breakdownWindowFrame.PlayerSelectionHeader, "topleft", 1, -((index) * (player_line_height+1))) PixelUtil.SetSize(line, scrollbox_size[1]-2, player_line_height) line:RegisterForClicks("LeftButtonDown", "RightButtonDown") line:SetScript("OnEnter", lineOnEnter) line:SetScript("OnLeave", lineOnLeave) line:SetScript("OnClick", lineOnClick) local specIcon = OTTFrame:CreateTexture("$parentSpecIcon", "artwork") specIcon:SetSize(headerTable[1].width - 1, headerTable[1].width - 1) specIcon:SetAlpha(0.834) local roleIcon = OTTFrame:CreateTexture("$parentRoleIcon", "overlay") roleIcon:SetSize((player_line_height-2) / 2, (player_line_height-2) / 2) roleIcon:SetAlpha(0.71) local playerName = OTTFrame:CreateFontString("$parentPlayerName", "artwork", "GameFontNormal") playerName:SetTextColor(1, 1, 1, .9) local className = detailsFramework:CreateLabel(OTTFrame, "", "GameFontNormal") className.textcolor = {.95, .8, .2, 0} className.textsize = 9 local itemLevelText = detailsFramework:CreateLabel(OTTFrame, "", "GameFontNormal") itemLevelText.textcolor = {1, 1, 1, .7} itemLevelText.textsize = 11 local percentileText = detailsFramework:CreateLabel(OTTFrame, "", "GameFontNormal") percentileText.textcolor = {1, 1, 1, .7} percentileText.textsize = 11 local rankText = detailsFramework:CreateLabel(OTTFrame, "", "GameFontNormal") rankText.textcolor = {.3, .3, .3, .7} rankText.textsize = fontSize local totalStatusBar = CreateFrame("statusbar", nil, line) totalStatusBar:SetSize(scrollbox_size[1]-player_line_height, player_line_height) totalStatusBar:SetMinMaxValues(0, 100) totalStatusBar:SetFrameLevel(line:GetFrameLevel()+1) totalStatusBar:SetAlpha(0.5) totalStatusBar:SetPoint("bottomleft", specIcon, "bottomright", 0, 0) line.specIcon = specIcon line.roleIcon = roleIcon line.playerName = playerName line.className = className line.rankText = rankText line.totalStatusBar = totalStatusBar line.itemLevelText = itemLevelText line.percentileText = percentileText line:AddFrameToHeaderAlignment(specIcon) line:AddFrameToHeaderAlignment(playerName) line:AddFrameToHeaderAlignment(itemLevelText) line:AddFrameToHeaderAlignment(percentileText) line:AlignWithHeader(breakdownWindowFrame.PlayerSelectionHeader, "left") line.UpdateLine = updatePlayerLine return line end ---@type width local width = player_scroll_size[1] + 22 ---@type height local height = player_scroll_size[2] local playerScroll = detailsFramework:CreateScrollBox(breakdownSideMenu, "DetailsBreakdownWindowPlayerScrollBox", refreshPlayerScrollFunc, {}, width, height, scrollbox_lines, player_line_height) detailsFramework:ReskinSlider(playerScroll) playerScroll.ScrollBar:ClearAllPoints() playerScroll.ScrollBar:SetPoint("topright", playerScroll, "topright", -2, -37) playerScroll.ScrollBar:SetPoint("bottomright", playerScroll, "bottomright", -2, 17) breakdownWindowFrame.playerScrollBox = playerScroll playerScroll.ScrollBar:Hide() --remove the standard backdrop playerScroll:SetBackdrop({}) playerScroll:SetBackdropColor(0, 0, 0, 0) playerScroll:SetBackdropBorderColor(0, 0, 0, 0) playerScroll.__background:Hide() --create the header frame for the player scrollbox selection ---@type df_headerframe breakdownWindowFrame.PlayerSelectionHeader = DetailsFramework:CreateHeader(playerScroll, headerTable, headerOptions) breakdownWindowFrame.PlayerSelectionHeader:SetAlpha(0.823) breakdownWindowFrame.PlayerSelectionHeader:SetPoint("topleft", playerSelectionHeaderFrame, "bottomleft", 0, -2) breakdownWindowFrame.PlayerSelectionHeader:SetPoint("topright", playerSelectionHeaderFrame, "bottomright", 0, -2) detailsFramework:ApplyStandardBackdrop(breakdownWindowFrame.PlayerSelectionHeader) breakdownWindowFrame.PlayerSelectionHeader.__background:SetTexture(.60, .60, .60) --create the scrollbox lines for i = 1, scrollbox_lines do playerScroll:CreateLine(createPlayerLine) end return playerScroll end local createSegmentsScrollBox = function(breakdownWindowFrame, breakdownSideMenu, playerSelectionHeaderFrame) local refreshSegmentsScrollFunc = function(self, data, offset, totalLines) for lineIndex = 1, totalLines do --~refresh local index = lineIndex + offset ---@type breakdownsegmentdata local segmentData = data[index] if (segmentData) then ---@type breakdownsegmentline local line = self:GetLine(lineIndex) if (line) then line:UpdateLine(lineIndex, segmentData) end end end end local lineOnClick = function(self) --unique combat id from the button clicked local combatUniqueID = self.combatUniqueID if (not Details:DoesCombatWithUIDExists(combatUniqueID)) then Details:Msg("This segment is not available anymore.") return end --current breakdown combat local currentBKCombat = Details:GetCombatFromBreakdownWindow() --unique combat id from the combat the breakdown window is using local currentBKCombatUniqueID = currentBKCombat:GetCombatUID() if (combatUniqueID ~= currentBKCombatUniqueID) then local newCombatToShowInBreakdownWindow = Details:GetCombatByUID(combatUniqueID) if (newCombatToShowInBreakdownWindow) then ---@cast newCombatToShowInBreakdownWindow combat local instanceObject = Details:GetActiveWindowFromBreakdownWindow() --set the segment of the instance to be the segment just selected by the user instanceObject:SetSegment(newCombatToShowInBreakdownWindow:GetSegmentSlotId()) local bFromAttributeChange = false local bIsRefresh = true local actor = getActorToShowInBreakdownWindow(newCombatToShowInBreakdownWindow) if (actor) then Details:OpenBreakdownWindow(instanceObject, actor, bFromAttributeChange, bIsRefresh) else local actorObject = Details:GetActorObjectFromBreakdownWindow() lastSelectedPlayerPerSegment[combatUniqueID] = actorObject:Name() Details:OpenBreakdownWindow(instanceObject, actorObject, bFromAttributeChange, bIsRefresh) end breakdownWindowFrame.segmentScrollBox:Refresh() end end end local lineOnEnter = function(self) if (not self.isSelected) then self:SetBackdropColor(unpack(scrollbox_line_backdrop_color_highlight)) end end local lineOnLeave = function(self) if (not self.isSelected) then self:SetBackdropColor(unpack(scrollbox_line_backdrop_color)) end end ---update the segment line from the segments scrollbox ---@param self breakdownsegmentline ---@param index number ---@param segmentData breakdownsegmentdata local updateSegmentLine = function(self, index, segmentData) --~update local combatName = segmentData.combatName local r, g, b = segmentData.r, segmentData.g, segmentData.b local combatIcon1 = segmentData.combatIcon self.segmentText:SetText(combatName) Details222.BreakdownWindow.ApplyFontSettings(self.segmentText) self.segmentText:SetTextColor(r, g, b) detailsFramework:TruncateText(self.segmentText, player_scroll_size[1] - 20) local bUseAtlasSize = true detailsFramework:SetAtlas(self.segmentIcon, combatIcon1, bUseAtlasSize) self.combatUniqueID = segmentData.UID local combatSelected = Details:GetCombatFromBreakdownWindow() if (combatSelected and combatSelected:GetCombatUID() == segmentData.UID) then self:SetBackdropColor(unpack(scrollbox_line_backdrop_color_selected)) self.isSelected = true else self:SetBackdropColor(unpack(scrollbox_line_backdrop_color)) self.isSelected = false end end --header setup local headerTable = { {text = "Segment Name", width = 100}, } local headerOptions = { padding = 2, } local createSegmentLine = function(self, index) --create a new line local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate") detailsFramework:Mixin(line, detailsFramework.HeaderFunctions) detailsFramework:SetTemplate(line, "STANDARD_GRAY") PixelUtil.SetPoint(line, "topleft", self, "topleft", 1, -((index-1) * (player_line_height+1))) PixelUtil.SetSize(line, scrollbox_size[1]-2, player_line_height) line:RegisterForClicks("LeftButtonDown", "RightButtonDown") line:SetScript("OnEnter", lineOnEnter) line:SetScript("OnLeave", lineOnLeave) line:SetScript("OnClick", lineOnClick) --segment icon, this icon will tell which type of segment the line is ---@type df_image local segmentIcon = detailsFramework:CreateTexture(line, "", player_line_height, player_line_height - 1, "artwork") segmentIcon:SetSize(player_line_height - 4, player_line_height - 4) segmentIcon:SetAlpha(0.834) local segmentText = line:CreateFontString("$parentSegmentName", "artwork", "GameFontNormal") line.segmentText = segmentText line.segmentIcon = segmentIcon segmentIcon:SetPoint("left", line, "left", 2, 0) segmentText:SetPoint("left", segmentIcon.widget, "right", 3, 1) line.UpdateLine = updateSegmentLine return line end ---@type width local width = player_scroll_size[1] + 22 ---@type height local height = player_scroll_size[2] local segmentsScroll = detailsFramework:CreateScrollBox(breakdownSideMenu, "DetailsBreakdownWindowSegmentsScrollBox", refreshSegmentsScrollFunc, {}, width, height, scrollbox_lines, player_line_height) detailsFramework:ReskinSlider(segmentsScroll) segmentsScroll.ScrollBar:ClearAllPoints() segmentsScroll.ScrollBar:SetPoint("topright", segmentsScroll, "topright", -2, -37) segmentsScroll.ScrollBar:SetPoint("bottomright", segmentsScroll, "bottomright", -2, 17) segmentsScroll.ScrollBar:Hide() breakdownWindowFrame.segmentScrollBox = segmentsScroll --remove the standard backdrop segmentsScroll:SetBackdrop({}) --create the scrollbox lines for i = 1, scrollbox_lines do segmentsScroll:CreateLine(createSegmentLine) end return segmentsScroll end function breakdownWindowPlayerList.CreatePlayerListFrame() ---@type breakdownwindow local breakdownWindowFrame = Details.BreakdownWindowFrame ---@type frame local breakdownSideMenu = breakdownWindowFrame.BreakdownSideMenuFrame ---@type frame local pluginsFrame = breakdownWindowFrame.BreakdownPluginSelectionFrame breakdownSideMenu:SetSize(scrollbox_size[1], scrollbox_size[2]) PixelUtil.SetPoint(breakdownSideMenu, "topright", breakdownWindowFrame, "topleft", -2, 0) PixelUtil.SetPoint(breakdownSideMenu, "bottomright", breakdownWindowFrame, "bottomleft", -2, 0) --> create headers local sectionHeaderHeight = 20 --plugins header frame local pluginHeaderFrame = CreateFrame("frame", nil, breakdownSideMenu, "BackdropTemplate") PixelUtil.SetPoint(pluginHeaderFrame, "topleft", breakdownSideMenu, "topleft", 2, -0) PixelUtil.SetPoint(pluginHeaderFrame, "topright", breakdownSideMenu, "topright", -2, -0) pluginHeaderFrame:SetHeight(sectionHeaderHeight) --plugins header label local titleBarPlugins_TitleLabel = detailsFramework:CreateLabel(pluginHeaderFrame, "Plugins", 12, "DETAILS_HEADER_YELLOW", "GameFontHighlightLeft", "pluginsLabel", nil, "overlay") PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "center", pluginHeaderFrame , "center", 0, 0) PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "top", pluginHeaderFrame , "top", 0, -5) --player selection header frame local playerSelectionHeaderFrame = CreateFrame("frame", nil, breakdownSideMenu, "BackdropTemplate") playerSelectionHeaderFrame:SetHeight(sectionHeaderHeight) playerSelectionHeaderFrame:SetPoint("topleft", pluginsFrame, "bottomleft", 0, -1) playerSelectionHeaderFrame:SetPoint("topright", pluginsFrame, "bottomright", 0, -1) --player selection header label --converting from detailsFramework:NewLabel to detailsFramework:CreateLabel --local titleBarTools_TitleLabel = detailsFramework:NewLabel(titleBarPlayerSeparator, titleBarPlayerSeparator, nil, "titulo", "Players", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255}) local titleBarTools_TitleLabel = detailsFramework:CreateLabel(playerSelectionHeaderFrame, "Select Player", 12, "DETAILS_HEADER_YELLOW", "GameFontHighlightLeft", "playersLabel", nil, "overlay") PixelUtil.SetPoint(titleBarTools_TitleLabel, "center", playerSelectionHeaderFrame , "center", 0, 0) PixelUtil.SetPoint(titleBarTools_TitleLabel, "top", playerSelectionHeaderFrame , "top", 0, -5) --segment selection header frame local segmentSelectionHeaderFrame = CreateFrame("frame", nil, breakdownSideMenu, "BackdropTemplate") segmentSelectionHeaderFrame:SetHeight(sectionHeaderHeight) --segment selection header label local titleBarSegment_TitleLabel = detailsFramework:CreateLabel(segmentSelectionHeaderFrame, "Select Segment", 12, "DETAILS_HEADER_YELLOW", "GameFontHighlightLeft", "segmentsLabel", nil, "overlay") PixelUtil.SetPoint(titleBarSegment_TitleLabel, "center", segmentSelectionHeaderFrame , "center", 0, 0) PixelUtil.SetPoint(titleBarSegment_TitleLabel, "top", segmentSelectionHeaderFrame , "top", 0, -5) local playerScroll = createPlayerScrollBox(breakdownWindowFrame, breakdownSideMenu, playerSelectionHeaderFrame) playerScroll:SetPoint("topleft", breakdownWindowFrame.PlayerSelectionHeader, "bottomleft", 0, -2) playerScroll:SetPoint("topright", breakdownWindowFrame.PlayerSelectionHeader, "bottomright", 0, -2) local segmentsScroll = createSegmentsScrollBox(breakdownWindowFrame, breakdownSideMenu, playerSelectionHeaderFrame) segmentsScroll:SetPoint("topleft", playerScroll, "bottomleft", 0, -20) segmentsScroll:SetPoint("topright", playerScroll, "bottomright", 0, -20) PixelUtil.SetPoint(segmentSelectionHeaderFrame, "topleft", playerScroll, "bottomleft", 0, -1) PixelUtil.SetPoint(segmentSelectionHeaderFrame, "topright", playerScroll, "bottomright", 0, -1) local classIds = detailsFramework.ClassFileNameToIndex ---get the player list from the segment and build a table compatible with the scroll box ---@return actor[] function breakdownWindowPlayerList.BuildPlayerList() ---@type combat local combatObject = Details:GetCombatFromBreakdownWindow() ---@type {key1: actor, key2: number, key3: number}[] local playerTable = {} if (combatObject) then local displayType = Details:GetDisplayTypeFromBreakdownWindow() local containerType = displayType == 1 and DETAILS_ATTRIBUTE_DAMAGE or DETAILS_ATTRIBUTE_HEAL ---@type actorcontainer local actorContainer = combatObject:GetContainer(containerType) for index, actorObject in actorContainer:ListActors() do ---@cast actorObject actor if (actorObject:IsPlayer() and actorObject:IsGroupPlayer()) then local unitClassID = classIds[actorObject:Class()] or 13 local unitName = actorObject:Name() --actor position calculation: if two actors has the same amount of a total number, the sort function would flip they around, so we need to add a unique number to the position based on the class and the two first letters of the name local playerPosition = (((unitClassID or 0) + 128) ^ 4) + tonumber(string.byte(unitName, 1) .. "" .. string.byte(unitName, 2)) ---@type {key1: actor, key2: number, key3: number} local data = {actorObject, playerPosition, actorObject.total} tinsert(playerTable, data) end end end table.sort(playerTable, detailsFramework.SortOrder3) ---@type actor[] local resultTable = {} for i = 1, #playerTable do ---@type actor local actor = playerTable[i][1] resultTable[#resultTable+1] = actor end return resultTable end local updatePlayerAndSegmentsList = function() --the left menu side has 620 pixels of height --when updating the player list, update the plugin buttons as well for convenience --the refreshPluginButtons function returns the height occupied by the pluginsFrame --this height is then used to set the amount of lines the player and segments scroll frames will show local heightOccupied = refreshPluginButtons(breakdownWindowFrame, pluginsFrame, breakdownSideMenu) --the height of the player and segments scroll is determined by the height of the pluginsFrame, by the amount of players needed to be shown and the amount of segments needed to be shown --calculate the height "free" to use for both scrolls local heightFree = breakdownSideMenu:GetHeight() - heightOccupied --the -60 is the space used by the player and segments labels, plus the player scroll header --the -5 is the space between the player and segments scroll heightFree = heightFree - 60 - 5 ---@type actor[] local playerList = breakdownWindowPlayerList.BuildPlayerList() local amountOfLines = math.floor(heightFree / player_line_height) local linesForPlayerScroll = math.floor(amountOfLines/2) if (linesForPlayerScroll < 5) then linesForPlayerScroll = 5 elseif (linesForPlayerScroll > 10) then linesForPlayerScroll = 10 end local selectedPlayerName = Details:GetActorObjectFromBreakdownWindow():Name() lastSelectedPlayerPerSegment[Details:GetCombatFromBreakdownWindow():GetCombatUID()] = selectedPlayerName lastSelectedPlayerName = selectedPlayerName local playerLineHeight = player_line_height+1 --the +1 is the space between the lines --recalculate the height free, now that we know the amount of lines the player scroll will show heightFree = heightFree - (linesForPlayerScroll * playerLineHeight) local linesForSegmentsScroll = math.floor(heightFree/playerLineHeight) playerScroll:SetNumFramesShown(linesForPlayerScroll) --looks like it is not updating the 'totalLines' at the refresh function playerScroll:SetHeight(linesForPlayerScroll * playerLineHeight) segmentsScroll:SetNumFramesShown(linesForSegmentsScroll) segmentsScroll:SetHeight(linesForSegmentsScroll * playerLineHeight) playerScroll:SetData(playerList) playerScroll:Refresh() playerScroll:Show() ---@type breakdownsegmentdata[] local segmentsData = {} ---@type combat[] local segmentsTable = Details:GetCombatSegments() for i = 1, #segmentsTable do ---@type combat local combatObject = segmentsTable[i] ---@type uniquecombatid local UID = combatObject:GetCombatUID() local combatName, r, g, b = combatObject:GetCombatName(true) local combatIcon, categoryIcon = combatObject:GetCombatIcon() segmentsData[i] = { UID = UID, combatName = combatName, combatIcon = combatIcon, r = r or 1, g = g or 1, b = b or 1, } end segmentsScroll:SetData(segmentsData) segmentsScroll:Refresh() segmentsScroll:Show() end function Details:UpdateBreakdownPlayerList() --run the update on the next tick C_Timer.After(0, updatePlayerAndSegmentsList) end breakdownWindowFrame:HookScript("OnShow", function() Details:UpdateBreakdownPlayerList() end) breakdownWindowFrame:HookScript("OnHide", function() for lineIndex, line in ipairs(breakdownWindowFrame.playerScrollBox:GetLines()) do line.playerObject = nil line.combatObject = nil end end) end function Details.PlayerBreakdown.CreatePlayerListFrame() if (not Details.PlayerBreakdown.playerListFrameCreated) then breakdownWindowPlayerList.CreatePlayerListFrame() Details.PlayerBreakdown.playerListFrameCreated = true end end function Details222.BreakdownWindow.RefreshScrolls() Details:UpdateBreakdownPlayerList() end