Skip to content

Commit 25cf4e9

Browse files
committed
feat: add Gear column with icons, quality border, rank overlay, and sorting
1 parent c849c96 commit 25cf4e9

2 files changed

Lines changed: 178 additions & 5 deletions

File tree

Main.lua

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,73 @@ function Main:ToggleWindow()
4444
self:Render()
4545
end
4646

47+
local EMPTY_SLOT_TEXTURE = 4760248 -- confirmed in-game via GetInventorySlotInfo [2]
48+
local GEAR_ICON_SIZE = 24
49+
50+
local function SlotBelongsToExpansion(slot, expansionID)
51+
return slot.itemExpansionID == expansionID
52+
end
53+
54+
local function GearCellIcons(characterProfession, skillLineVariantID)
55+
local function onLeave() GameTooltip:Hide() end
56+
57+
if characterProfession.equipment == nil then
58+
-- Never scanned: 3 dimmed empty slot icons with no overlay
59+
local onEnter = function(frame)
60+
GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")
61+
GameTooltip:SetText("Not yet scanned", 1, 1, 1)
62+
GameTooltip:AddLine("Log in on this character to scan their gear.", nil, nil, nil, true)
63+
GameTooltip:Show()
64+
end
65+
return {
66+
{ iconFileID = EMPTY_SLOT_TEXTURE, unscanned = true, size = GEAR_ICON_SIZE, onEnter = onEnter, onLeave = onLeave },
67+
{ iconFileID = EMPTY_SLOT_TEXTURE, unscanned = true, size = GEAR_ICON_SIZE, onEnter = onEnter, onLeave = onLeave },
68+
{ iconFileID = EMPTY_SLOT_TEXTURE, unscanned = true, size = GEAR_ICON_SIZE, onEnter = onEnter, onLeave = onLeave },
69+
}
70+
end
71+
72+
local variant = Data:GetSkillLineVariantByID(skillLineVariantID)
73+
local expansionID = variant and variant.expansionID
74+
75+
local icons = {}
76+
for i = 1, 3 do
77+
local slot = characterProfession.equipment[i]
78+
local slotBelongs = slot and not slot.pending and expansionID and SlotBelongsToExpansion(slot, expansionID)
79+
if slotBelongs then
80+
-- Item equipped and belongs to this expansion: full brightness icon + quality star overlay
81+
local itemLink = slot.itemLink
82+
local qualityColor = ITEM_QUALITY_COLORS[slot.itemQuality]
83+
icons[i] = {
84+
iconFileID = slot.iconFileID,
85+
overlayAtlas = slot.craftingRank > 0 and ("Professions-ChatIcon-Quality-Tier" .. slot.craftingRank) or nil,
86+
borderColor = qualityColor and {r = qualityColor.r, g = qualityColor.g, b = qualityColor.b},
87+
size = GEAR_ICON_SIZE,
88+
onEnter = function(frame)
89+
GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")
90+
GameTooltip:SetHyperlink(itemLink)
91+
GameTooltip:Show()
92+
end,
93+
onLeave = onLeave,
94+
}
95+
else
96+
-- Scanned empty or wrong expansion gear; pending = item data still loading
97+
local isPending = slot and slot.pending
98+
icons[i] = {
99+
iconFileID = EMPTY_SLOT_TEXTURE,
100+
size = GEAR_ICON_SIZE,
101+
onEnter = function(frame)
102+
GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")
103+
GameTooltip:SetText(isPending and "Loading..." or "Empty", 1, 1, 1)
104+
GameTooltip:Show()
105+
end,
106+
onLeave = onLeave,
107+
}
108+
end
109+
end
110+
return icons
111+
end
112+
113+
47114
function Main:Render()
48115
local selectedExpansions = Data.db.global.main.selectedExpansions or {}
49116
local expansions = Data:GetExpansions()
@@ -1039,6 +1106,39 @@ function Main:GetTableColumns(unfiltered)
10391106
end,
10401107
},
10411108
},
1109+
{
1110+
id = "gear",
1111+
headerText = "Gear",
1112+
width = 90,
1113+
align = "CENTER",
1114+
toggleHidden = true,
1115+
onEnter = function(cellFrame)
1116+
GameTooltip:SetOwner(cellFrame, "ANCHOR_RIGHT")
1117+
GameTooltip:SetText("Gear", 1, 1, 1)
1118+
GameTooltip:AddLine("Profession tool and accessories.", nil, nil, nil, true)
1119+
GameTooltip:AddLine(" ")
1120+
GameTooltip:AddLine("Sorted by gear score (0-45): each slot scores 1-5 for Uncommon, 6-10 for Rare, and 11-15 for Epic, based on item rank.", nil, nil, nil, true)
1121+
GameTooltip:Show()
1122+
end,
1123+
onLeave = function() GameTooltip:Hide() end,
1124+
renderCell = function(data)
1125+
return { icons = GearCellIcons(data.characterProfession, data.skillLineVariantID) }
1126+
end,
1127+
sorting = {
1128+
enabled = true,
1129+
compare = function(a, b)
1130+
local scoreA = a.data.characterProfession.profGearScore
1131+
local scoreB = b.data.characterProfession.profGearScore
1132+
if scoreA == nil and scoreB == nil then
1133+
return (a.data.character.lastUpdate or 0) < (b.data.character.lastUpdate or 0)
1134+
end
1135+
if scoreA == nil then return true end
1136+
if scoreB == nil then return false end
1137+
if scoreA ~= scoreB then return scoreA < scoreB end
1138+
return (a.data.character.lastUpdate or 0) < (b.data.character.lastUpdate or 0)
1139+
end,
1140+
},
1141+
},
10421142
}
10431143

