4628f3b4fb
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
274 lines
11 KiB
Lua
274 lines
11 KiB
Lua
-- ForeverUI : la page "Who" de la fenetre Social (onglet 2 du client).
|
|
--
|
|
-- La page reprend WotLK (FriendsFrame.lua et .xml du client, WhoList_Update
|
|
-- et WhoFrame) -- saisie, totaux, boutons -- habille comme le reste de la
|
|
-- fenetre. LA LISTE DES JOUEURS est celle de camelot (2026-09-26, demande de
|
|
-- l'utilisateur) : camelot range son "Qui" dans le chercheur de groupe
|
|
-- (blizzard_groupfinder_vanillastyle, charge par [Family]\WhoList.xml),
|
|
-- LFGWhoListFrame.
|
|
--
|
|
-- RELEVE camelot (wholist.xml et .lua) :
|
|
-- carte LFGWhoListButtonTemplate, 69 de haut, large comme la liste ;
|
|
-- fond common-button-list-large, choisie
|
|
-- common-button-list-large-selected, survol
|
|
-- common-button-list-large-hover en ADD ; pas d'ecart entre les
|
|
-- cartes ; pas d'en-tetes de colonnes, pas de tri. Les trois
|
|
-- images en NEUF TRANCHES, coins de 9 (mesures sur l'art 169 x 69) :
|
|
-- etirees d'un bloc, leurs angles se deformaient (2026-09-26)
|
|
-- textes GameFontNormalMed1 (SystemFont_Med2, ombre 1,-1, or) :
|
|
-- ligne 1 le nom (10, -6) jusqu'au bord droit ; ligne 2, 6 plus
|
|
-- bas, LFG_WHO_LEVEL, la race (+10), la classe (+10, teinte
|
|
-- RAID_CLASS_COLORS) en blanc ; ligne 3, 6 plus bas, la colonne
|
|
-- variable -- whoSortValue = 1 : la zone -- puis la guilde (+10)
|
|
-- en FRIENDS_GRAY_COLOR
|
|
-- clics gauche : la selection, un second clic la retire ; droit :
|
|
-- FriendsFrame_ShowDropdown(nom, 1)
|
|
-- infobulle si le nom, le niveau ou la colonne variable sont coupes : le
|
|
-- nom, WHO_LIST_LEVEL_TOOLTIP, la colonne variable
|
|
--
|
|
-- ECARTS : 3.3.5 n'a ni GameFontNormalMed1 (on en tire une de SystemFont_Med2,
|
|
-- qu'il a), ni LFG_WHO_LEVEL / WHO_LIST_LEVEL_TOOLTIP (UNIT_LEVEL_TEMPLATE,
|
|
-- "Level %d", dans la langue du client), ni IsTruncated (la largeur du texte
|
|
-- comparee a celle du champ). Les lignes 1 a 3 sont posees a hauteur fixe,
|
|
-- la classe et la guilde bornees au bord droit a la hauteur de leur ligne.
|
|
--
|
|
-- RELEVE WotLK (ce qui entoure la liste) :
|
|
-- donnees numWhos, totalCount = GetNumWhoResults() ;
|
|
-- name, guild, level, race, class, zone, classFileName =
|
|
-- GetWhoInfo(i) ; SendWho(texte)
|
|
-- totaux format(WHO_FRAME_TOTAL_TEMPLATE, total), suivi de
|
|
-- format(WHO_FRAME_SHOWN_TEMPLATE, 50) au-dela de
|
|
-- MAX_WHOS_FROM_SERVER
|
|
-- saisie Entree : SendWho(texte), puis la saisie perd le focus
|
|
-- boutons REFRESH (85) : SendWho(texte), plus de selection ; ADD_FRIEND
|
|
-- (120) : AddFriend(nom) ; GROUP_INVITE (120) : InviteUnit(nom) ;
|
|
-- les deux derniers eteints sans selection
|
|
-- ecran SetWhoToUI(1) a l'affichage de WhoFrame, 0 au masquage : les
|
|
-- resultats d'un /who viennent dans la fenetre, pas dans le chat
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
local S = ForeverUI.Social
|
|
if not S or not S.inscrirePage then
|
|
return
|
|
end
|
|
|
|
local W = {}
|
|
S.Who = W
|
|
|
|
local P = {
|
|
encadreX1 = 4, encadreY1 = -60, encadreX2 = -6, encadreY2 = 74,
|
|
listeX = 4, listeY = -4, listeX2 = -22, listeX2Seule = -4, listeBas = 4,
|
|
carteH = 69, coin = 9, texteH = 13, texteX = 10, texteY = -6, ecartLigne = 6, ecartMot = 10,
|
|
fond = "common-button-list-large",
|
|
choisie = "common-button-list-large-selected",
|
|
survol = "common-button-list-large-hover",
|
|
totauxY = 58, saisieY = 30, saisieH = 20, saisieX = 12,
|
|
boutonBas = 4, boutonDroite = -6, refreshL = 85, boutonL = 120,
|
|
}
|
|
|
|
local txt = S.txt
|
|
|
|
local function actif(b, oui)
|
|
if b.Activer then b:Activer(oui) elseif oui then b:Enable() else b:Disable() end
|
|
end
|
|
|
|
-- GameFontNormalMed1 de camelot, tiree de SystemFont_Med2
|
|
local function police()
|
|
if W.police then return W.police end
|
|
local f = CreateFont("ForeverUIFontNormalMed1")
|
|
f:SetFontObject(SystemFont_Med2)
|
|
f:SetShadowOffset(1, -1)
|
|
f:SetShadowColor(0, 0, 0)
|
|
f:SetTextColor(1, 0.82, 0)
|
|
W.police = f
|
|
return f
|
|
end
|
|
|
|
-- IsTruncated, que 3.3.5 n'a pas : un champ de largeur fixee trop etroit
|
|
local function tronque(fs)
|
|
local l = fs:GetWidth()
|
|
return l and l > 0 and fs:GetStringWidth() > l + 0.5
|
|
end
|
|
|
|
local function niveauTexte(niveau)
|
|
return string.format(txt("UNIT_LEVEL_TEMPLATE"), niveau or 0)
|
|
end
|
|
|
|
function W.maj()
|
|
if not W.liste then return end
|
|
local nombre, total = GetNumWhoResults()
|
|
nombre, total = nombre or 0, total or 0
|
|
local shown = ""
|
|
if total > (MAX_WHOS_FROM_SERVER or 50) then
|
|
shown = string.format(txt("WHO_FRAME_SHOWN_TEMPLATE"), MAX_WHOS_FROM_SERVER or 50)
|
|
end
|
|
W.totaux:SetText(string.format(txt("WHO_FRAME_TOTAL_TEMPLATE"), total) .. " " .. shown)
|
|
if W.choisi and W.choisi > nombre then W.choisi = nil end
|
|
W.nomChoisi = W.choisi and GetWhoInfo(W.choisi) or nil
|
|
actif(W.ajouter, W.choisi ~= nil)
|
|
actif(W.inviter, W.choisi ~= nil)
|
|
W.liste:Maj(nombre)
|
|
end
|
|
|
|
-- -------------------------------------------------------------- les cartes
|
|
|
|
local function montrer(tranches, oui)
|
|
for _, t in ipairs(tranches) do
|
|
if oui then t:Show() else t:Hide() end
|
|
end
|
|
end
|
|
|
|
local function creerCarte(l)
|
|
l:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
local bords = { 0, 0, 0, 0 }
|
|
l.fond = ForeverUI.CreateNineSlice(l, P.fond, P.coin, bords, "BACKGROUND") or {}
|
|
l.choisie = ForeverUI.CreateNineSlice(l, P.choisie, P.coin, bords, "BORDER") or {}
|
|
montrer(l.choisie, false)
|
|
-- le survol : la couche HIGHLIGHT, que le bouton montre sous la souris
|
|
l.survol = ForeverUI.CreateNineSlice(l, P.survol, P.coin, bords, "HIGHLIGHT") or {}
|
|
for _, t in ipairs(l.survol) do t:SetBlendMode("ADD") end
|
|
|
|
local blanc = HIGHLIGHT_FONT_COLOR or { r = 1, g = 1, b = 1 }
|
|
local gris = FRIENDS_GRAY_COLOR or { r = 0.486, g = 0.518, b = 0.541 }
|
|
local function texte(couleur)
|
|
local fs = l:CreateFontString(nil, "ARTWORK")
|
|
fs:SetFontObject(police())
|
|
fs:SetJustifyH("LEFT")
|
|
fs:SetHeight(P.texteH)
|
|
if couleur then fs:SetTextColor(couleur.r, couleur.g, couleur.b) end
|
|
return fs
|
|
end
|
|
-- les centres des lignes 2 et 3, pour borner la classe et la guilde
|
|
local y2 = P.texteY - P.texteH - P.ecartLigne
|
|
local y3 = y2 - P.texteH - P.ecartLigne
|
|
l.nom = texte()
|
|
l.nom:SetPoint("TOPLEFT", l, "TOPLEFT", P.texteX, P.texteY)
|
|
l.nom:SetPoint("TOPRIGHT", l, "TOPRIGHT", 0, P.texteY)
|
|
l.niveau = texte(blanc)
|
|
l.niveau:SetPoint("TOPLEFT", l.nom, "BOTTOMLEFT", 0, -P.ecartLigne)
|
|
l.race = texte(blanc)
|
|
l.race:SetPoint("LEFT", l.niveau, "RIGHT", P.ecartMot, 0)
|
|
l.classe = texte(blanc)
|
|
l.classe:SetPoint("LEFT", l.race, "RIGHT", P.ecartMot, 0)
|
|
l.classe:SetPoint("RIGHT", l, "TOPRIGHT", 0, y2 - P.texteH / 2)
|
|
l.variable = texte(gris)
|
|
l.variable:SetPoint("TOPLEFT", l.niveau, "BOTTOMLEFT", 0, -P.ecartLigne)
|
|
l.guilde = texte(gris)
|
|
l.guilde:SetPoint("LEFT", l.variable, "RIGHT", P.ecartMot, 0)
|
|
l.guilde:SetPoint("RIGHT", l, "TOPRIGHT", 0, y3 - P.texteH / 2)
|
|
|
|
l:SetScript("OnClick", function(self, bouton)
|
|
if bouton == "LeftButton" then
|
|
if W.choisi == self.index then W.choisi = nil else W.choisi = self.index end
|
|
W.maj()
|
|
else
|
|
FriendsFrame_ShowDropdown(GetWhoInfo(self.index), 1)
|
|
end
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
end)
|
|
l:SetScript("OnEnter", function(self)
|
|
if self.bulle then
|
|
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
|
|
GameTooltip:SetText(self.bulle[1])
|
|
GameTooltip:AddLine(self.bulle[2], 1, 1, 1)
|
|
GameTooltip:AddLine(self.bulle[3], 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end
|
|
end)
|
|
l:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
end
|
|
|
|
-- LFGWhoListButtonMixin:InitButton
|
|
local function remplirCarte(l, index)
|
|
local nom, guilde, niveau, race, classe, zone, fichier = GetWhoInfo(index)
|
|
local c = fichier and RAID_CLASS_COLORS and RAID_CLASS_COLORS[fichier] or HIGHLIGHT_FONT_COLOR
|
|
l.nom:SetText(nom)
|
|
l.niveau:SetText(niveauTexte(niveau))
|
|
l.race:SetText(race)
|
|
l.classe:SetText(classe)
|
|
l.classe:SetTextColor(c.r, c.g, c.b)
|
|
l.variable:SetText(zone)
|
|
l.guilde:SetText(guilde)
|
|
montrer(l.choisie, W.choisi == index)
|
|
if tronque(l.variable) or tronque(l.niveau) or tronque(l.nom) then
|
|
l.bulle = { nom, niveauTexte(niveau), zone }
|
|
else
|
|
l.bulle = nil
|
|
end
|
|
end
|
|
|
|
local function construire(cadre)
|
|
local encadre = ForeverUI.CreateInset(cadre, "ForeverUIWhoInset")
|
|
encadre:SetPoint("TOPLEFT", S.cadre, "TOPLEFT", P.encadreX1, P.encadreY1)
|
|
encadre:SetPoint("BOTTOMRIGHT", S.cadre, "BOTTOMRIGHT", P.encadreX2, P.encadreY2)
|
|
|
|
W.liste = S.creerListe(encadre, "ForeverUIWhoList", P.carteH, creerCarte, remplirCarte)
|
|
W.liste:SuivreBarre({ "TOPLEFT", encadre, "TOPLEFT", P.listeX, P.listeY },
|
|
{ "BOTTOMRIGHT", encadre, "BOTTOMRIGHT", P.listeX2, P.listeBas }, P.listeX2Seule)
|
|
|
|
W.totaux = cadre:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
|
W.totaux:SetPoint("BOTTOM", S.cadre, "BOTTOM", 0, P.totauxY)
|
|
|
|
-- LA SAISIE : le champ de camelot (InputBoxVisualTemplate), comme la
|
|
-- recherche du grimoire
|
|
local b = CreateFrame("EditBox", "ForeverUIWhoEditBox", cadre)
|
|
b:SetAutoFocus(false)
|
|
b:SetHeight(P.saisieH)
|
|
b:SetPoint("BOTTOMLEFT", S.cadre, "BOTTOMLEFT", P.saisieX, P.saisieY)
|
|
b:SetPoint("BOTTOMRIGHT", S.cadre, "BOTTOMRIGHT", -P.saisieX, P.saisieY)
|
|
b:SetFontObject(ChatFontNormal or GameFontHighlightSmall)
|
|
b:SetTextInsets(6, 6, 0, 0)
|
|
local g = b:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(g, "common-search-border-left", true)
|
|
g:SetWidth(8) g:SetHeight(20)
|
|
g:SetPoint("LEFT", b, "LEFT", -5, 0)
|
|
local d = b:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(d, "common-search-border-right", true)
|
|
d:SetWidth(8) d:SetHeight(20)
|
|
d:SetPoint("RIGHT", b, "RIGHT", 0, 0)
|
|
local m = b:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(m, "common-search-border-middle", true)
|
|
m:SetHeight(20)
|
|
m:SetPoint("LEFT", g, "RIGHT", 0, 0)
|
|
m:SetPoint("RIGHT", d, "LEFT", 0, 0)
|
|
b:SetScript("OnEnterPressed", function(self)
|
|
SendWho(self:GetText())
|
|
self:ClearFocus()
|
|
end)
|
|
b:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
W.saisie = b
|
|
|
|
W.inviter = S.bouton(cadre, txt("GROUP_INVITE"), P.boutonL)
|
|
W.inviter:SetPoint("BOTTOMRIGHT", S.cadre, "BOTTOMRIGHT", P.boutonDroite, P.boutonBas)
|
|
W.inviter:SetScript("OnClick", function()
|
|
if W.nomChoisi then InviteUnit(W.nomChoisi) end
|
|
end)
|
|
W.ajouter = S.bouton(cadre, txt("ADD_FRIEND"), P.boutonL)
|
|
W.ajouter:SetPoint("RIGHT", W.inviter, "LEFT", 0, 0)
|
|
W.ajouter:SetScript("OnClick", function()
|
|
if W.nomChoisi then AddFriend(W.nomChoisi) end
|
|
end)
|
|
W.rafraichir = S.bouton(cadre, txt("REFRESH"), P.refreshL)
|
|
W.rafraichir:SetPoint("RIGHT", W.ajouter, "LEFT", 0, 0)
|
|
W.rafraichir:SetScript("OnClick", function()
|
|
SendWho(W.saisie:GetText())
|
|
W.choisi = nil
|
|
end)
|
|
end
|
|
|
|
S.inscrirePage(2, {
|
|
construire = construire,
|
|
titre = function() return txt("WHO_LIST") end,
|
|
maj = W.maj,
|
|
-- WhoFrame OnShow / OnHide
|
|
montrer = function() SetWhoToUI(1) end,
|
|
cacher = function() SetWhoToUI(0) end,
|
|
})
|
|
|
|
local veilleur = CreateFrame("Frame")
|
|
veilleur:RegisterEvent("WHO_LIST_UPDATE")
|
|
veilleur:SetScript("OnEvent", function()
|
|
if W.liste and W.liste:IsVisible() then W.maj() end
|
|
end)
|