66ccb1ba1f
Ensembles d'équipement : le crochet qui abandonne une modification sur Annuler ou Échap visait la globale GearManagerDialogPopup_OnHide, que le XML lie directement (function=) : il ne se déclenchait jamais. La session restée ouverte faisait de la sauvegarde suivante une modification : l'ancien ensemble était rééquipé, enregistré sous le nom tapé, puis supprimé. Le script du cadre est désormais greffé (comme Taxi.lua). Réputation : la description et les trois cases venaient de la liste du client, qui ne les remplit que pour ses 15 lignes visibles ; cachée et jamais défilée, elle laissait à partir de la 16e faction celles de la précédente, et un clic agissait sur la nouvelle à contresens (en guerre, barre suivie). Elles sont lues sur la faction elle-même. Combat : PetPaperDollFrame, et donc CharacterFrame, sont protégés par les boutons de compagnon sécurisés. Les masquer, les déplacer ou retailler la feuille depuis l'addon en combat était bloqué : à chaque rafraîchissement du familier (PET_BAR_UPDATE...), à chaque ouverture de la feuille, à chaque onglet. Ces appels attendent la fin du combat ; Panes n'appelle plus Show ou Hide sans changement, que le client refuse aussi. Performance : les événements d'unité de la feuille (inventaire, portrait, modèle) ne relancent plus toute la mise en page pour les autres unités ni feuille fermée ; l'onglet du familier ne réagit plus qu'à son familier ; l'onglet des statistiques relit l'arbre au plus deux fois par seconde. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KxRZNHkq453dyUMcWsyUf1
234 lines
6.7 KiB
Lua
234 lines
6.7 KiB
Lua
-- Hosts and their contents: the single place that decides what a window shows.
|
|
-- A host is a fixed surface (a pane, a column) in which contents replace each other, like
|
|
-- LeftPaneHost / RightPaneHost in camelot CharacterFrame.xml. A content is built once, on
|
|
-- first show, then only shown or hidden; nothing is recomputed.
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
|
|
local Panes = {}
|
|
ForeverUI.Panes = Panes
|
|
|
|
local hosts = {} -- name -> host (frame, contents, pages, furniture, group, current)
|
|
local hostOrder = {}
|
|
local L = ForeverUI.L
|
|
|
|
-- ---------------------------------------------------------------- hosts
|
|
|
|
-- Declares a host on an existing frame; the library only records where contents go.
|
|
function Panes.NewHost(name, frame)
|
|
local host = hosts[name]
|
|
if not host then
|
|
host = { name = name, contents = {}, order = {}, pages = {},
|
|
furniture = {}, displayed = true }
|
|
hosts[name] = host
|
|
hostOrder[#hostOrder + 1] = name
|
|
end
|
|
host.frame = frame
|
|
return host
|
|
end
|
|
|
|
-- ------------------------------------------------------------ contents
|
|
|
|
-- def = { host, group, id, build }: group is the screen a tab opens (it sets every host);
|
|
-- id names the page. Pages of the same host and group replace each other.
|
|
-- build(hostFrame) runs once, on first show, and returns our root frame (or nil) and the
|
|
-- list of client frames the content owns. Client frames are not reparented (they would
|
|
-- lose their level and strata), so they are shown and hidden with the root.
|
|
function Panes.Register(def)
|
|
local host = hosts[def.host]
|
|
if not host then
|
|
error(ForeverUI.L.PANES_ERROR_UNKNOWN_HOST .. tostring(def.host))
|
|
end
|
|
|
|
local content = {
|
|
id = def.id,
|
|
group = def.group,
|
|
build = def.build,
|
|
host = host,
|
|
built = false,
|
|
frames = {},
|
|
}
|
|
host.contents[def.id] = content
|
|
host.order[#host.order + 1] = def.id
|
|
|
|
-- The first page declared for a group becomes its default page.
|
|
if host.pages[def.group] == nil then
|
|
host.pages[def.group] = def.id
|
|
end
|
|
return content
|
|
end
|
|
|
|
local function assemble(content)
|
|
if content.built then
|
|
return
|
|
end
|
|
content.built = true -- set before the call: no re-entry
|
|
|
|
if content.build then
|
|
local root, frames = content.build(content.host.frame)
|
|
content.root = root
|
|
content.frames = frames or {}
|
|
end
|
|
end
|
|
|
|
-- Furniture: frames a host shows for a group whatever the page (stone band, page tabs),
|
|
-- like camelot UpdateRightPaneHeader. Can be called several times; frames add up.
|
|
function Panes.Furniture(name, group, frames)
|
|
local host = hosts[name]
|
|
if not host then
|
|
return
|
|
end
|
|
local list = host.furniture[group] or {}
|
|
host.furniture[group] = list
|
|
for _, frame in ipairs(frames or {}) do
|
|
if frame then
|
|
list[#list + 1] = frame
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Shows or hides a frame only on a change: a protected client frame (PetPaperDollFrame holds
|
|
-- secure companion buttons) refuses even a call that changes nothing, in combat
|
|
local function setShown(frame, visible)
|
|
if (frame:IsShown() and true or false) ~= visible then
|
|
if visible then frame:Show() else frame:Hide() end
|
|
end
|
|
end
|
|
|
|
-- Shows or hides a content and the client frames it owns; builds it on first show
|
|
local function place(content, visible)
|
|
if visible then
|
|
assemble(content)
|
|
elseif not content.built then
|
|
-- Never shown, so nothing to hide: do not build it just for that.
|
|
return
|
|
end
|
|
|
|
if content.root then
|
|
setShown(content.root, visible)
|
|
end
|
|
for _, frame in ipairs(content.frames) do
|
|
if frame and frame.Show then
|
|
setShown(frame, visible)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------- display
|
|
|
|
-- Applies a host's group and page: shows the wanted content and furniture, hides the rest
|
|
local function apply(host)
|
|
local wanted = host.displayed and host.pages[host.group or ""] or nil
|
|
|
|
for _, id in ipairs(host.order) do
|
|
place(host.contents[id], id == wanted)
|
|
end
|
|
host.current = wanted
|
|
|
|
-- Furniture: hide everything declared, then show the current group's, so a frame shared by
|
|
-- two groups does not depend on the loop order.
|
|
local activeFrames = {}
|
|
local ownScreen = host.furniture[host.group or ""]
|
|
if host.displayed and wanted and ownScreen then
|
|
for _, frame in ipairs(ownScreen) do
|
|
activeFrames[frame] = true
|
|
end
|
|
end
|
|
for _, list in pairs(host.furniture) do
|
|
for _, frame in ipairs(list) do
|
|
if frame and frame.Hide and not activeFrames[frame] then
|
|
frame:Hide()
|
|
end
|
|
end
|
|
end
|
|
for frame in pairs(activeFrames) do
|
|
if frame.Show then
|
|
frame:Show()
|
|
end
|
|
end
|
|
|
|
-- A host with no content is hidden, so an empty right pane (with its background and stone
|
|
-- band) does not stay on a tab that has nothing to put there.
|
|
if host.frame then
|
|
local needed = host.displayed and wanted ~= nil
|
|
if needed then host.frame:Show() else host.frame:Hide() end
|
|
end
|
|
end
|
|
|
|
-- Opens a group: a whole screen, all hosts at once.
|
|
function Panes.ShowGroup(group)
|
|
for _, name in ipairs(hostOrder) do
|
|
local host = hosts[name]
|
|
host.group = group
|
|
apply(host)
|
|
end
|
|
Panes.group = group
|
|
end
|
|
|
|
function Panes.CurrentGroup()
|
|
return Panes.group
|
|
end
|
|
|
|
-- Switches the page of a host without changing the group (two buttons sharing one surface).
|
|
function Panes.ShowPage(name, id)
|
|
local host = hosts[name]
|
|
if not host or not host.contents[id] then
|
|
return
|
|
end
|
|
host.pages[host.group or ""] = id
|
|
apply(host)
|
|
end
|
|
|
|
function Panes.CurrentPage(name)
|
|
local host = hosts[name]
|
|
return host and host.current
|
|
end
|
|
|
|
-- Hides a whole host (a collapsed pane). The group and the chosen page are kept for when it
|
|
-- is expanded again.
|
|
function Panes.SetHostShown(name, state)
|
|
local host = hosts[name]
|
|
if not host then
|
|
return
|
|
end
|
|
host.displayed = state and true or false
|
|
apply(host)
|
|
end
|
|
|
|
-- Tells whether a host has something to show for this group, without building anything
|
|
-- (e.g. whether the collapse button makes sense).
|
|
function Panes.HasContent(name, group)
|
|
local host = hosts[name]
|
|
return host ~= nil and host.pages[group or host.group or ""] ~= nil
|
|
end
|
|
|
|
-- Re-applies the current state. Call it when a content is registered after its group was
|
|
-- opened, never from a display loop.
|
|
function Panes.Refresh()
|
|
for _, name in ipairs(hostOrder) do
|
|
apply(hosts[name])
|
|
end
|
|
end
|
|
|
|
-- Debug report: what each host shows and owns.
|
|
function Panes.Report()
|
|
local rows = {}
|
|
for _, name in ipairs(hostOrder) do
|
|
local host = hosts[name]
|
|
local pages = {}
|
|
for _, id in ipairs(host.order) do
|
|
local content = host.contents[id]
|
|
if content.group == host.group then
|
|
pages[#pages + 1] = string.format(L.PANES_REPORT_PAGE, id,
|
|
#content.frames, content.built and "" or L.PANES_REPORT_NEVER_BUILT)
|
|
end
|
|
end
|
|
rows[#rows + 1] = string.format(
|
|
L.PANES_REPORT_LINE,
|
|
name, tostring(host.group), tostring(host.current),
|
|
tostring(host.displayed), table.concat(pages, ", "))
|
|
end
|
|
return rows
|
|
end
|