Files
moon-well-ui/data/addon/ForeverUI/Titles.lua
T
Adrestie 5842eb7a2b ForeverUI : code en anglais, commentaires resserres, code mort retire
Traduction
- Identifiants en anglais dans tout le module : addon, ecrans d'accueil,
  outils Python, banc d'essai et patcheur C#.
- Fichiers au nom francais renommes (Gabarits.lua -> Templates.lua,
  Textes_*.lua -> Texts_*.lua, deployer.py -> deploy.py,
  tools/patcheur -> tools/patcher, etc.).
- Commandes /fui et options de deploy.py en anglais (--check, --server,
  --remove-dbc).
- Cles des variables sauvegardees et de data/dbc/statistics.json
  traduites, sans reprise des anciennes cles.
- API de la micro-barre : ForeverUI.AddMicroButton(def) avec les champs
  name, atlasSet, after, tooltip, onClick, ready, et
  ForeverUI.UpdateMicro(name, isOpen).
- Commentaires reecrits en anglais, courts, sans dates ni historique ;
  les fonctions au nom peu parlant et leurs parametres sont expliques.

Code mort
- Exports, fonctions et variables jamais lus retires.
- Retires a la demande des modules : ForeverUI.PvPJauge, les exports
  FondEntete / TuilerEntete / Polices de TradeSkill, l'art legacy-up-c60,
  honorfill(half)blue et inv_misc_book_09, leurs entrees d'atlas et les
  parties d'outils correspondantes.

Verifications : liaisons des noms comparees avant et apres, banc vert,
chemins de textures inchanges, generateurs reproduisant les fichiers,
patcheur identique octet pour octet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 09:15:52 +02:00

329 lines
10 KiB
Lua

