2 Commits
Author SHA1 Message Date
Brues ec410996ec Gate the macro icon hook behind a config flag
Run the Blizzard_MacroUI hook only when C.disabled["macroicons"] is
"1".
2026-08-05 03:44:11 -05:00
Brues b08198145a Add pfUI-native macro icon picker
Replace Blizzard's MacroPopupFrame (the name + icon dialog) with a
custom pfUI picker driven by IconDataProviderMixin, so the full spell +
item + loose icon set is available instead of the stock spell-only list.
It has a searchable, filterable icon grid and saves through
C_Macro.CreateMacro / C_Macro.EditMacro, which take the icon as a texture
string -- so arbitrary icons (including index-less INV_* item icons)
persist. The macro-frame API is identical on the modern (Turtle/Octo)
and stock-vanilla macro UIs, so the picker works on both with no client
detection.

The new macroicons module takes over the New / Change-Icon buttons and
retires the stock popup; the blizzard macro skin now only skins
MacroPopupFrame when that module is disabled.
2026-08-05 03:03:30 -05:00
5 changed files with 106 additions and 207 deletions
+3 -59
View File
@@ -1209,72 +1209,16 @@ function pfUI.uf:EnableEvents()
'MiddleButtonUp', 'Button4Up', 'Button5Up')
end
-- ============================================================
-- Clique compatibility
-- Clique's pfUI plugin replaces pfUI.uf.ClickAction and expects an
-- OnClick script to call it (with `this` = frame, `arg1` = button). The
-- secure attribute path replaced that dispatch, so when Clique is loaded
-- EnableScripts routes clicks through this legacy Lua path instead. The
-- secure path is skipped there because type1="target" switches the target
-- before Clique can cast.
-- ============================================================
function pfUI.uf.OnClick()
if not this.label and this.unitname then
TargetByName(this.unitname, true)
else
pfUI.uf:ClickAction(arg1)
end
end
function pfUI.uf:ClickAction(button)
local label = this.label or ""
local id = this.id or ""
local unitstr = label .. id
if SpellIsTargeting() and button == "RightButton" then
SpellStopTargeting()
return
end
if SpellIsTargeting() and button == "LeftButton" then
SpellTargetUnit(unitstr)
elseif CursorHasItem() then
DropItemOnUnit(unitstr)
end
-- right-click opens the standard unit menu (ClassicAPI resolves the type)
if button == "RightButton" then
ClassicAPI_ToggleUnitMenu(unitstr)
return
end
-- drop food on petframe
if label == "pet" and CursorHasItem() then
if UnitClassBase("player") == "HUNTER" then
DropItemOnUnit("pet")
return
end
end
-- default click
TargetUnit(unitstr)
end
function pfUI.uf:EnableScripts()
local f = self
if IsAddOnLoaded("Clique") then
f:SetScript("OnClick", pfUI.uf.OnClick)
else
f:SetAttribute("type1", "target")
f:SetAttribute("type2", "menu")
f:EnableClickCast()
end
f:SetAttribute("type1", "target")
f:SetAttribute("type2", "menu")
f:SetScript("OnShow", pfUI.uf.OnShow)
f:SetScript("OnEvent", pfUI.uf.OnEvent)
f:SetScript("OnUpdate", pfUI.uf.OnUpdate)
f:EnableClickCast()
-- add frame to visibility refresh handler
visibilityscan.frames[f] = true
+96 -129
View File
@@ -1,10 +1,11 @@
-- Equipment Manager module
-- Backport of the 4.3.4 GearManagerDialog UI on top of ClassicAPI's C_EquipmentSet.* API.
-- Backport of the 4.3.4 GearManagerDialog UI on top of ClassicAPI's
-- C_EquipmentSet.* API. Adds a 6th tab to CharacterFrame.
pfUI:RegisterModule("equipmentmanager", function()
if not C_EquipmentSet or not C_EquipmentSet.CanUseEquipmentSets() then return end
pfUI.equipmentmanager = {}
pfUI.equipmentmanager = pfUI.equipmentmanager or {}
local SET_ROW_HEIGHT = 36
@@ -54,7 +55,7 @@ pfUI:RegisterModule("equipmentmanager", function()
local function EquipSet(setID)
if not setID then return end
if C_EquipmentSet.EquipmentSetContainsLockedItems(setID) then
UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1, .1, .1, 1)
UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT or "Locked items in set", 1, .1, .1, 1)
return
end
ClearCursor()
@@ -67,7 +68,8 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local frame = CreateFrame("Frame", "pfEquipmentManagerFrame", CharacterFrame)
frame:SetSize(220, 350)
frame:SetWidth(220)
frame:SetHeight(350)
frame:SetFrameStrata("HIGH")
frame:SetScript("OnShow", function()
this:ClearAllPoints()
@@ -84,7 +86,7 @@ pfUI:RegisterModule("equipmentmanager", function()
frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
frame.title:SetPoint("TOP", frame, "TOP", 0, -10)
frame.title:SetText(EQUIPMENT_MANAGER)
frame.title:SetText(T["Equipment Manager"] or "Equipment Manager")
local closeBtn = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
closeBtn:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -4, -4)
@@ -96,14 +98,15 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local toggleBtn = CreateFrame("Button", "pfEqMgrToggleButton", PaperDollFrame)
toggleBtn:SetSize(28, 28)
toggleBtn:SetWidth(28)
toggleBtn:SetHeight(28)
toggleBtn:SetPoint("BOTTOM", CharacterHandsSlot, "TOP", 0, 4)
toggleBtn:SetNormalTexture(pfUI.path.."\\img\\UI-GearManager-Button")
toggleBtn:SetPushedTexture(pfUI.path.."\\img\\UI-GearManager-Button-Pushed")
toggleBtn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
toggleBtn:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText(PAPERDOLL_EQUIPMENTMANAGER)
GameTooltip:SetText(T["Equipment Manager"] or "Equipment Manager")
GameTooltip:Show()
end)
toggleBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -123,13 +126,13 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local btnEquip = CreateFrame("Button", "pfEqMgrEquip", frame, "UIPanelButtonTemplate")
btnEquip:SetSize(86, 22); btnEquip:SetText(EQUIPSET_EQUIP)
btnEquip:SetWidth(86); btnEquip:SetHeight(22); btnEquip:SetText(T["Equip"] or "Equip")
btnEquip:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -30)
SkinButton(btnEquip)
btnEquip:SetScript("OnClick", function() EquipSet(selectedSetID) end)
local btnSave = CreateFrame("Button", "pfEqMgrSave", frame, "UIPanelButtonTemplate")
btnSave:SetSize(86, 22); btnSave:SetText(SAVE)
btnSave:SetWidth(86); btnSave:SetHeight(22); btnSave:SetText(T["Save"] or "Save")
btnSave:SetPoint("LEFT", btnEquip, "RIGHT", 6, 0)
SkinButton(btnSave)
btnSave:SetScript("OnClick", function()
@@ -138,7 +141,7 @@ pfUI:RegisterModule("equipmentmanager", function()
if not name then return end
local targetID = selectedSetID
StaticPopupDialogs["PFUI_EQMGR_SAVE_CONFIRM"] = {
text = string.format(CONFIRM_SAVE_EQUIPMENT_SET, name),
text = string.format(T["Would you like to save the equipment set '%s'?"] or "Would you like to save the equipment set '%s'?", name),
button1 = YES, button2 = NO,
OnAccept = function()
C_EquipmentSet.ClearIgnoredSlotsForSave()
@@ -163,7 +166,7 @@ pfUI:RegisterModule("equipmentmanager", function()
local rowMenu = CreateFrame("Frame", "pfEqMgrRowMenu", UIParent)
rowMenu:SetFrameStrata("DIALOG")
rowMenu:SetSize(140, 50);
rowMenu:SetWidth(140); rowMenu:SetHeight(50)
rowMenu:Hide()
CreateBackdrop(rowMenu, nil, nil, .95)
CreateBackdropShadow(rowMenu)
@@ -182,9 +185,9 @@ pfUI:RegisterModule("equipmentmanager", function()
tinsert(UISpecialFrames, "pfEqMgrRowMenu") -- Escape closes it
rowMenu.changeBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate")
rowMenu.changeBtn:SetSize(130, 20);
rowMenu.changeBtn:SetWidth(130); rowMenu.changeBtn:SetHeight(20)
rowMenu.changeBtn:SetPoint("TOPLEFT", rowMenu, "TOPLEFT", 5, -3)
rowMenu.changeBtn:SetText(EQUIPMENT_SET_EDIT)
rowMenu.changeBtn:SetText(T["Change Name/Icon"] or "Change Name/Icon")
SkinButton(rowMenu.changeBtn)
rowMenu.changeBtn:SetScript("OnClick", function()
rowMenu:Hide()
@@ -195,9 +198,9 @@ pfUI:RegisterModule("equipmentmanager", function()
end)
rowMenu.deleteBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate")
rowMenu.deleteBtn:SetSize(130, 20);
rowMenu.deleteBtn:SetWidth(130); rowMenu.deleteBtn:SetHeight(20)
rowMenu.deleteBtn:SetPoint("TOP", rowMenu.changeBtn, "BOTTOM", 0, -2)
rowMenu.deleteBtn:SetText(DELETE)
rowMenu.deleteBtn:SetText(T["Delete"] or "Delete")
SkinButton(rowMenu.deleteBtn)
rowMenu.deleteBtn:SetScript("OnClick", function()
rowMenu:Hide()
@@ -205,7 +208,7 @@ pfUI:RegisterModule("equipmentmanager", function()
local targetID = rowMenu.targetSetID
local name = C_EquipmentSet.GetEquipmentSetInfo(targetID)
StaticPopupDialogs["PFUI_EQMGR_DELETE"] = {
text = string.format(CONFIRM_DELETE_EQUIPMENT_SET, name or "?"),
text = string.format(T["Delete equipment set '%s'?"] or "Delete equipment set '%s'?", name or "?"),
button1 = YES, button2 = NO,
OnAccept = function()
pendingIgnoredToggles[targetID] = nil
@@ -226,8 +229,9 @@ pfUI:RegisterModule("equipmentmanager", function()
local LIST_ROW_STRIDE = SET_ROW_HEIGHT + 2
local listFrame = CreateFrame("Frame", nil, frame)
listFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -58)
listFrame:SetWidth(180)
-- Height fits N rows + (N-1) inter-row gaps + 3px top/bottom padding.
listFrame:SetSize(180, LIST_VISIBLE_ROWS * LIST_ROW_STRIDE + 4)
listFrame:SetHeight(LIST_VISIBLE_ROWS * LIST_ROW_STRIDE + 4)
CreateBackdrop(listFrame, nil, nil, .75)
-- Mouse-wheel scroll: list of [sets..., newSetRow] is virtualized
@@ -243,13 +247,15 @@ pfUI:RegisterModule("equipmentmanager", function()
local setRows = {}
local function CreateSetRow()
local row = CreateFrame("Button", nil, listFrame)
row:SetSize(170, SET_ROW_HEIGHT)
row:SetWidth(170)
row:SetHeight(SET_ROW_HEIGHT)
-- Position is set per-Refresh based on the row's visible slot;
-- start anchored to avoid uninitialized geometry before first Refresh.
row:SetPoint("TOPLEFT", listFrame, "TOPLEFT", 5, -3)
row.icon = row:CreateTexture(nil, "ARTWORK")
row.icon:SetSize(30, 30)
row.icon:SetWidth(30)
row.icon:SetHeight(30)
row.icon:SetPoint("LEFT", row, "LEFT", 2, 0)
row.icon:SetTexCoord(.08, .92, .08, .92)
@@ -264,7 +270,7 @@ pfUI:RegisterModule("equipmentmanager", function()
row.highlight:Hide()
row.gear = CreateFrame("Button", nil, row)
row.gear:SetSize(16, 16);
row.gear:SetWidth(16); row.gear:SetHeight(16)
row.gear:SetPoint("RIGHT", row, "RIGHT", -4, 0)
row.gear.tex = row.gear:CreateTexture(nil, "ARTWORK")
row.gear.tex:SetAllPoints(row.gear)
@@ -300,27 +306,27 @@ pfUI:RegisterModule("equipmentmanager", function()
pfUI.equipmentmanager.Refresh()
end)
-- Show the gear and tooltip while the cursor is over the row or its
-- gear child. The gear sits inside the row's rectangle, so a single
-- MouseIsOver(row) check covers both. OnLeave on the row and the gear
-- catches every exit path, so no OnUpdate poll is needed.
local function HideRowHover()
if MouseIsOver(row) then return end
GameTooltip:Hide()
row.gear:Hide()
end
-- Hover handling: OnLeave fires when the cursor moves onto a child
-- (the gear button becomes the topmost mouse target). Use an
-- OnUpdate poll so the gear stays shown while the cursor is over
-- the row OR the gear itself.
row:SetScript("OnEnter", function()
if not row.setID then return end
local name = C_EquipmentSet.GetEquipmentSetInfo(row.setID)
if not this.setID then return end
local name = C_EquipmentSet.GetEquipmentSetInfo(this.setID)
if name then
GameTooltip:SetOwner(row, "ANCHOR_RIGHT")
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetEquipmentSet(name)
GameTooltip:Show()
end
row.gear:Show()
this:SetScript("OnUpdate", function()
if not MouseIsOver(this) and not MouseIsOver(row.gear) then
this:SetScript("OnUpdate", nil)
GameTooltip:Hide()
row.gear:Hide()
end
end)
end)
row:SetScript("OnLeave", HideRowHover)
row.gear:SetScript("OnLeave", HideRowHover)
return row
end
@@ -332,10 +338,10 @@ pfUI:RegisterModule("equipmentmanager", function()
-- specific set index (row[i] always shows ids[i]).
local newSetRow = CreateFrame("Button", nil, listFrame)
newSetRow:SetSize(170, SET_ROW_HEIGHT);
newSetRow:SetWidth(170); newSetRow:SetHeight(SET_ROW_HEIGHT)
newSetRow.icon = newSetRow:CreateTexture(nil, "ARTWORK")
newSetRow.icon:SetSize(24, 24);
newSetRow.icon:SetWidth(24); newSetRow.icon:SetHeight(24)
newSetRow.icon:SetPoint("LEFT", newSetRow, "LEFT", 5, 0)
newSetRow.icon:SetTexture(pfUI.path.."\\img\\Character-Plus")
@@ -343,7 +349,7 @@ pfUI:RegisterModule("equipmentmanager", function()
newSetRow.text:SetPoint("LEFT", newSetRow.icon, "RIGHT", 8, 0)
newSetRow.text:SetPoint("RIGHT", newSetRow, "RIGHT", -4, 0)
newSetRow.text:SetJustifyH("LEFT")
newSetRow.text:SetText(PAPERDOLL_NEWEQUIPMENTSET)
newSetRow.text:SetText(T["New Set"] or "New Set")
newSetRow.text:SetTextColor(0.2, 1, 0.2)
newSetRow.highlight = newSetRow:CreateTexture(nil, "BACKGROUND")
@@ -356,7 +362,8 @@ pfUI:RegisterModule("equipmentmanager", function()
local function MakeButton(name, label, parent, anchor, ax, ay, width)
local b = CreateFrame("Button", name, parent, "UIPanelButtonTemplate")
b:SetSize(width or 70, 22)
b:SetWidth(width or 70)
b:SetHeight(22)
b:SetText(label)
b:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", ax, ay)
SkinButton(b)
@@ -369,7 +376,8 @@ pfUI:RegisterModule("equipmentmanager", function()
local namePopup = CreateFrame("Frame", "pfEqMgrNamePopup", UIParent)
namePopup:SetFrameStrata("DIALOG")
namePopup:SetSize(472, 484)
namePopup:SetWidth(472)
namePopup:SetHeight(498)
namePopup:SetPoint("CENTER", UIParent, "CENTER")
namePopup:Hide()
CreateBackdrop(namePopup, nil, nil, .9)
@@ -380,33 +388,39 @@ pfUI:RegisterModule("equipmentmanager", function()
namePopup:SetScript("OnDragStart", function() this:StartMoving() end)
namePopup:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
namePopup.title = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
namePopup.title:SetPoint("TOP", namePopup, "TOP", 0, -10)
namePopup.title:SetText(T["Save Set"] or "Save Set")
namePopup.nameLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
namePopup.nameLabel:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -20)
namePopup.nameLabel:SetText(GEARSETS_POPUP_TEXT)
namePopup.nameLabel:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -34)
namePopup.nameLabel:SetText(T["Enter Set Name (Max 16 Characters):"] or "Enter Set Name (Max 16 Characters):")
namePopup.editbox = CreateFrame("EditBox", "pfEqMgrNameEdit", namePopup, "InputBoxTemplate")
namePopup.editbox:SetSize(280, 20)
namePopup.editbox:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -38)
namePopup.editbox:SetWidth(280)
namePopup.editbox:SetHeight(20)
namePopup.editbox:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -52)
namePopup.editbox:SetAutoFocus(false)
namePopup.editbox:SetMaxLetters(16)
CreateBackdrop(namePopup.editbox)
namePopup.selectedLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
namePopup.selectedLabel:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", -14, -14)
namePopup.selectedLabel:SetText(ICON_SELECTION_TITLE_CURRENT)
namePopup.selectedLabel:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", -14, -28)
namePopup.selectedLabel:SetText(T["Currently Selected"] or "Currently Selected")
namePopup.selectedLabel:SetTextColor(1, 0.82, 0)
namePopup.selectedPreview = CreateFrame("Frame", nil, namePopup)
namePopup.selectedPreview:SetSize(42, 42)
namePopup.selectedPreview:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", -14, -30)
namePopup.selectedPreview:SetWidth(42)
namePopup.selectedPreview:SetHeight(42)
namePopup.selectedPreview:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", -14, -44)
CreateBackdrop(namePopup.selectedPreview)
namePopup.selectedPreview.tex = namePopup.selectedPreview:CreateTexture(nil, "ARTWORK")
namePopup.selectedPreview.tex:SetAllPoints(namePopup.selectedPreview)
namePopup.selectedPreview.tex:SetTexCoord(.08, .92, .08, .92)
namePopup.iconLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
namePopup.iconLabel:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -86)
namePopup.iconLabel:SetText(MACRO_POPUP_CHOOSE_ICON)
namePopup.iconLabel:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -100)
namePopup.iconLabel:SetText(T["Choose an Icon:"] or "Choose an Icon:")
-- Icon picker: 10×8 grid of buttons + scroll
local ICON_GRID_COLS = 10
@@ -415,7 +429,7 @@ pfUI:RegisterModule("equipmentmanager", function()
local ICON_BTN_PAD = 6
local iconScroll = CreateFrame("ScrollFrame", "pfEqMgrIconScroll", namePopup, "FauxScrollFrameTemplate")
iconScroll:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -116)
iconScroll:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -130)
iconScroll:SetWidth(ICON_GRID_COLS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD)
iconScroll:SetHeight(ICON_GRID_ROWS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD)
@@ -427,9 +441,6 @@ pfUI:RegisterModule("equipmentmanager", function()
-- you switch the filter to "Items" and it's no longer in the visible list.
local QUESTION_MARK = "INTERFACE\\ICONS\\INV_MISC_QUESTIONMARK"
local selectedIconPath = QUESTION_MARK
local searchText = ""
local filtered = nil -- provider indices matching the search, or nil when empty
local RebuildFilter -- forward-declared; assigned below
local function EnsureProvider()
if not provider then
@@ -451,7 +462,7 @@ pfUI:RegisterModule("equipmentmanager", function()
-- Filter dropdown: "All Icons" / "Spells" / "Items" (top right of icon area).
local filterDropdown = CreateFrame("Frame", "pfEqMgrIconFilter", namePopup, "UIDropDownMenuTemplate")
filterDropdown:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", 0, -80)
filterDropdown:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", 0, -94)
local currentFilter = "all"
local function ApplyFilter(value)
currentFilter = value
@@ -463,21 +474,20 @@ pfUI:RegisterModule("equipmentmanager", function()
-- Don't reset selection — selectedIconPath persists. If the
-- selected icon isn't in the new filter, no grid entry will be
-- highlighted but Save will still write the chosen icon.
RebuildFilter()
pfUI.equipmentmanager.RefreshIconGrid()
end
end
UIDropDownMenu_Initialize(filterDropdown, function()
local info
info = {}; info.text = ICON_FILTER_ALL; info.value = "all"
info = {}; info.text = T["All Icons"] or "All Icons"; info.value = "all"
info.func = function() ApplyFilter("all") end
info.checked = currentFilter == "all"
UIDropDownMenu_AddButton(info)
info = {}; info.text = ICON_FILTER_SPELL; info.value = "spells"
info = {}; info.text = T["Spells"] or "Spells"; info.value = "spells"
info.func = function() ApplyFilter("spells") end
info.checked = currentFilter == "spells"
UIDropDownMenu_AddButton(info)
info = {}; info.text = ICON_FILTER_ITEM; info.value = "items"
info = {}; info.text = T["Items"] or "Items"; info.value = "items"
info.func = function() ApplyFilter("items") end
info.checked = currentFilter == "items"
UIDropDownMenu_AddButton(info)
@@ -521,32 +531,9 @@ pfUI:RegisterModule("equipmentmanager", function()
end
end
-- Normalize a texture path to an uppercase basename for search matching.
local function IconKey(path)
if type(path) ~= "string" then return path end
return string.gsub(string.upper(path), "^.*[\\/]", "")
end
-- Rebuild the search-filtered index list (provider indices whose icon
-- basename contains the search text); nil when the search box is empty.
function RebuildFilter()
EnsureProvider()
if searchText == "" then
filtered = nil
return
end
filtered = {}
for i = 1, provider:GetNumIcons() do
local path = provider:GetIconByIndex(i)
if type(path) == "string" and string.find(IconKey(path), searchText, 1, true) then
table.insert(filtered, i)
end
end
end
function pfUI.equipmentmanager.RefreshIconGrid()
EnsureProvider()
local numIcons = filtered and table.getn(filtered) or provider:GetNumIcons()
local numIcons = provider:GetNumIcons()
local numRows = math.ceil(numIcons / ICON_GRID_COLS)
FauxScrollFrame_Update(iconScroll, numRows, ICON_GRID_ROWS, ICON_BTN_SIZE + ICON_BTN_PAD)
local offset = FauxScrollFrame_GetOffset(iconScroll)
@@ -555,11 +542,10 @@ pfUI:RegisterModule("equipmentmanager", function()
local btn = iconButtons[i]
if listIdx <= numIcons then
btn:Show()
local providerIdx = filtered and filtered[listIdx] or listIdx
btn.iconIndex = providerIdx
local path = provider:GetIconByIndex(providerIdx)
btn.iconIndex = listIdx
local path = provider:GetIconByIndex(listIdx)
btn.texture:SetTexture(path)
if IconKey(path) == IconKey(selectedIconPath) then
if path == selectedIconPath then
btn.backdrop:SetBackdropBorderColor(1, 0.82, 0, 1)
else
btn.backdrop:SetBackdropBorderColor(pfUI.cache.er, pfUI.cache.eg, pfUI.cache.eb, pfUI.cache.ea)
@@ -582,17 +568,15 @@ pfUI:RegisterModule("equipmentmanager", function()
if provider then provider:Release(); provider = nil end
end)
local btnPopupOK = MakeButton("pfEqMgrPopupOK", OKAY, namePopup, namePopup, 14, -340, 80)
local btnPopupOK = MakeButton("pfEqMgrPopupOK", T["OK"] or "OK", namePopup, namePopup, 14, -340, 80)
btnPopupOK:ClearAllPoints()
btnPopupOK:SetPoint("BOTTOMLEFT", namePopup, "BOTTOMLEFT", 14, 12)
local btnPopupCancel = MakeButton("pfEqMgrPopupCancel", CANCEL, namePopup, namePopup, 0, 0, 80)
local btnPopupCancel = MakeButton("pfEqMgrPopupCancel", T["Cancel"] or "Cancel", namePopup, namePopup, 0, 0, 80)
btnPopupCancel:ClearAllPoints()
btnPopupCancel:SetPoint("BOTTOMRIGHT", namePopup, "BOTTOMRIGHT", -14, 12)
btnPopupCancel:SetScript("OnClick", function() namePopup:Hide() end)
-- Okay | Cancel, both anchored to the bottom-right corner.
btnPopupOK:ClearAllPoints()
btnPopupOK:SetPoint("BOTTOMRIGHT", btnPopupCancel, "BOTTOMLEFT", -6, 0)
btnPopupOK:SetScript("OnClick", function()
local name = namePopup.editbox:GetText()
if not name or name == "" then return end
@@ -620,24 +604,6 @@ pfUI:RegisterModule("equipmentmanager", function()
pfUI.equipmentmanager.Refresh()
end)
-- Search box (bottom-left) filters the icon grid by name.
namePopup.searchLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
namePopup.searchLabel:SetPoint("BOTTOMLEFT", namePopup, "BOTTOMLEFT", 16, 18)
namePopup.searchLabel:SetText(SEARCH)
namePopup.search = CreateFrame("EditBox", "pfEqMgrIconSearch", namePopup, "InputBoxTemplate")
namePopup.search:SetSize(180, 20)
namePopup.search:SetPoint("LEFT", namePopup.searchLabel, "RIGHT", 10, 0)
namePopup.search:SetAutoFocus(false)
CreateBackdrop(namePopup.search)
namePopup.search:SetScript("OnEscapePressed", function() this:ClearFocus() end)
namePopup.search:SetScript("OnTextChanged", function()
searchText = strupper(strtrim(this:GetText()))
RebuildFilter()
if scrollbar then scrollbar:SetValue(0) end
pfUI.equipmentmanager.RefreshIconGrid()
end)
-- Assignment (not `local function`) so this fills in the forward
-- declaration at the top of the module — closures created earlier
-- (row gear menu, "+ New Set" row, etc.) capture the same upvalue.
@@ -646,32 +612,26 @@ pfUI:RegisterModule("equipmentmanager", function()
namePopup.editbox:SetText(prefillName or "")
EnsureProvider()
if prefillIcon then
-- Stored icons come back either as a full path or a bare basename
-- (see the row rendering in Refresh). Only prepend the prefix when
-- there's no path separator, so a full path isn't double-prefixed.
selectedIconPath = string.find(prefillIcon, "\\") and prefillIcon
or ("INTERFACE\\ICONS\\" .. prefillIcon)
local short = string.gsub(prefillIcon, "INTERFACE\\ICONS\\", "")
selectedIconPath = "INTERFACE\\ICONS\\" .. strupper(short)
else
selectedIconPath = QUESTION_MARK
end
namePopup.search:SetText("")
if action == "rename" then
namePopup.title:SetText(T["Rename Set"] or "Rename Set")
iconScroll:Hide()
for _, b in ipairs(iconButtons) do b:Hide() end
namePopup.iconLabel:Hide()
namePopup.selectedLabel:Hide()
namePopup.selectedPreview:Hide()
filterDropdown:Hide()
namePopup.searchLabel:Hide()
namePopup.search:Hide()
else
namePopup.title:SetText(action == "new" and (T["Name Set"] or "Name Set") or (T["Save Set"] or "Save Set"))
iconScroll:Show()
namePopup.iconLabel:Show()
namePopup.selectedLabel:Show()
namePopup.selectedPreview:Show()
filterDropdown:Show()
namePopup.searchLabel:Show()
namePopup.search:Show()
end
namePopup:Show()
if action ~= "rename" then pfUI.equipmentmanager.RefreshIconGrid() end
@@ -683,13 +643,9 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local flyout = CreateFrame("Frame", "pfEqMgrFlyout", UIParent)
-- Everything tied to the EM sidecar closes with it: the popout arrows,
-- the per-slot flyout, and the name/icon popup. (OnShow re-shows the
-- popout arrows.)
frame:SetScript("OnHide", function()
for _, b in ipairs(popoutButtons) do b:Hide() end
flyout:Hide()
namePopup:Hide()
end)
flyout:SetFrameStrata("DIALOG")
flyout:Hide()
@@ -720,7 +676,7 @@ pfUI:RegisterModule("equipmentmanager", function()
end
end
ClearCursor()
UIErrorsFrame:AddMessage(ERR_EQUIPMENT_MANAGER_BAGS_FULL, 1, .1, .1, 1)
UIErrorsFrame:AddMessage(EQUIPMENT_MANAGER_BAGS_FULL or "Your bags are full.", 1, .1, .1, 1)
end
local function MakeFlyoutButton(i)
@@ -736,11 +692,11 @@ pfUI:RegisterModule("equipmentmanager", function()
b:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
if this.specialAction == "placeInBags" then
GameTooltip:SetText(EQUIPMENT_MANAGER_PLACE_IN_BAGS, 1, 1, 1)
GameTooltip:SetText(EQUIPMENT_MANAGER_PLACE_IN_BAGS or "Place in Bags", 1, 1, 1)
elseif this.specialAction == "ignore" then
GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT, 1, 1, 1)
GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT or "Ignore this slot", 1, 1, 1)
elseif this.specialAction == "unignore" then
GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT, 1, 1, 1)
GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT or "Stop ignoring this slot", 1, 1, 1)
elseif this.bag then
GameTooltip:SetBagItem(this.bag, this.slot)
elseif this.invSlot then
@@ -748,7 +704,7 @@ pfUI:RegisterModule("equipmentmanager", function()
end
GameTooltip:Show()
end)
b:SetScript("OnLeave", GameTooltip_Hide)
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
b:SetScript("OnClick", function()
if this.specialAction == "placeInBags" then
UnequipToBags(flyout.targetInvSlot)
@@ -853,6 +809,7 @@ pfUI:RegisterModule("equipmentmanager", function()
if num == 0 then
flyout:Hide()
UIErrorsFrame:AddMessage(T["No matching items in bags"] or "No matching items in bags", 1, 1, 0, 1)
return
end
@@ -981,6 +938,16 @@ pfUI:RegisterModule("equipmentmanager", function()
end
end
-- Tie popout visibility to the EM sidecar. They appear when the
-- sidecar opens, hide when it closes, and the flyout closes too.
frame:HookScript("OnShow", function()
for _, b in ipairs(popoutButtons) do b:Show() end
end)
frame:HookScript("OnHide", function()
for _, b in ipairs(popoutButtons) do b:Hide() end
if flyout then flyout:Hide() end
end)
-- ============================================================
-- Refresh
-- ============================================================
+4 -10
View File
@@ -7,7 +7,6 @@
-- string -- so arbitrary icons (including index-less INV_* item icons) persist
-- on both the modern (Turtle/Octo) and stock-vanilla macro UIs. The surrounding
-- MacroFrame (list + body editor) is Blizzard's, already skinned elsewhere.
if not C_Macro or not C_Macro.CreateMacro then return end
pfUI:RegisterModule("macroicons", function ()
HookAddonOrVariable("Blizzard_MacroUI", function()
local QUESTION_MARK = "INTERFACE\\ICONS\\INV_MISC_QUESTIONMARK"
@@ -77,14 +76,9 @@ pfUI:RegisterModule("macroicons", function ()
picker.selectedPreview.tex:SetAllPoints(picker.selectedPreview)
picker.selectedPreview.tex:SetTexCoord(.08, .92, .08, .92)
picker.selectedLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontNormal")
picker.selectedLabel:SetPoint("TOPRIGHT", picker, "TOPRIGHT", -14, -28)
picker.selectedLabel:SetText(ICON_SELECTION_TITLE_CURRENT)
picker.selectedLabel:SetTextColor(1, 0.82, 0)
picker.iconLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontNormal")
picker.iconLabel:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, -100)
picker.iconLabel:SetText(MACRO_POPUP_CHOOSE_ICON)
picker.iconLabel:SetText(T["Choose an Icon:"] or "Choose an Icon:")
-- Icon grid + scroll
local iconScroll = CreateFrame("ScrollFrame", "pfMacroIconScroll", picker, "FauxScrollFrameTemplate")
@@ -114,15 +108,15 @@ pfUI:RegisterModule("macroicons", function ()
end
UIDropDownMenu_Initialize(filterDropdown, function()
local info
info = {}; info.text = ICON_FILTER_ALL; info.value = "all"
info = {}; info.text = T["All Icons"] or "All Icons"; info.value = "all"
info.func = function() ApplyFilter("all") end
info.checked = currentFilter == "all"
UIDropDownMenu_AddButton(info)
info = {}; info.text = ICON_FILTER_SPELL; info.value = "spells"
info = {}; info.text = T["Spells"] or "Spells"; info.value = "spells"
info.func = function() ApplyFilter("spells") end
info.checked = currentFilter == "spells"
UIDropDownMenu_AddButton(info)
info = {}; info.text = ICON_FILTER_ITEM; info.value = "items"
info = {}; info.text = T["Items"] or "Items"; info.value = "items"
info.func = function() ApplyFilter("items") end
info.checked = currentFilter == "items"
UIDropDownMenu_AddButton(info)
+2 -8
View File
@@ -55,7 +55,6 @@ pfUI:RegisterModule("nameplates", function ()
local savedHostileState = nil
local savedFriendlyState = nil
local inFriendlyZone = false
local myGuild = nil
local platecount = 0
local registry = {}
-- Subset of registry that currently has a unit assigned (between
@@ -483,7 +482,6 @@ nameplates:RegisterEvent("UNIT_SPELLCAST_START")
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
nameplates:RegisterEvent("UNIT_SPELLCAST_STOP")
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
nameplates:SetScript("OnEvent", function()
-- Stop event handling during logout to prevent crash 132
@@ -495,17 +493,13 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
nameplates.mouselook:SetScript("OnUpdate", nil)
end
return
elseif event == "PLAYER_GUILD_UPDATE" and arg1 == 'player' then
myGuild = GetGuildInfo("player")
elseif event == "PLAYER_ENTERING_WORLD" or event == "ZONE_CHANGED_NEW_AREA" then
if event == "PLAYER_ENTERING_WORLD" then
CacheConfig()
this:SetGameVariables()
RebuildRaidGuidCache()
frameState.targetGuid = UnitGUID("target")
myGuild = GetGuildInfo("player")
end
-- Handle friendly zone nameplate disable feature
@@ -1127,7 +1121,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
if guild and C.nameplates.showguildname == "1" then
plate.guild:SetText(guild)
if guild == myGuild then
if UnitIsInMyGuild(plate.unit) then
plate.guild:SetTextColor(0, 0.9, 0, 1)
else
plate.guild:SetTextColor(0.8, 0.8, 0.8, 1)
+1 -1
View File
@@ -355,7 +355,7 @@ pfUI:RegisterModule("turtle-wow", function ()
end
end)
if C.disabled["macroicons"] == "1" or not C_Macro or not C_Macro.CreateMacro then
if C.disabled["macroicons"] == "1" then
HookAddonOrVariable("Blizzard_MacroUI", function()
if type(UpdateMacroIconFilenames) ~= "function" then return end
function _G.UpdateMacroIconFilenames()