diff --git a/EUI_QoL.lua b/EUI_QoL.lua index e6fe3e5a..1b15b5a3 100644 --- a/EUI_QoL.lua +++ b/EUI_QoL.lua @@ -728,6 +728,8 @@ qolFrame:SetScript("OnEvent", function(self) local function GetApplicantScore(applicantID) if not C_LFGList or not C_LFGList.GetApplicantMemberInfo then return nil end local _, _, _, _, _, _, _, _, _, _, _, dungeonScore = C_LFGList.GetApplicantMemberInfo(applicantID, 1) + if dungeonScore == nil then return nil end + if issecretvalue and issecretvalue(dungeonScore) then return nil end if type(dungeonScore) ~= "number" then return nil end return dungeonScore end @@ -754,9 +756,9 @@ qolFrame:SetScript("OnEvent", function(self) table.sort(applicants, function(a, b) local sa = scores[a] local sb = scores[b] - if sa ~= nil and sb ~= nil and sa ~= sb then return sa > sb end - if sa ~= nil and sb == nil then return true end - if sa == nil and sb ~= nil then return false end + if sa and sb and sa ~= sb then return sa > sb end + if sa and not sb then return true end + if not sa and sb then return false end return (originalOrder[a] or 0) < (originalOrder[b] or 0) end) end) @@ -960,6 +962,152 @@ qolFrame:SetScript("OnEvent", function(self) return false end + --------------------------------------------------------------------------- + -- Bag Item Level Labels + -- Draws a small item-level number on every equippable item in the bag. + -- Setting: EllesmereUIDB.bagIlvlEnabled (default: true) + --------------------------------------------------------------------------- + do + -- Items worth showing a level on: anything that occupies a gear slot. + -- Bags, tabards, ammo pouches and cosmetics are intentionally excluded. + local function IsGearSlot(equipSlot, classID, subclassID) + if not equipSlot or equipSlot == "" then return false end + if equipSlot == "INVTYPE_NON_EQUIP_IGNORE" then return false end + if equipSlot == "INVTYPE_TABARD" then return false end + if equipSlot == "INVTYPE_BAG" then return false end + if equipSlot == "INVTYPE_QUIVER" then return false end + -- classID 4 = Armor, subclassID 5 = Cosmetic + if classID == 4 and subclassID == 5 then return false end + return true + end + + -- Pixel nudge per corner so the number sits just inside the icon edge. + local CORNER_OFFSET = { + TOPLEFT = { 1, -1 }, + TOPRIGHT = { -1, -1 }, + BOTTOMLEFT = { 1, 1 }, + BOTTOMRIGHT = { -1, 1 }, + } + + local function GetCorner() + return (EllesmereUIDB and EllesmereUIDB.bagIlvlAnchor) or "BOTTOMLEFT" + end + + local function GetSize() + return (EllesmereUIDB and EllesmereUIDB.bagIlvlFontSize) or 11 + end + + local function GetFace() + return (EllesmereUI and EllesmereUI.GetFont and EllesmereUI.GetFont()) + or STANDARD_TEXT_FONT + end + + local function IsActive() + return not (EllesmereUIDB and EllesmereUIDB.bagIlvlEnabled == false) + end + + -- Retrieve or create the FontString attached to a button. + local function GetOrCreateTag(btn) + if btn._euiIlvlTag then return btn._euiIlvlTag end + -- Use OVERLAY so the text renders above the item icon texture + -- but stays below Blizzard's own search-dimming overlay. + local tag = btn:CreateFontString(nil, "OVERLAY") + tag:SetFont(GetFace(), GetSize(), "THINOUTLINE") + tag:SetShadowOffset(1, -1) + tag:SetShadowColor(0, 0, 0, 0.9) + btn._euiIlvlTag = tag + return tag + end + + local function PaintButton(btn, bag, slot) + if not btn then return end + local tag = GetOrCreateTag(btn) + + if not IsActive() then tag:Hide(); return end + + local link = C_Container.GetContainerItemLink(bag, slot) + if not link then tag:Hide(); return end + + local _, _, quality, _, _, classID, subclassID, _, equipSlot = + C_Item.GetItemInfo(link) + + if not IsGearSlot(equipSlot, classID, subclassID) then + tag:Hide(); return + end + + -- GetCurrentItemLevel via ItemLocation is the only reliable way + -- to get the actual equipped/upgraded level rather than base level. + local loc = ItemLocation:CreateFromBagAndSlot(bag, slot) + local lvl = loc and C_Item.GetCurrentItemLevel(loc) + if not lvl or lvl <= 0 then tag:Hide(); return end + + -- Refresh font in case the user changed size in settings + tag:SetFont(GetFace(), GetSize(), "THINOUTLINE") + + local corner = GetCorner() + local off = CORNER_OFFSET[corner] or CORNER_OFFSET.BOTTOMLEFT + tag:ClearAllPoints() + tag:SetPoint(corner, btn, corner, off[1], off[2]) + + -- Colour by quality; grey fallback for unknown quality + if quality and quality >= 0 then + local r, g, b = C_Item.GetItemQualityColor(quality) + tag:SetTextColor(r, g, b, 1) + else + tag:SetTextColor(0.8, 0.8, 0.8, 1) + end + + tag:SetText(lvl) + tag:Show() + end + + local function ScanOpenBags() + if ContainerFrameCombinedBags and ContainerFrameCombinedBags:IsShown() then + for _, btn in ContainerFrameCombinedBags:EnumerateValidItems() do + PaintButton(btn, btn:GetBagID(), btn:GetID()) + end + end + for _, frame in ipairs((ContainerFrameContainer and + ContainerFrameContainer.ContainerFrames) or {}) do + if frame:IsShown() then + for _, btn in frame:EnumerateValidItems() do + PaintButton(btn, btn:GetBagID(), btn:GetID()) + end + end + end + end + + -- Event-driven refresh + local watchFrame = CreateFrame("Frame") + watchFrame:RegisterEvent("BAG_UPDATE_DELAYED") + watchFrame:RegisterEvent("ITEM_UPGRADE_MASTER_SET_ITEM") + watchFrame:RegisterEvent("PLAYER_ENTERING_WORLD") + watchFrame:RegisterEvent("BAG_OPEN") + watchFrame:SetScript("OnEvent", function(_, event) + if event == "PLAYER_ENTERING_WORLD" then + C_Timer.After(2, ScanOpenBags) + else + ScanOpenBags() + end + end) + + -- Refresh when any individual bag frame becomes visible + for _, frame in ipairs((ContainerFrameContainer and + ContainerFrameContainer.ContainerFrames) or {}) do + frame:HookScript("OnShow", function() + C_Timer.After(0.1, ScanOpenBags) + end) + end + if ContainerFrameCombinedBags then + ContainerFrameCombinedBags:HookScript("OnShow", function() + C_Timer.After(0.1, ScanOpenBags) + end) + end + + -- Expose a refresh handle for the options panel + EllesmereUI._refreshBagIlvl = ScanOpenBags + end + local resetAnnounceFrame = CreateFrame("Frame") resetAnnounceFrame:RegisterEvent("CHAT_MSG_SYSTEM") resetAnnounceFrame:SetScript("OnEvent", function(self, event, msg) diff --git a/EUI__General_Options.lua b/EUI__General_Options.lua index e3eb3dd1..ceb71046 100644 --- a/EUI__General_Options.lua +++ b/EUI__General_Options.lua @@ -1616,7 +1616,7 @@ initFrame:SetScript("OnEvent", function(self) local function CreateFPSCounter() if fpsFrame then return end local FONT = EllesmereUI.GetFontPath("extras") - local FONT_SIZE = 12 + local FONT_SIZE = (EllesmereUIDB and EllesmereUIDB.fpsTextSize) or 12 local LABEL_SIZE = FONT_SIZE - 2 local SHADOW_X, SHADOW_Y = 1, -1 fpsFrame = CreateFrame("Frame", "EUI_FPSCounter", UIParent) @@ -1742,6 +1742,16 @@ initFrame:SetScript("OnEvent", function(self) local shouldShow = EllesmereUIDB and EllesmereUIDB.showFPS if shouldShow then CreateFPSCounter() + -- Re-apply text size from DB + local sz = (EllesmereUIDB and EllesmereUIDB.fpsTextSize) or 12 + local lblSz = sz - 2 + local fp = EllesmereUI.GetFontPath("extras") + local outF = EllesmereUI.GetFontOutlineFlag() + if fpsFrame._text then fpsFrame._text:SetFont(fp, sz, outF) end + if fpsFrame._textWorld then fpsFrame._textWorld:SetFont(fp, sz, outF) end + if fpsFrame._textLocal then fpsFrame._textLocal:SetFont(fp, sz, outF) end + if fpsFrame._lblWorld then fpsFrame._lblWorld:SetFont(fp, lblSz, outF) end + if fpsFrame._lblLocal then fpsFrame._lblLocal:SetFont(fp, lblSz, outF) end -- Apply saved position and scale local pos = EllesmereUIDB and EllesmereUIDB.fpsPos if pos and pos.point then @@ -1918,7 +1928,8 @@ initFrame:SetScript("OnEvent", function(self) -- Font -- pull from the global "extras" font key local fontPath = EllesmereUI.GetFontPath("extras") - fs:SetFont(fontPath, 18, EllesmereUI.GetFontOutlineFlag()) + local durSz = (EllesmereUIDB and EllesmereUIDB.durWarnTextSize) or 30 + fs:SetFont(fontPath, durSz, EllesmereUI.GetFontOutlineFlag()) -- Color local c = EllesmereUIDB and EllesmereUIDB.durWarnColor @@ -1962,6 +1973,7 @@ initFrame:SetScript("OnEvent", function(self) CreateDurabilityWarning() durWarnOverlay._applySettings() end + EllesmereUI._durWarnApplySettings = EllesmereUI._applyDurWarn -- Preview: show durability warning at its configured position EllesmereUI._durWarnPreview = function() @@ -2465,6 +2477,16 @@ initFrame:SetScript("OnEvent", function(self) local _, fpsCogShow = EllesmereUI.BuildCogPopup({ title = "FPS Counter Settings", rows = { + { type="slider", label="Text Size", + min=8, max=24, step=1, + get=function() + return (EllesmereUIDB and EllesmereUIDB.fpsTextSize) or 12 + end, + set=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + EllesmereUIDB.fpsTextSize = v + if EllesmereUI._applyFPSCounter then EllesmereUI._applyFPSCounter() end + end }, { type="toggle", label="Show Local MS", get=function() if not EllesmereUIDB or EllesmereUIDB.fpsShowLocalMS == nil then return true end @@ -2729,6 +2751,16 @@ initFrame:SetScript("OnEvent", function(self) local _, durCogShow = EllesmereUI.BuildCogPopup({ title = "Durability Settings", rows = { + { type="slider", label="Text Size", + min=10, max=50, step=1, + get=function() + return (EllesmereUIDB and EllesmereUIDB.durWarnTextSize) or 30 + end, + set=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + EllesmereUIDB.durWarnTextSize = v + if EllesmereUI._durWarnApplySettings then EllesmereUI._durWarnApplySettings() end + end }, { type="slider", label="Y-Offset", min=-600, max=600, step=1, get=function() @@ -3342,6 +3374,104 @@ initFrame:SetScript("OnEvent", function(self) end } ); y = y - h + --------------------------------------------------------------------------- + -- BAGS + --------------------------------------------------------------------------- + _, h = W:SectionHeader(parent, "BAGS", y); y = y - h + + local ilvlRow + ilvlRow, h = W:DualRow(parent, y, + { type="toggle", text="Show Item Level in Bags", + tooltip="Displays the current item level as a small label on each equippable item in your bags. The label colour matches the item quality.", + getValue=function() + return not (EllesmereUIDB and EllesmereUIDB.bagIlvlEnabled == false) + end, + setValue=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + EllesmereUIDB.bagIlvlEnabled = v and true or false + if EllesmereUI._refreshBagIlvl then EllesmereUI._refreshBagIlvl() end + EllesmereUI:RefreshPage() + end }, + { type="label", text="" } + ); y = y - h + + -- Cog on the item-level toggle (position & font-size sub-settings) + do + local leftRgn = ilvlRow._leftRegion + local function ilvlOff() + return EllesmereUIDB and EllesmereUIDB.bagIlvlEnabled == false + end + + -- Pre-declare the values table as upvalue so the CogPopup closure + -- captures a fully-initialised table (inline literals can arrive nil + -- if the popup is created lazily before the table is resolved). + local posValues = { + TOPLEFT = "Top Left", + TOPRIGHT = "Top Right", + BOTTOMLEFT = "Bottom Left", + BOTTOMRIGHT= "Bottom Right", + } + local posOrder = { "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT" } + + local _, ilvlCogShow = EllesmereUI.BuildCogPopup({ + title = "Bag Item Level Settings", + rows = { + { type="dropdown", + label="Position", + values=posValues, + order=posOrder, + get=function() + return (EllesmereUIDB and EllesmereUIDB.bagIlvlAnchor) or "BOTTOMLEFT" + end, + set=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + EllesmereUIDB.bagIlvlAnchor = v + if EllesmereUI._refreshBagIlvl then EllesmereUI._refreshBagIlvl() end + end }, + { type="slider", + label="Font Size", + min=6, max=20, step=1, + get=function() + return (EllesmereUIDB and EllesmereUIDB.bagIlvlFontSize) or 11 + end, + set=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + EllesmereUIDB.bagIlvlFontSize = v + if EllesmereUI._refreshBagIlvl then EllesmereUI._refreshBagIlvl() end + end }, + }, + }) + + local ilvlCogBtn = CreateFrame("Button", nil, leftRgn) + ilvlCogBtn:SetSize(26, 26) + ilvlCogBtn:SetPoint("RIGHT", leftRgn._lastInline or leftRgn._control, "LEFT", -9, 0) + leftRgn._lastInline = ilvlCogBtn + ilvlCogBtn:SetFrameLevel(leftRgn:GetFrameLevel() + 5) + ilvlCogBtn:SetAlpha(ilvlOff() and 0.15 or 0.4) + local ilvlCogTex = ilvlCogBtn:CreateTexture(nil, "OVERLAY") + ilvlCogTex:SetAllPoints() + ilvlCogTex:SetTexture(EllesmereUI.COGS_ICON) + ilvlCogBtn:SetScript("OnEnter", function(self) self:SetAlpha(0.7) end) + ilvlCogBtn:SetScript("OnLeave", function(self) self:SetAlpha(ilvlOff() and 0.15 or 0.4) end) + ilvlCogBtn:SetScript("OnClick", function(self) ilvlCogShow(self) end) + + local ilvlCogBlock = CreateFrame("Frame", nil, ilvlCogBtn) + ilvlCogBlock:SetAllPoints() + ilvlCogBlock:SetFrameLevel(ilvlCogBtn:GetFrameLevel() + 10) + ilvlCogBlock:EnableMouse(true) + ilvlCogBlock:SetScript("OnEnter", function() + EllesmereUI.ShowWidgetTooltip(ilvlCogBtn, EllesmereUI.DisabledTooltip("Show Item Level in Bags")) + end) + ilvlCogBlock:SetScript("OnLeave", function() EllesmereUI.HideWidgetTooltip() end) + + EllesmereUI.RegisterWidgetRefresh(function() + local off = ilvlOff() + ilvlCogBtn:SetAlpha(off and 0.15 or 0.4) + if off then ilvlCogBlock:Show() else ilvlCogBlock:Hide() end + end) + if ilvlOff() then ilvlCogBlock:Show() else ilvlCogBlock:Hide() end + end + _, h = W:Spacer(parent, y, 20); y = y - h return math.abs(y) end