-- Title list, a page of the character sheet's right pane.
-- Row layout from camelot PlayerTitleButtonTemplate (paperdollframe.xml): check 16 x 16 at
-- LEFT (8, 0), text 3 px right of it to RIGHT (-3, 0), SelectedBar alpha 0.4 ADD, blue
-- highlight ADD.
-- Data API, as used by the client's PlayerTitleFrame_UpdateTitles:
-- IsTitleKnown returns 0 or 1, and 0 is true in Lua: test `~= 0`, as the client does.
-- GetTitleName pads the name with spaces ("Private "): strtrim it, as the client does.
-- GetCurrentTitle returns 0 when nothing is chosen, -1 for None, else the id;
-- SetCurrentTitle(-1) sets None.
-- Differences from camelot:
-- * The tab is not in camelot's PAPERDOLL_SIDEBARS; it comes from
-- mainline/PaperDollFrameConstants.lua PAPERDOLL_SIDEBARTAB_TITLES.
-- * camelot's TitleManagerPane keeps a dead TOPLEFT (4, -4) anchor, under the stone band
-- and tabs. We use EquipmentManagerPane's: stone bottom to pane bottom.
-- * No scroll bar: mouse wheel only, like reputation and skills.
local ForeverUI = ForeverUI or {}
_G.ForeverUI = ForeverUI
local L = ForeverUI.L
-- Rows span the pane width minus the stat rows' margin (camelot: 169 wide in a 233 pane),
-- so both pages of the pane share the same edge.
local ROW_H = 22
local MARGIN = 20 -- STAT_MARGIN of CharacterFrame.lua, on each side
local LIST_Y = -4 -- SetPadding(4, 0, 2, 0, 0)
local CHECKMARK = 16
local CHECKMARK_X = 8
local TEXT_X, TEXT_X2 = 3, -3
local SELECTED_ALPHA = 0.4
-- Alternating background, the same as the stat rows: the two bands of paperdollinfopart1c60
-- whose alpha fades at both ends.
-- UI-Character-Info-ItemLevel-Bounce 204 x 21, dark (27, 21, 16) at 255
-- UI-Character-Info-Line-Bounce 213 x 18, light (87, 67, 46) at 102
-- Dark first. Alternation follows the list index (scroll included), not the screen slot,
-- as camelot's PaperDollTitlesPane_InitButton does with `index % 2`.
local ATLAS_DARK_BACKGROUND = "ui-character-info-itemlevel-bounce"
local ATLAS_LIGHT_BACKGROUND = "ui-character-info-line-bounce"
local CHECKMARK_PATH = "Interface\\Buttons\\UI-CheckBox-Check"
local SELECTED_PATH = "Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar"
local HOVER_PATH =
"Interface\\ForeverUI\\FriendsFrame\\UI-FriendsFrame-HighlightBar-Blue"
-- Pane size, used when content is built on first open before the window is laid out
-- (GetHeight returns 0 then). Same guard as reputation and skills.
-- Right pane 233 x 464; the stone band takes the top 85.
local PANE_W, PANE_H, STONE_H = 233, 464, 85
local panel, offset, rows, titles, selected = nil, 0, {}, {}, -1
-- ---------- Data
local function noneName()
return NONE
end
-- Titles the character owns, sorted by name, with None first (as in camelot's list).
local function readTitles()
local list = {}
local count = GetNumTitles and GetNumTitles() or 0
for identifier = 1, count do
if IsTitleKnown and IsTitleKnown(identifier) ~= 0 then
local name = GetTitleName and GetTitleName(identifier)
if name then
name = strtrim(name)
if name ~= "" then
list[#list + 1] = { id = identifier, name = name }
end
end
end
end
table.sort(list, function(a, b) return a.name < b.name end)
table.insert(list, 1, { id = -1, name = noneName() })
return list
end
-- Worn title as camelot keeps it: the current id if it is a known title, else None (-1).
-- GetCurrentTitle returns 0 while nothing is chosen.
local function wornTitle()
local current = GetCurrentTitle and GetCurrentTitle() or 0
local count = GetNumTitles and GetNumTitles() or 0
if current and current > 0 and current <= count
and IsTitleKnown and IsTitleKnown(current) ~= 0 then
return current
end
return -1
end
-- ---------- Display
local function applyChoice(row, marker)
if marker then
row.checkMark:Show()
row.selected:Show()
else
row.checkMark:Hide()
row.selected:Hide()
end
end
-- Row width: pane width minus margins. Falls back to PANE_W when content is built before
-- the window is laid out (GetWidth returns 0 then).
local function rowWidth()
local width = (panel and panel:GetWidth()) or 0
if width < 50 then
width = PANE_W
end
return width - 2 * MARGIN
end
local function createRow(rank)
local row = CreateFrame("Button", "ForeverUITitleRow" .. rank, panel)
row:SetWidth(rowWidth())
row:SetHeight(ROW_H)
-- Background: one texture whose atlas changes on each pass. SetAtlas keeps the size
-- (third argument): it comes from the two anchors.
local background = row:CreateTexture(nil, "BACKGROUND")
background:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0)
background:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0)
row.background = background
local selectedBar = row:CreateTexture(nil, "OVERLAY")
selectedBar:SetTexture(SELECTED_PATH)
selectedBar:SetBlendMode("ADD")
selectedBar:SetAlpha(SELECTED_ALPHA)
selectedBar:SetAllPoints(row)
selectedBar:Hide()
row.selected = selectedBar
local checkMark = row:CreateTexture(nil, "BORDER")
checkMark:SetTexture(CHECKMARK_PATH)
checkMark:SetWidth(CHECKMARK)
checkMark:SetHeight(CHECKMARK)
checkMark:SetPoint("LEFT", row, "LEFT", CHECKMARK_X, 0)
checkMark:Hide()
row.checkMark = checkMark
local text = row:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
text:SetJustifyH("LEFT")
text:SetPoint("LEFT", checkMark, "RIGHT", TEXT_X, 0)
text:SetPoint("RIGHT", row, "RIGHT", TEXT_X2, 0)
row.text = text
row:SetFontString(text)
-- 3.3.5: SetHighlightTexture takes a path and a blend mode, never a texture object, so the
-- highlight cannot be built separately as camelot's XML does.
row:SetHighlightTexture(HOVER_PATH, "ADD")
local hover = row.GetHighlightTexture and row:GetHighlightTexture()
if hover then
hover:SetAllPoints(row)
end
row:SetScript("OnClick", function(self)
if not self.titleId then
return
end
if PlaySound then
PlaySound("igMainMenuOptionCheckBoxOff")
end
if SetCurrentTitle then
SetCurrentTitle(self.titleId)
end
selected = self.titleId
if ForeverUI.TitlesUpdate then
ForeverUI.TitlesUpdate()
end
end)
if rank == 1 then
row:SetPoint("TOPLEFT", panel, "TOPLEFT", MARGIN, LIST_Y)
else
row:SetPoint("TOPLEFT", rows[rank - 1], "BOTTOMLEFT", 0, 0)
end
rows[rank] = row
return row
end
-- How many rows fit in the panel, top margin deducted.
local function fitCount()
local height = (panel and panel:GetHeight()) or 0
if height < 50 then
height = PANE_H - STONE_H
end
local count = math.floor((height + LIST_Y) / ROW_H)
if count < 1 then
count = 1
end
return count
end
-- Stacks rows from the scroll offset down to the panel bottom; returns the count shown.
local function place()
if not panel then
return 0
end
local slots = fitCount()
local total = #titles
if offset > 0 and offset + slots > total then
offset = math.max(0, total - slots)
end
local width = rowWidth()
local placedCount = 0
for rank = 1, slots do
local index = offset + rank
local title = titles[index]
local row = rows[rank] or createRow(rank)
row:SetWidth(width)
if title then
row.titleId = title.id
row.text:SetText(title.name)
applyChoice(row, title.id == selected)
ForeverUI.SetAtlas(row.background,
(index % 2 == 1) and ATLAS_DARK_BACKGROUND or ATLAS_LIGHT_BACKGROUND,
true)
row:Show()
placedCount = placedCount + 1
else
row.titleId = nil
row:Hide()
end
end
for rank = slots + 1, #rows do
rows[rank]:Hide()
end
return placedCount
end
-- The client's title drop-down is hidden on every pass: PlayerTitleFrame_UpdateTitles shows
-- it again (PlayerTitleFrame:Show()) whenever a title changes.
local CLIENT_MENU = { "PlayerTitleFrame", "PlayerTitlePickerFrame" }
local function suppressClientMenu()
for _, name in ipairs(CLIENT_MENU) do
local frame = _G[name]
if frame then
frame:Hide()
if frame.EnableMouse then
frame:EnableMouse(false)
end
end
end
end
local function update()
suppressClientMenu()
if not panel then
return
end
titles = readTitles()
selected = wornTitle()
place()
end
ForeverUI.TitlesUpdate = update
-- ---------- Construction
-- Builds the pane once. host: the character sheet's right pane (host.stone: its stone band).
local function build(host)
if panel then
return panel, {}
end
-- EquipmentManagerPane's anchor: stone bottom to pane bottom (see the file header).
panel = CreateFrame("Frame", "ForeverUITitlesPane", host)
if host.stone then
panel:SetPoint("TOPLEFT", host.stone, "BOTTOMLEFT", 0, 0)
else
panel:SetPoint("TOPLEFT", host, "TOPLEFT", 0, 0)
end
panel:SetPoint("BOTTOMRIGHT", host, "BOTTOMRIGHT", 0, 0)
panel:EnableMouseWheel(true)
panel:SetScript("OnMouseWheel", function(_self, direction)
offset = math.max(0, math.min(offset - direction, #titles - fitCount()))
place()
end)
update()
return panel, {}
end
ForeverUI.TitlesPane = { Build = build, Update = update }
-- The client rebuilds its list in PlayerTitleFrame_UpdateTitles: run after it to refresh
-- ours and hide its own.
if hooksecurefunc and type(_G["PlayerTitleFrame_UpdateTitles"]) == "function" then
hooksecurefunc("PlayerTitleFrame_UpdateTitles", function()
update()
end)
end
-- KNOWN_TITLES_UPDATE: a title is earned; UNIT_NAME_UPDATE on the player: the worn title
-- changes. camelot listens to these same two events.
local listener = CreateFrame("Frame")
listener:RegisterEvent("KNOWN_TITLES_UPDATE")
listener:RegisterEvent("UNIT_NAME_UPDATE")
listener:SetScript("OnEvent", function(_self, event, unit)
if event == "UNIT_NAME_UPDATE" and unit ~= "player" then
return
end
update()
end)
-- Debug report: /fui titles.
function ForeverUI.TitlesDebug()
local say = function(t)
DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffForeverUI|r " .. t)
end
local list = readTitles()
say(string.format(L.TITLES_DEBUG_SUMMARY, #list - 1, tostring(wornTitle()),
offset, panel and fitCount() or 0))
local names = {}
for index = 1, math.min(#list, 8) do
names[#names + 1] = string.format("%s(%d)", list[index].name,
list[index].id)
end
say(" " .. table.concat(names, ", "))
for _, name in ipairs(CLIENT_MENU) do
local frame = _G[name]
say(string.format(" %s : %s", name,
frame and (frame:IsShown() and L.TITLES_DEBUG_VISIBLE or L.TITLES_DEBUG_HIDDEN)
or L.TITLES_DEBUG_ABSENT))
end
end