Show pfUI's dropdowns and menus with ClassicAPI's menu system

pfUIDropdownTemplate (a DropdownButton) replaces CreateDropDownButton in
the config GUI, addon profiles, the trigger editor and the icon picker
filter. The equipment set gear menu and the tracking menu open
MenuUtil context menus. pfUIMenuStyleMixin draws pfUI's backdrop behind
them, and the skin module makes it the default style and draws the
checkboxes and radios as pfUI boxes.
This commit is contained in:
Brues
2026-10-30 19:33:40 -05:00
parent f37ea00226
commit af9edb215d
7 changed files with 292 additions and 444 deletions
+51 -226
View File
@@ -100,219 +100,53 @@ do -- statusbars
end end
end end
do -- dropdown -- [ pfUIMenuStyleMixin ]
local function ListEntryOnShow() -- Style for ClassicAPI's menus: pfUI's backdrop behind the entries. A dropdown
this.icon:SetShown(this.parent.id == this.id) -- takes it as its menuMixin, and a context menu takes it from the menuMixin
-- field of its owner.
_G.pfUIMenuStyleMixin = CreateFromMixins(MenuStyleMixin)
-- Menus share pooled frames that clear their backdrop on release, so the
-- backdrop goes on the frame itself.
function pfUIMenuStyleMixin:Generate()
CreateBackdrop(self, nil, true)
end
do
local inset = { left = 4, top = 4, right = 4, bottom = 4 }
function pfUIMenuStyleMixin:GetInset()
return inset
end end
local function ListEntryOnClick() -- room for a submenu arrow or a color swatch, as in the stock styles
this.parent:SetSelection(this.id) local padding = { width = 10, height = 0 }
function pfUIMenuStyleMixin:GetChildExtentPadding()
if this.parent.mode == "MULTISELECT" then return padding
this.parent:ShowMenu()
else
this.parent:HideMenu()
end
if this.parent.menu[this.id].func then
this.parent.menu[this.id].func()
end
end end
end
local function ListEntryOnEnter() -- [ pfUIDropdownTemplate ]
this.hover:Show() -- Mixin of the template in ui-widgets.xml: a dropdown that shows its selection
end -- as text, with pfUI's arrow box at the right.
_G.pfUIDropdownMixin = CreateFromMixins(ButtonStateBehaviorMixin, DropdownSelectionTextMixin)
local function ListEntryOnLeave() function pfUIDropdownMixin:OnLoad()
this.hover:Hide() self.Text:SetFont(pfUI.font_default, pfUI_config.global.font_size - 1, "OUTLINE")
end CreateBackdrop(self.Arrow, nil, true)
self.Arrow.Icon:SetTexture(pfUI.media["img:down"])
self.Arrow.Icon:SetVertexColor(.8, .8, .8)
self.Arrow.Icon:SetAlpha(.8)
local function ListButtonOnClick() ButtonStateBehaviorMixin.OnLoad(self)
if this.ToggleMenu then DropdownSelectionTextMixin.OnLoad(self)
this:ToggleMenu() end
else
this:GetParent():ToggleMenu()
end
end
local function MenuOnUpdate() -- the arrow box takes the class color while the cursor is over the dropdown
if not this:IsMouseOver(100, -100, -100, 100) then function pfUIDropdownMixin:OnButtonStateChanged()
this.button:HideMenu() if self:IsOver() then
end self.Arrow:SetBackdropBorderColor(PFUI_CLASS_COLORS[UnitClassBase("player")]:GetRGB())
end else
self.Arrow:SetBackdropBorderColor(GetStringColor(pfUI_config.appearance.border.color))
local function ListButtonOnEnter()
this.button:SetBackdropBorderColor(this.button.cr,this.button.cg,this.button.cb,(this.button.ca or 1))
end
local function ListButtonOnLeave()
this.button:SetBackdropBorderColor(this.button.rr,this.button.rg,this.button.rb,(this.button.ra or 1))
end
local handlers = {
["SetSelection"] = function(self, id)
if id and self.menu and self.menu[id] then
self.text:SetText(self.menu[id].text)
self.id = id
end
end,
["SetSelectionByText"] = function(self, name)
self:UpdateMenu()
for id, entry in pairs(self.menu) do
if entry.text == name then
self:SetSelection(id)
return true
end
end
self.text:SetText(name)
return nil
end,
["GetSelection"] = function(self)
self:UpdateMenu()
if self.menu and self.menu[self.id] then
return self.id, self.menu[self.id].text, self.menu[self.id].func
end
end,
["SetMenu"] = function(self, menu)
if type(menu) == "function" then
self.menu = menu()
self.menufunc = menu
else
self.menu = menu
self.menufunc = nil
end
end,
["GetMenu"] = function(self)
self:UpdateMenu()
return self.menu
end,
["ShowMenu"] = function(self)
self:UpdateMenu()
self.menuframe:SetFrameLevel(self:GetFrameLevel() + 8)
self.menuframe:SetHeight(table.getn(self.menu)*20+4)
self.menuframe:Show()
end,
["HideMenu"] = function(self)
self.menuframe:Hide()
end,
["ToggleMenu"] = function(self)
if self.menuframe:IsShown() then
self:HideMenu()
else
self:ShowMenu()
end
end,
["UpdateMenu"] = function(self)
-- run/reload menu function if available
if self.menufunc then self.menu = self.menufunc() end
if not self.menu then return end
-- set caption to the current value
self.text:SetText(self.menu[self.id] and self.menu[self.id].text or "")
-- refresh menu buttons
for id, element in pairs(self.menuframe.elements) do
element:Hide()
end
for id, data in pairs(self.menu) do
self:CreateMenuEntry(id)
end
end,
["CreateMenuEntry"] = function(self, id)
if not self.menu[id] then return end
local frame, entry
for count, existing in pairs(self.menuframe.elements) do
if not existing:IsShown() then
frame = existing
entry = count
break
end
end
if not frame and not entry then
entry = table.getn(self.menuframe.elements) + 1
frame = CreateFrame("Button", nil, self.menuframe)
frame:SetFrameStrata("FULLSCREEN")
frame:ClearAllPoints()
frame:SetPoint("TOPLEFT", self.menuframe, "TOPLEFT", 2, -(entry-1)*20-2)
frame:SetPoint("TOPRIGHT", self.menuframe, "TOPRIGHT", -2, -(entry-1)*20-2)
frame:SetHeight(20)
frame.parent = self
frame.icon = frame:CreateTexture(nil, "OVERLAY")
frame.icon:SetPoint("RIGHT", frame, "RIGHT", -2, 0)
frame.icon:SetSize(16, 16)
frame.icon:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
frame.text = frame:CreateFontString(nil, "OVERLAY")
frame.text:SetFontObject(GameFontWhite)
frame.text:SetFont(pfUI.font_default, pfUI_config.global.font_size-1, "OUTLINE")
frame.text:SetJustifyH("RIGHT")
frame.text:SetPoint("LEFT", frame, "LEFT", 2, 0)
frame.text:SetPoint("RIGHT", frame.icon, "LEFT", -2, 0)
frame.hover = frame:CreateTexture(nil, "BACKGROUND")
frame.hover:SetAllPoints(frame)
frame.hover:SetTexture(.4,.4,.4,.4)
frame.hover:Hide()
table.insert(self.menuframe.elements, frame)
end
frame.id = id
frame.text:SetText(self.menu[id].text)
frame:SetScript("OnShow", ListEntryOnShow)
frame:SetScript("OnClick", ListEntryOnClick)
frame:SetScript("OnEnter", ListEntryOnEnter)
frame:SetScript("OnLeave", ListEntryOnLeave)
frame:Show()
end,
}
function pfUI.api.CreateDropDownButton(name, parent)
local frame = CreateFrame("Button", name, parent)
frame:SetScript("OnEnter", ListButtonOnEnter)
frame:SetScript("OnLeave", ListButtonOnLeave)
frame:SetScript("OnClick", ListButtonOnClick)
frame:SetHeight(20)
frame.id = nil
CreateBackdrop(frame, nil, true)
local button = CreateFrame("Button", nil, frame)
button:SetPoint("RIGHT", frame, "RIGHT", -2, 0)
button:SetSize(16, 16)
button:SetScript("OnClick", ListButtonOnClick)
SkinArrowButton(button, "down")
button.icon:SetVertexColor(1,.9,.1)
local text = frame:CreateFontString(nil, "OVERLAY")
text:SetFontObject(GameFontWhite)
text:SetFont(pfUI.font_default, pfUI_config.global.font_size-1, "OUTLINE")
text:SetPoint("RIGHT", button, "LEFT", -4, 0)
text:SetJustifyH("RIGHT")
local menuframe = CreateFrame("Frame", tostring(frame).."menu", parent)
menuframe.button = frame
menuframe.elements = {}
menuframe:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 0, -2)
menuframe:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 2)
menuframe:SetScript("OnUpdate", MenuOnUpdate)
menuframe:Hide()
CreateBackdrop(menuframe, nil, true)
for name, func in pairs(handlers) do
frame[name] = func
end
frame.menuframe = menuframe
frame.button = button
frame.text = text
return frame
end end
end end
@@ -1149,11 +983,11 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
grid:SetSize(gridWidth + 4 + 7 + 10, gridHeight + 10) grid:SetSize(gridWidth + 4 + 7 + 10, gridHeight + 10)
-- Filter dropdown: All / Spells / Items -- Filter dropdown: All / Spells / Items
local filterDropdown = CreateFrame("Frame", name.."Filter", parent, "UIDropDownMenuTemplate") local function IsFilter(value)
filterDropdown:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, -80) return currentFilter == value
end
local function ApplyFilter(value) local function ApplyFilter(value)
currentFilter = value currentFilter = value
UIDropDownMenu_SetSelectedValue(filterDropdown, value)
if provider then if provider then
if value == "spells" then provider:SetIconTypes({ IconDataProviderIconType.Spell }) if value == "spells" then provider:SetIconTypes({ IconDataProviderIconType.Spell })
elseif value == "items" then provider:SetIconTypes({ IconDataProviderIconType.Item }) elseif value == "items" then provider:SetIconTypes({ IconDataProviderIconType.Item })
@@ -1162,24 +996,15 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
RefreshIconGrid() RefreshIconGrid()
end end
end end
UIDropDownMenu_Initialize(filterDropdown, function() local filterDropdown = CreateFrame("DropdownButton", nil, parent, "pfUIDropdownTemplate")
local info filterDropdown:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -14, -84)
info = {}; info.text = ICON_FILTER_ALL; info.value = "all" filterDropdown:SetWidth(140)
info.func = function() ApplyFilter("all") end CreateBackdrop(filterDropdown, nil, true)
info.checked = currentFilter == "all" filterDropdown:SetupMenu(function(dropdown, rootDescription)
UIDropDownMenu_AddButton(info) rootDescription:CreateRadio(ICON_FILTER_ALL, IsFilter, ApplyFilter, "all")
info = {}; info.text = ICON_FILTER_SPELL; info.value = "spells" rootDescription:CreateRadio(ICON_FILTER_SPELL, IsFilter, ApplyFilter, "spells")
info.func = function() ApplyFilter("spells") end rootDescription:CreateRadio(ICON_FILTER_ITEM, IsFilter, ApplyFilter, "items")
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) end)
UIDropDownMenu_SetWidth(120, filterDropdown)
UIDropDownMenu_SetSelectedValue(filterDropdown, "all")
SkinDropDown(filterDropdown)
-- the selected icon gets a gold border in the grid and shows in the preview -- the selected icon gets a gold border in the grid and shows in the preview
local function UpdateSelection() local function UpdateSelection()
+48
View File
@@ -102,4 +102,52 @@
<OnLoad method="InitScrollBar" inherit="prepend"/> <OnLoad method="InitScrollBar" inherit="prepend"/>
</Scripts> </Scripts>
</Frame> </Frame>
<!--
A ClassicAPI dropdown in pfUI's style: the selection as right-aligned text
and pfUI's arrow box at the right. Its menu takes pfUIMenuStyleMixin. Fill it
with dropdown:SetupMenu(function(dropdown, rootDescription) ... end), and call
dropdown:GenerateMenu() when the data behind the selection changes.
-->
<DropdownButton name="pfUIDropdownTemplate" mixin="pfUIDropdownMixin" virtual="true">
<Size y="20"/>
<KeyValues>
<KeyValue key="menuMixin" value="pfUIMenuStyleMixin" type="global"/>
<KeyValue key="menuPointY" value="-2" type="number"/>
</KeyValues>
<Frames>
<Frame parentKey="Arrow">
<Size x="16" y="16"/>
<Anchors>
<Anchor point="RIGHT" x="-2"/>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture parentKey="Icon">
<Anchors>
<Anchor point="TOPLEFT" x="3" y="-3"/>
<Anchor point="BOTTOMRIGHT" x="-3" y="3"/>
</Anchors>
</Texture>
</Layer>
</Layers>
</Frame>
</Frames>
<Layers>
<Layer level="OVERLAY">
<FontString parentKey="Text" inherits="GameFontWhite" wordwrap="false" justifyH="RIGHT">
<Anchors>
<Anchor point="LEFT" x="2"/>
<Anchor point="RIGHT" relativeKey="$parent.Arrow" relativePoint="LEFT" x="-4"/>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad method="OnLoad"/>
<OnShow method="OnShow"/>
<OnEnter method="OnEnter"/>
<OnLeave method="OnLeave"/>
</Scripts>
</DropdownButton>
</Ui> </Ui>
+14 -22
View File
@@ -110,6 +110,12 @@ pfUI:RegisterModule("addons", function ()
return selected_addons return selected_addons
end end
local selectedProfile
local function IsSelectedProfile(profile)
return profile == selectedProfile
end
local function SetAddonProfile(profile) local function SetAddonProfile(profile)
-- create new profile if not existing -- create new profile if not existing
if not pfUI_addon_profiles[profile] then if not pfUI_addon_profiles[profile] then
@@ -117,7 +123,8 @@ pfUI:RegisterModule("addons", function ()
end end
-- set dropdown to profile -- set dropdown to profile
pfUI.addons.profile.dropdown:SetSelectionByText(profile) selectedProfile = profile
pfUI.addons.profile.dropdown:GenerateMenu()
-- load profile -- load profile
local selected = {} local selected = {}
@@ -163,7 +170,7 @@ pfUI:RegisterModule("addons", function ()
pfUI.addons.profile.del:SetText("-") pfUI.addons.profile.del:SetText("-")
pfUI.addons.profile.del:SetTextColor(1,.5,.5,1) pfUI.addons.profile.del:SetTextColor(1,.5,.5,1)
pfUI.addons.profile.del:SetScript("OnClick", function() -- TODO pfUI.addons.profile.del:SetScript("OnClick", function() -- TODO
local id, name = pfUI.addons.profile.dropdown:GetSelection() local name = selectedProfile
if not name then return end if not name then return end
CreateQuestionDialog(T["Delete profile"] .. " '|cff33ffcc" .. name .. "|r'?", function() CreateQuestionDialog(T["Delete profile"] .. " '|cff33ffcc" .. name .. "|r'?", function()
pfUI_addon_profiles[name] = nil pfUI_addon_profiles[name] = nil
@@ -193,26 +200,13 @@ pfUI:RegisterModule("addons", function ()
end) end)
-- addon profile: dropdown -- addon profile: dropdown
pfUI.addons.profile.dropdown = CreateDropDownButton("pfAddonListProfileList", pfUI.addons.profile) pfUI.addons.profile.dropdown = CreateFrame("DropdownButton", nil, pfUI.addons.profile, "pfUIDropdownTemplate")
pfUI.addons.profile.dropdown:SetBackdrop(nil)
pfUI.addons.profile.dropdown:ClearAllPoints()
pfUI.addons.profile.dropdown:SetPoint("RIGHT", pfUI.addons.profile.add, "LEFT", -2, 0) pfUI.addons.profile.dropdown:SetPoint("RIGHT", pfUI.addons.profile.add, "LEFT", -2, 0)
pfUI.addons.profile.dropdown:SetWidth(220) pfUI.addons.profile.dropdown:SetWidth(220)
pfUI.addons.profile.dropdown:SetMenu(function() pfUI.addons.profile.dropdown:SetupMenu(function(dropdown, rootDescription)
local menu = {} for name in pairs(pfUI_addon_profiles) do
rootDescription:CreateRadio(name, IsSelectedProfile, SetAddonProfile, name)
for name, list in pairs(pfUI_addon_profiles) do
local name = name
local entry = {}
entry.text = name
entry.checked = false
entry.func = function()
SetAddonProfile(name)
end
table.insert(menu, entry)
end end
return menu
end) end)
local function AddDependencyLines(header, deps) local function AddDependencyLines(header, deps)
@@ -263,9 +257,7 @@ pfUI:RegisterModule("addons", function ()
local function InputOnClick(self) local function InputOnClick(self)
SetAddonEnabled(self:GetParent().addon.index, self:GetChecked()) SetAddonEnabled(self:GetParent().addon.index, self:GetChecked())
local _, name = pfUI.addons.profile.dropdown:GetSelection() pfUI_addon_profiles[selectedProfile or T["Current"]] = GetSelectedAddonsList()
name = name or T["Current"]
pfUI_addon_profiles[name] = GetSelectedAddonsList()
end end
local function InitRow(row, addon) local function InitRow(row, addon)
+63 -125
View File
@@ -204,66 +204,37 @@ pfUI:RegisterModule("equipmentmanager", function()
end) end)
-- ============================================================ -- ============================================================
-- Per-row context menu (single instance, repositioned per click). -- Per-row context menu, opened from the gear icon on each set row.
-- Triggered by the gear icon on each set row.
-- ============================================================ -- ============================================================
local rowMenu = CreateFrame("Frame", "pfEqMgrRowMenu", UIParent) local function EditSet(setID)
rowMenu:SetFrameStrata("DIALOG") local name, icon = C_EquipmentSet.GetEquipmentSetInfo(setID)
rowMenu:SetSize(140, 50); selectedSetID = setID
rowMenu:Hide()
CreateBackdrop(rowMenu, nil, nil, .95)
CreateBackdropShadow(rowMenu)
rowMenu:EnableMouse(true)
-- Close on click outside via GLOBAL_MOUSE_DOWN (fires on any click
-- without consuming it). The anchorBtn check defers the gear-click
-- toggle to the gear's own OnClick so opening doesn't trigger close.
rowMenu:RegisterEvent("GLOBAL_MOUSE_DOWN")
rowMenu:SetScript("OnEvent", function()
if not this:IsShown() then return end
if MouseIsOverHitRect(this) then return end
if this.anchorBtn and MouseIsOverHitRect(this.anchorBtn) then return end
this:Hide()
end)
tinsert(UISpecialFrames, "pfEqMgrRowMenu") -- Escape closes it
rowMenu.changeBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate")
rowMenu.changeBtn:SetSize(130, 20);
rowMenu.changeBtn:SetPoint("TOPLEFT", rowMenu, "TOPLEFT", 5, -3)
rowMenu.changeBtn:SetText(EQUIPMENT_SET_EDIT)
SkinButton(rowMenu.changeBtn)
rowMenu.changeBtn:SetScript("OnClick", function()
rowMenu:Hide()
if not rowMenu.targetSetID then return end
local name, icon = C_EquipmentSet.GetEquipmentSetInfo(rowMenu.targetSetID)
selectedSetID = rowMenu.targetSetID
OpenNamePopup("save", name, icon) OpenNamePopup("save", name, icon)
end) end
rowMenu.deleteBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate") local function DeleteSet(setID)
rowMenu.deleteBtn:SetSize(130, 20); local name = C_EquipmentSet.GetEquipmentSetInfo(setID)
rowMenu.deleteBtn:SetPoint("TOP", rowMenu.changeBtn, "BOTTOM", 0, -2)
rowMenu.deleteBtn:SetText(DELETE)
SkinButton(rowMenu.deleteBtn)
rowMenu.deleteBtn:SetScript("OnClick", function()
rowMenu:Hide()
if not rowMenu.targetSetID then return end
local targetID = rowMenu.targetSetID
local name = C_EquipmentSet.GetEquipmentSetInfo(targetID)
StaticPopupDialogs["PFUI_EQMGR_DELETE"] = { StaticPopupDialogs["PFUI_EQMGR_DELETE"] = {
text = string.format(CONFIRM_DELETE_EQUIPMENT_SET, name or "?"), text = string.format(CONFIRM_DELETE_EQUIPMENT_SET, name or "?"),
button1 = YES, button2 = NO, button1 = YES, button2 = NO,
OnAccept = function() OnAccept = function()
pendingIgnoredToggles[targetID] = nil pendingIgnoredToggles[setID] = nil
C_EquipmentSet.DeleteEquipmentSet(targetID) C_EquipmentSet.DeleteEquipmentSet(setID)
if selectedSetID == targetID then selectedSetID = nil end if selectedSetID == setID then selectedSetID = nil end
pfUI.equipmentmanager.Refresh() pfUI.equipmentmanager.Refresh()
end, end,
timeout = 0, whileDead = 1, hideOnEscape = 1, exclusive = 1, timeout = 0, whileDead = 1, hideOnEscape = 1, exclusive = 1,
} }
StaticPopup_Show("PFUI_EQMGR_DELETE") StaticPopup_Show("PFUI_EQMGR_DELETE")
end) end
-- The row owns the menu, not the gear: the gear hides when the cursor
-- leaves the row for the menu, and a menu closes with its owner.
local function GenerateSetMenu(row, rootDescription)
rootDescription:CreateButton(EQUIPMENT_SET_EDIT, EditSet, row.setID)
rootDescription:CreateButton(DELETE, DeleteSet, row.setID)
end
-- ============================================================ -- ============================================================
-- Set list (left column) -- Set list (left column)
@@ -303,20 +274,9 @@ pfUI:RegisterModule("equipmentmanager", function()
-- moving onto the gear does not leave the row -- moving onto the gear does not leave the row
row.gear:SetPropagateMouseMotion(true) row.gear:SetPropagateMouseMotion(true)
row.gear:Hide() row.gear:Hide()
row.menuMixin = pfUIMenuStyleMixin
row.gear:SetScript("OnClick", function() row.gear:SetScript("OnClick", function()
if not row.setID then return end if row.setID then MenuUtil.CreateContextMenu(row, GenerateSetMenu) end
-- Toggle: clicking the gear that owns the open menu closes it.
-- GLOBAL_MOUSE_DOWN's anchorBtn check excludes the gear, so the
-- close has to happen here.
if rowMenu:IsShown() and rowMenu.targetSetID == row.setID then
rowMenu:Hide()
return
end
rowMenu.targetSetID = row.setID
rowMenu.anchorBtn = row.gear
rowMenu:ClearAllPoints()
rowMenu:SetPoint("TOPRIGHT", row.gear, "BOTTOMRIGHT", 0, 0)
rowMenu:Show()
end) end)
row:SetScript("OnClick", function() row:SetScript("OnClick", function()
@@ -904,19 +864,6 @@ pfUI:RegisterModule("equipmentmanager", function()
return b return b
end end
-- Dropdown entries carry a `.value`; select one by value instead of index.
local function SelectDropdownValue(dd, value)
local menu = dd:GetMenu()
for i, entry in ipairs(menu or {}) do
if entry.value == value then
dd:SetSelection(i)
return
end
end
dd.id = nil
dd.text:SetText("")
end
local function Print(msg) local function Print(msg)
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpf|cffffffffUI|r: " .. msg) DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpf|cffffffffUI|r: " .. msg)
end end
@@ -1783,9 +1730,10 @@ pfUI:RegisterModule("equipmentmanager", function()
end end
local function EditorDropdown(row) local function EditorDropdown(row)
local dd = CreateDropDownButton(nil, editor) local dd = CreateFrame("DropdownButton", nil, editor, "pfUIDropdownTemplate")
dd:SetWidth(190) dd:SetWidth(190)
dd:SetPoint("TOPRIGHT", editor, "TOPRIGHT", 0, EDITOR_ROW_Y[row]) dd:SetPoint("TOPRIGHT", editor, "TOPRIGHT", 0, EDITOR_ROW_Y[row])
CreateBackdrop(dd, nil, true)
return dd return dd
end end
@@ -1801,41 +1749,49 @@ pfUI:RegisterModule("equipmentmanager", function()
RefreshTriggerPanel() RefreshTriggerPanel()
end end
-- The radio callbacks for one field of the selected trigger; a trigger
-- without the field reads as `default`.
local function TriggerField(field, default)
local function IsSelected(value)
local t = SelectedTrigger()
return t ~= nil and (t[field] or default) == value
end
local function SetSelected(value)
local t = SelectedTrigger()
if not t then return end
t[field] = value
OnTriggerEdited()
end
return IsSelected, SetSelected
end
EditorLabel(T["When"], 1) EditorLabel(T["When"], 1)
local ddType = EditorDropdown(1) local ddType = EditorDropdown(1)
ddType:SetMenu(function() local IsType = TriggerField("type")
local menu = {} local function SetType(key)
local t = SelectedTrigger()
if not t or t.type == key then return end
t.type = key
t.value = DefaultTriggerValue(key)
OnTriggerEdited()
end
ddType:SetupMenu(function(dropdown, rootDescription)
for _, info in ipairs(TRIGGER_TYPES) do for _, info in ipairs(TRIGGER_TYPES) do
if info.value ~= "list" or info.options then if info.value ~= "list" or info.options then
local key = info.key rootDescription:CreateRadio(info.text, IsType, SetType, info.key)
table.insert(menu, { text = info.text, value = key, func = function()
local t = SelectedTrigger()
if not t or t.type == key then return end
t.type = key
t.value = DefaultTriggerValue(key)
OnTriggerEdited()
end })
end end
end end
return menu
end) end)
local valueLabel = EditorLabel(T["Value"], 2) local valueLabel = EditorLabel(T["Value"], 2)
local ddValue = EditorDropdown(2) local ddValue = EditorDropdown(2)
ddValue:SetMenu(function() local IsValue, SetValue = TriggerField("value")
local menu = {} ddValue:SetupMenu(function(dropdown, rootDescription)
local t = SelectedTrigger() local t = SelectedTrigger()
local info = t and TRIGGER_TYPE[t.type] local info = t and TRIGGER_TYPE[t.type]
for _, o in ipairs(info and info.options or {}) do for _, o in ipairs(info and info.options or {}) do
local value = o.value rootDescription:CreateRadio(o.text, IsValue, SetValue, o.value)
table.insert(menu, { text = o.text, value = value, func = function()
local t = SelectedTrigger()
if not t then return end
t.value = value
OnTriggerEdited()
end })
end end
return menu
end) end)
local editValue = CreateTextBox(nil, editor) local editValue = CreateTextBox(nil, editor)
@@ -1907,39 +1863,22 @@ pfUI:RegisterModule("equipmentmanager", function()
EditorLabel(T["Equip"], 3) EditorLabel(T["Equip"], 3)
local ddSet = EditorDropdown(3) local ddSet = EditorDropdown(3)
ddSet:SetMenu(function() local IsSet, SetSet = TriggerField("setID")
local menu = {} ddSet:SetupMenu(function(dropdown, rootDescription)
for _, id in ipairs(GetVisibleSetIDs()) do for _, id in ipairs(GetVisibleSetIDs()) do
local setID = id rootDescription:CreateRadio(SetName(id), IsSet, SetSet, id)
table.insert(menu, { text = SetName(setID), value = setID, func = function()
local t = SelectedTrigger()
if not t then return end
t.setID = setID
OnTriggerEdited()
end })
end end
return menu
end) end)
EditorLabel(T["When It Ends"], 4) EditorLabel(T["When It Ends"], 4)
local ddLeave = EditorDropdown(4) local ddLeave = EditorDropdown(4)
ddLeave:SetMenu(function() local IsLeave, SetLeave = TriggerField("leave", "restore")
local function Choose(value) ddLeave:SetupMenu(function(dropdown, rootDescription)
return function() rootDescription:CreateRadio(T["Restore Previous Gear"], IsLeave, SetLeave, "restore")
local t = SelectedTrigger() rootDescription:CreateRadio(T["Do Nothing"], IsLeave, SetLeave, "none")
if not t then return end
t.leave = value
OnTriggerEdited()
end
end
local menu = {
{ text = T["Restore Previous Gear"], value = "restore", func = Choose("restore") },
{ text = T["Do Nothing"], value = "none", func = Choose("none") },
}
for _, id in ipairs(GetVisibleSetIDs()) do for _, id in ipairs(GetVisibleSetIDs()) do
table.insert(menu, { text = T["Equip"] .. " " .. SetName(id), value = id, func = Choose(id) }) rootDescription:CreateRadio(T["Equip"] .. " " .. SetName(id), IsLeave, SetLeave, id)
end end
return menu
end) end)
editor.noSets = editor:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall") editor.noSets = editor:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
@@ -1984,7 +1923,7 @@ pfUI:RegisterModule("equipmentmanager", function()
editor:Show() editor:Show()
editor.placeholder:Hide() editor.placeholder:Hide()
SelectDropdownValue(ddType, t.type) ddType:GenerateMenu()
local info = TRIGGER_TYPE[t.type] local info = TRIGGER_TYPE[t.type]
local kind = info and info.value local kind = info and info.value
@@ -1993,7 +1932,7 @@ pfUI:RegisterModule("equipmentmanager", function()
editValue:SetShown(kind == "text") editValue:SetShown(kind == "text")
btnCurrentZone:SetShown(t.type == "zone") btnCurrentZone:SetShown(t.type == "zone")
if kind == "list" then if kind == "list" then
SelectDropdownValue(ddValue, t.value) ddValue:GenerateMenu()
elseif kind == "text" then elseif kind == "text" then
editValue:ClearAllPoints() editValue:ClearAllPoints()
editValue:SetPoint("TOPLEFT", editor, "TOPRIGHT", -190, EDITOR_ROW_Y[2]) editValue:SetPoint("TOPLEFT", editor, "TOPRIGHT", -190, EDITOR_ROW_Y[2])
@@ -2014,8 +1953,8 @@ pfUI:RegisterModule("equipmentmanager", function()
local hasSets = table.getn(GetVisibleSetIDs()) > 0 local hasSets = table.getn(GetVisibleSetIDs()) > 0
ddSet:SetShown(hasSets) ddSet:SetShown(hasSets)
editor.noSets:SetShown(not hasSets) editor.noSets:SetShown(not hasSets)
SelectDropdownValue(ddSet, t.setID) ddSet:GenerateMenu()
SelectDropdownValue(ddLeave, t.leave or "restore") ddLeave:GenerateMenu()
end end
triggerPanel:SetScript("OnShow", function() RefreshTriggerPanel() end) triggerPanel:SetScript("OnShow", function() RefreshTriggerPanel() end)
@@ -2027,7 +1966,6 @@ pfUI:RegisterModule("equipmentmanager", function()
RefreshTriggerRows() RefreshTriggerRows()
end) end)
triggerPanel:SetScript("OnHide", function() triggerPanel:SetScript("OnHide", function()
for _, dd in ipairs({ ddType, ddValue, ddSet, ddLeave }) do dd:HideMenu() end
editValue:ClearFocus() editValue:ClearFocus()
end) end)
+42 -46
View File
@@ -48,9 +48,8 @@ pfUI:RegisterModule("gui", function ()
end}) end})
function EntryUpdate() function EntryUpdate()
-- detect and skip during dropdowns -- skip while the cursor is over an open menu
local focus = GetMouseFocus() if Menu.GetManager():ContainsCursor() then
if focus and focus.parent and focus.parent.menu then
if this.over then if this.over then
this.tex:Hide() this.tex:Hide()
this.over = nil this.over = nil
@@ -344,45 +343,43 @@ pfUI:RegisterModule("gui", function ()
-- use dropdown widget -- use dropdown widget
if widget == "dropdown" and values then if widget == "dropdown" and values then
frame.input = CreateDropDownButton(nil, frame) local function IsSelected(value)
frame.input:SetBackdrop(nil) return category[config] == value
frame.input.menuframe:SetParent(pfUI.gui) end
local function SetSelected(value)
if category[config] ~= value then
category[config] = value
if ufunc then ufunc() else pfUI.gui.settingChanged = true end
pfUI.events:TriggerEvent("config:changed", category, config)
end
end
frame.input = CreateFrame("DropdownButton", nil, frame, "pfUIDropdownTemplate")
frame.input:SetPoint("RIGHT", frame, "RIGHT", 0, 0) frame.input:SetPoint("RIGHT", frame, "RIGHT", 0, 0)
frame.input:SetWidth(180) frame.input:SetWidth(180)
frame.input:SetMenu(function() frame.input:SetupMenu(function(dropdown, rootDescription)
local menu = {} for _, k in pairs(_G.type(values) == "function" and values() or values) do
for i, k in pairs(_G.type(values) == "function" and values() or values) do
local entry = {}
-- get human readable -- get human readable
local value, text = strsplit(":", k) local value, text = strsplit(":", k)
text = text or value rootDescription:CreateRadio(text or value, IsSelected, SetSelected, value)
entry.text = text
entry.func = function()
if category and category[config] ~= value then
category[config] = value
if ufunc then ufunc() else pfUI.gui.settingChanged = true end
pfUI.events:TriggerEvent("config:changed", category, config)
end
end
if category and category[config] == value then
frame.input.current = i
end
table.insert(menu, entry)
end end
return menu
end) end)
frame.input:SetSelection(frame.input.current)
end end
-- use list widget -- use list widget
if widget == "list" then if widget == "list" then
-- index of the selected entry among the "#" separated ones
local selected
local function IsSelected(index)
return index == selected
end
local function Select(index)
selected = index
end
frame.del = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate") frame.del = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
SkinButton(frame.del) SkinButton(frame.del)
frame.del:SetWidth(16) frame.del:SetWidth(16)
@@ -392,15 +389,16 @@ pfUI:RegisterModule("gui", function ()
frame.del:SetText("-") frame.del:SetText("-")
frame.del:SetTextColor(1,.5,.5,1) frame.del:SetTextColor(1,.5,.5,1)
frame.del:SetScript("OnClick", function() frame.del:SetScript("OnClick", function()
local sel = frame.input:GetSelection() if not selected then return end
local newconf = "" local newconf = ""
for id, val in pairs({strsplit("#", category[config])}) do for id, val in ipairs({strsplit("#", category[config])}) do
if id ~= sel then newconf = newconf .. "#" .. val end if id ~= selected and val ~= "" then newconf = newconf .. "#" .. val end
end end
selected = nil
category[config] = newconf category[config] = newconf
if ufunc then ufunc() else pfUI.gui.settingChanged = true end if ufunc then ufunc() else pfUI.gui.settingChanged = true end
pfUI.events:TriggerEvent("config:changed", category, config) pfUI.events:TriggerEvent("config:changed", category, config)
frame.input:UpdateMenu() frame.input:GenerateMenu()
end) end)
frame.add = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate") frame.add = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
@@ -416,21 +414,19 @@ pfUI:RegisterModule("gui", function ()
category[config] = category[config] .. "#" .. this:GetParent().input:GetText() category[config] = category[config] .. "#" .. this:GetParent().input:GetText()
if ufunc then ufunc() else pfUI.gui.settingChanged = true end if ufunc then ufunc() else pfUI.gui.settingChanged = true end
pfUI.events:TriggerEvent("config:changed", category, config) pfUI.events:TriggerEvent("config:changed", category, config)
frame.input:UpdateMenu() frame.input:GenerateMenu()
end, false, true) end, false, true)
end) end)
frame.input = CreateDropDownButton(nil, frame) frame.input = CreateFrame("DropdownButton", nil, frame, "pfUIDropdownTemplate")
frame.input:SetBackdrop(nil)
frame.input.menuframe:SetParent(pfUI.gui)
frame.input:SetPoint("RIGHT", frame.add, "LEFT", -2, 0) frame.input:SetPoint("RIGHT", frame.add, "LEFT", -2, 0)
frame.input:SetWidth(140) frame.input:SetWidth(140)
frame.input:SetMenu(function() frame.input:SetupMenu(function(dropdown, rootDescription)
local menu = {} for id, val in ipairs({strsplit("#", category[config])}) do
for i, val in pairs({strsplit("#", category[config])}) do if val ~= "" then
table.insert(menu, { text = val }) rootDescription:CreateRadio(val, IsSelected, Select, id)
end
end end
return menu
end) end)
end end
@@ -2700,8 +2696,8 @@ pfUI:RegisterModule("gui", function ()
elseif is_horizontal then elseif is_horizontal then
if uneven ~= "Left" and uneven ~= "Right" then C.bars["bar"..id].uneven = "Left" end if uneven ~= "Left" and uneven ~= "Right" then C.bars["bar"..id].uneven = "Left" end
end end
if uneven_frame and uneven_frame.input and uneven_frame.input.UpdateMenu then if uneven_frame then
uneven_frame.input:UpdateMenu() uneven_frame.input:GenerateMenu()
end end
if U["bars"] then U["bars"]() end if U["bars"] then U["bars"]() end
end end
+56
View File
@@ -35,6 +35,62 @@ pfUI:RegisterModule("skin", function ()
CreateBackdropShadow(_G["DropDownList"..i.."Backdrop"]) CreateBackdropShadow(_G["DropDownList"..i.."Backdrop"])
end end
-- ClassicAPI menus that don't name a style of their own take pfUI's
function MenuVariants.GetDefaultMenuMixin() return pfUIMenuStyleMixin end
function MenuVariants.GetDefaultContextMenuMixin() return pfUIMenuStyleMixin end
-- ClassicAPI menus draw their checkboxes and radios with these. Both get a
-- pfUI box: a checked box holds a check, a selected radio a filled square.
local function CreateSelectionBox(frame, text)
local _, border = GetBorderSize()
local box = frame:AttachTexture()
frame.leftTexture1 = box
box:SetDrawLayer("BORDER")
box:SetPoint("LEFT")
box:SetSize(12, 12)
box:SetColorTexture(GetStringColorObject(C.appearance.border.color):GetRGBA())
local inside = frame:AttachTexture()
inside:SetDrawLayer("ARTWORK")
inside:SetPoint("TOPLEFT", box, "TOPLEFT", border, -border)
inside:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -border, border)
local r, g, b = GetStringColorObject(C.appearance.border.background):GetRGB()
inside:SetColorTexture(r, g, b, 1)
local fontString = frame:AttachFontString()
frame.fontString = fontString
fontString:SetPoint("LEFT", box, "RIGHT", 6, 0)
fontString:SetHeight(20)
fontString:SetTextToFit(text)
return box
end
function MenuVariants.CreateCheckbox(text, frame, isSelected, data)
local box = CreateSelectionBox(frame, text)
if isSelected(data) then
local check = frame:AttachTexture()
check:SetDrawLayer("OVERLAY")
check:SetPoint("CENTER", box)
check:SetSize(16, 16)
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
end
return box
end
function MenuVariants.CreateRadio(text, frame, isSelected, data)
local box = CreateSelectionBox(frame, text)
if isSelected(data) then
local dot = frame:AttachTexture()
dot:SetDrawLayer("OVERLAY")
dot:SetPoint("TOPLEFT", box, "TOPLEFT", 3, -3)
dot:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -3, 3)
dot:SetColorTexture(.2, 1, .8, 1)
end
return box
end
if C.global.errors_limit == "1" then if C.global.errors_limit == "1" then
UIErrorsFrame:SetHeight(25) UIErrorsFrame:SetHeight(25)
end end
+18 -25
View File
@@ -42,7 +42,23 @@ pfUI:RegisterModule("tracking", function ()
fade:SetDuration(.5) fade:SetDuration(.5)
fade:SetSmoothing("IN_OUT") fade:SetSmoothing("IN_OUT")
pfUI.tracking.menu = CreateFrame("Frame", "pfUIDropDownMenuTracking", nil, "UIDropDownMenuTemplate") pfUI.tracking.menuMixin = pfUIMenuStyleMixin
local function IsTracking(spell)
return spell.texture == state.texture
end
local function Track(spell)
SetTracking(spell.index)
end
local function GenerateTrackingMenu(owner, rootDescription)
rootDescription:CreateTitle(T["Minimap Tracking"])
for _, spell in pairs(state.spells) do
local icon = CreateTextureMarkup(spell.texture, 64, 64, 16, 16, .1, .9, .1, .9)
rootDescription:CreateRadio(icon .. " " .. spell.name, IsTracking, Track, spell)
end
end
pfUI.tracking:RegisterEvent("PLAYER_ENTERING_WORLD") pfUI.tracking:RegisterEvent("PLAYER_ENTERING_WORLD")
pfUI.tracking:RegisterEvent("PLAYER_AURAS_CHANGED") pfUI.tracking:RegisterEvent("PLAYER_AURAS_CHANGED")
@@ -59,8 +75,7 @@ pfUI:RegisterModule("tracking", function ()
pfUI.tracking:RegisterForClicks("LeftButtonUp", "RightButtonUp") pfUI.tracking:RegisterForClicks("LeftButtonUp", "RightButtonUp")
pfUI.tracking:SetScript("OnClick", function() pfUI.tracking:SetScript("OnClick", function()
if arg1 == "RightButton" then if arg1 == "RightButton" then
pfUI.tracking:InitMenu() MenuUtil.CreateContextMenu(this, GenerateTrackingMenu)
ToggleDropDownMenu(1, nil, pfUI.tracking.menu, this, -5, -5)
end end
if arg1 == "LeftButton" and state.texture then if arg1 == "LeftButton" and state.texture then
CancelTrackingBuff() CancelTrackingBuff()
@@ -128,26 +143,4 @@ pfUI:RegisterModule("tracking", function ()
function pfUI.tracking:PlayerIsDruidInCatForm(playerClass) function pfUI.tracking:PlayerIsDruidInCatForm(playerClass)
return playerClass == "DRUID" and GetShapeshiftFormID() == 1 return playerClass == "DRUID" and GetShapeshiftFormID() == 1
end end
function pfUI.tracking:InitMenu()
UIDropDownMenu_Initialize(pfUI.tracking.menu, function ()
UIDropDownMenu_AddButton({text = T["Minimap Tracking"], isTitle = 1})
for _, spell in pairs(state.spells) do
UIDropDownMenu_AddButton({
text = spell.name,
icon = spell.texture,
tCoordLeft = .1,
tCoordRight = .9,
tCoordTop = .1,
tCoordBottom = .9,
checked = spell.texture == state.texture,
arg1 = spell,
func = function (arg1)
SetTracking(arg1.index)
CloseDropDownMenus()
end
})
end
end, "MENU")
end
end) end)