local _, ns = ... ns.UI = ns.UI or {} local Amibis = ns.Amibis ns.UI.Frame = {} local ELVUI_BACKDROP_COLOR = { 0.07, 0.07, 0.07 } local ELVUI_BACKDROP_ALPHA = 0.95 local ELVUI_BORDER_COLOR = { 0.23, 0.23, 0.23 } local ELVUI_BORDER_ALPHA = 1.0 local ELVUI_TITLE_BG = { 0.15, 0.15, 0.15 } local COLOR_BIS = { 0.0, 1.0, 0.0 } local COLOR_UPGRADE = { 1.0, 0.82, 0.0 } local COLOR_EMPTY = { 0.6, 0.6, 0.6 } local MainFrame = nil local TitleText = nil local SummaryText = nil local UpgradeText = nil local ScrollFrame = nil local SlotRows = {} local MAX_VISIBLE_ROWS = 17 local ROW_HEIGHT = 22 local ROW_SPACING = 24 local function CreateMainFrame() local frame = CreateFrame("Frame", "AmibisMainFrame", UIParent, "BackdropTemplate") frame:SetSize(480, 680) frame:SetFrameStrata("MEDIUM") frame:SetFrameLevel(10) frame:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", tile = false, tileSize = 0, edgeSize = 1, insets = { left = 0, right = 0, top = 0, bottom = 0 } }) frame:SetBackdropColor(ELVUI_BACKDROP_COLOR[1], ELVUI_BACKDROP_COLOR[2], ELVUI_BACKDROP_COLOR[3], ELVUI_BACKDROP_ALPHA) frame:SetBackdropBorderColor(ELVUI_BORDER_COLOR[1], ELVUI_BORDER_COLOR[2], ELVUI_BORDER_COLOR[3], ELVUI_BORDER_ALPHA) frame:SetMovable(true) frame:EnableMouse(true) frame:RegisterForDrag("LeftButton") frame:SetClampedToScreen(true) frame:SetScript("OnDragStart", function(self) self:StartMoving() end) frame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() Amibis:SaveFramePosition(self) end) frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0) return frame end local function CreateTitleBar(parent) local titleBar = CreateFrame("Frame", nil, parent, "BackdropTemplate") titleBar:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, 0) titleBar:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, 0) titleBar:SetHeight(28) titleBar:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", tile = false, edgeSize = 1, insets = { left = 0, right = 0, top = 0, bottom = 0 } }) titleBar:SetBackdropColor(ELVUI_TITLE_BG[1], ELVUI_TITLE_BG[2], ELVUI_TITLE_BG[3], 1.0) titleBar:SetBackdropBorderColor(ELVUI_BORDER_COLOR[1], ELVUI_BORDER_COLOR[2], ELVUI_BORDER_COLOR[3], 1.0) local titleText = titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal") titleText:SetPoint("LEFT", titleBar, "LEFT", 8, 0) titleText:SetText("Amibis - Gear Comparison") titleText:SetTextColor(1, 1, 1, 1) local closeBtn = CreateFrame("Button", nil, titleBar) closeBtn:SetSize(20, 20) closeBtn:SetPoint("RIGHT", titleBar, "RIGHT", -4, 0) closeBtn:SetText("X") closeBtn:SetNormalFontObject("GameFontNormal") closeBtn:SetScript("OnClick", function() if MainFrame and MainFrame:IsShown() then MainFrame:Hide() end end) titleBar:EnableMouse(true) titleBar:RegisterForDrag("LeftButton") titleBar:SetScript("OnDragStart", function() parent:StartMoving() end) titleBar:SetScript("OnDragStop", function() parent:StopMovingOrSizing() Amibis:SaveFramePosition(parent) end) return titleBar, titleText end local function CreateSummaryBar(parent, anchor) local bar = CreateFrame("Frame", nil, parent) bar:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -4) bar:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -4) bar:SetHeight(20) local summaryText = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") summaryText:SetPoint("LEFT", bar, "LEFT", 8, 0) summaryText:SetTextColor(0.8, 0.8, 0.8, 1) local upgradeText = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") upgradeText:SetPoint("BOTTOMLEFT", bar, "TOPLEFT", 8, 2) upgradeText:SetPoint("BOTTOMRIGHT", bar, "TOPRIGHT", -8, 2) upgradeText:SetJustifyH("LEFT") upgradeText:SetTextColor(COLOR_UPGRADE[1], COLOR_UPGRADE[2], COLOR_UPGRADE[3], 1) return bar, summaryText, upgradeText end local function CreateColumnHeaders(parent, anchor) local header = CreateFrame("Frame", nil, parent, "BackdropTemplate") header:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -4) header:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -4) header:SetHeight(18) header:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1, insets = { left = 0, right = 0, top = 0, bottom = 0 } }) header:SetBackdropColor(0.12, 0.12, 0.12, 0.5) local slotHeader = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") slotHeader:SetPoint("LEFT", header, "LEFT", 8, 0) slotHeader:SetWidth(55) slotHeader:SetJustifyH("LEFT") slotHeader:SetText("Slot") slotHeader:SetTextColor(0.7, 0.7, 0.7, 1) local equippedHeader = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") equippedHeader:SetPoint("LEFT", slotHeader, "RIGHT", 5, 0) equippedHeader:SetWidth(115) equippedHeader:SetJustifyH("LEFT") equippedHeader:SetText("Equipped") equippedHeader:SetTextColor(0.7, 0.7, 0.7, 1) local bisHeader = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") bisHeader:SetPoint("LEFT", equippedHeader, "RIGHT", 5, 0) bisHeader:SetWidth(115) bisHeader:SetJustifyH("LEFT") bisHeader:SetText("BIS Item") bisHeader:SetTextColor(0.7, 0.7, 0.7, 1) local enchantHeader = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") enchantHeader:SetPoint("LEFT", bisHeader, "RIGHT", 5, 0) enchantHeader:SetWidth(60) enchantHeader:SetJustifyH("LEFT") enchantHeader:SetText("Enchant") enchantHeader:SetTextColor(0.7, 0.7, 0.7, 1) local sourceHeader = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") sourceHeader:SetPoint("RIGHT", header, "RIGHT", -8, 0) sourceHeader:SetWidth(70) sourceHeader:SetJustifyH("RIGHT") sourceHeader:SetText("Source") sourceHeader:SetTextColor(0.7, 0.7, 0.7, 1) return header end local function CreateSlotRows(parent, anchor) local container = CreateFrame("Frame", nil, parent) container:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -4) container:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -4) container:SetHeight(MAX_VISIBLE_ROWS * ROW_SPACING) for i = 1, MAX_VISIBLE_ROWS do local row = CreateFrame("Button", nil, container) row:SetPoint("TOPLEFT", container, "TOPLEFT", 0, -(i - 1) * ROW_SPACING) row:SetPoint("TOPRIGHT", container, "TOPRIGHT", 0, -(i - 1) * ROW_SPACING) row:SetHeight(ROW_HEIGHT) row.slotText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.slotText:SetPoint("LEFT", row, "LEFT", 8, 0) row.slotText:SetWidth(55) row.slotText:SetJustifyH("LEFT") row.equippedText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.equippedText:SetPoint("LEFT", row.slotText, "RIGHT", 5, 0) row.equippedText:SetWidth(115) row.equippedText:SetJustifyH("LEFT") row.equippedText:SetWordWrap(true) row.bisText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.bisText:SetPoint("LEFT", row.equippedText, "RIGHT", 5, 0) row.bisText:SetWidth(115) row.bisText:SetJustifyH("LEFT") row.bisText:SetWordWrap(true) row.enchantText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.enchantText:SetPoint("LEFT", row.bisText, "RIGHT", 5, 0) row.enchantText:SetWidth(60) row.enchantText:SetJustifyH("LEFT") row.sourceText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.sourceText:SetPoint("RIGHT", row, "RIGHT", -8, 0) row.sourceText:SetWidth(70) row.sourceText:SetJustifyH("RIGHT") row.sourceText:SetWordWrap(true) row:SetScript("OnEnter", function(self) if self.bisLink then GameTooltip:SetOwner(self, "ANCHOR_RIGHT") GameTooltip:SetHyperlink(self.bisLink) GameTooltip:Show() end end) row:SetScript("OnLeave", function() GameTooltip:Hide() end) row:RegisterForClicks("LeftButtonUp", "RightButtonUp") row:SetScript("OnClick", function(self, button) if self.bisLink and button == "LeftButton" then if IsShiftKeyDown() then ChatEdit_InsertLink(self.bisLink) elseif IsControlKeyDown() then DressUpItemLink(self.bisLink) end end end) SlotRows[i] = row end return container end local StatsPanel = nil local StatsPanelTitle = nil local StatLabels = {} local StatValues = {} local STAT_DISPLAY = { { key = "healing", label = "+Healing" }, { key = "spellPower", label = "+Spell Power" }, { key = "intellect", label = "Intellect" }, { key = "spirit", label = "Spirit" }, { key = "mp5", label = "MP5" }, { key = "haste", label = "Haste" }, { key = "crit", label = "Crit" }, } local function CreateStatsPanel(parent, anchor) local panel = CreateFrame("Frame", nil, parent, "BackdropTemplate") panel:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -8) panel:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -8) panel:SetHeight(#STAT_DISPLAY * 16 + 24) panel:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1, insets = { left = 0, right = 0, top = 0, bottom = 0 } }) panel:SetBackdropColor(0.1, 0.1, 0.1, 0.6) panel:SetBackdropBorderColor(0.2, 0.2, 0.2, 1) local title = panel:CreateFontString(nil, "OVERLAY", "GameFontNormal") title:SetPoint("TOPLEFT", panel, "TOPLEFT", 8, -4) title:SetText("Stats Comparison") title:SetTextColor(1, 0.82, 0, 1) StatsPanelTitle = title local colW = 60 local labelW = 80 local currentX = labelW + 16 local bisX = currentX + colW local diffX = bisX + colW local currentLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") currentLabel:SetPoint("TOPLEFT", panel, "TOPLEFT", currentX, -4) currentLabel:SetWidth(colW) currentLabel:SetJustifyH("CENTER") currentLabel:SetText("Current") currentLabel:SetTextColor(0.7, 0.7, 0.7, 1) local bisLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") bisLabel:SetPoint("TOPLEFT", panel, "TOPLEFT", bisX, -4) bisLabel:SetWidth(colW) bisLabel:SetJustifyH("CENTER") bisLabel:SetText("BIS") bisLabel:SetTextColor(0.7, 0.7, 0.7, 1) local diffLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") diffLabel:SetPoint("TOPLEFT", panel, "TOPLEFT", diffX, -4) diffLabel:SetWidth(colW) diffLabel:SetJustifyH("CENTER") diffLabel:SetText("Diff") diffLabel:SetTextColor(0.7, 0.7, 0.7, 1) for i, stat in ipairs(STAT_DISPLAY) do local y = -(i - 1) * 16 - 22 local label = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") label:SetPoint("TOPLEFT", panel, "TOPLEFT", 8, y) label:SetWidth(labelW) label:SetJustifyH("RIGHT") label:SetText(stat.label) label:SetTextColor(0.6, 0.6, 0.6, 1) local current = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") current:SetPoint("TOPLEFT", panel, "TOPLEFT", currentX, y) current:SetWidth(colW) current:SetJustifyH("CENTER") current:SetText("0") current:SetTextColor(1, 0.5, 0.5, 1) local bis = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") bis:SetPoint("TOPLEFT", panel, "TOPLEFT", bisX, y) bis:SetWidth(colW) bis:SetJustifyH("CENTER") bis:SetText("0") bis:SetTextColor(0, 1, 0, 1) local diff = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") diff:SetPoint("TOPLEFT", panel, "TOPLEFT", diffX, y) diff:SetWidth(colW) diff:SetJustifyH("CENTER") diff:SetText("0") diff:SetTextColor(1, 1, 1, 1) StatLabels[stat.key] = label StatValues[stat.key] = { current = current, bis = bis, diff = diff } end StatsPanel = panel return panel end local function InitializeUI() if MainFrame then return end MainFrame = CreateMainFrame() local titleBar, title = CreateTitleBar(MainFrame) TitleText = title local summaryBar, summary, upgrade = CreateSummaryBar(MainFrame, titleBar) SummaryText = summary UpgradeText = upgrade local header = CreateColumnHeaders(MainFrame, summaryBar) local slotContainer = CreateSlotRows(MainFrame, header) CreateStatsPanel(MainFrame, slotContainer) if AmibisCharDB and AmibisCharDB.frameX then MainFrame:ClearAllPoints() Amibis:LoadFramePosition(MainFrame) end MainFrame:Hide() end function ns.UI.Initialize() InitializeUI() end function ns.UI.ToggleFrame() if not MainFrame then InitializeUI() end if MainFrame:IsShown() then MainFrame:Hide() if Amibis._statsRetryTimer then Amibis._statsRetryTimer:Hide() Amibis._statsRetryTimer = nil end else MainFrame:Show() ns.UI.RefreshUI() end end function ns.UI.RefreshUI() if not MainFrame or not MainFrame:IsShown() then return end local data = Amibis:CompareGear() TitleText:SetText(string.format("Amibis - %s %s (%s)", data.class, data.spec or "Unknown", data.phase)) if not data.hasBISList then SummaryText:SetText(string.format("|cffff6666No BIS list available for %s %s in %s|r", data.class, data.spec or "Unknown", data.phase)) UpgradeText:SetText("") for i = 1, MAX_VISIBLE_ROWS do SlotRows[i].slotText:SetText("") SlotRows[i].equippedText:SetText("") SlotRows[i].bisText:SetText("") SlotRows[i].enchantText:SetText("") SlotRows[i].sourceText:SetText("") SlotRows[i].bisLink = nil end return end SummaryText:SetText(string.format("BIS: %d/%d slots", data.bisCount, data.totalSlots)) if data.biggestUpgrade then local bu = data.biggestUpgrade if bu.equipped then UpgradeText:SetText(string.format("Biggest upgrade: %s -> %s (%s)", bu.equipped.name, bu.bis.name, bu.bis.source)) else UpgradeText:SetText(string.format("Empty slot: %s -> %s (%s)", bu.slot, bu.bis.name, bu.bis.source)) end else UpgradeText:SetText("|cff00ff00All slots are BIS!|r") end for i = 1, MAX_VISIBLE_ROWS do local row = SlotRows[i] local slotData = data.slots[i] if slotData then row.slotText:SetText(slotData.slotName) row.slotText:SetTextColor(0.7, 0.7, 0.7, 1) if slotData.isBIS then row.equippedText:SetText(slotData.equipped.link or slotData.equipped.name) row.equippedText:SetTextColor(COLOR_BIS[1], COLOR_BIS[2], COLOR_BIS[3], 1) row.bisText:SetText("|cff00ff00BIS|r") row.bisText:SetTextColor(COLOR_BIS[1], COLOR_BIS[2], COLOR_BIS[3], 1) row.sourceText:SetText(slotData.bis.source) row.sourceText:SetTextColor(0.5, 0.5, 0.5, 1) row.bisLink = slotData.equipped and slotData.equipped.link if slotData.bis.enchant and slotData.equipped then local hasEnchant = false local link = slotData.equipped.link if link then local parts = {} for part in link:gmatch("([^:]+)") do table.insert(parts, part) end local enchantID = tonumber(parts[3]) if enchantID and enchantID > 0 then hasEnchant = true end end if hasEnchant then row.enchantText:SetText("|cff00ff00" .. slotData.bis.enchant.name .. "|r") else row.enchantText:SetText("|cffff6666" .. slotData.bis.enchant.name .. "|r") end elseif slotData.bis.enchant then row.enchantText:SetText("|cffffcc00" .. slotData.bis.enchant.name .. "|r") else row.enchantText:SetText("") end else if slotData.equipped then row.equippedText:SetText(slotData.equipped.link or slotData.equipped.name) row.equippedText:SetTextColor(1, 0.5, 0.5, 1) else row.equippedText:SetText("|cff666666Empty|r") row.equippedText:SetTextColor(COLOR_EMPTY[1], COLOR_EMPTY[2], COLOR_EMPTY[3], 1) end row.bisText:SetText(slotData.bis.name) row.bisText:SetTextColor(COLOR_UPGRADE[1], COLOR_UPGRADE[2], COLOR_UPGRADE[3], 1) row.sourceText:SetText(slotData.bis.source) row.sourceText:SetTextColor(0.5, 0.5, 0.5, 1) if slotData.bis.enchant then row.enchantText:SetText("|cffffcc00" .. slotData.bis.enchant.name .. "|r") else row.enchantText:SetText("") end local _, bisLink = GetItemInfo(slotData.bis.itemID) row.bisLink = bisLink or ("|Hitem:" .. slotData.bis.itemID .. ":0:0:0:0:0:0:0:0|h[" .. slotData.bis.name .. "]|h") end else row.slotText:SetText("") row.equippedText:SetText("") row.bisText:SetText("") row.enchantText:SetText("") row.sourceText:SetText("") row.bisLink = nil end end if data.equippedStats and data.bisStats then if not data.statsComplete then if StatsPanelTitle then StatsPanelTitle:SetText("Stats Comparison |cff888888(loading...)|r") end for _, stat in ipairs(STAT_DISPLAY) do local vals = StatValues[stat.key] if vals then local current = data.equippedStats[stat.key] or 0 vals.current:SetText(current) vals.bis:SetText("|cff888888...|r") vals.diff:SetText("") end end if not Amibis._statsRetryTimer then Amibis._statsRetryTimer = CreateFrame("Frame") Amibis._statsRetryTimer.elapsed = 0 Amibis._statsRetryTimer:SetScript("OnUpdate", function(self, elapsed) self.elapsed = self.elapsed + elapsed if self.elapsed >= 1.5 then self:Hide() Amibis._statsRetryTimer = nil if MainFrame and MainFrame:IsShown() then ns.UI.RefreshUI() end end end) Amibis._statsRetryTimer:Show() end else if StatsPanelTitle then StatsPanelTitle:SetText("Stats Comparison") end for _, stat in ipairs(STAT_DISPLAY) do local vals = StatValues[stat.key] if vals then local current = data.equippedStats[stat.key] or 0 local bis = data.bisStats[stat.key] or 0 local diff = bis - current vals.current:SetText(current) vals.bis:SetText(bis) if diff > 0 then vals.diff:SetText("+" .. diff) vals.diff:SetTextColor(1, 0.5, 0.5, 1) elseif diff < 0 then vals.diff:SetText(tostring(diff)) vals.diff:SetTextColor(0, 1, 0, 1) else vals.diff:SetText("-") vals.diff:SetTextColor(0.5, 0.5, 0.5, 1) end end end end end end local initFrame = CreateFrame("Frame") initFrame:RegisterEvent("PLAYER_LOGIN") initFrame:SetScript("OnEvent", function(self, event) if event == "PLAYER_LOGIN" then InitializeUI() self:UnregisterEvent("PLAYER_LOGIN") end end)