local addonName, addonTable = ... -- Global functions for faster access local tinsert = tinsert; local tContains = tContains; -- Set up module local addon = addonTable[1]; local gui = addon:NewModule("gui", "AceHook-3.0") addon.gui = gui; -- AceGUI local AceGUI = LibStub("AceGUI-3.0"); local classIdToClassName = {}; FillLocalizedClassList(classIdToClassName); function gui:FormatNumber(number) if Skada and Skada.FormatNumber then return Skada:FormatNumber(number) else -- Default to Skada's implementation with numberformat enabled if number > 1000000 then return ("%02.2fM"):format(number / 1000000) else return ("%02.1fK"):format(number / 1000) end end end function gui:CreateHighScoreParseEntry(parse, role, rank) local entryWidget = AceGUI:Create("SimpleGroup"); entryWidget:SetFullWidth(true); entryWidget:SetLayout("Flow"); entryWidget:SetHeight(30); local classId = parse.class; local classColor = RAID_CLASS_COLORS[classId]; local className = classIdToClassName[classId]; local relativeWidth = floor((1/6)*100)/100; local rankLabel = AceGUI:Create("Label"); rankLabel:SetText(rank); rankLabel:SetFontObject(GameFontHighlightSmall); rankLabel:SetRelativeWidth(relativeWidth); local dpsHpsLabel = AceGUI:Create("Label"); local dpsHps = self:FormatNumber((role == "HEALER") and parse.hps or parse.dps); dpsHpsLabel:SetText(dpsHps); dpsHpsLabel:SetFontObject(GameFontHighlightSmall); dpsHpsLabel:SetRelativeWidth(relativeWidth); local nameLabel = AceGUI:Create("Label"); nameLabel:SetText(parse.name); nameLabel:SetColor(classColor.r, classColor.g, classColor.b); nameLabel:SetFontObject(GameFontHighlightSmall); nameLabel:SetRelativeWidth(relativeWidth); local specLabel = AceGUI:Create("Label"); specLabel:SetText(parse.specName or ""); specLabel:SetFontObject(GameFontHighlightSmall); specLabel:SetRelativeWidth(relativeWidth); local ilvlLabel = AceGUI:Create("Label"); ilvlLabel:SetText(parse.itemLevel or ""); ilvlLabel:SetFontObject(GameFontHighlightSmall); ilvlLabel:SetRelativeWidth(relativeWidth); local dateLabel = AceGUI:Create("Label"); dateLabel:SetText(date("%m/%d/%y", parse.startTime)); dateLabel:SetFontObject(GameFontHighlightSmall); dateLabel:SetRelativeWidth(relativeWidth); entryWidget:AddChild(rankLabel); entryWidget:AddChild(dpsHpsLabel); entryWidget:AddChild(nameLabel); entryWidget:AddChild(specLabel); entryWidget:AddChild(ilvlLabel); entryWidget:AddChild(dateLabel); return entryWidget; end function gui:CreateGuildDropdown() local dropdown = AceGUI:Create("Dropdown"); self.guildDropdown = dropdown; dropdown:SetLabel("Guild"); dropdown:SetRelativeWidth(0.25); dropdown:SetCallback("OnValueChanged", function(widget, evt, guildId) gui:SetSelectedGuild(guildId); end) local guilds, numGuilds = addon.highscore:GetGuilds(); if numGuilds > 0 then dropdown:SetList(guilds); else dropdown:SetDisabled(true); dropdown:SetText("No Guilds."); end return dropdown; end function gui:CreateZoneDropdown() local dropdown = AceGUI:Create("Dropdown"); self.zoneDropdown = dropdown; dropdown:SetLabel("Zone"); dropdown:SetRelativeWidth(0.25); dropdown:SetList(nil); dropdown:SetDisabled(true); dropdown:SetCallback("OnValueChanged", function(widget, evt, zoneId) gui:SetSelectedZone(zoneId); end) return dropdown; end function gui:CreateDifficultyDropdown() local dropdown = AceGUI:Create("Dropdown"); self.difficultyDropdown = dropdown; dropdown:SetLabel("Difficulty"); dropdown:SetRelativeWidth(0.25); dropdown:SetList(nil); dropdown:SetDisabled(true); dropdown:SetCallback("OnValueChanged", function(widget, evt, difficultyId) gui:SetSelectedDifficulty(difficultyId); end) return dropdown; end function gui:CreateEncounterDropdown() local dropdown = AceGUI:Create("Dropdown"); self.encounterDropdown = dropdown; dropdown:SetLabel("Encounter"); dropdown:SetRelativeWidth(0.25); dropdown:SetList(nil); dropdown:SetDisabled(true); dropdown:SetCallback("OnValueChanged", function(widget, evt, encounterId) gui:SetSelectedEncounter(encounterId); end) return dropdown; end function gui:CreateHighScoreScrollFrame() local scrollFrame = AceGUI:Create("ScrollFrame"); scrollFrame:SetLayout("Flow"); scrollFrame:SetFullWidth(true); scrollFrame:SetFullHeight(true); self.highScoreParsesScrollFrame = scrollFrame; local relativeWidth = floor((1/6)*100)/100; -- Header: -- Rank | DPS/HPS | Name | Class | Spec | Item Level | Date local headerContainer = AceGUI:Create("SimpleGroup"); headerContainer:SetFullWidth(true); headerContainer:SetLayout("Flow"); local rankLabel = AceGUI:Create("Label"); rankLabel:SetText("Rank"); rankLabel:SetFontObject(GameFontHighlightSmall); rankLabel:SetRelativeWidth(relativeWidth); local dpsHpsLabel = AceGUI:Create("Label"); dpsHpsLabel:SetText("DPS/HPS"); dpsHpsLabel:SetFontObject(GameFontHighlightSmall); dpsHpsLabel:SetRelativeWidth(relativeWidth); local nameLabel = AceGUI:Create("Label"); nameLabel:SetText("Name"); nameLabel:SetFontObject(GameFontHighlightSmall); nameLabel:SetRelativeWidth(relativeWidth); local specLabel = AceGUI:Create("Label"); specLabel:SetText("Spec"); specLabel:SetFontObject(GameFontHighlightSmall); specLabel:SetRelativeWidth(relativeWidth); local ilvlLabel = AceGUI:Create("Label"); ilvlLabel:SetText("Item Level"); ilvlLabel:SetFontObject(GameFontHighlightSmall); ilvlLabel:SetRelativeWidth(relativeWidth); local dateLabel = AceGUI:Create("Label"); dateLabel:SetText("Date"); dateLabel:SetFontObject(GameFontHighlightSmall); dateLabel:SetRelativeWidth(relativeWidth); headerContainer:AddChild(rankLabel); headerContainer:AddChild(dpsHpsLabel); headerContainer:AddChild(nameLabel); headerContainer:AddChild(specLabel); headerContainer:AddChild(ilvlLabel); headerContainer:AddChild(dateLabel); local parsesContainer = AceGUI:Create("SimpleGroup"); self.highScoreParsesContainer = parsesContainer; parsesContainer:SetFullWidth(true); parsesContainer:SetLayout("Flow"); scrollFrame:AddChild(headerContainer); scrollFrame:AddChild(parsesContainer); return scrollFrame; end function gui:CreateHighScoreTabGroup() local container = AceGUI:Create("TabGroup"); self.highScoreTabGroup = container; container:SetFullWidth(true); container:SetFullHeight(true); container:SetLayout("Fill"); container:SetTabs({ {value = "DAMAGER", text = "DPSers"}, {value = "HEALER", text = "Healers"}, {value = "TANK", text = "Tanks"} }); container:SetCallback("OnGroupSelected", function(widget, evt, roleId) gui:SetSelectedRole(roleId); end) container:AddChild(self:CreateHighScoreScrollFrame()); return container; end function gui:CreateMainFrame() local frame = AceGUI:Create("Frame") self.mainFrame = frame; frame:Hide() frame:SetWidth(800) frame:SetHeight(600) frame:SetTitle(format("Guild Skada High Score (%s)", addon.versionName)); frame:SetLayout("Flow") frame:SetCallback("OnClose", function() gui:HideMainFrame() end) frame:AddChild(self:CreateGuildDropdown()); frame:AddChild(self:CreateZoneDropdown()); frame:AddChild(self:CreateDifficultyDropdown()); frame:AddChild(self:CreateEncounterDropdown()); frame:AddChild(self:CreateHighScoreTabGroup()); return frame; end function gui:DisplayParses() local guildName = self.selectedGuild; local zoneId = self.selectedZone; local difficultyId = self.selectedDifficulty; local encounter = self.selectedEncounter; local roleId = self.selectedRole; local parsesContainer = self.highScoreParsesContainer; local scrollFrame = self.highScoreParsesScrollFrame; parsesContainer:ReleaseChildren(); if guildName and zoneId and difficultyId and encounter and roleId then local parses, numParses = addon.highscore:GetParses(guildName, zoneId, difficultyId, encounter, roleId); if numParses > 0 then parsesContainer:PauseLayout(); scrollFrame:PauseLayout(); for rank, parse in ipairs(parses) do local entryWidget = self:CreateHighScoreParseEntry(parse, roleId, rank); parsesContainer:AddChild(entryWidget); end parsesContainer:ResumeLayout(); parsesContainer:DoLayout(); scrollFrame:ResumeLayout(); scrollFrame:DoLayout(); return; end end local noParsesLabel = AceGUI:Create("Label"); noParsesLabel:SetText("No parses found."); parsesContainer:AddChild(noParsesLabel); end function gui:SetSelectedRole(roleId, noPropagation) -- SelectTab, unlike SetValue for dropdowns, triggers the callback if self.selectedRole ~= roleId then self.selectedRole = roleId; self.highScoreTabGroup:SelectTab(roleId); self:DisplayParses(); end end function gui:SetSelectedEncounter(encounterId, noPropagation) self.selectedEncounter = encounterId; self.encounterDropdown:SetValue(encounterId); self:DisplayParses(); end function gui:SetSelectedDifficulty(difficultyId, noPropagation) self.selectedDifficulty = difficultyId; self.difficultyDropdown:SetValue(difficultyId); -- Update encounter dropdown with new guild, zone, difficulty local encounters, numEncounters = addon.highscore:GetEncounters(self.selectedGuild, self.selectedZone, self.selectedDifficulty); if numEncounters > 0 then self.encounterDropdown:SetDisabled(false); self.encounterDropdown:SetList(encounters); else self.encounterDropdown:SetDisabled(true); self.encounterDropdown:SetList(nil); self.encounterDropdown:SetText(nil); end if not noPropagation then if numEncounters == 1 then -- If only one option, select it. local encounterId, _ = next(encounters); self:SetSelectedEncounter(encounterId); else self:SetSelectedEncounter(nil); end end end function gui:SetSelectedZone(zoneId, noPropagation) self.selectedZone = zoneId; self.zoneDropdown:SetValue(zoneId); -- Update difficulty dropdown with new guild, zone local difficulties, numDifficulties = addon.highscore:GetDifficulties(self.selectedGuild, self.selectedZone); if numDifficulties > 0 then self.difficultyDropdown:SetDisabled(false); self.difficultyDropdown:SetList(difficulties); else self.difficultyDropdown:SetDisabled(true); self.difficultyDropdown:SetList(nil); self.difficultyDropdown:SetText(nil); end if not noPropagation then if numDifficulties == 1 then -- If only one option, select it. local difficultyId, _ = next(difficulties); self:SetSelectedDifficulty(difficultyId); else self:SetSelectedDifficulty(nil); end end end function gui:SetSelectedGuild(guildId, noPropagation) self.selectedGuild = guildId; self.guildDropdown:SetValue(guildId); -- Update zone dropdown for the new guild local zones, numZones = addon.highscore:GetZones(guildId); if numZones > 0 then self.zoneDropdown:SetDisabled(false); self.zoneDropdown:SetList(zones); else self.zoneDropdown:SetDisabled(true); self.zoneDropdown:SetList(nil); self.zoneDropdown:SetText(nil); end if not noPropagation then if numZones == 1 then -- If only one option, select it. local zoneId, _ = next(zones); self:SetSelectedZone(zoneId); else self:SetSelectedZone(nil); end end end function gui:ShowMainFrame() if not self.mainFrame then -- Only show if not already shown self:CreateMainFrame():Show(); if self.selectedGuild then -- Try to restore to same values as before gui:SetSelectedGuild(self.selectedGuild, true); gui:SetSelectedZone(self.selectedZone, true); gui:SetSelectedDifficulty(self.selectedDifficulty, true); gui:SetSelectedEncounter(self.selectedEncounter, true); gui:SetSelectedRole(self.selectedRole, true); elseif addon.guildName then -- Try pre-selecting own guild if has one. gui:SetSelectedGuild(addon.guildName); end -- Have to do special for our tab group as it is never disabled gui:SetSelectedRole(self.selectedRole or "DAMAGER"); end end function gui:HideMainFrame() if self.mainFrame then self.mainFrame:Release(); -- Unset references self.mainFrame = nil; self.guildDropdown = nil; self.zoneDropdown = nil; self.difficultyDropdown = nil; self.encounterDropdown = nil; self.highScoreTabGroup = nil; self.highScoreParsesContainer = nil; self.highScoreParsesScrollFrame = nil; end end function gui:OnCloseSpecialWindows() local found; if self.mainFrame then self:HideMainFrame() found = 1 end return self.hooks["CloseSpecialWindows"]() or found; end function gui:OnEnable() self:RawHook("CloseSpecialWindows", "OnCloseSpecialWindows", true); end function gui:OnDisable() self:HideMainFrame(); self:UnHook("CloseSpecialWindows"); end