Files
AnySCT/menu.lua
T
2026-10-15 13:52:38 +02:00

140 lines
5.5 KiB
Lua

-- AnySCT menu.lua -- "Mark as targetSCT" in the unit right-click menus (target, party and raid frames;
-- pfUI uses the same Blizzard UnitPopup dropdowns). Hooks the 1.12 UnitPopup system:
-- UnitPopupButtons / UnitPopupMenus register the button, inserted before CANCEL
-- UnitPopup_ShowMenu sets the label: Mark as targetSCT / Unmark targetSCT
-- UnitPopup_HideButtons hides the entry for hostile units and non-players
-- UnitPopup_OnClick handles our value, everything else goes to the original
-- Everything is guarded so a missing menu table or function never errors.
AnySCT_Menu = {}
local M = AnySCT_Menu
local KEY = "ANYSCT_TOGGLE"
-- Menus the client opens for a unit: PLAYER (other players, incl. hostile), PARTY, RAID, FRIEND list.
-- NPC targets open "RAID_TARGET_ICON" (the title is the icon list); the key is added to it at
-- level 1 only and removed again for the nested icon submenu of the player menus.
local MENUS = { "PLAYER", "PARTY", "RAID", "FRIEND" }
M.KEY = KEY
local origShow, origHide, origClick
-- The name the menu is about: captured when the menu opened (ShowMenu wrapper), else the unit's
-- current name. Never dd.name: for NPC targets that is the menu title.
local function nameOf(dd)
if type(dd) ~= "table" then return nil end
if dd.anyName then return dd.anyName end
if dd.unit then return UnitName(dd.unit) end
return nil
end
local function listed(name)
return name ~= nil and AnySCT_Core.state.byName[name] ~= nil
end
function M.Label(name)
if listed(name) then return "Unmark targetSCT" end
return "Mark as targetSCT"
end
-- true when the entry must not be offered: no name, or the player themself (own events are never shown)
function M.Hidden(dd)
if type(dd) ~= "table" then return true end
local n = nameOf(dd)
if n == nil then return true end
return n == UnitName("player")
end
-- Add (or remove) the key in the NPC menu depending on the menu level.
local function syncIconMenu(which)
local menu = UnitPopupMenus["RAID_TARGET_ICON"]
if type(menu) ~= "table" then return end
local level = UIDROPDOWNMENU_MENU_LEVEL or 1
local at
for i = 1, table.getn(menu) do
if menu[i] == KEY then at = i end
end
if level == 1 and which == "RAID_TARGET_ICON" then
if not at then table.insert(menu, KEY) end
elseif at then
table.remove(menu, at)
end
end
-- Mark / unmark. unit (optional) lets the list learn the GUID of a unit outside the group.
function M.Toggle(name, unit)
local C = AnySCT_Core
if C.state.byName[name] then
C.RemoveSource(name)
C.Print(name .. " is no longer a targetSCT")
else
-- what is known about the unit decides the default of the threat switch (pets, mobs and hostile
-- players off; players on)
local info
if unit and UnitIsPlayer and UnitCanAttack then
info = { player = UnitIsPlayer(unit) and true or false, friendly = not UnitCanAttack("player", unit) }
end
C.AddSource(name, "manual", nil, info)
if unit and C.SeeUnit then C.SeeUnit(name, unit) end
-- no token from the menu (or it did not resolve): look at target / targettarget / mouseover
if C.ProbeLoose then C.ProbeLoose() end
C.Print(name .. " marked as targetSCT")
end
end
local function insertKey(menu)
if type(menu) ~= "table" then return end
local n = table.getn(menu)
local at = n + 1
for i = 1, n do
if menu[i] == KEY then return end
if menu[i] == "CANCEL" then at = i; break end
end
table.insert(menu, at, KEY)
end
-- Installs the hooks once. Returns true when the UnitPopup tables exist.
function M.Install()
if M.installed then return true end
if type(UnitPopupButtons) ~= "table" or type(UnitPopupMenus) ~= "table" then return false end
UnitPopupButtons[KEY] = { text = "Mark as targetSCT", dist = 0 }
for i = 1, table.getn(MENUS) do insertKey(UnitPopupMenus[MENUS[i]]) end
if type(UnitPopup_ShowMenu) == "function" then
origShow = UnitPopup_ShowMenu
UnitPopup_ShowMenu = function(dropdownMenu, which, unit, name, userData)
syncIconMenu(which)
local n = unit and UnitName(unit) or ((not unit) and name) or nil
if type(dropdownMenu) == "table" then dropdownMenu.anyName = n end
UnitPopupButtons[KEY].text = M.Label(n)
return origShow(dropdownMenu, which, unit, name, userData)
end
end
if type(UnitPopup_HideButtons) == "function" then
origHide = UnitPopup_HideButtons
UnitPopup_HideButtons = function()
origHide()
local dd = getglobal(UIDROPDOWNMENU_INIT_MENU)
if type(dd) ~= "table" or type(UnitPopupShown) ~= "table" then return end
local menu = UnitPopupMenus[dd.which]
if type(menu) ~= "table" then return end
for i = 1, table.getn(menu) do
if menu[i] == KEY and M.Hidden(dd) then UnitPopupShown[i] = 0 end
end
end
end
if type(UnitPopup_OnClick) == "function" then
origClick = UnitPopup_OnClick
UnitPopup_OnClick = function()
if this and this.value == KEY then
local dd = getglobal(UIDROPDOWNMENU_INIT_MENU)
local n = nameOf(dd)
if n then M.Toggle(n, dd.unit) end
return
end
return origClick()
end
end
M.installed = true
return true
end