mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-21 20:00:48 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d149b60b6c | ||
|
|
be8a8c26b5 | ||
|
|
0778f9a7be | ||
|
|
0cc9cf4165 | ||
|
|
76927c2c18 |
@@ -6,7 +6,7 @@
|
|||||||
[](https://github.com/balakethelock/SuperWoW)
|
[](https://github.com/balakethelock/SuperWoW)
|
||||||
[](https://github.com/brues-code/UnitXP_SP3)
|
[](https://github.com/brues-code/UnitXP_SP3)
|
||||||
|
|
||||||
**A pfUI fork specifically optimized for ClassicAPI on [Octo WoW](https://octowow.st/)**
|
**A pfUI fork specifically optimized for ClassicAPI on [Octo WoW](https://octowow.st/) which requires Nampower and SuperWoW with optional UnitXP_SP3 DLL integration.**
|
||||||
|
|
||||||
This version includes significant performance improvements and DLL-enhanced features.
|
This version includes significant performance improvements and DLL-enhanced features.
|
||||||
|
|
||||||
|
|||||||
@@ -785,7 +785,6 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("tooltip", nil, "extguild", "1")
|
pfUI:UpdateConfig("tooltip", nil, "extguild", "1")
|
||||||
pfUI:UpdateConfig("tooltip", nil, "itemid", "0")
|
pfUI:UpdateConfig("tooltip", nil, "itemid", "0")
|
||||||
pfUI:UpdateConfig("tooltip", nil, "movespeed", "0")
|
pfUI:UpdateConfig("tooltip", nil, "movespeed", "0")
|
||||||
pfUI:UpdateConfig("tooltip", nil, "aurasource", "0")
|
|
||||||
pfUI:UpdateConfig("tooltip", nil, "alpha", "0.8")
|
pfUI:UpdateConfig("tooltip", nil, "alpha", "0.8")
|
||||||
pfUI:UpdateConfig("tooltip", nil, "alwaysperc", "0")
|
pfUI:UpdateConfig("tooltip", nil, "alwaysperc", "0")
|
||||||
pfUI:UpdateConfig("tooltip", "compare", "basestats", "1")
|
pfUI:UpdateConfig("tooltip", "compare", "basestats", "1")
|
||||||
|
|||||||
@@ -1246,249 +1246,3 @@ function pfUI.api.SkinMoneyInputFrame(frame)
|
|||||||
copperIcon:ClearAllPoints()
|
copperIcon:ClearAllPoints()
|
||||||
copperIcon:SetPoint("LEFT", copper_editbox, "RIGHT", 2, 0)
|
copperIcon:SetPoint("LEFT", copper_editbox, "RIGHT", 2, 0)
|
||||||
end
|
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\<name>"
|
|
||||||
-- 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
|
|
||||||
|
|||||||
+1
-1
@@ -402,7 +402,7 @@ function pfUI.uf:UpdateConfig()
|
|||||||
if tonumber(f.config.pheight) < 0 then f.power:Hide() end
|
if tonumber(f.config.pheight) < 0 then f.power:Hide() end
|
||||||
|
|
||||||
pfUI.api.CreateBackdrop(f.power, default_border)
|
pfUI.api.CreateBackdrop(f.power, default_border)
|
||||||
f.power.bar:SetFrameLevel(f.power.backdrop:GetFrameLevel() + 1)
|
f.power.bar:SetFrameLevel(f.power:GetFrameLevel() + 1)
|
||||||
f.power.bar:SetStatusBarTexture(pfUI.media[f.config.pbartexture])
|
f.power.bar:SetStatusBarTexture(pfUI.media[f.config.pbartexture])
|
||||||
f.power.bar:SetAllPoints(f.power)
|
f.power.bar:SetAllPoints(f.power)
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -138,10 +138,16 @@ pfUI:RegisterModule("buff", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
buff:SetScript("OnLeave", GameTooltip_Hide)
|
buff:SetScript("OnLeave", function()
|
||||||
|
GameTooltip:Hide()
|
||||||
|
end)
|
||||||
|
|
||||||
buff:SetScript("OnClick", function()
|
buff:SetScript("OnClick", function()
|
||||||
if this.spellId then
|
if CancelItemTempEnchantment and this.mode and this.mode == "MAINHAND" then
|
||||||
|
CancelItemTempEnchantment(1)
|
||||||
|
elseif CancelItemTempEnchantment and this.mode and this.mode == "OFFHAND" then
|
||||||
|
CancelItemTempEnchantment(2)
|
||||||
|
elseif this.spellId then
|
||||||
C_Spell.CancelSpellByID(this.spellId)
|
C_Spell.CancelSpellByID(this.spellId)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
+243
-12
@@ -380,11 +380,207 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
namePopup:SetScript("OnDragStart", function() this:StartMoving() end)
|
namePopup:SetScript("OnDragStart", function() this:StartMoving() end)
|
||||||
namePopup:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
namePopup:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
||||||
|
|
||||||
-- Equipment seed leads the grid with gear-relevant item icons. The widget
|
namePopup.nameLabel = namePopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||||
-- owns the name field, preview, grid, filter, and search; this module keeps
|
namePopup.nameLabel:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -20)
|
||||||
-- the OK/Cancel buttons and the create/save/rename flow below.
|
namePopup.nameLabel:SetText(GEARSETS_POPUP_TEXT)
|
||||||
local iconPicker = CreateIconPicker("pfEqMgrIcon", namePopup,
|
|
||||||
IconDataProviderExtraType.Equipment, GEARSETS_POPUP_TEXT)
|
namePopup.editbox = CreateFrame("EditBox", "pfEqMgrNameEdit", namePopup, "InputBoxTemplate")
|
||||||
|
namePopup.editbox:SetSize(280, 20)
|
||||||
|
namePopup.editbox:SetPoint("TOPLEFT", namePopup, "TOPLEFT", 14, -38)
|
||||||
|
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:SetTextColor(1, 0.82, 0)
|
||||||
|
|
||||||
|
namePopup.selectedPreview = CreateFrame("Frame", nil, namePopup)
|
||||||
|
namePopup.selectedPreview:SetSize(42, 42)
|
||||||
|
namePopup.selectedPreview:SetPoint("TOPRIGHT", namePopup, "TOPRIGHT", -14, -30)
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- 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, -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)
|
||||||
|
|
||||||
|
-- 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 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
|
||||||
|
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, -80)
|
||||||
|
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.
|
||||||
|
RebuildFilter()
|
||||||
|
pfUI.equipmentmanager.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, 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
|
||||||
|
|
||||||
|
-- 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 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
|
||||||
|
-- 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", OKAY, namePopup, namePopup, 14, -340, 80)
|
local btnPopupOK = MakeButton("pfEqMgrPopupOK", OKAY, namePopup, namePopup, 14, -340, 80)
|
||||||
|
|
||||||
@@ -401,7 +597,7 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
local name = namePopup.editbox:GetText()
|
local name = namePopup.editbox:GetText()
|
||||||
if not name or name == "" then return end
|
if not name or name == "" then return end
|
||||||
-- Strip the prefix to match ClassicAPI's persisted short-form basenames.
|
-- Strip the prefix to match ClassicAPI's persisted short-form basenames.
|
||||||
local iconForSave = string.gsub(iconPicker.GetIcon(), "INTERFACE\\ICONS\\", "")
|
local iconForSave = string.gsub(selectedIconPath, "INTERFACE\\ICONS\\", "")
|
||||||
if pendingAction == "new" then
|
if pendingAction == "new" then
|
||||||
C_EquipmentSet.CreateEquipmentSet(name, iconForSave)
|
C_EquipmentSet.CreateEquipmentSet(name, iconForSave)
|
||||||
C_EquipmentSet.ClearIgnoredSlotsForSave()
|
C_EquipmentSet.ClearIgnoredSlotsForSave()
|
||||||
@@ -424,26 +620,61 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
pfUI.equipmentmanager.Refresh()
|
pfUI.equipmentmanager.Refresh()
|
||||||
end)
|
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
|
-- Assignment (not `local function`) so this fills in the forward
|
||||||
-- declaration at the top of the module — closures created earlier
|
-- declaration at the top of the module — closures created earlier
|
||||||
-- (row gear menu, "+ New Set" row, etc.) capture the same upvalue.
|
-- (row gear menu, "+ New Set" row, etc.) capture the same upvalue.
|
||||||
function OpenNamePopup(action, prefillName, prefillIcon)
|
function OpenNamePopup(action, prefillName, prefillIcon)
|
||||||
pendingAction = action
|
pendingAction = action
|
||||||
namePopup.editbox:SetText(prefillName or "")
|
namePopup.editbox:SetText(prefillName or "")
|
||||||
|
EnsureProvider()
|
||||||
if prefillIcon then
|
if prefillIcon then
|
||||||
-- Stored icons come back either as a full path or a bare basename
|
-- Stored icons come back either as a full path or a bare basename
|
||||||
-- (see the row rendering in Refresh). Only prepend the prefix when
|
-- (see the row rendering in Refresh). Only prepend the prefix when
|
||||||
-- there's no path separator, so a full path isn't double-prefixed.
|
-- there's no path separator, so a full path isn't double-prefixed.
|
||||||
iconPicker.SetIcon(string.find(prefillIcon, "\\") and prefillIcon
|
selectedIconPath = string.find(prefillIcon, "\\") and prefillIcon
|
||||||
or ("INTERFACE\\ICONS\\" .. prefillIcon))
|
or ("INTERFACE\\ICONS\\" .. prefillIcon)
|
||||||
else
|
else
|
||||||
iconPicker.SetIcon(nil)
|
selectedIconPath = QUESTION_MARK
|
||||||
end
|
end
|
||||||
namePopup.search:SetText("")
|
namePopup.search:SetText("")
|
||||||
-- Rename only changes the name, so hide the whole icon-picking area.
|
if action == "rename" then
|
||||||
iconPicker.SetIconAreaShown(action ~= "rename")
|
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
|
||||||
|
iconScroll:Show()
|
||||||
|
namePopup.iconLabel:Show()
|
||||||
|
namePopup.selectedLabel:Show()
|
||||||
|
namePopup.selectedPreview:Show()
|
||||||
|
filterDropdown:Show()
|
||||||
|
namePopup.searchLabel:Show()
|
||||||
|
namePopup.search:Show()
|
||||||
|
end
|
||||||
namePopup:Show()
|
namePopup:Show()
|
||||||
if action ~= "rename" then iconPicker.Refresh() end
|
if action ~= "rename" then pfUI.equipmentmanager.RefreshIconGrid() end
|
||||||
namePopup.editbox:SetFocus()
|
namePopup.editbox:SetFocus()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2772,7 +2772,6 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(nil, T["Always Show Health In Percent"], C.tooltip, "alwaysperc", "checkbox")
|
CreateConfig(nil, T["Always Show Health In Percent"], C.tooltip, "alwaysperc", "checkbox")
|
||||||
CreateConfig(nil, T["Show Item IDs"], C.tooltip, "itemid", "checkbox")
|
CreateConfig(nil, T["Show Item IDs"], C.tooltip, "itemid", "checkbox")
|
||||||
CreateConfig(nil, T["Show Movement Speed"], C.tooltip, "movespeed", "checkbox")
|
CreateConfig(nil, T["Show Movement Speed"], C.tooltip, "movespeed", "checkbox")
|
||||||
CreateConfig(nil, T["Show Aura Caster"], C.tooltip, "aurasource", "checkbox")
|
|
||||||
CreateConfig(nil, T["Custom Transparency"], C.tooltip, "alpha")
|
CreateConfig(nil, T["Custom Transparency"], C.tooltip, "alpha")
|
||||||
CreateConfig(nil, T["Status Bar Texture"], C.tooltip.statusbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture)
|
CreateConfig(nil, T["Status Bar Texture"], C.tooltip.statusbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture)
|
||||||
CreateConfig(nil, T["Always Show Item Comparison"], C.tooltip.compare, "showalways", "checkbox")
|
CreateConfig(nil, T["Always Show Item Comparison"], C.tooltip.compare, "showalways", "checkbox")
|
||||||
|
|||||||
+220
-11
@@ -7,15 +7,39 @@
|
|||||||
-- string -- so arbitrary icons (including index-less INV_* item icons) persist
|
-- string -- so arbitrary icons (including index-less INV_* item icons) persist
|
||||||
-- on both the modern (Turtle/Octo) and stock-vanilla macro UIs. The surrounding
|
-- on both the modern (Turtle/Octo) and stock-vanilla macro UIs. The surrounding
|
||||||
-- MacroFrame (list + body editor) is Blizzard's, already skinned elsewhere.
|
-- 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 ()
|
pfUI:RegisterModule("macroicons", function ()
|
||||||
HookAddonOrVariable("Blizzard_MacroUI", function()
|
HookAddonOrVariable("Blizzard_MacroUI", function()
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Shared picker state (forward-declared so the grid/filter closures below
|
||||||
|
-- can capture them before RefreshIconGrid is assigned).
|
||||||
|
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
|
||||||
|
-- Spellbook extra type leads with class-relevant spell/talent icons.
|
||||||
|
provider = CreateAndInitFromMixin(IconDataProviderMixin, IconDataProviderExtraType.Spellbook)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
-- Popup frame
|
-- Popup frame
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
|
|
||||||
local picker = CreateFrame("Frame", "pfMacroIconPicker", UIParent)
|
local picker = CreateFrame("Frame", "pfMacroIconPicker", UIParent)
|
||||||
picker:SetFrameStrata("DIALOG")
|
picker:SetFrameStrata("DIALOG")
|
||||||
picker:SetSize(472, 484)
|
picker:SetSize(472, 498)
|
||||||
-- Starts anchored to the right of the macro panel (re-anchored at open
|
-- 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.
|
-- once the skin's backdrop exists); dragging pins it in place after.
|
||||||
picker:SetPoint("BOTTOMLEFT", MacroFrame, "BOTTOMRIGHT", 8, 0)
|
picker:SetPoint("BOTTOMLEFT", MacroFrame, "BOTTOMRIGHT", 8, 0)
|
||||||
@@ -31,9 +55,172 @@ pfUI:RegisterModule("macroicons", function ()
|
|||||||
this.userMoved = true
|
this.userMoved = true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Spellbook seed leads the grid with class-relevant spell/talent icons.
|
picker.title = picker:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||||
local iconPicker = CreateIconPicker("pfMacroIcon", picker,
|
picker.title:SetPoint("TOP", picker, "TOP", 0, -10)
|
||||||
IconDataProviderExtraType.Spellbook, MACRO_POPUP_TEXT)
|
|
||||||
|
picker.nameLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||||
|
picker.nameLabel:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, -34)
|
||||||
|
picker.nameLabel:SetText(MACRO_POPUP_TEXT)
|
||||||
|
|
||||||
|
picker.editbox = CreateFrame("EditBox", "pfMacroIconPickerName", picker, "InputBoxTemplate")
|
||||||
|
picker.editbox:SetSize(280, 20)
|
||||||
|
picker.editbox:SetPoint("TOPLEFT", picker, "TOPLEFT", 14, -52)
|
||||||
|
picker.editbox:SetAutoFocus(false)
|
||||||
|
picker.editbox:SetMaxLetters(16)
|
||||||
|
CreateBackdrop(picker.editbox)
|
||||||
|
|
||||||
|
picker.selectedPreview = CreateFrame("Frame", nil, picker)
|
||||||
|
picker.selectedPreview:SetSize(42, 42)
|
||||||
|
picker.selectedPreview:SetPoint("TOPRIGHT", picker, "TOPRIGHT", -14, -44)
|
||||||
|
CreateBackdrop(picker.selectedPreview)
|
||||||
|
picker.selectedPreview.tex = picker.selectedPreview:CreateTexture(nil, "ARTWORK")
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- Icon grid + scroll
|
||||||
|
local iconScroll = CreateFrame("ScrollFrame", "pfMacroIconScroll", picker, "FauxScrollFrameTemplate")
|
||||||
|
iconScroll:SetPoint("TOPLEFT", picker, "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)
|
||||||
|
|
||||||
|
local scrollbar = _G["pfMacroIconScrollScrollBar"]
|
||||||
|
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", "pfMacroIconFilter", picker, "UIDropDownMenuTemplate")
|
||||||
|
filterDropdown:SetPoint("TOPRIGHT", picker, "TOPRIGHT", 0, -94)
|
||||||
|
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, picker)
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Normalize a texture to an uppercase basename so selection matching
|
||||||
|
-- works across sources: GetMacroInfo returns "Interface\Icons\<name>"
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
picker.selectedPreview.tex:SetTexture(selectedIconPath)
|
||||||
|
end
|
||||||
|
|
||||||
|
iconScroll:SetScript("OnVerticalScroll", function()
|
||||||
|
FauxScrollFrame_OnVerticalScroll(ICON_BTN_SIZE + ICON_BTN_PAD, function() RefreshIconGrid() end)
|
||||||
|
end)
|
||||||
|
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
-- Open / save
|
-- Open / save
|
||||||
@@ -54,11 +241,13 @@ pfUI:RegisterModule("macroicons", function ()
|
|||||||
picker.mode = "edit"
|
picker.mode = "edit"
|
||||||
local name, texture = GetMacroInfo(MacroFrame.selectedMacro)
|
local name, texture = GetMacroInfo(MacroFrame.selectedMacro)
|
||||||
picker.editbox:SetText(name or "")
|
picker.editbox:SetText(name or "")
|
||||||
iconPicker.SetIcon(texture)
|
selectedIconPath = texture or QUESTION_MARK
|
||||||
|
picker.title:SetText(T["Edit Macro"] or "Edit Macro")
|
||||||
else
|
else
|
||||||
picker.mode = "new"
|
picker.mode = "new"
|
||||||
picker.editbox:SetText("")
|
picker.editbox:SetText("")
|
||||||
iconPicker.SetIcon(nil)
|
selectedIconPath = QUESTION_MARK
|
||||||
|
picker.title:SetText(T["New Macro"] or "New Macro")
|
||||||
end
|
end
|
||||||
picker.search:SetText("")
|
picker.search:SetText("")
|
||||||
if not picker.userMoved then
|
if not picker.userMoved then
|
||||||
@@ -68,25 +257,27 @@ pfUI:RegisterModule("macroicons", function ()
|
|||||||
SetMacroButtons(false)
|
SetMacroButtons(false)
|
||||||
picker:Show()
|
picker:Show()
|
||||||
picker.editbox:SetFocus()
|
picker.editbox:SetFocus()
|
||||||
iconPicker.Refresh()
|
RefreshIconGrid()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SaveMacroPopup()
|
local function SaveMacroPopup()
|
||||||
local text = strtrim(picker.editbox:GetText())
|
local text = strtrim(picker.editbox:GetText())
|
||||||
if text == "" then return end
|
if text == "" then return end
|
||||||
|
|
||||||
local icon = iconPicker.GetIcon()
|
|
||||||
if picker.mode == "edit" and MacroFrame.selectedMacro then
|
if picker.mode == "edit" and MacroFrame.selectedMacro then
|
||||||
C_Macro.EditMacro(MacroFrame.selectedMacro, text, icon, nil)
|
C_Macro.EditMacro(MacroFrame.selectedMacro, text, selectedIconPath, nil)
|
||||||
MacroFrame_SelectMacro(MacroFrame.selectedMacro)
|
MacroFrame_SelectMacro(MacroFrame.selectedMacro)
|
||||||
else
|
else
|
||||||
local idx = C_Macro.CreateMacro(text, icon, nil, (MacroFrame.macroBase or 0) > 0)
|
local idx = C_Macro.CreateMacro(text, selectedIconPath, nil, (MacroFrame.macroBase or 0) > 0)
|
||||||
if idx then MacroFrame_SelectMacro(idx) end
|
if idx then MacroFrame_SelectMacro(idx) end
|
||||||
end
|
end
|
||||||
picker:Hide()
|
picker:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
picker:SetScript("OnHide", function() MacroFrame_Update() end)
|
picker:SetScript("OnHide", function()
|
||||||
|
if provider then provider:Release(); provider = nil end
|
||||||
|
MacroFrame_Update()
|
||||||
|
end)
|
||||||
|
|
||||||
picker.editbox:SetScript("OnEnterPressed", SaveMacroPopup)
|
picker.editbox:SetScript("OnEnterPressed", SaveMacroPopup)
|
||||||
picker.editbox:SetScript("OnEscapePressed", function() picker:Hide() end)
|
picker.editbox:SetScript("OnEscapePressed", function() picker:Hide() end)
|
||||||
@@ -108,6 +299,24 @@ pfUI:RegisterModule("macroicons", function ()
|
|||||||
-- Okay | Cancel, both anchored to the bottom-right corner.
|
-- Okay | Cancel, both anchored to the bottom-right corner.
|
||||||
okay:SetPoint("BOTTOMRIGHT", cancel, "BOTTOMLEFT", -6, 0)
|
okay:SetPoint("BOTTOMRIGHT", cancel, "BOTTOMLEFT", -6, 0)
|
||||||
|
|
||||||
|
-- Search box (bottom-left) filters the grid by icon name.
|
||||||
|
picker.searchLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||||
|
picker.searchLabel:SetPoint("BOTTOMLEFT", picker, "BOTTOMLEFT", 16, 18)
|
||||||
|
picker.searchLabel:SetText(SEARCH)
|
||||||
|
|
||||||
|
picker.search = CreateFrame("EditBox", "pfMacroIconSearch", picker, "InputBoxTemplate")
|
||||||
|
picker.search:SetSize(180, 20)
|
||||||
|
picker.search:SetPoint("LEFT", picker.searchLabel, "RIGHT", 10, 0)
|
||||||
|
picker.search:SetAutoFocus(false)
|
||||||
|
CreateBackdrop(picker.search)
|
||||||
|
picker.search:SetScript("OnEscapePressed", function() this:ClearFocus() end)
|
||||||
|
picker.search:SetScript("OnTextChanged", function()
|
||||||
|
searchText = strupper(strtrim(this:GetText()))
|
||||||
|
RebuildFilter()
|
||||||
|
scrollbar:SetValue(0)
|
||||||
|
RefreshIconGrid()
|
||||||
|
end)
|
||||||
|
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
-- Take over the New / Change-Icon buttons; retire Blizzard's popup
|
-- Take over the New / Change-Icon buttons; retire Blizzard's popup
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
|
|||||||
@@ -266,18 +266,4 @@ pfUI:RegisterModule("tooltip", function ()
|
|||||||
end
|
end
|
||||||
GameTooltip:Show()
|
GameTooltip:Show()
|
||||||
end
|
end
|
||||||
|
|
||||||
if C.tooltip.aurasource == "1" then
|
|
||||||
hooksecurefunc(GameTooltip, "SetUnitAura", function(self, ...)
|
|
||||||
local aura = C_UnitAuras.GetAuraDataByIndex(unpack(arg))
|
|
||||||
if not aura then return end
|
|
||||||
local caster = aura.sourceUnit and UnitName(aura.sourceUnit)
|
|
||||||
if not caster and aura.sourceGUID then
|
|
||||||
caster = UnitNameFromGUID(aura.sourceGUID)
|
|
||||||
end
|
|
||||||
if not caster or caster == "" then return end
|
|
||||||
self:AddLine(T["Cast by"] .. ": " .. caster, .7, .7, 1)
|
|
||||||
self:Show()
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ pfUI:RegisterModule("turtle-wow", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if C.disabled["macroicons"] == "1" then
|
if C.disabled["macroicons"] == "1" or not C_Macro or not C_Macro.CreateMacro then
|
||||||
HookAddonOrVariable("Blizzard_MacroUI", function()
|
HookAddonOrVariable("Blizzard_MacroUI", function()
|
||||||
if type(UpdateMacroIconFilenames) ~= "function" then return end
|
if type(UpdateMacroIconFilenames) ~= "function" then return end
|
||||||
function _G.UpdateMacroIconFilenames()
|
function _G.UpdateMacroIconFilenames()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ do
|
|||||||
-- ClassicAPI dependency check.
|
-- ClassicAPI dependency check.
|
||||||
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
||||||
-- API surface that ClassicAPI polyfills, so presence is required.
|
-- API surface that ClassicAPI polyfills, so presence is required.
|
||||||
local PFUI_CLASSIC_API_MIN = 10903 -- (X*10000 + Y*100 + Z)
|
local PFUI_CLASSIC_API_MIN = 10900 -- (X*10000 + Y*100 + Z)
|
||||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||||
|
|||||||
Reference in New Issue
Block a user