diff --git a/api/ui-widgets.lua b/api/ui-widgets.lua index ad2b7a18..afda557c 100644 --- a/api/ui-widgets.lua +++ b/api/ui-widgets.lua @@ -100,219 +100,53 @@ do -- statusbars end end -do -- dropdown - local function ListEntryOnShow() - this.icon:SetShown(this.parent.id == this.id) +-- [ pfUIMenuStyleMixin ] +-- Style for ClassicAPI's menus: pfUI's backdrop behind the entries. A dropdown +-- 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 - local function ListEntryOnClick() - this.parent:SetSelection(this.id) - - if this.parent.mode == "MULTISELECT" then - this.parent:ShowMenu() - else - this.parent:HideMenu() - end - - if this.parent.menu[this.id].func then - this.parent.menu[this.id].func() - end + -- room for a submenu arrow or a color swatch, as in the stock styles + local padding = { width = 10, height = 0 } + function pfUIMenuStyleMixin:GetChildExtentPadding() + return padding end +end - local function ListEntryOnEnter() - this.hover:Show() - end +-- [ pfUIDropdownTemplate ] +-- Mixin of the template in ui-widgets.xml: a dropdown that shows its selection +-- as text, with pfUI's arrow box at the right. +_G.pfUIDropdownMixin = CreateFromMixins(ButtonStateBehaviorMixin, DropdownSelectionTextMixin) - local function ListEntryOnLeave() - this.hover:Hide() - end +function pfUIDropdownMixin:OnLoad() + self.Text:SetFont(pfUI.font_default, pfUI_config.global.font_size - 1, "OUTLINE") + 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() - if this.ToggleMenu then - this:ToggleMenu() - else - this:GetParent():ToggleMenu() - end - end + ButtonStateBehaviorMixin.OnLoad(self) + DropdownSelectionTextMixin.OnLoad(self) +end - local function MenuOnUpdate() - if not this:IsMouseOver(100, -100, -100, 100) then - this.button:HideMenu() - end - end - - 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 +-- the arrow box takes the class color while the cursor is over the dropdown +function pfUIDropdownMixin:OnButtonStateChanged() + if self:IsOver() then + self.Arrow:SetBackdropBorderColor(PFUI_CLASS_COLORS[UnitClassBase("player")]:GetRGB()) + else + self.Arrow:SetBackdropBorderColor(GetStringColor(pfUI_config.appearance.border.color)) end end @@ -1149,11 +983,11 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText) grid:SetSize(gridWidth + 4 + 7 + 10, gridHeight + 10) -- Filter dropdown: All / Spells / Items - local filterDropdown = CreateFrame("Frame", name.."Filter", parent, "UIDropDownMenuTemplate") - filterDropdown:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, -80) + local function IsFilter(value) + return currentFilter == value + end 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 }) @@ -1162,24 +996,15 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText) 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) + local filterDropdown = CreateFrame("DropdownButton", nil, parent, "pfUIDropdownTemplate") + filterDropdown:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -14, -84) + filterDropdown:SetWidth(140) + CreateBackdrop(filterDropdown, nil, true) + filterDropdown:SetupMenu(function(dropdown, rootDescription) + rootDescription:CreateRadio(ICON_FILTER_ALL, IsFilter, ApplyFilter, "all") + rootDescription:CreateRadio(ICON_FILTER_SPELL, IsFilter, ApplyFilter, "spells") + rootDescription:CreateRadio(ICON_FILTER_ITEM, IsFilter, ApplyFilter, "items") 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 local function UpdateSelection() diff --git a/api/ui-widgets.xml b/api/ui-widgets.xml index 9fd6dc72..df083d14 100644 --- a/api/ui-widgets.xml +++ b/api/ui-widgets.xml @@ -102,4 +102,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/addons.lua b/modules/addons.lua index aac03cc8..37f16cc5 100644 --- a/modules/addons.lua +++ b/modules/addons.lua @@ -110,6 +110,12 @@ pfUI:RegisterModule("addons", function () return selected_addons end + local selectedProfile + + local function IsSelectedProfile(profile) + return profile == selectedProfile + end + local function SetAddonProfile(profile) -- create new profile if not existing if not pfUI_addon_profiles[profile] then @@ -117,7 +123,8 @@ pfUI:RegisterModule("addons", function () end -- set dropdown to profile - pfUI.addons.profile.dropdown:SetSelectionByText(profile) + selectedProfile = profile + pfUI.addons.profile.dropdown:GenerateMenu() -- load profile local selected = {} @@ -163,7 +170,7 @@ pfUI:RegisterModule("addons", function () pfUI.addons.profile.del:SetText("-") pfUI.addons.profile.del:SetTextColor(1,.5,.5,1) 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 CreateQuestionDialog(T["Delete profile"] .. " '|cff33ffcc" .. name .. "|r'?", function() pfUI_addon_profiles[name] = nil @@ -193,26 +200,13 @@ pfUI:RegisterModule("addons", function () end) -- addon profile: dropdown - pfUI.addons.profile.dropdown = CreateDropDownButton("pfAddonListProfileList", pfUI.addons.profile) - pfUI.addons.profile.dropdown:SetBackdrop(nil) - pfUI.addons.profile.dropdown:ClearAllPoints() + pfUI.addons.profile.dropdown = CreateFrame("DropdownButton", nil, pfUI.addons.profile, "pfUIDropdownTemplate") pfUI.addons.profile.dropdown:SetPoint("RIGHT", pfUI.addons.profile.add, "LEFT", -2, 0) pfUI.addons.profile.dropdown:SetWidth(220) - pfUI.addons.profile.dropdown:SetMenu(function() - local menu = {} - - 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) + pfUI.addons.profile.dropdown:SetupMenu(function(dropdown, rootDescription) + for name in pairs(pfUI_addon_profiles) do + rootDescription:CreateRadio(name, IsSelectedProfile, SetAddonProfile, name) end - - return menu end) local function AddDependencyLines(header, deps) @@ -263,9 +257,7 @@ pfUI:RegisterModule("addons", function () local function InputOnClick(self) SetAddonEnabled(self:GetParent().addon.index, self:GetChecked()) - local _, name = pfUI.addons.profile.dropdown:GetSelection() - name = name or T["Current"] - pfUI_addon_profiles[name] = GetSelectedAddonsList() + pfUI_addon_profiles[selectedProfile or T["Current"]] = GetSelectedAddonsList() end local function InitRow(row, addon) diff --git a/modules/equipmentmanager.lua b/modules/equipmentmanager.lua index b32e8ad0..2bd6aa83 100644 --- a/modules/equipmentmanager.lua +++ b/modules/equipmentmanager.lua @@ -204,66 +204,37 @@ pfUI:RegisterModule("equipmentmanager", function() end) -- ============================================================ - -- Per-row context menu (single instance, repositioned per click). - -- Triggered by the gear icon on each set row. + -- Per-row context menu, opened from the gear icon on each set row. -- ============================================================ - local rowMenu = CreateFrame("Frame", "pfEqMgrRowMenu", UIParent) - rowMenu:SetFrameStrata("DIALOG") - rowMenu:SetSize(140, 50); - 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 + local function EditSet(setID) + local name, icon = C_EquipmentSet.GetEquipmentSetInfo(setID) + selectedSetID = setID OpenNamePopup("save", name, icon) - end) + end - rowMenu.deleteBtn = CreateFrame("Button", nil, rowMenu, "UIPanelButtonTemplate") - rowMenu.deleteBtn:SetSize(130, 20); - 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) + local function DeleteSet(setID) + local name = C_EquipmentSet.GetEquipmentSetInfo(setID) StaticPopupDialogs["PFUI_EQMGR_DELETE"] = { text = string.format(CONFIRM_DELETE_EQUIPMENT_SET, name or "?"), button1 = YES, button2 = NO, OnAccept = function() - pendingIgnoredToggles[targetID] = nil - C_EquipmentSet.DeleteEquipmentSet(targetID) - if selectedSetID == targetID then selectedSetID = nil end + pendingIgnoredToggles[setID] = nil + C_EquipmentSet.DeleteEquipmentSet(setID) + if selectedSetID == setID then selectedSetID = nil end pfUI.equipmentmanager.Refresh() end, timeout = 0, whileDead = 1, hideOnEscape = 1, exclusive = 1, } 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) @@ -303,20 +274,9 @@ pfUI:RegisterModule("equipmentmanager", function() -- moving onto the gear does not leave the row row.gear:SetPropagateMouseMotion(true) row.gear:Hide() + row.menuMixin = pfUIMenuStyleMixin row.gear:SetScript("OnClick", function() - if not row.setID then return 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() + if row.setID then MenuUtil.CreateContextMenu(row, GenerateSetMenu) end end) row:SetScript("OnClick", function() @@ -904,19 +864,6 @@ pfUI:RegisterModule("equipmentmanager", function() return b 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) DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpf|cffffffffUI|r: " .. msg) end @@ -1783,9 +1730,10 @@ pfUI:RegisterModule("equipmentmanager", function() end local function EditorDropdown(row) - local dd = CreateDropDownButton(nil, editor) + local dd = CreateFrame("DropdownButton", nil, editor, "pfUIDropdownTemplate") dd:SetWidth(190) dd:SetPoint("TOPRIGHT", editor, "TOPRIGHT", 0, EDITOR_ROW_Y[row]) + CreateBackdrop(dd, nil, true) return dd end @@ -1801,41 +1749,49 @@ pfUI:RegisterModule("equipmentmanager", function() RefreshTriggerPanel() 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) local ddType = EditorDropdown(1) - ddType:SetMenu(function() - local menu = {} + local IsType = TriggerField("type") + 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 if info.value ~= "list" or info.options then - local key = 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 }) + rootDescription:CreateRadio(info.text, IsType, SetType, info.key) end end - return menu end) local valueLabel = EditorLabel(T["Value"], 2) local ddValue = EditorDropdown(2) - ddValue:SetMenu(function() - local menu = {} + local IsValue, SetValue = TriggerField("value") + ddValue:SetupMenu(function(dropdown, rootDescription) local t = SelectedTrigger() local info = t and TRIGGER_TYPE[t.type] for _, o in ipairs(info and info.options or {}) do - local value = 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 }) + rootDescription:CreateRadio(o.text, IsValue, SetValue, o.value) end - return menu end) local editValue = CreateTextBox(nil, editor) @@ -1907,39 +1863,22 @@ pfUI:RegisterModule("equipmentmanager", function() EditorLabel(T["Equip"], 3) local ddSet = EditorDropdown(3) - ddSet:SetMenu(function() - local menu = {} + local IsSet, SetSet = TriggerField("setID") + ddSet:SetupMenu(function(dropdown, rootDescription) for _, id in ipairs(GetVisibleSetIDs()) do - local setID = 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 }) + rootDescription:CreateRadio(SetName(id), IsSet, SetSet, id) end - return menu end) EditorLabel(T["When It Ends"], 4) local ddLeave = EditorDropdown(4) - ddLeave:SetMenu(function() - local function Choose(value) - return function() - local t = SelectedTrigger() - 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") }, - } + local IsLeave, SetLeave = TriggerField("leave", "restore") + ddLeave:SetupMenu(function(dropdown, rootDescription) + rootDescription:CreateRadio(T["Restore Previous Gear"], IsLeave, SetLeave, "restore") + rootDescription:CreateRadio(T["Do Nothing"], IsLeave, SetLeave, "none") 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 - return menu end) editor.noSets = editor:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall") @@ -1984,7 +1923,7 @@ pfUI:RegisterModule("equipmentmanager", function() editor:Show() editor.placeholder:Hide() - SelectDropdownValue(ddType, t.type) + ddType:GenerateMenu() local info = TRIGGER_TYPE[t.type] local kind = info and info.value @@ -1993,7 +1932,7 @@ pfUI:RegisterModule("equipmentmanager", function() editValue:SetShown(kind == "text") btnCurrentZone:SetShown(t.type == "zone") if kind == "list" then - SelectDropdownValue(ddValue, t.value) + ddValue:GenerateMenu() elseif kind == "text" then editValue:ClearAllPoints() editValue:SetPoint("TOPLEFT", editor, "TOPRIGHT", -190, EDITOR_ROW_Y[2]) @@ -2014,8 +1953,8 @@ pfUI:RegisterModule("equipmentmanager", function() local hasSets = table.getn(GetVisibleSetIDs()) > 0 ddSet:SetShown(hasSets) editor.noSets:SetShown(not hasSets) - SelectDropdownValue(ddSet, t.setID) - SelectDropdownValue(ddLeave, t.leave or "restore") + ddSet:GenerateMenu() + ddLeave:GenerateMenu() end triggerPanel:SetScript("OnShow", function() RefreshTriggerPanel() end) @@ -2027,7 +1966,6 @@ pfUI:RegisterModule("equipmentmanager", function() RefreshTriggerRows() end) triggerPanel:SetScript("OnHide", function() - for _, dd in ipairs({ ddType, ddValue, ddSet, ddLeave }) do dd:HideMenu() end editValue:ClearFocus() end) diff --git a/modules/gui.lua b/modules/gui.lua index dc59de0a..beb96f44 100644 --- a/modules/gui.lua +++ b/modules/gui.lua @@ -48,9 +48,8 @@ pfUI:RegisterModule("gui", function () end}) function EntryUpdate() - -- detect and skip during dropdowns - local focus = GetMouseFocus() - if focus and focus.parent and focus.parent.menu then + -- skip while the cursor is over an open menu + if Menu.GetManager():ContainsCursor() then if this.over then this.tex:Hide() this.over = nil @@ -344,45 +343,43 @@ pfUI:RegisterModule("gui", function () -- use dropdown widget if widget == "dropdown" and values then - frame.input = CreateDropDownButton(nil, frame) - frame.input:SetBackdrop(nil) - frame.input.menuframe:SetParent(pfUI.gui) + local function IsSelected(value) + return category[config] == value + 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:SetWidth(180) - frame.input:SetMenu(function() - local menu = {} - - for i, k in pairs(_G.type(values) == "function" and values() or values) do - local entry = {} + frame.input:SetupMenu(function(dropdown, rootDescription) + for _, k in pairs(_G.type(values) == "function" and values() or values) do -- get human readable local value, text = strsplit(":", k) - text = text or 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) + rootDescription:CreateRadio(text or value, IsSelected, SetSelected, value) end - - return menu end) - - frame.input:SetSelection(frame.input.current) end -- use list widget 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") SkinButton(frame.del) frame.del:SetWidth(16) @@ -392,15 +389,16 @@ pfUI:RegisterModule("gui", function () frame.del:SetText("-") frame.del:SetTextColor(1,.5,.5,1) frame.del:SetScript("OnClick", function() - local sel = frame.input:GetSelection() + if not selected then return end local newconf = "" - for id, val in pairs({strsplit("#", category[config])}) do - if id ~= sel then newconf = newconf .. "#" .. val end + for id, val in ipairs({strsplit("#", category[config])}) do + if id ~= selected and val ~= "" then newconf = newconf .. "#" .. val end end + selected = nil category[config] = newconf if ufunc then ufunc() else pfUI.gui.settingChanged = true end pfUI.events:TriggerEvent("config:changed", category, config) - frame.input:UpdateMenu() + frame.input:GenerateMenu() end) frame.add = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate") @@ -416,21 +414,19 @@ pfUI:RegisterModule("gui", function () category[config] = category[config] .. "#" .. this:GetParent().input:GetText() if ufunc then ufunc() else pfUI.gui.settingChanged = true end pfUI.events:TriggerEvent("config:changed", category, config) - frame.input:UpdateMenu() + frame.input:GenerateMenu() end, false, true) end) - frame.input = CreateDropDownButton(nil, frame) - frame.input:SetBackdrop(nil) - frame.input.menuframe:SetParent(pfUI.gui) + frame.input = CreateFrame("DropdownButton", nil, frame, "pfUIDropdownTemplate") frame.input:SetPoint("RIGHT", frame.add, "LEFT", -2, 0) frame.input:SetWidth(140) - frame.input:SetMenu(function() - local menu = {} - for i, val in pairs({strsplit("#", category[config])}) do - table.insert(menu, { text = val }) + frame.input:SetupMenu(function(dropdown, rootDescription) + for id, val in ipairs({strsplit("#", category[config])}) do + if val ~= "" then + rootDescription:CreateRadio(val, IsSelected, Select, id) + end end - return menu end) end @@ -2700,8 +2696,8 @@ pfUI:RegisterModule("gui", function () elseif is_horizontal then if uneven ~= "Left" and uneven ~= "Right" then C.bars["bar"..id].uneven = "Left" end end - if uneven_frame and uneven_frame.input and uneven_frame.input.UpdateMenu then - uneven_frame.input:UpdateMenu() + if uneven_frame then + uneven_frame.input:GenerateMenu() end if U["bars"] then U["bars"]() end end diff --git a/modules/skin.lua b/modules/skin.lua index d7f98e49..69081ee8 100644 --- a/modules/skin.lua +++ b/modules/skin.lua @@ -35,6 +35,62 @@ pfUI:RegisterModule("skin", function () CreateBackdropShadow(_G["DropDownList"..i.."Backdrop"]) 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 UIErrorsFrame:SetHeight(25) end diff --git a/modules/tracking.lua b/modules/tracking.lua index 5e4e99a9..974edc97 100644 --- a/modules/tracking.lua +++ b/modules/tracking.lua @@ -42,7 +42,23 @@ pfUI:RegisterModule("tracking", function () fade:SetDuration(.5) 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_AURAS_CHANGED") @@ -59,8 +75,7 @@ pfUI:RegisterModule("tracking", function () pfUI.tracking:RegisterForClicks("LeftButtonUp", "RightButtonUp") pfUI.tracking:SetScript("OnClick", function() if arg1 == "RightButton" then - pfUI.tracking:InitMenu() - ToggleDropDownMenu(1, nil, pfUI.tracking.menu, this, -5, -5) + MenuUtil.CreateContextMenu(this, GenerateTrackingMenu) end if arg1 == "LeftButton" and state.texture then CancelTrackingBuff() @@ -128,26 +143,4 @@ pfUI:RegisterModule("tracking", function () function pfUI.tracking:PlayerIsDruidInCatForm(playerClass) return playerClass == "DRUID" and GetShapeshiftFormID() == 1 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) \ No newline at end of file