10441144
-- Category Progress

Table.lua

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,84 @@ function Table:CreateFrame(config)
353353
if isHeaderRow and tableFrame.config.sorting and tableFrame.config.sorting.enabled then
354354
columnFrame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
355355
end
356-
columnFrame.text:SetWordWrap(false)
357-
columnFrame.text:SetJustifyH(columnTextAlign)
358-
columnFrame.text:SetPoint("TOPLEFT", columnFrame, "TOPLEFT", tableFrame.config.cells.padding, -tableFrame.config.cells.padding)
359-
columnFrame.text:SetPoint("BOTTOMRIGHT", columnFrame, "BOTTOMRIGHT", -tableFrame.config.cells.padding, tableFrame.config.cells.padding)
360-
columnFrame.text:SetText(column.text)
356+
if column.icons then
357+
-- Icon cell: hide the FontString, show/create icon child frames
358+
columnFrame.text:Hide()
359+
columnFrame.iconFrames = columnFrame.iconFrames or {}
360+
361+
for i, iconData in ipairs(column.icons) do
362+
local iconFrame = columnFrame.iconFrames[i]
363+
if not iconFrame then
364+
iconFrame = CreateFrame("Frame", nil, columnFrame)
365+
iconFrame.texture = iconFrame:CreateTexture(nil, "ARTWORK")
366+
iconFrame.texture:SetPoint("TOPLEFT", iconFrame, "TOPLEFT", 1, -1)
367+
iconFrame.texture:SetPoint("BOTTOMRIGHT", iconFrame, "BOTTOMRIGHT", -1, 1)
368+
iconFrame.border = iconFrame:CreateTexture(nil, "BACKGROUND")
369+
iconFrame.border:SetAllPoints()
370+
iconFrame.overlay = iconFrame:CreateTexture(nil, "OVERLAY")
371+
columnFrame.iconFrames[i] = iconFrame
372+
end
373+
374+
local iconSize = iconData.size or 18
375+
iconFrame:SetSize(iconSize, iconSize)
376+
iconFrame.texture:SetTexture(iconData.iconFileID)
377+
if iconData.unscanned then
378+
iconFrame.texture:SetVertexColor(0.4, 0.4, 0.4, 1)
379+
else
380+
iconFrame.texture:SetVertexColor(1, 1, 1, 1)
381+
end
382+
383+
if iconData.borderColor then
384+
local bc = iconData.borderColor
385+
iconFrame.border:SetColorTexture(bc.r, bc.g, bc.b, 1)
386+
iconFrame.border:Show()
387+
else
388+
iconFrame.border:Hide()
389+
end
390+
391+
iconFrame.overlay:SetSize(10, 10)
392+
iconFrame.overlay:ClearAllPoints()
393+
iconFrame.overlay:SetPoint("TOPLEFT", iconFrame, "TOPLEFT", -2, 2)
394+
if iconData.overlayAtlas then
395+
iconFrame.overlay:SetAtlas(iconData.overlayAtlas)
396+
iconFrame.overlay:Show()
397+
else
398+
iconFrame.overlay:Hide()
399+
end
400+
401+
iconFrame:ClearAllPoints()
402+
iconFrame:SetPoint("LEFT", columnFrame, "LEFT",
403+
tableFrame.config.cells.padding + (i - 1) * (iconSize + 2), 0)
404+
if iconData.onEnter or iconData.onLeave then
405+
iconFrame:EnableMouse(true)
406+
iconFrame:SetScript("OnEnter", iconData.onEnter or nil)
407+
iconFrame:SetScript("OnLeave", iconData.onLeave or nil)
408+
iconFrame:SetScript("OnMouseUp", function() columnFrame:onClickHandler(columnFrame) end)
409+
else
410+
iconFrame:EnableMouse(false)
411+
iconFrame:SetScript("OnEnter", nil)
412+
iconFrame:SetScript("OnLeave", nil)
413+
iconFrame:SetScript("OnMouseUp", nil)
414+
end
415+
iconFrame:Show()
416+
end
417+
418+
-- Hide leftover icon frames from a previous wider render
419+
for i = #column.icons + 1, #columnFrame.iconFrames do
420+
columnFrame.iconFrames[i]:Hide()
421+
end
422+
else
423+
-- Text cell: show the FontString, hide any icon child frames
424+
columnFrame.text:Show()
425+
columnFrame.text:SetWordWrap(false)
426+
columnFrame.text:SetJustifyH(columnTextAlign)
427+
columnFrame.text:SetPoint("TOPLEFT", columnFrame, "TOPLEFT", tableFrame.config.cells.padding, -tableFrame.config.cells.padding)
428+
columnFrame.text:SetPoint("BOTTOMRIGHT", columnFrame, "BOTTOMRIGHT", -tableFrame.config.cells.padding, tableFrame.config.cells.padding)
429+
columnFrame.text:SetText(column.text)
430+
if columnFrame.iconFrames then
431+
for _, f in ipairs(columnFrame.iconFrames) do f:Hide() end
432+
end
433+
end
361434
columnFrame:Show()
362435

363436
if column.backgroundColor then

0 commit comments

Comments
 (0)