Initial publication

This commit is contained in:
dfj
2026-06-04 00:04:49 +02:00
commit 5284007998
6 changed files with 1597 additions and 0 deletions

View File

@@ -0,0 +1,561 @@
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)