diff --git a/api/ui-widgets.lua b/api/ui-widgets.lua index 561092a0..2f848094 100644 --- a/api/ui-widgets.lua +++ b/api/ui-widgets.lua @@ -1246,3 +1246,249 @@ function pfUI.api.SkinMoneyInputFrame(frame) copperIcon:ClearAllPoints() copperIcon:SetPoint("LEFT", copper_editbox, "RIGHT", 2, 0) end + +-- Shared icon picker widget. Builds a name field, a "currently selected" +-- preview, and a 10x8 icon grid backed by IconDataProviderMixin with an +-- All/Spells/Items filter and a name search. Used by the macro icon picker +-- and the equipment manager's name/icon popup. The widgets attach to +-- `parent`; the caller owns the surrounding frame, its OK/Cancel buttons, +-- and the save flow. Selection is tracked by texture PATH (not index) so it +-- survives filter changes -- a spell icon you picked still saves after you +-- switch the filter to "Items" and it drops out of the visible grid. +-- +-- name global-name prefix for the scroll frame and editboxes +-- parent the popup frame to attach the widgets to +-- extraType IconDataProviderExtraType.* seed (Spellbook / Equipment) +-- nameLabelText header shown above the name field +-- +-- Returns a handle: +-- .editbox name EditBox (caller wires enter/escape) +-- .search search EditBox +-- .GetIcon() current selected texture path +-- .SetIcon(path) set selection (nil -> question mark) +-- .Refresh() ensure provider, redraw grid + preview +-- .SetIconAreaShown(shown) show/hide the grid, filter, search, and labels +function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText) + local QUESTION_MARK = "INTERFACE\\ICONS\\INV_MISC_QUESTIONMARK" + + local ICON_GRID_COLS = 10 + local ICON_GRID_ROWS = 8 + local ICON_BTN_SIZE = 36 + local ICON_BTN_PAD = 6 + + local provider = nil + local selectedIconPath = QUESTION_MARK + local currentFilter = "all" + local searchText = "" + local filtered = nil -- provider indices matching the search, or nil when empty + local RefreshIconGrid, RebuildFilter + + local function EnsureProvider() + if not provider then + provider = CreateAndInitFromMixin(IconDataProviderMixin, extraType) + end + end + + -- Normalize a texture to an uppercase basename so matching works across + -- sources: GetMacroInfo / stored set icons return "Interface\Icons\" + -- while provider paths are uppercase-prefixed for base icons and + -- mixed-case for spellbook extras. + local function IconKey(path) + if type(path) ~= "string" then return path end + return string.gsub(string.upper(path), "^.*[\\/]", "") + end + + parent.nameLabel = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal") + parent.nameLabel:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -20) + parent.nameLabel:SetText(nameLabelText) + + parent.editbox = CreateFrame("EditBox", name.."Name", parent, "InputBoxTemplate") + parent.editbox:SetSize(280, 20) + parent.editbox:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -38) + parent.editbox:SetAutoFocus(false) + parent.editbox:SetMaxLetters(16) + CreateBackdrop(parent.editbox) + + parent.selectedLabel = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal") + parent.selectedLabel:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -14, -14) + parent.selectedLabel:SetText(ICON_SELECTION_TITLE_CURRENT) + parent.selectedLabel:SetTextColor(1, 0.82, 0) + + parent.selectedPreview = CreateFrame("Frame", nil, parent) + parent.selectedPreview:SetSize(42, 42) + parent.selectedPreview:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -14, -30) + CreateBackdrop(parent.selectedPreview) + parent.selectedPreview.tex = parent.selectedPreview:CreateTexture(nil, "ARTWORK") + parent.selectedPreview.tex:SetAllPoints(parent.selectedPreview) + parent.selectedPreview.tex:SetTexCoord(.08, .92, .08, .92) + + parent.iconLabel = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal") + parent.iconLabel:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -86) + parent.iconLabel:SetText(MACRO_POPUP_CHOOSE_ICON) + + -- Icon grid + scroll + local iconScroll = CreateFrame("ScrollFrame", name.."Scroll", parent, "FauxScrollFrameTemplate") + iconScroll:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -116) + 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) + + local scrollbar = _G[name.."ScrollScrollBar"] + scrollbar:ClearAllPoints() + scrollbar:SetPoint("TOPLEFT", iconScroll, "TOPRIGHT", 8, -16) + scrollbar:SetPoint("BOTTOMLEFT", iconScroll, "BOTTOMRIGHT", 8, 16) + SkinScrollbar(scrollbar) + + -- Filter dropdown: All / Spells / Items + local filterDropdown = CreateFrame("Frame", name.."Filter", parent, "UIDropDownMenuTemplate") + filterDropdown:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, -80) + local function ApplyFilter(value) + currentFilter = value + UIDropDownMenu_SetSelectedValue(filterDropdown, value) + if provider then + if value == "spells" then provider:SetIconTypes({ IconDataProviderIconType.Spell }) + elseif value == "items" then provider:SetIconTypes({ IconDataProviderIconType.Item }) + else provider:SetIconTypes(nil) end + RebuildFilter() + RefreshIconGrid() + end + end + UIDropDownMenu_Initialize(filterDropdown, function() + local info + info = {}; info.text = ICON_FILTER_ALL; 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.func = function() ApplyFilter("spells") end + info.checked = currentFilter == "spells" + UIDropDownMenu_AddButton(info) + info = {}; info.text = ICON_FILTER_ITEM; info.value = "items" + info.func = function() ApplyFilter("items") end + info.checked = currentFilter == "items" + UIDropDownMenu_AddButton(info) + end) + UIDropDownMenu_SetWidth(120, filterDropdown) + UIDropDownMenu_SetSelectedValue(filterDropdown, "all") + SkinDropDown(filterDropdown) + + local iconButtons = {} + for r = 1, ICON_GRID_ROWS do + for c = 1, ICON_GRID_COLS do + local i = (r - 1) * ICON_GRID_COLS + c + local btn = CreateFrame("Button", nil, parent) + btn:SetSize(ICON_BTN_SIZE, ICON_BTN_SIZE) + btn:SetPoint("TOPLEFT", iconScroll, "TOPLEFT", (c-1) * (ICON_BTN_SIZE + ICON_BTN_PAD), -(r-1) * (ICON_BTN_SIZE + ICON_BTN_PAD)) + CreateBackdrop(btn) + btn.texture = btn:CreateTexture(nil, "ARTWORK") + btn.texture:SetAllPoints(btn) + btn.texture:SetTexCoord(.08, .92, .08, .92) + btn:SetScript("OnClick", function() + if this.iconIndex and provider then + local path = provider:GetIconByIndex(this.iconIndex) + if path then selectedIconPath = path end + RefreshIconGrid() + end + end) + btn:SetScript("OnEnter", function() + if not this.iconIndex or not provider then return end + local path = provider:GetIconByIndex(this.iconIndex) + if type(path) == "string" then + GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetText(IconKey(path), 1, 1, 1) + GameTooltip:Show() + end + end) + btn:SetScript("OnLeave", GameTooltip_Hide) + iconButtons[i] = btn + end + 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 RefreshIconGrid() + EnsureProvider() + local numIcons = filtered and table.getn(filtered) or 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) + for i = 1, ICON_GRID_ROWS * ICON_GRID_COLS do + local listIdx = i + offset * ICON_GRID_COLS + 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.texture:SetTexture(path) + if IconKey(path) == IconKey(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) + end + else + btn:Hide() + btn.iconIndex = nil + end + end + parent.selectedPreview.tex:SetTexture(selectedIconPath) + end + + iconScroll:SetScript("OnVerticalScroll", function() + FauxScrollFrame_OnVerticalScroll(ICON_BTN_SIZE + ICON_BTN_PAD, function() RefreshIconGrid() end) + end) + + -- Search box (bottom-left) filters the grid by icon name. + parent.searchLabel = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal") + parent.searchLabel:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 16, 18) + parent.searchLabel:SetText(SEARCH) + + parent.search = CreateFrame("EditBox", name.."Search", parent, "InputBoxTemplate") + parent.search:SetSize(180, 20) + parent.search:SetPoint("LEFT", parent.searchLabel, "RIGHT", 10, 0) + parent.search:SetAutoFocus(false) + CreateBackdrop(parent.search) + parent.search:SetScript("OnEscapePressed", function() this:ClearFocus() end) + parent.search:SetScript("OnTextChanged", function() + searchText = strupper(strtrim(this:GetText())) + RebuildFilter() + scrollbar:SetValue(0) + RefreshIconGrid() + end) + + -- Release the provider when the popup closes so its icon cache GCs. + parent:HookScript("OnHide", function() + if provider then provider:Release(); provider = nil end + end) + + local handle = { editbox = parent.editbox, search = parent.search } + function handle.GetIcon() return selectedIconPath end + function handle.SetIcon(path) selectedIconPath = path or QUESTION_MARK end + function handle.Refresh() RefreshIconGrid() end + function handle.SetIconAreaShown(shown) + local method = shown and "Show" or "Hide" + iconScroll[method](iconScroll) + for _, b in ipairs(iconButtons) do b[method](b) end + parent.iconLabel[method](parent.iconLabel) + parent.selectedLabel[method](parent.selectedLabel) + parent.selectedPreview[method](parent.selectedPreview) + filterDropdown[method](filterDropdown) + parent.searchLabel[method](parent.searchLabel) + parent.search[method](parent.search) + end + return handle +end diff --git a/init/modules.xml b/init/modules.xml index 67111e42..182c993a 100644 --- a/init/modules.xml +++ b/init/modules.xml @@ -71,6 +71,7 @@ + diff --git a/modules/equipmentmanager.lua b/modules/equipmentmanager.lua index d27cf723..6afbc5a1 100644 --- a/modules/equipmentmanager.lua +++ b/modules/equipmentmanager.lua @@ -1,11 +1,10 @@ -- Equipment Manager module --- Backport of the 4.3.4 GearManagerDialog UI on top of ClassicAPI's --- C_EquipmentSet.* API. Adds a 6th tab to CharacterFrame. +-- Backport of the 4.3.4 GearManagerDialog UI on top of ClassicAPI's C_EquipmentSet.* API. pfUI:RegisterModule("equipmentmanager", function() if not C_EquipmentSet or not C_EquipmentSet.CanUseEquipmentSets() then return end - pfUI.equipmentmanager = pfUI.equipmentmanager or {} + pfUI.equipmentmanager = {} local SET_ROW_HEIGHT = 36 @@ -55,7 +54,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 or "Locked items in set", 1, .1, .1, 1) + UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1, .1, .1, 1) return end ClearCursor() @@ -68,8 +67,7 @@ pfUI:RegisterModule("equipmentmanager", function() -- ============================================================ local frame = CreateFrame("Frame", "pfEquipmentManagerFrame", CharacterFrame) - frame:SetWidth(220) - frame:SetHeight(350) + frame:SetSize(220, 350) frame:SetFrameStrata("HIGH") frame:SetScript("OnShow", function() this:ClearAllPoints() @@ -86,7 +84,7 @@ pfUI:RegisterModule("equipmentmanager", function() frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") frame.title:SetPoint("TOP", frame, "TOP", 0, -10) - frame.title:SetText(T["Equipment Manager"] or "Equipment Manager") + frame.title:SetText(EQUIPMENT_MANAGER) local closeBtn = CreateFrame("Button", nil, frame, "UIPanelCloseButton") closeBtn:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -4, -4) @@ -98,15 +96,14 @@ pfUI:RegisterModule("equipmentmanager", function() -- ============================================================ local toggleBtn = CreateFrame("Button", "pfEqMgrToggleButton", PaperDollFrame) - toggleBtn:SetWidth(28) - toggleBtn:SetHeight(28) + toggleBtn:SetSize(28, 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(T["Equipment Manager"] or "Equipment Manager") + GameTooltip:SetText(PAPERDOLL_EQUIPMENTMANAGER) GameTooltip:Show() end) toggleBtn:SetScript("OnLeave", function() GameTooltip:Hide() end) @@ -126,13 +123,13 @@ pfUI:RegisterModule("equipmentmanager", function() -- ============================================================ local btnEquip = CreateFrame("Button", "pfEqMgrEquip", frame, "UIPanelButtonTemplate") - btnEquip:SetWidth(86); btnEquip:SetHeight(22); btnEquip:SetText(T["Equip"] or "Equip") + btnEquip:SetSize(86, 22); btnEquip:SetText(EQUIPSET_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:SetWidth(86); btnSave:SetHeight(22); btnSave:SetText(T["Save"] or "Save") + btnSave:SetSize(86, 22); btnSave:SetText(SAVE) btnSave:SetPoint("LEFT", btnEquip, "RIGHT", 6, 0) SkinButton(btnSave) btnSave:SetScript("OnClick", function() @@ -141,7 +138,7 @@ pfUI:RegisterModule("equipmentmanager", function() if not name then return end local targetID = selectedSetID StaticPopupDialogs["PFUI_EQMGR_SAVE_CONFIRM"] = { - text = string.format(T["Would you like to save the equipment set '%s'?"] or "Would you like to save the equipment set '%s'?", name), + text = string.format(CONFIRM_SAVE_EQUIPMENT_SET, name), button1 = YES, button2 = NO, OnAccept = function() C_EquipmentSet.ClearIgnoredSlotsForSave() @@ -166,7 +163,7 @@ pfUI:RegisterModule("equipmentmanager", function() local rowMenu = CreateFrame("Frame", "pfEqMgrRowMenu", UIParent) rowMenu:SetFrameStrata("DIALOG") - rowMenu:SetWidth(140); rowMenu:SetHeight(50) + rowMenu:SetSize(140, 50); rowMenu:Hide() CreateBackdrop(rowMenu, nil, nil, .95) CreateBackdropShadow(rowMenu) @@ -185,9 +182,9 @@ pfUI:RegisterModule("equipmentmanager", function() tinsert(UISpecialFrames, "pfEqMgrRowMenu") -- Escape closes it rowMenu.changeBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate") - rowMenu.changeBtn:SetWidth(130); rowMenu.changeBtn:SetHeight(20) + rowMenu.changeBtn:SetSize(130, 20); rowMenu.changeBtn:SetPoint("TOPLEFT", rowMenu, "TOPLEFT", 5, -3) - rowMenu.changeBtn:SetText(T["Change Name/Icon"] or "Change Name/Icon") + rowMenu.changeBtn:SetText(EQUIPMENT_SET_EDIT) SkinButton(rowMenu.changeBtn) rowMenu.changeBtn:SetScript("OnClick", function() rowMenu:Hide() @@ -198,9 +195,9 @@ pfUI:RegisterModule("equipmentmanager", function() end) rowMenu.deleteBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate") - rowMenu.deleteBtn:SetWidth(130); rowMenu.deleteBtn:SetHeight(20) + rowMenu.deleteBtn:SetSize(130, 20); rowMenu.deleteBtn:SetPoint("TOP", rowMenu.changeBtn, "BOTTOM", 0, -2) - rowMenu.deleteBtn:SetText(T["Delete"] or "Delete") + rowMenu.deleteBtn:SetText(DELETE) SkinButton(rowMenu.deleteBtn) rowMenu.deleteBtn:SetScript("OnClick", function() rowMenu:Hide() @@ -208,7 +205,7 @@ pfUI:RegisterModule("equipmentmanager", function() local targetID = rowMenu.targetSetID local name = C_EquipmentSet.GetEquipmentSetInfo(targetID) StaticPopupDialogs["PFUI_EQMGR_DELETE"] = { - text = string.format(T["Delete equipment set '%s'?"] or "Delete equipment set '%s'?", name or "?"), + text = string.format(CONFIRM_DELETE_EQUIPMENT_SET, name or "?"), button1 = YES, button2 = NO, OnAccept = function() pendingIgnoredToggles[targetID] = nil @@ -229,9 +226,8 @@ 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:SetHeight(LIST_VISIBLE_ROWS * LIST_ROW_STRIDE + 4) + listFrame:SetSize(180, LIST_VISIBLE_ROWS * LIST_ROW_STRIDE + 4) CreateBackdrop(listFrame, nil, nil, .75) -- Mouse-wheel scroll: list of [sets..., newSetRow] is virtualized @@ -247,15 +243,13 @@ pfUI:RegisterModule("equipmentmanager", function() local setRows = {} local function CreateSetRow() local row = CreateFrame("Button", nil, listFrame) - row:SetWidth(170) - row:SetHeight(SET_ROW_HEIGHT) + row:SetSize(170, 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:SetWidth(30) - row.icon:SetHeight(30) + row.icon:SetSize(30, 30) row.icon:SetPoint("LEFT", row, "LEFT", 2, 0) row.icon:SetTexCoord(.08, .92, .08, .92) @@ -270,7 +264,7 @@ pfUI:RegisterModule("equipmentmanager", function() row.highlight:Hide() row.gear = CreateFrame("Button", nil, row) - row.gear:SetWidth(16); row.gear:SetHeight(16) + row.gear:SetSize(16, 16); row.gear:SetPoint("RIGHT", row, "RIGHT", -4, 0) row.gear.tex = row.gear:CreateTexture(nil, "ARTWORK") row.gear.tex:SetAllPoints(row.gear) @@ -306,27 +300,27 @@ pfUI:RegisterModule("equipmentmanager", function() pfUI.equipmentmanager.Refresh() 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. + -- 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 row:SetScript("OnEnter", function() - if not this.setID then return end - local name = C_EquipmentSet.GetEquipmentSetInfo(this.setID) + if not row.setID then return end + local name = C_EquipmentSet.GetEquipmentSetInfo(row.setID) if name then - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetOwner(row, "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 @@ -338,10 +332,10 @@ pfUI:RegisterModule("equipmentmanager", function() -- specific set index (row[i] always shows ids[i]). local newSetRow = CreateFrame("Button", nil, listFrame) - newSetRow:SetWidth(170); newSetRow:SetHeight(SET_ROW_HEIGHT) + newSetRow:SetSize(170, SET_ROW_HEIGHT); newSetRow.icon = newSetRow:CreateTexture(nil, "ARTWORK") - newSetRow.icon:SetWidth(24); newSetRow.icon:SetHeight(24) + newSetRow.icon:SetSize(24, 24); newSetRow.icon:SetPoint("LEFT", newSetRow, "LEFT", 5, 0) newSetRow.icon:SetTexture(pfUI.path.."\\img\\Character-Plus") @@ -349,7 +343,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(T["New Set"] or "New Set") + newSetRow.text:SetText(PAPERDOLL_NEWEQUIPMENTSET) newSetRow.text:SetTextColor(0.2, 1, 0.2) newSetRow.highlight = newSetRow:CreateTexture(nil, "BACKGROUND") @@ -362,8 +356,7 @@ pfUI:RegisterModule("equipmentmanager", function() local function MakeButton(name, label, parent, anchor, ax, ay, width) local b = CreateFrame("Button", name, parent, "UIPanelButtonTemplate") - b:SetWidth(width or 70) - b:SetHeight(22) + b:SetSize(width or 70, 22) b:SetText(label) b:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", ax, ay) SkinButton(b) @@ -376,8 +369,7 @@ pfUI:RegisterModule("equipmentmanager", function() local namePopup = CreateFrame("Frame", "pfEqMgrNamePopup", UIParent) namePopup:SetFrameStrata("DIALOG") - namePopup:SetWidth(472) - namePopup:SetHeight(498) + namePopup:SetSize(472, 484) namePopup:SetPoint("CENTER", UIParent, "CENTER") namePopup:Hide() CreateBackdrop(namePopup, nil, nil, .9) @@ -388,200 +380,28 @@ 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") + -- Equipment seed leads the grid with gear-relevant item icons. The widget + -- owns the name field, preview, grid, filter, and search; this module keeps + -- the OK/Cancel buttons and the create/save/rename flow below. + local iconPicker = CreateIconPicker("pfEqMgrIcon", namePopup, + IconDataProviderExtraType.Equipment, GEARSETS_POPUP_TEXT) - namePopup.nameLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal") - 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):") + local btnPopupOK = MakeButton("pfEqMgrPopupOK", OKAY, namePopup, namePopup, 14, -340, 80) - namePopup.editbox = CreateFrame("EditBox", "pfEqMgrNameEdit", namePopup, "InputBoxTemplate") - 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, -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: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, -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 - local ICON_GRID_ROWS = 8 - local ICON_BTN_SIZE = 36 - local ICON_BTN_PAD = 6 - - local iconScroll = CreateFrame("ScrollFrame", "pfEqMgrIconScroll", namePopup, "FauxScrollFrameTemplate") - 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) - - -- IconDataProviderMixin owns the icon DB, dedup, and lazy load. - -- Init on first picker open; release on hide so the cache GCs. - local provider = nil - -- Selection is tracked by PATH (not index) so it survives filter - -- changes: a spell icon you picked still saves correctly even after - -- 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 function EnsureProvider() - if not provider then - provider = CreateAndInitFromMixin(IconDataProviderMixin, - IconDataProviderExtraType.Equipment) - end - end - - -- Anchor scrollbar to iconScroll's right edge so its position tracks - -- the icon grid rather than the popup. -16/+16 vertical insets are the - -- standard up/down arrow spacing for UIPanelScrollBarTemplate. - local scrollbar = _G["pfEqMgrIconScrollScrollBar"] - if scrollbar then - scrollbar:ClearAllPoints() - scrollbar:SetPoint("TOPLEFT", iconScroll, "TOPRIGHT", 8, -16) - scrollbar:SetPoint("BOTTOMLEFT", iconScroll, "BOTTOMRIGHT", 8, 16) - SkinScrollbar(scrollbar) - end - - -- Filter dropdown: "All Icons" / "Spells" / "Items" (top right of icon area). - local filterDropdown = CreateFrame("Frame", "pfEqMgrIconFilter", namePopup, "UIDropDownMenuTemplate") - filterDropdown:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", 0, -94) - local currentFilter = "all" - local function ApplyFilter(value) - currentFilter = value - UIDropDownMenu_SetSelectedValue(filterDropdown, value) - if provider then - if value == "spells" then provider:SetIconTypes({ IconDataProviderIconType.Spell }) - elseif value == "items" then provider:SetIconTypes({ IconDataProviderIconType.Item }) - else provider:SetIconTypes(nil) end - -- 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. - pfUI.equipmentmanager.RefreshIconGrid() - end - end - UIDropDownMenu_Initialize(filterDropdown, function() - local info - 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 = T["Spells"] or "Spells"; info.value = "spells" - info.func = function() ApplyFilter("spells") end - info.checked = currentFilter == "spells" - UIDropDownMenu_AddButton(info) - info = {}; info.text = T["Items"] or "Items"; info.value = "items" - info.func = function() ApplyFilter("items") end - info.checked = currentFilter == "items" - UIDropDownMenu_AddButton(info) - end) - UIDropDownMenu_SetWidth(120, filterDropdown) - UIDropDownMenu_SetSelectedValue(filterDropdown, "all") - SkinDropDown(filterDropdown) - - local iconButtons = {} - for r = 1, ICON_GRID_ROWS do - for c = 1, ICON_GRID_COLS do - local i = (r - 1) * ICON_GRID_COLS + c - local btn = CreateFrame("Button", nil, namePopup) - btn:SetWidth(ICON_BTN_SIZE) - btn:SetHeight(ICON_BTN_SIZE) - btn:SetPoint("TOPLEFT", iconScroll, "TOPLEFT", (c-1) * (ICON_BTN_SIZE + ICON_BTN_PAD), -(r-1) * (ICON_BTN_SIZE + ICON_BTN_PAD)) - CreateBackdrop(btn) - btn.texture = btn:CreateTexture(nil, "ARTWORK") - btn.texture:SetAllPoints(btn) - btn.texture:SetTexCoord(.08, .92, .08, .92) - btn.gridIndex = i - btn:SetScript("OnClick", function() - if this.iconIndex and provider then - local path = provider:GetIconByIndex(this.iconIndex) - if path then selectedIconPath = path end - pfUI.equipmentmanager.RefreshIconGrid() - end - end) - btn:SetScript("OnEnter", function() - if not this.iconIndex or not provider then return end - local path = provider:GetIconByIndex(this.iconIndex) - if type(path) == "string" then - local name = string.gsub(path, "^.-INTERFACE\\\\ICONS\\\\", "") - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(name) - GameTooltip:Show() - end - end) - btn:SetScript("OnLeave", GameTooltip_Hide) - iconButtons[i] = btn - end - end - - function pfUI.equipmentmanager.RefreshIconGrid() - EnsureProvider() - 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) - for i = 1, ICON_GRID_ROWS * ICON_GRID_COLS do - local listIdx = i + offset * ICON_GRID_COLS - local btn = iconButtons[i] - if listIdx <= numIcons then - btn:Show() - btn.iconIndex = listIdx - local path = provider:GetIconByIndex(listIdx) - btn.texture:SetTexture(path) - 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) - end - else - btn:Hide() - btn.iconIndex = nil - end - end - -- Sync the "Currently Selected" preview from the path directly so it - -- still shows the chosen icon when filtered out of the grid. - namePopup.selectedPreview.tex:SetTexture(selectedIconPath) - end - - iconScroll:SetScript("OnVerticalScroll", function() - FauxScrollFrame_OnVerticalScroll(ICON_BTN_SIZE + ICON_BTN_PAD, function() pfUI.equipmentmanager.RefreshIconGrid() end) - end) - - namePopup:SetScript("OnHide", function() - if provider then provider:Release(); provider = nil end - end) - - 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", T["Cancel"] or "Cancel", namePopup, namePopup, 0, 0, 80) + local btnPopupCancel = MakeButton("pfEqMgrPopupCancel", 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 -- Strip the prefix to match ClassicAPI's persisted short-form basenames. - local iconForSave = string.gsub(selectedIconPath, "INTERFACE\\ICONS\\", "") + local iconForSave = string.gsub(iconPicker.GetIcon(), "INTERFACE\\ICONS\\", "") if pendingAction == "new" then C_EquipmentSet.CreateEquipmentSet(name, iconForSave) C_EquipmentSet.ClearIgnoredSlotsForSave() @@ -610,31 +430,20 @@ pfUI:RegisterModule("equipmentmanager", function() function OpenNamePopup(action, prefillName, prefillIcon) pendingAction = action namePopup.editbox:SetText(prefillName or "") - EnsureProvider() if prefillIcon then - local short = string.gsub(prefillIcon, "INTERFACE\\ICONS\\", "") - selectedIconPath = "INTERFACE\\ICONS\\" .. strupper(short) + -- 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. + iconPicker.SetIcon(string.find(prefillIcon, "\\") and prefillIcon + or ("INTERFACE\\ICONS\\" .. prefillIcon)) else - selectedIconPath = QUESTION_MARK - end - 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() - 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() + iconPicker.SetIcon(nil) end + namePopup.search:SetText("") + -- Rename only changes the name, so hide the whole icon-picking area. + iconPicker.SetIconAreaShown(action ~= "rename") namePopup:Show() - if action ~= "rename" then pfUI.equipmentmanager.RefreshIconGrid() end + if action ~= "rename" then iconPicker.Refresh() end namePopup.editbox:SetFocus() end @@ -643,9 +452,13 @@ 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() @@ -676,7 +489,7 @@ pfUI:RegisterModule("equipmentmanager", function() end end ClearCursor() - UIErrorsFrame:AddMessage(EQUIPMENT_MANAGER_BAGS_FULL or "Your bags are full.", 1, .1, .1, 1) + UIErrorsFrame:AddMessage(ERR_EQUIPMENT_MANAGER_BAGS_FULL, 1, .1, .1, 1) end local function MakeFlyoutButton(i) @@ -692,11 +505,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 or "Place in Bags", 1, 1, 1) + GameTooltip:SetText(EQUIPMENT_MANAGER_PLACE_IN_BAGS, 1, 1, 1) elseif this.specialAction == "ignore" then - GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT or "Ignore this slot", 1, 1, 1) + GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT, 1, 1, 1) elseif this.specialAction == "unignore" then - GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT or "Stop ignoring this slot", 1, 1, 1) + GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT, 1, 1, 1) elseif this.bag then GameTooltip:SetBagItem(this.bag, this.slot) elseif this.invSlot then @@ -704,7 +517,7 @@ pfUI:RegisterModule("equipmentmanager", function() end GameTooltip:Show() end) - b:SetScript("OnLeave", function() GameTooltip:Hide() end) + b:SetScript("OnLeave", GameTooltip_Hide) b:SetScript("OnClick", function() if this.specialAction == "placeInBags" then UnequipToBags(flyout.targetInvSlot) @@ -809,7 +622,6 @@ 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 @@ -938,16 +750,6 @@ 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 -- ============================================================ diff --git a/modules/macroicons.lua b/modules/macroicons.lua new file mode 100644 index 00000000..3ab134fa --- /dev/null +++ b/modules/macroicons.lua @@ -0,0 +1,128 @@ +-- Macro icon picker +-- Replaces Blizzard's MacroPopupFrame (the "name + icon" dialog opened by the +-- New / Change-Icon buttons) with a pfUI-native picker driven by +-- IconDataProviderMixin, so the full spell + item + loose icon set is +-- available instead of the stock spell-only list. Saving goes 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 +-- on both the modern (Turtle/Octo) and stock-vanilla macro UIs. The surrounding +-- MacroFrame (list + body editor) is Blizzard's, already skinned elsewhere. +pfUI:RegisterModule("macroicons", function () + HookAddonOrVariable("Blizzard_MacroUI", function() + -- ============================================================ + -- Popup frame + -- ============================================================ + + local picker = CreateFrame("Frame", "pfMacroIconPicker", UIParent) + picker:SetFrameStrata("DIALOG") + picker:SetSize(472, 484) + -- Starts anchored to the right of the macro panel (re-anchored at open + -- once the skin's backdrop exists); dragging pins it in place after. + picker:SetPoint("BOTTOMLEFT", MacroFrame, "BOTTOMRIGHT", 8, 0) + picker:Hide() + CreateBackdrop(picker, nil, nil, .9) + CreateBackdropShadow(picker) + picker:EnableMouse(true) + picker:SetMovable(true) + picker:RegisterForDrag("LeftButton") + picker:SetScript("OnDragStart", function() this:StartMoving() end) + picker:SetScript("OnDragStop", function() + this:StopMovingOrSizing() + this.userMoved = true + end) + + -- Spellbook seed leads the grid with class-relevant spell/talent icons. + local iconPicker = CreateIconPicker("pfMacroIcon", picker, + IconDataProviderExtraType.Spellbook, MACRO_POPUP_TEXT) + + -- ============================================================ + -- Open / save + -- ============================================================ + + -- Blizzard's popup disables these while it is open; mirror that so the + -- underlying frame can't be double-driven, then let MacroFrame_Update + -- restore the correct states on close. + local function SetMacroButtons(enabled) + local m = enabled and "Enable" or "Disable" + MacroNewButton[m](MacroNewButton) + MacroEditButton[m](MacroEditButton) + MacroDeleteButton[m](MacroDeleteButton) + end + + local function OpenMacroPopup(mode) + if mode == "edit" and MacroFrame.selectedMacro then + picker.mode = "edit" + local name, texture = GetMacroInfo(MacroFrame.selectedMacro) + picker.editbox:SetText(name or "") + iconPicker.SetIcon(texture) + else + picker.mode = "new" + picker.editbox:SetText("") + iconPicker.SetIcon(nil) + end + picker.search:SetText("") + if not picker.userMoved then + picker:ClearAllPoints() + picker:SetPoint("BOTTOMLEFT", MacroFrame.backdrop or MacroFrame, "BOTTOMRIGHT", 8, 0) + end + SetMacroButtons(false) + picker:Show() + picker.editbox:SetFocus() + iconPicker.Refresh() + end + + local function SaveMacroPopup() + local text = strtrim(picker.editbox:GetText()) + if text == "" then return end + + local icon = iconPicker.GetIcon() + if picker.mode == "edit" and MacroFrame.selectedMacro then + C_Macro.EditMacro(MacroFrame.selectedMacro, text, icon, nil) + MacroFrame_SelectMacro(MacroFrame.selectedMacro) + else + local idx = C_Macro.CreateMacro(text, icon, nil, (MacroFrame.macroBase or 0) > 0) + if idx then MacroFrame_SelectMacro(idx) end + end + picker:Hide() + end + + picker:SetScript("OnHide", function() MacroFrame_Update() end) + + picker.editbox:SetScript("OnEnterPressed", SaveMacroPopup) + picker.editbox:SetScript("OnEscapePressed", function() picker:Hide() end) + + -- OK / Cancel + local okay = CreateFrame("Button", "pfMacroIconPickerOkay", picker, "UIPanelButtonTemplate") + okay:SetSize(80, 22) + okay:SetText(OKAY) + okay:SetScript("OnClick", SaveMacroPopup) + SkinButton(okay) + + local cancel = CreateFrame("Button", "pfMacroIconPickerCancel", picker, "UIPanelButtonTemplate") + cancel:SetSize(80, 22) + cancel:SetText(CANCEL) + cancel:SetPoint("BOTTOMRIGHT", picker, "BOTTOMRIGHT", -14, 12) + cancel:SetScript("OnClick", function() picker:Hide() end) + SkinButton(cancel) + + -- Okay | Cancel, both anchored to the bottom-right corner. + okay:SetPoint("BOTTOMRIGHT", cancel, "BOTTOMLEFT", -6, 0) + + -- ============================================================ + -- Take over the New / Change-Icon buttons; retire Blizzard's popup + -- ============================================================ + + MacroNewButton:SetScript("OnClick", function() + MacroFrame_SaveMacro() + OpenMacroPopup("new") + end) + + MacroEditButton:SetScript("OnClick", function() + MacroFrame_SaveMacro() + OpenMacroPopup("edit") + end) + + -- Closing the macro window takes the picker with it. + MacroFrame:HookScript("OnHide", function() picker:Hide() end) + end) +end) diff --git a/modules/turtle-wow.lua b/modules/turtle-wow.lua index 31f98361..2f229023 100644 --- a/modules/turtle-wow.lua +++ b/modules/turtle-wow.lua @@ -355,24 +355,25 @@ pfUI:RegisterModule("turtle-wow", function () end end) - HookAddonOrVariable("Blizzard_MacroUI", function() - if type(UpdateMacroIconFilenames) ~= "function" then return end - function _G.UpdateMacroIconFilenames() - wipe(MACRO_ICON_FILENAMES) - local provider = CreateAndInitFromMixin(IconDataProviderMixin, IconDataProviderExtraType.Spellbook) - local seen = {} - for i = 1, provider:GetNumIcons() do - -- uppercase, prefix-stripped basename, matching Blizzard's original - local icon = string.gsub(string.upper(provider:GetIconByIndex(i)), "INTERFACE\\ICONS\\", "") - if not seen[icon] then - seen[icon] = true - table.insert(MACRO_ICON_FILENAMES, icon) + if C.disabled["macroicons"] == "1" then + HookAddonOrVariable("Blizzard_MacroUI", function() + if type(UpdateMacroIconFilenames) ~= "function" then return end + function _G.UpdateMacroIconFilenames() + wipe(MACRO_ICON_FILENAMES) + local provider = CreateAndInitFromMixin(IconDataProviderMixin, IconDataProviderExtraType.Spellbook) + local seen = {} + for i = 1, provider:GetNumIcons() do + -- uppercase, prefix-stripped basename, matching Blizzard's original + local icon = string.gsub(string.upper(provider:GetIconByIndex(i)), "INTERFACE\\ICONS\\", "") + if not seen[icon] then + seen[icon] = true + table.insert(MACRO_ICON_FILENAMES, icon) + end end + provider:Release() end - provider:Release() - end - end) - + end) + end -- add turtle-wow sell values pfSellData = { diff --git a/pfUI.lua b/pfUI.lua index 27552d32..0dd694c1 100644 --- a/pfUI.lua +++ b/pfUI.lua @@ -23,7 +23,7 @@ do -- ClassicAPI dependency check. -- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus -- API surface that ClassicAPI polyfills, so presence is required. - local PFUI_CLASSIC_API_MIN = 10900 -- (X*10000 + Y*100 + Z) + local PFUI_CLASSIC_API_MIN = 10903 -- (X*10000 + Y*100 + Z) local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI" local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest" diff --git a/skins/blizzard/macro.lua b/skins/blizzard/macro.lua index ec5638ef..c50477d2 100644 --- a/skins/blizzard/macro.lua +++ b/skins/blizzard/macro.lua @@ -60,33 +60,35 @@ pfUI:RegisterSkin("Macro", function () MacroFrameScrollFrame:ClearAllPoints() MacroFrameScrollFrame:SetPoint("TOPLEFT", MacroFrameSelectedMacroBackground, "BOTTOMLEFT", 11, -13) + -- The macroicons module replaces MacroPopupFrame with its own picker. + -- Only skin the stock popup when that module is disabled. + if pfUI_config["disabled"] and pfUI_config["disabled"]["macroicons"] == "1" then + StripTextures(MacroPopupFrame) + CreateBackdrop(MacroPopupFrame, nil, nil, .75) + MacroPopupFrame:SetFrameStrata("DIALOG") + MacroPopupFrame:ClearAllPoints() + MacroPopupFrame:SetPoint("TOPLEFT", MacroFrame.backdrop, "TOPRIGHT", 2*border, 0) + StripTextures(MacroPopupScrollFrame) + SkinScrollbar(MacroPopupScrollFrameScrollBar) - StripTextures(MacroPopupFrame) - CreateBackdrop(MacroPopupFrame, nil, nil, .75) - MacroPopupFrame:SetFrameStrata("DIALOG") - MacroPopupFrame:ClearAllPoints() - MacroPopupFrame:SetPoint("TOPLEFT", MacroFrame.backdrop, "TOPRIGHT", 2*border, 0) + MacroPopupEditBox:DisableDrawLayer("BACKGROUND") + CreateBackdrop(MacroPopupEditBox, nil, true) + MacroPopupEditBox:SetScript("OnEscapePressed", function() + MacroPopupFrame:Hide() + MacroFrame_Update() + end) - StripTextures(MacroPopupScrollFrame) - SkinScrollbar(MacroPopupScrollFrameScrollBar) - - MacroPopupEditBox:DisableDrawLayer("BACKGROUND") - CreateBackdrop(MacroPopupEditBox, nil, true) - MacroPopupEditBox:SetScript("OnEscapePressed", function() - MacroPopupFrame:Hide() - MacroFrame_Update() - end) - - for i=1, NUM_MACRO_ICONS_SHOWN do - local button = _G["MacroPopupButton"..i] - local icon = _G["MacroPopupButton"..i..'Icon'] - StripTextures(button) - SkinButton(button, nil, nil, nil, icon) + for i=1, NUM_MACRO_ICONS_SHOWN do + local button = _G["MacroPopupButton"..i] + local icon = _G["MacroPopupButton"..i..'Icon'] + StripTextures(button) + SkinButton(button, nil, nil, nil, icon) + end + SkinButton(MacroPopupCancelButton) + SkinButton(MacroPopupOkayButton) + MacroPopupOkayButton:ClearAllPoints() + MacroPopupOkayButton:SetPoint("RIGHT", MacroPopupCancelButton, "LEFT", -2*bpad, 0) end - SkinButton(MacroPopupCancelButton) - SkinButton(MacroPopupOkayButton) - MacroPopupOkayButton:ClearAllPoints() - MacroPopupOkayButton:SetPoint("RIGHT", MacroPopupCancelButton, "LEFT", -2*bpad, 0) end) end)