eb681aa9cd
- socle : Textes.lua (ForeverUI.L) et ForeverUIGlueTextes.lua (G.L) ; les textes dans Textes_enUS / Textes_frFR (325 cles en jeu) et ForeverUIGlueTextes_enUS / _frFR (41 cles aux ecrans d'accueil) ; une cle absente prend l'anglais, une langue sans fichier lit l'anglais ; ajouter une langue = un fichier de plus - les textes que le client 3.3.5 connait se lisent dans ses globales (GlobalStrings, GlueStrings en glue) ; les textes de secours sont retires - tous les fichiers repris : libelles, infobulles, mode edition, messages et aide de /fui, erreurs internes ; .toc : Notes + Notes-frFR - selection des personnages : race et classe traduites ramenees a leur jeton par les tables de langue (GetAvailableRaces / GetAvailableClasses font planter le client hors de la creation) - tools/cartes_instances.py : noms des instances dans toutes les langues de la LibBabble-Zone de WDM (portails de la carte sur tout client) - banc : toute cle employee existe en anglais et en francais, memes cles dans les deux, bascule frFR / deDE essayee ; chaines 3.3.5 ajoutees au faux client - README : etat des sections mis a jour, langues, glue, deploiement --glue Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1578 lines
59 KiB
Lua
1578 lines
59 KiB
Lua
-- ForeverUI : le chercheur de donjon de WotLK, a la DA du chercheur de groupe
|
|
-- de camelot, dans une fenetre deplacable (demande de l'utilisateur,
|
|
-- 2026-09-26 ; memoire foreverui-chercheur).
|
|
--
|
|
-- CAMELOT N'A PAS DE CHERCHEUR DE DONJON : blizzard_groupfinder.toc porte
|
|
-- ExcludeLoadGameType camelot. Il charge a la place
|
|
-- Blizzard_GroupFinder_VanillaStyle (LFGParentFrame), qui liste des groupes.
|
|
-- DECISION DE L'UTILISATEUR : la file de WotLK et ses donnees, presentees
|
|
-- comme le LFGParentFrame de camelot ; le navigateur de raid en onglet
|
|
-- lateral de la meme fenetre (etape 2).
|
|
--
|
|
-- RELEVE -- blizzard_groupfinder_vanillastyle/mainline (charge par [Family]) :
|
|
-- blizzard_lfgvanilla_parentframe.xml, blizzard_lfgvanilla_listing.xml/.lua,
|
|
-- lfgvanilla_constants.lua ; blizzard_sharedxml (PortraitFrameTemplate,
|
|
-- InsetFrameTemplate, LargeSideTabButtonTemplate, camelot/nineslicelayout
|
|
-- overrides) ; sharedutils.lua (GetTexCoordsForRole,
|
|
-- GetBackgroundTexCoordsForRole) :
|
|
-- fenetre 458 x 535 ; roche (2,-21 / -2,2), stries (6,-21 / -2,-21),
|
|
-- metal du cadre a portrait (coins -13,16 / 2,16 / -13,-8 /
|
|
-- 2,-8) ; portrait groupfinder-eye-frame 62 x 62 a (-5, 7) ;
|
|
-- titre LFG_TITLE, bande (58,-1 / -24,-1), texte TOP (0,-5) ;
|
|
-- croix TOPRIGHT (0, 0)
|
|
-- roles bandeau UI-LFG-BlueBG de (2,-25) au TOPRIGHT (248,-169),
|
|
-- etire, sans TexCoords ; boutons 64 x 64 a y -41 : tank
|
|
-- x 70, soigneur x 174, degats x 278, le quatrieme (celui du
|
|
-- nouveau venu, ici le CHEF de WotLK) TOPRIGHT (-20,-41) ; fond
|
|
-- UI-LFG-ICONS-ROLEBACKGROUNDS 80 x 80 centre (alpha 0,6 / 0,4
|
|
-- / 0,6), icone UI-LFG-ICON-ROLES, voile (0,5) quand le role
|
|
-- est refuse ; case UI-CheckBox 24 x 24 a BOTTOMLEFT (-5,-5)
|
|
-- encadre (4,-118 / -4,37), sans marbre ; groupfinder-background de
|
|
-- (3,-3) a (-3,3), TexCoords top 0,093
|
|
-- categories (8,-124 / -8,40) ; boutons 380 x 60, le premier a TOP
|
|
-- (0,-20), pas de 68 [RESSERRES, voir plus bas] ; image
|
|
-- groupfinder-button-* (5,-8 /
|
|
-- -5,5), couvercle groupfinder-button-cover, selection et
|
|
-- surbrillance PvPMegaQueue 366 x 48 en ADD, texte
|
|
-- GameFontNormalLarge a LEFT (20, 0)
|
|
-- liste (7,-125 / -7,40), marge 4, lignes de 22 ; barre a droite
|
|
-- (liste a -28 avec, 0 sans) ; ligne : +/- 16 x 16 a LEFT,
|
|
-- case 30 x 30 a sa droite (+4), nom, niveau 60 x 22 a RIGHT ;
|
|
-- en-tete gris 0,7, entree or, trop facile gris 0,5, trop dur
|
|
-- orange (1, 0,5, 0,25)
|
|
-- boutons Back 111 x 28 BOTTOMLEFT (4,6), Post 109 x 28 BOTTOMRIGHT
|
|
-- (-4,6)
|
|
-- onglets LargeSideTabButtonTemplate 55 x 55 a TOPLEFT sur TOPRIGHT
|
|
-- (0,-60), les suivants 2 plus bas ; icone INV_Helmet_08 pour
|
|
-- le premier
|
|
--
|
|
-- CE QUI VIENT DE WotLK (LFDFrame.lua, LFGFrame.lua) : TOUT ce qui est donnee
|
|
-- ou action. Le panneau LFDParentFrame reste celui du client -- le
|
|
-- micro-bouton, /lfd, la touche, l'oeil de la minimap, Echap et la
|
|
-- conversation d'un PNJ l'ouvrent et le ferment comme avant. Son contenu
|
|
-- (LFDQueueFrame) reste affiche mais transparent, SOUS notre fenetre : toute
|
|
-- sa logique tourne donc comme prevu (demandes de verrous a l'ouverture,
|
|
-- listes filtrees, bouton de recherche, attente, reprise de groupe). Notre
|
|
-- fenetre en lit l'etat apres chacune de ses mises a jour, et agit par ses
|
|
-- fonctions : LFDQueueFrame_SetType, les cases et les +/- de la liste, les
|
|
-- cases de role, le bouton de recherche.
|
|
--
|
|
-- CORRESPONDANCES (camelot -> WotLK) :
|
|
-- categories le menu "Type" de WotLK : un bouton par donjon aleatoire
|
|
-- affichable, puis "Specific Dungeons" (meme ordre, memes
|
|
-- refus et meme infobulle) ; le bouton du type choisi porte
|
|
-- la selection
|
|
-- liste la liste des donjons specifiques (en-tetes, +/-, cases a
|
|
-- trois etats, verrous)
|
|
-- details le texte et les recompenses du donjon aleatoire choisi
|
|
-- (texte, recompenses, argent, experience) -- camelot n'en a
|
|
-- pas : sous les categories, aux polices de camelot
|
|
-- Back retour aux categories, visible dans la liste seulement ; Post -> le bouton
|
|
-- de recherche du client (Find Group / Join as Party / Leave
|
|
-- Queue)
|
|
-- voiles l'attente et la desertion, la reprise d'un groupe, "pas de
|
|
-- donjon pendant le raid" : ceux de WotLK, sur ce qui suit le
|
|
-- choix du type, comme chez WotLK ou le menu "Type" restait
|
|
-- accessible -- les details, ou toute la liste
|
|
--
|
|
-- DEMANDE DE L'UTILISATEUR (2026-09-26, apres la premiere livraison) : les
|
|
-- boutons resserres vers le haut (premier a 6 sous le haut de la zone, pas
|
|
-- de 62 au lieu de 68), un separateur dessous (le filet de camelot,
|
|
-- shop-list-rule), et sous le separateur le texte et les recompenses du
|
|
-- bouton choisi. Choisir un donjon aleatoire reste sur la page ; seul
|
|
-- "Specific Dungeons" ouvre la liste.
|
|
-- PUIS (meme jour) : boutons encore resserres et amincis -- 380 x 40 au
|
|
-- lieu de 60, colles (pas de 40), le premier a 4 sous le haut de la zone ;
|
|
-- l'image, la selection et la surbrillance suivent la meme proportion
|
|
-- (40 / 60) ; filet et details rapproches, ecarts du texte reduits : le
|
|
-- but est de loger le texte et les recompenses sans barre. La barre reste,
|
|
-- pour le cas qui depasse encore.
|
|
-- PUIS : le filet DESCEND sur le contenu. Les details sont poses en bas de
|
|
-- l'encadre, a leur hauteur, et le filet juste au-dessus ; il ne monte
|
|
-- jamais plus haut que sous le dernier bouton (6 dessous), ou la barre
|
|
-- prend le relais.
|
|
-- PUIS ("un peu trop descendu, le scroller est reapparu") : trois causes
|
|
-- corrigees -- la barre comptait en crans arrondis (contenu vers le haut,
|
|
-- zone vers le bas) et apparaissait des qu'une hauteur n'etait pas un
|
|
-- multiple de 20 ; la zone visible etait lue par GetHeight juste apres le
|
|
-- reancrage, ou le client peut encore rendre l'ancienne ; la hauteur d'un
|
|
-- texte replie peut etre sous-estimee a la premiere mesure. Desormais : la
|
|
-- zone visible se calcule d'apres nos propres ecarts, 6 d'air au-dessus du
|
|
-- contenu, une tolerance de 2, et une seconde mesure a l'image suivante (du
|
|
-- haut du contenu au bas de sa derniere piece) qui replace le filet si la
|
|
-- premiere etait courte.
|
|
-- PUIS : les boutons s'epaississent LEGEREMENT, de 40 a 46 -- la hauteur
|
|
-- propre de groupfinder-button-cover, sans etirement vertical -- toujours
|
|
-- colles (pas de 46) ; image, selection et surbrillance au prorata (46 /
|
|
-- 60). Le filet et les details ne bougent pas : poses sur le contenu.
|
|
-- PUIS : les details prennent le decalage des boutons -- 380 de large,
|
|
-- centres dans la zone de 442 qui part a 8 : leur bord gauche tombe a
|
|
-- 8 + (442 - 380) / 2 = 39, le droit a 39 du bord droit. La barre, si elle
|
|
-- vient, se pose 5 a droite.
|
|
-- PUIS ("un peu plus") : le bord gauche avance de 6, a 45 ; le droit reste.
|
|
-- PUIS : l'argent devient une case comme les objets -- l'icone de pieces
|
|
-- de WotLK (inv_misc_coin_02, celle de sa fenetre "donjon pret") et le
|
|
-- montant dans le cadre de nom, a la place suivante de la grille.
|
|
-- PUIS : filet et details remontes de 5 -- le bas des details passe de 45
|
|
-- a 50 au-dessus du bas de la fenetre.
|
|
-- PUIS : boutons epaissis de 2, a 48 (pas de 48, selection 38 = 48 x 48 / 60).
|
|
--
|
|
-- ETAPE 2 (2026-09-26) : le navigateur de raid, dans GroupFinderRaid.lua. Deux
|
|
-- onglets lateraux (demande de l'utilisateur, apres un premier essai a trois) :
|
|
-- donjons (INV_Helmet_08) et "Raid Browser" (Achievement_General_StayClassy),
|
|
-- une seule page a deux sections retractables. Les deux
|
|
-- panneaux du client restent les portes d'entree : LFDParentFrame pour le
|
|
-- premier onglet, LFRParentFrame pour le second. Notre fenetre -- la notre, pas un cadre du client -- passe de
|
|
-- l'un a l'autre (F.attacher) ; un seul des deux est ouvert a la fois. Les
|
|
-- lignes de liste, le bandeau des roles et l'encadre sont communs aux pages.
|
|
-- PUIS ("encore") : 2 de plus, a 50 (pas de 50, selection 40).
|
|
--
|
|
-- ECARTS SIGNALES : pas de bouton d'options (camelot en a un, rien a y
|
|
-- mettre) ; pas de commentaire ni de filet shop-list-rule sous la liste des
|
|
-- donjons (WotLK n'a pas de commentaire pour les donjons : la liste descend
|
|
-- jusqu'en bas) ; le verrou de WotLK (UI-LFG-ICON-LOCK) prend la place de la
|
|
-- case d'un donjon interdit ; pas d'icone heroique sur les en-tetes (leur
|
|
-- nom le dit).
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
|
|
local F = {}
|
|
ForeverUI.GroupFinder = F
|
|
|
|
local SEP = string.char(92)
|
|
local L = ForeverUI.L
|
|
local LFG = "Interface" .. SEP .. "LFGFrame" .. SEP
|
|
local BOUTONS = "Interface" .. SEP .. "Buttons" .. SEP
|
|
|
|
-- une table : Lua 5.1 limite a 60 les valeurs capturees par une fonction
|
|
local G = {
|
|
largeur = 458, hauteur = 535,
|
|
roche = "interface" .. SEP .. "ForeverUI" .. SEP .. "framegeneral" .. SEP .. "ui-background-rock",
|
|
portraitCote = 62, portraitX = -5, portraitY = 7,
|
|
titreX1 = 58, titreX2 = -24, titreY = -1, titreH = 20, titreTexteY = -5,
|
|
croix = 24, croixX = 0, croixY = 0,
|
|
bleu = "interface" .. SEP .. "ForeverUI" .. SEP .. "lfgframe" .. SEP .. "ui-lfg-bluebg",
|
|
bleuX1 = 2, bleuY1 = -25, bleuX2 = 248, bleuY2 = -169,
|
|
role = 64, roleY = -41, roleFond = 80, caseRole = 24, caseRoleX = -5, caseRoleY = -5,
|
|
roleIcones = LFG .. "UI-LFG-ICON-ROLES",
|
|
roleFonds = LFG .. "UI-LFG-ICONS-ROLEBACKGROUNDS",
|
|
encadreX1 = 4, encadreY1 = -118, encadreX2 = -4, encadreY2 = 37,
|
|
fondHaut = 0.093,
|
|
catX1 = 8, catY1 = -124, catX2 = -8, catY2 = 40, catPremier = -4, catPas = 50,
|
|
-- le filet sous les boutons, puis les details
|
|
regleEcart = 6, regleH = 16, detailsEcart = 6, detailsAir = 6, tolerance = 2, detailsX1 = 45, detailsX2 = -39, detailsBas = 50,
|
|
cran = 20,
|
|
catL = 380, catH = 50, catSelL = 366, catSelH = 40,
|
|
-- l'image dans le bouton : (5,-8 / -5,5) de camelot, ramenes a 50 de haut
|
|
catImageHaut = -6, catImageBas = 4,
|
|
mega = "interface" .. SEP .. "ForeverUI" .. SEP .. "pvpframe" .. SEP .. "pvpmegaqueue",
|
|
pieces = "Interface" .. SEP .. "Icons" .. SEP .. "inv_misc_coin_02",
|
|
listeX1 = 7, listeY1 = -125, listeX2 = -7, listeY2 = 40, marge = 4, barreDroite = -28,
|
|
ligne = 22, plus = 16, case = 30, niveauL = 60,
|
|
backL = 111, postL = 109, boutonH = 28, boutonBas = 6, boutonCote = 4,
|
|
onglet = 55, ongletY = -60, ongletEcart = -2, ongletIcone = 50, ongletIconeX = -3, rognage = 0.03125,
|
|
voileL = 330, voileH = 257,
|
|
}
|
|
|
|
-- les coordonnees de sharedutils.lua (GetTexCoordsForRole : 256 x 256,
|
|
-- cases de 67 ; GetBackgroundTexCoordsForRole : 256 x 128, cases de 75)
|
|
local ROLES = {
|
|
{ cle = "tank", client = "LFDQueueFrameRoleButtonTank", id = 2, x = 70, alpha = 0.6,
|
|
icone = { 0, 0.26171875, 0.26171875, 0.5234375 }, fond = { 0.29296875, 0.5859375, 0, 0.5859375 } },
|
|
{ cle = "soin", client = "LFDQueueFrameRoleButtonHealer", id = 3, x = 174, alpha = 0.4,
|
|
icone = { 0.26171875, 0.5234375, 0, 0.26171875 }, fond = { 0, 0.29296875, 0, 0.5859375 } },
|
|
{ cle = "degats", client = "LFDQueueFrameRoleButtonDPS", id = 1, x = 278, alpha = 0.6,
|
|
icone = { 0.26171875, 0.5234375, 0.26171875, 0.5234375 }, fond = { 0.5859375, 0.87890625, 0, 0.5859375 } },
|
|
-- le quatrieme emplacement de camelot (TOPRIGHT -20,-41), sans fond
|
|
{ cle = "chef", client = "LFDQueueFrameRoleButtonLeader", id = 4, droite = -20,
|
|
icone = { 0, 0.26171875, 0, 0.26171875 } },
|
|
}
|
|
local VOILE_ROLE = { 0, 0.2617, 0.5234, 0.7851 }
|
|
|
|
-- les polices de fontstyles.xml (LFGActivityHeader, LFGActivityEntry...)
|
|
local COULEURS = {
|
|
entete = { 0.7, 0.7, 0.7 },
|
|
entree = { 1.0, 0.82, 0 },
|
|
facile = { 0.5, 0.5, 0.5 },
|
|
dur = { 1.0, 0.5, 0.25 },
|
|
}
|
|
|
|
-- l'image d'un bouton de categorie
|
|
local ART = {
|
|
aleatoire = "groupfinder-button-dungeons",
|
|
fete = "groupfinder-button-questing",
|
|
specifique = "groupfinder-button-custom-pve",
|
|
}
|
|
|
|
local function txt(cle)
|
|
return _G[cle] or cle
|
|
end
|
|
|
|
-- 3.3.5 rend 1 ou nil (et le banc 0 ou 1) : on compare
|
|
local function actif(b)
|
|
return b ~= nil and b.IsEnabled ~= nil and b:IsEnabled() == 1
|
|
end
|
|
|
|
-- visible pour de bon : le cadre et ses parents jusqu'au panneau
|
|
local function affiche(c)
|
|
while c do
|
|
if not c:IsShown() then return false end
|
|
if c == LFDParentFrame then return true end
|
|
c = c:GetParent()
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- ------------------------------------------------------------------ le cadre
|
|
|
|
local METAL = {
|
|
{ cle = "hg", nom = "ui-frame-portraitmetal-cornertopleft", point = "TOPLEFT", x = -13, y = 16 },
|
|
{ cle = "hd", nom = "ui-frame-metal-cornertopright", point = "TOPRIGHT", x = 2, y = 16 },
|
|
{ cle = "bg", nom = "ui-frame-metal-cornerbottomleft", point = "BOTTOMLEFT", x = -13, y = -8 },
|
|
{ cle = "bd", nom = "ui-frame-metal-cornerbottomright", point = "BOTTOMRIGHT", x = 2, y = -8 },
|
|
}
|
|
|
|
local function croixRouge(b)
|
|
for _, etat in ipairs({
|
|
{ "SetNormalTexture", "GetNormalTexture", "redbutton-exit" },
|
|
{ "SetPushedTexture", "GetPushedTexture", "redbutton-exit-pressed" },
|
|
{ "SetHighlightTexture", "GetHighlightTexture", "redbutton-highlight" },
|
|
}) do
|
|
local e = ForeverUI.AtlasEntry(etat[3])
|
|
b[etat[1]](b, e and e[1] or "")
|
|
local t = b[etat[2]](b)
|
|
if t then
|
|
ForeverUI.SetAtlas(t, etat[3], true)
|
|
t:ClearAllPoints()
|
|
t:SetAllPoints(b)
|
|
if etat[3] == "redbutton-highlight" then t:SetBlendMode("ADD") end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function construireCadre(f)
|
|
local roche = f:CreateTexture(nil, "BACKGROUND")
|
|
roche:SetTexture(G.roche, true)
|
|
if roche.SetHorizTile then roche:SetHorizTile(true) roche:SetVertTile(true) end
|
|
roche:SetPoint("TOPLEFT", f, "TOPLEFT", 2, -21)
|
|
roche:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -2, 2)
|
|
|
|
local stries = f:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(stries, "_ui-frame-toptilestreaks", true)
|
|
stries:SetHeight(43)
|
|
stries:SetPoint("TOPLEFT", f, "TOPLEFT", 6, -21)
|
|
stries:SetPoint("TOPRIGHT", f, "TOPRIGHT", -2, -21)
|
|
|
|
local metal = CreateFrame("Frame", nil, f)
|
|
metal:SetAllPoints(f)
|
|
metal:SetFrameLevel(f:GetFrameLevel() + 20)
|
|
local p = {}
|
|
for _, coin in ipairs(METAL) do
|
|
local t = metal:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(t, coin.nom)
|
|
t:SetPoint(coin.point, metal, coin.point, coin.x, coin.y)
|
|
p[coin.cle] = t
|
|
end
|
|
local function bord(nom, a1, c1, r1, a2, c2, r2)
|
|
local t = metal:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(t, nom)
|
|
t:SetPoint(a1, c1, r1)
|
|
t:SetPoint(a2, c2, r2)
|
|
end
|
|
bord("_ui-frame-metal-edgetop", "TOPLEFT", p.hg, "TOPRIGHT", "TOPRIGHT", p.hd, "TOPLEFT")
|
|
bord("_ui-frame-metal-edgebottom", "BOTTOMLEFT", p.bg, "BOTTOMRIGHT", "BOTTOMRIGHT", p.bd, "BOTTOMLEFT")
|
|
bord("!ui-frame-metal-edgeleft", "TOPLEFT", p.hg, "BOTTOMLEFT", "BOTTOMLEFT", p.bg, "TOPLEFT")
|
|
bord("!ui-frame-metal-edgeright", "TOPRIGHT", p.hd, "BOTTOMRIGHT", "BOTTOMRIGHT", p.bd, "TOPRIGHT")
|
|
|
|
-- le portrait : l'oeil de camelot (SetPortraitAtlasRaw, 62 x 62)
|
|
local cadrePortrait = CreateFrame("Frame", nil, f)
|
|
cadrePortrait:SetAllPoints(f)
|
|
cadrePortrait:SetFrameLevel(f:GetFrameLevel() + 19)
|
|
local portrait = cadrePortrait:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(portrait, "groupfinder-eye-frame", true)
|
|
portrait:SetWidth(G.portraitCote)
|
|
portrait:SetHeight(G.portraitCote)
|
|
portrait:SetPoint("TOPLEFT", f, "TOPLEFT", G.portraitX, G.portraitY)
|
|
f.portrait = portrait
|
|
|
|
local bandeau = CreateFrame("Frame", nil, f)
|
|
bandeau:SetFrameLevel(f:GetFrameLevel() + 21)
|
|
bandeau:SetHeight(G.titreH)
|
|
bandeau:SetPoint("TOPLEFT", f, "TOPLEFT", G.titreX1, G.titreY)
|
|
bandeau:SetPoint("TOPRIGHT", f, "TOPRIGHT", G.titreX2, G.titreY)
|
|
f.titre = bandeau:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
f.titre:SetPoint("TOP", bandeau, "TOP", 0, G.titreTexteY)
|
|
f.titre:SetText(txt("LFG_TITLE"))
|
|
f.bandeau = bandeau
|
|
|
|
-- LA CROIX : elle ferme le panneau du client qui porte la fenetre, comme
|
|
-- la sienne
|
|
local croix = CreateFrame("Button", "ForeverUIGroupFinderCloseButton", f)
|
|
croix:SetWidth(G.croix)
|
|
croix:SetHeight(G.croix)
|
|
croix:SetFrameLevel(f:GetFrameLevel() + 22)
|
|
croix:SetPoint("TOPRIGHT", f, "TOPRIGHT", G.croixX, G.croixY)
|
|
croixRouge(croix)
|
|
croix:SetScript("OnClick", function() HideUIPanel(F.cadre:GetParent()) end)
|
|
f.croix = croix
|
|
end
|
|
|
|
-- ------------------------------------------------------------ les onglets
|
|
-- LargeSideTabButtonTemplate, comme ceux de la feuille (CharacterFrame.lua) :
|
|
-- fond common-sidetab, icone cuite par tools/cuire_masque.py a 50 x 50 en
|
|
-- (-3, 0) rognee de 0,03125, marqueur common-sidetab-selected, survol
|
|
-- common-sidetab-hover.
|
|
local ICONES = "Interface" .. SEP .. "ForeverUI" .. SEP .. "tabicons" .. SEP
|
|
local ONGLETS = {
|
|
{ cle = "donjons", texte = "LOOKING_FOR_DUNGEON", icone = ICONES .. "inv_helmet_08" },
|
|
-- un seul onglet pour le navigateur de raid (demande du 2026-09-26), a
|
|
-- l'icone de l'ancien onglet de parcours
|
|
{ cle = "raid", texte = "LOOKING_FOR_RAID", raid = true,
|
|
icone = ICONES .. "achievement_general_stayclassy" },
|
|
}
|
|
|
|
local function creerOnglet(f, def, n)
|
|
local o = CreateFrame("Button", "ForeverUIGroupFinderTab" .. n, f)
|
|
o:SetWidth(G.onglet)
|
|
o:SetHeight(G.onglet)
|
|
local fond = o:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(fond, "common-sidetab", true)
|
|
fond:SetAllPoints(o)
|
|
local icone = o:CreateTexture(nil, "ARTWORK")
|
|
icone:SetWidth(G.ongletIcone)
|
|
icone:SetHeight(G.ongletIcone)
|
|
icone:SetPoint("CENTER", o, "CENTER", G.ongletIconeX, 0)
|
|
icone:SetTexCoord(G.rognage, 1 - G.rognage, G.rognage, 1 - G.rognage)
|
|
icone:SetTexture(def.icone)
|
|
o.icone = icone
|
|
local choisi = o:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(choisi, "common-sidetab-selected", true)
|
|
choisi:SetAllPoints(o)
|
|
choisi:Hide()
|
|
o.choisi = choisi
|
|
local survol = o:CreateTexture(nil, "HIGHLIGHT")
|
|
ForeverUI.SetAtlas(survol, "common-sidetab-hover", true)
|
|
survol:SetAllPoints(o)
|
|
o:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT", -4, -4)
|
|
GameTooltip:SetText(txt(def.texte))
|
|
if def.detail then GameTooltip:AddLine(txt(def.detail), 1, 1, 1) end
|
|
GameTooltip:Show()
|
|
end)
|
|
o:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
o:SetScript("OnClick", function()
|
|
PlaySound("igCharacterInfoTab")
|
|
F.allerA(def.cle)
|
|
end)
|
|
o.cle = def.cle
|
|
return o
|
|
end
|
|
|
|
function F.choisirOnglet(cle)
|
|
F.onglet = cle
|
|
for _, o in ipairs(F.onglets or {}) do
|
|
if o.cle == cle then o.choisi:Show() else o.choisi:Hide() end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ les roles
|
|
|
|
local function creerRole(parent, r)
|
|
local b = CreateFrame("Button", "ForeverUIGroupFinderRole" .. (r.page or "") .. r.cle, parent)
|
|
b:SetWidth(G.role)
|
|
b:SetHeight(G.role)
|
|
if r.droite then
|
|
b:SetPoint("TOPRIGHT", F.cadre, "TOPRIGHT", r.droite, G.roleY)
|
|
else
|
|
b:SetPoint("TOPLEFT", F.cadre, "TOPLEFT", r.x, G.roleY)
|
|
end
|
|
if r.fond then
|
|
local fond = b:CreateTexture(nil, "BACKGROUND")
|
|
fond:SetTexture(G.roleFonds)
|
|
fond:SetTexCoord(r.fond[1], r.fond[2], r.fond[3], r.fond[4])
|
|
fond:SetWidth(G.roleFond)
|
|
fond:SetHeight(G.roleFond)
|
|
fond:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
fond:SetAlpha(r.alpha)
|
|
b.fond = fond
|
|
end
|
|
local icone = b:CreateTexture(nil, "ARTWORK")
|
|
icone:SetTexture(G.roleIcones)
|
|
icone:SetTexCoord(r.icone[1], r.icone[2], r.icone[3], r.icone[4])
|
|
icone:SetAllPoints(b)
|
|
b.icone = icone
|
|
local voile = b:CreateTexture(nil, "OVERLAY")
|
|
voile:SetTexture(G.roleIcones)
|
|
voile:SetTexCoord(VOILE_ROLE[1], VOILE_ROLE[2], VOILE_ROLE[3], VOILE_ROLE[4])
|
|
voile:SetAllPoints(b)
|
|
voile:SetAlpha(0.5)
|
|
voile:Hide()
|
|
b.voile = voile
|
|
|
|
local c = CreateFrame("CheckButton", "ForeverUIGroupFinderRole" .. (r.page or "") .. r.cle .. "Check", b)
|
|
c:SetWidth(G.caseRole)
|
|
c:SetHeight(G.caseRole)
|
|
c:SetPoint("BOTTOMLEFT", b, "BOTTOMLEFT", G.caseRoleX, G.caseRoleY)
|
|
c:SetNormalTexture(BOUTONS .. "UI-CheckBox-Up")
|
|
c:SetPushedTexture(BOUTONS .. "UI-CheckBox-Down")
|
|
c:SetHighlightTexture(BOUTONS .. "UI-CheckBox-Highlight")
|
|
local s = c:GetHighlightTexture()
|
|
if s then s:SetBlendMode("ADD") end
|
|
c:SetCheckedTexture(BOUTONS .. "UI-CheckBox-Check")
|
|
c:SetDisabledCheckedTexture(BOUTONS .. "UI-CheckBox-Check-Disabled")
|
|
b.case = c
|
|
|
|
-- LA CASE DU CLIENT FAIT LE TRAVAIL : son Click la bascule et joue son
|
|
-- OnClick (son, LFDQueueFrame_SetRoles). La notre suit ensuite.
|
|
c:SetScript("OnClick", function(self)
|
|
local client = _G[r.client]
|
|
self:SetChecked(not self:GetChecked())
|
|
if client and client.checkButton and actif(client.checkButton) then
|
|
client.checkButton:Click()
|
|
end
|
|
F.majRoles()
|
|
end)
|
|
b:SetScript("OnClick", function()
|
|
if actif(c) then c:Click() end
|
|
end)
|
|
b:SetScript("OnEnter", function(self)
|
|
local client = _G[r.client]
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
if r.cle == "chef" then
|
|
GameTooltip:SetText(txt("GUIDE_TOOLTIP"), nil, nil, nil, nil, 1)
|
|
else
|
|
GameTooltip:SetText(txt("ROLE_DESCRIPTION" .. r.id), nil, nil, nil, nil, 1)
|
|
if client and client.permDisabled then
|
|
local rouge = RED_FONT_COLOR or { r = 1, g = 0.1, b = 0.1 }
|
|
GameTooltip:AddLine(txt("YOUR_CLASS_MAY_NOT_PERFORM_ROLE"), rouge.r, rouge.g, rouge.b, 1)
|
|
end
|
|
end
|
|
GameTooltip:Show()
|
|
if actif(c) then c:LockHighlight() end
|
|
end)
|
|
b:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
c:UnlockHighlight()
|
|
end)
|
|
b.def = r
|
|
return b
|
|
end
|
|
|
|
F.creerRole = creerRole
|
|
|
|
-- l'etat de chaque bouton de role du client, recopie (ceux de toutes les
|
|
-- pages)
|
|
function F.majRoles()
|
|
for _, b in ipairs(F.tousRoles or {}) do
|
|
local client = _G[b.def.client]
|
|
if client and client.checkButton then
|
|
b.case:SetChecked(client.checkButton:GetChecked())
|
|
if client.checkButton:IsShown() then b.case:Show() else b.case:Hide() end
|
|
if actif(client.checkButton) then b.case:Enable() else b.case:Disable() end
|
|
if client.cover and client.cover:IsShown() then
|
|
b.voile:SetAlpha(client.cover:GetAlpha())
|
|
b.voile:Show()
|
|
else
|
|
b.voile:Hide()
|
|
end
|
|
if b.fond then
|
|
if client.background and client.background:IsShown() then b.fond:Show() else b.fond:Hide() end
|
|
end
|
|
b.icone:SetDesaturated(client.permDisabled and true or false)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ les categories
|
|
|
|
-- isRandomDungeonDisplayable de LFDFrame.lua (locale au client)
|
|
local function aleatoireAffichable(id)
|
|
local _, _, minimum, maximum, _, _, _, extension = GetLFGDungeonInfo(id)
|
|
local niveau = UnitLevel("player")
|
|
local ext = (GetExpansionLevel and GetExpansionLevel()) or 2
|
|
return minimum and niveau >= minimum and niveau <= maximum and ext >= (extension or 0)
|
|
end
|
|
|
|
-- LFDQueueFrameTypeDropDown_Initialize : "specific" d'abord, puis chaque
|
|
-- aleatoire affichable, rejoignable ou non
|
|
function F.categories()
|
|
local l = { { valeur = "specific", texte = txt("SPECIFIC_DUNGEONS"), art = ART.specifique, dispo = true } }
|
|
for i = 1, (GetNumRandomDungeons and GetNumRandomDungeons() or 0) do
|
|
local id, nom = GetLFGRandomDungeonInfo(i)
|
|
if id and aleatoireAffichable(id) then
|
|
local fete = select(14, GetLFGDungeonInfo(id))
|
|
table.insert(l, { valeur = id, texte = nom, art = fete and ART.fete or ART.aleatoire,
|
|
dispo = IsLFGDungeonJoinable(id) and true or false })
|
|
end
|
|
end
|
|
return l
|
|
end
|
|
|
|
local function creerCategorie(ligne)
|
|
local b = CreateFrame("Button", nil, ligne)
|
|
b:SetWidth(G.catL)
|
|
b:SetHeight(G.catH)
|
|
b:SetPoint("TOP", ligne, "TOP", 0, 0)
|
|
local image = b:CreateTexture(nil, "BACKGROUND")
|
|
image:SetPoint("TOPLEFT", b, "TOPLEFT", 5, G.catImageHaut)
|
|
image:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", -5, G.catImageBas)
|
|
b.image = image
|
|
local couvercle = b:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(couvercle, "groupfinder-button-cover", true)
|
|
couvercle:SetAllPoints(b)
|
|
local choix = b:CreateTexture(nil, "OVERLAY")
|
|
choix:SetTexture(G.mega)
|
|
choix:SetTexCoord(0.00195313, 0.63867188, 0.76953125, 0.83007813)
|
|
choix:SetBlendMode("ADD")
|
|
choix:SetWidth(G.catSelL)
|
|
choix:SetHeight(G.catSelH)
|
|
choix:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
choix:Hide()
|
|
b.choix = choix
|
|
b:SetHighlightTexture(G.mega)
|
|
local s = b:GetHighlightTexture()
|
|
if s then
|
|
s:SetTexCoord(0.00195313, 0.63867188, 0.70703125, 0.76757813)
|
|
s:SetBlendMode("ADD")
|
|
s:ClearAllPoints()
|
|
s:SetWidth(G.catSelL)
|
|
s:SetHeight(G.catSelH)
|
|
s:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
end
|
|
local texte = b:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
texte:SetPoint("LEFT", b, "LEFT", 20, 0)
|
|
texte:SetJustifyH("LEFT")
|
|
b.texte = texte
|
|
b:SetScript("OnClick", function(self)
|
|
local c = self.categorie
|
|
if not c or not c.dispo then return end
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
LFDQueueFrame_SetType(c.valeur)
|
|
F.vue = (c.valeur == "specific") and "liste" or "categories"
|
|
F.maj()
|
|
end)
|
|
b:SetScript("OnEnter", function(self)
|
|
local c = self.categorie
|
|
if c and not c.dispo then
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(txt("YOU_MAY_NOT_QUEUE_FOR_THIS"), 1, 1, 1)
|
|
local raison = LFDConstructDeclinedMessage and LFDConstructDeclinedMessage(c.valeur)
|
|
if raison then GameTooltip:AddLine(raison, nil, nil, nil, 1) end
|
|
GameTooltip:Show()
|
|
end
|
|
end)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
ligne.bouton = b
|
|
end
|
|
|
|
local function remplirCategorie(ligne, index)
|
|
local c = F.liste_categories[index]
|
|
local b = ligne.bouton
|
|
b.categorie = c
|
|
ForeverUI.SetAtlas(b.image, c.art, true)
|
|
b.image:SetDesaturated(not c.dispo)
|
|
b.texte:SetText(c.texte)
|
|
if c.dispo then
|
|
b.texte:SetTextColor(1, 0.82, 0)
|
|
else
|
|
b.texte:SetTextColor(0.5, 0.5, 0.5)
|
|
end
|
|
if LFDQueueFrame.type == c.valeur then b.choix:Show() else b.choix:Hide() end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ la liste
|
|
-- Les lignes des donjons et celles des raids sont les memes ; ce qui
|
|
-- differe -- la liste, les fonctions du client, les cases rondes d'un
|
|
-- groupe pour les raids -- vient de la SOURCE de la liste (zone.src).
|
|
|
|
-- LFGSpecificChoiceEnableButton_SetIsRadio (LFGFrame.lua) : en groupe, un
|
|
-- raid se choisit par un bouton rond, UI-RadioButton en quatre quarts, 17 x
|
|
-- 17 ; seul, par une case.
|
|
-- LA CASE DE CAMELOT (source de style "camelot" : la liste des raids,
|
|
-- demande du 2026-09-26) : checkbox-minimal / checkmark-minimal, comme les
|
|
-- cases de la feuille et de Social (S.habillerCase) ; en groupe,
|
|
-- common-radiobutton-circle / -dot. 20 x 20 dans une ligne de 22 (camelot
|
|
-- pose sa case a l'echelle 0,7 sur 30 x 29), le rond a 16.
|
|
local CASE_CAMELOT, ROND_CAMELOT = 20, 16
|
|
|
|
local function caseCamelot(c, radio)
|
|
if not radio then
|
|
ForeverUI.Social.habillerCase(c)
|
|
return
|
|
end
|
|
local function poser(set, get, atlas, grise)
|
|
local e = ForeverUI.AtlasEntry(atlas)
|
|
c[set](c, e and e[1] or "")
|
|
local t = c[get](c)
|
|
if t then
|
|
ForeverUI.SetAtlas(t, atlas, true)
|
|
t:ClearAllPoints()
|
|
t:SetWidth(ROND_CAMELOT)
|
|
t:SetHeight(ROND_CAMELOT)
|
|
t:SetPoint("CENTER", c, "CENTER", 0, 0)
|
|
if grise then t:SetDesaturated(true) end
|
|
end
|
|
end
|
|
poser("SetNormalTexture", "GetNormalTexture", "common-radiobutton-circle")
|
|
poser("SetPushedTexture", "GetPushedTexture", "common-radiobutton-circle")
|
|
poser("SetCheckedTexture", "GetCheckedTexture", "common-radiobutton-dot")
|
|
poser("SetDisabledCheckedTexture", "GetDisabledCheckedTexture", "common-radiobutton-dot", true)
|
|
c:SetHighlightTexture("")
|
|
end
|
|
|
|
local function caseRadio(c, radio)
|
|
if c.radio == radio then return end
|
|
c.radio = radio
|
|
if c.style == "camelot" then
|
|
caseCamelot(c, radio)
|
|
return
|
|
end
|
|
local etats = {
|
|
{ "SetNormalTexture", "GetNormalTexture", "UI-CheckBox-Up", 0, 0.25 },
|
|
{ "SetPushedTexture", "GetPushedTexture", "UI-CheckBox-Down", 0, 0.25 },
|
|
{ "SetHighlightTexture", "GetHighlightTexture", "UI-CheckBox-Highlight", 0.5, 0.75 },
|
|
{ "SetCheckedTexture", "GetCheckedTexture", "UI-CheckBox-Check", 0.25, 0.5 },
|
|
}
|
|
for _, e in ipairs(etats) do
|
|
c[e[1]](c, BOUTONS .. (radio and "UI-RadioButton" or e[3]))
|
|
local t = c[e[2]](c)
|
|
if t then
|
|
t:ClearAllPoints()
|
|
if radio then
|
|
t:SetTexCoord(e[4], e[5], 0, 1)
|
|
t:SetWidth(17)
|
|
t:SetHeight(17)
|
|
t:SetPoint("CENTER", c, "CENTER", 0, 0)
|
|
else
|
|
t:SetTexCoord(0, 1, 0, 1)
|
|
t:SetAllPoints(c)
|
|
end
|
|
if e[1] == "SetHighlightTexture" then t:SetBlendMode("ADD") end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- la source des donjons (LFDFrame.lua)
|
|
local SOURCE_LFD = {
|
|
liste = function() return LFDDungeonList end,
|
|
habilite = function() return LFD_IsEmpowered() end,
|
|
plus = function(b) LFDQueueFrameExpandOrCollapseButton_OnClick(b) end,
|
|
case = function(c) LFDQueueFrameDungeonChoiceEnableButton_OnClick(c) end,
|
|
plusieurs = function() return true end,
|
|
verrou = function(id) return LFGLockList[id] end,
|
|
etat = function(id, mode)
|
|
if mode == "queued" or mode == "listed" then return LFGQueuedForList[id] end
|
|
return LFGEnabledList[id]
|
|
end,
|
|
}
|
|
F.SOURCE_LFD = SOURCE_LFD
|
|
|
|
local function creerLigne(ligne)
|
|
ligne.src = ligne:GetParent().src
|
|
local plus = CreateFrame("Button", nil, ligne)
|
|
plus:SetWidth(G.plus)
|
|
plus:SetHeight(G.plus)
|
|
plus:SetPoint("LEFT", ligne, "LEFT", 0, 0)
|
|
plus:SetHitRectInsets(1, -4, -2, -2)
|
|
plus:SetNormalTexture(BOUTONS .. "UI-MinusButton-UP")
|
|
local n = plus:GetNormalTexture()
|
|
if n then
|
|
n:ClearAllPoints()
|
|
n:SetWidth(20)
|
|
n:SetHeight(20)
|
|
n:SetPoint("LEFT", plus, "LEFT", 3, 0)
|
|
end
|
|
plus:SetHighlightTexture(BOUTONS .. "UI-PlusButton-Hilight")
|
|
local s = plus:GetHighlightTexture()
|
|
if s then
|
|
s:SetBlendMode("ADD")
|
|
s:ClearAllPoints()
|
|
s:SetWidth(20)
|
|
s:SetHeight(20)
|
|
s:SetPoint("LEFT", plus, "LEFT", 3, 0)
|
|
end
|
|
-- le +/- du client : LFDQueueFrameExpandOrCollapseButton_OnClick lit
|
|
-- self:GetParent().id et .isCollapsed
|
|
plus:SetScript("OnClick", function(self)
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
ligne.src.plus(self)
|
|
end)
|
|
ligne.plus = plus
|
|
|
|
local c = CreateFrame("CheckButton", nil, ligne)
|
|
c.style = ligne.src.style
|
|
local cote = (c.style == "camelot") and CASE_CAMELOT or G.case
|
|
c:SetWidth(cote)
|
|
c:SetHeight(cote)
|
|
c:SetPoint("LEFT", plus, "RIGHT", 4, 0)
|
|
c:SetNormalTexture(BOUTONS .. "UI-CheckBox-Up")
|
|
c:SetPushedTexture(BOUTONS .. "UI-CheckBox-Down")
|
|
c:SetHighlightTexture(BOUTONS .. "UI-CheckBox-Highlight")
|
|
local h = c:GetHighlightTexture()
|
|
if h then h:SetBlendMode("ADD") end
|
|
c:SetCheckedTexture(BOUTONS .. "UI-CheckBox-Check")
|
|
c:SetDisabledCheckedTexture(BOUTONS .. "UI-CheckBox-Check-Disabled")
|
|
-- la case du client : LFDQueueFrameDungeonChoiceEnableButton_OnClick lit
|
|
-- self:GetParent().id et self:GetChecked()
|
|
c:SetScript("OnClick", function(self)
|
|
ligne.src.case(self)
|
|
end)
|
|
ligne.case = c
|
|
|
|
-- le verrou de WotLK, a la place de la case
|
|
local verrou = ligne:CreateTexture(nil, "ARTWORK")
|
|
verrou:SetTexture(LFG .. "UI-LFG-ICON-LOCK")
|
|
verrou:SetTexCoord(0, 0.71875, 0, 0.875)
|
|
verrou:SetWidth(12)
|
|
verrou:SetHeight(14)
|
|
verrou:SetPoint("CENTER", c, "CENTER", 0, 0)
|
|
verrou:Hide()
|
|
ligne.lockedIndicator = verrou
|
|
|
|
local niveau = ligne:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
niveau:SetWidth(G.niveauL)
|
|
niveau:SetHeight(G.ligne)
|
|
niveau:SetPoint("RIGHT", ligne, "RIGHT", 0, 0)
|
|
niveau:SetJustifyH("LEFT")
|
|
ligne.niveau = niveau
|
|
|
|
local nom = ligne:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
nom:SetHeight(G.ligne)
|
|
nom:SetPoint("LEFT", c, "RIGHT", 0, 0)
|
|
nom:SetPoint("RIGHT", niveau, "LEFT", -4, 0)
|
|
nom:SetJustifyH("LEFT")
|
|
ligne.nom = nom
|
|
|
|
-- le nom clique la case, et la survole (NameButton de camelot) ;
|
|
-- l'infobulle des verrous est celle du client
|
|
ligne:EnableMouse(true)
|
|
ligne:SetScript("OnEnter", function(self)
|
|
if actif(self.case) and self.case:IsShown() then self.case:LockHighlight() end
|
|
LFDQueueFrameDungeonListButton_OnEnter(self)
|
|
end)
|
|
ligne:SetScript("OnLeave", function(self)
|
|
self.case:UnlockHighlight()
|
|
GameTooltip:Hide()
|
|
end)
|
|
ligne:SetScript("OnClick", function(self)
|
|
if self.case:IsShown() and actif(self.case) then self.case:Click() end
|
|
end)
|
|
end
|
|
|
|
local function couleur(fs, c)
|
|
fs:SetTextColor(c[1], c[2], c[3])
|
|
end
|
|
|
|
-- LFDQueueFrameSpecificListButton_SetDungeon (et celle des raids), a la
|
|
-- maniere de camelot
|
|
local function remplirLigne(ligne, index)
|
|
local src = ligne.src
|
|
local id = src.liste()[index]
|
|
local info = LFGDungeonInfo and LFGDungeonInfo[id] or {}
|
|
local mode = GetLFGMode()
|
|
local fige = mode == "rolecheck" or mode == "queued" or mode == "listed" or not src.habilite()
|
|
ligne.id = id
|
|
ligne.nom:SetText(info[1] or "")
|
|
if id < 0 then
|
|
ligne.plus:Show()
|
|
ligne.isCollapsed = LFGCollapseList[id]
|
|
ligne.plus:SetNormalTexture(BOUTONS .. (ligne.isCollapsed and "UI-PlusButton-UP" or "UI-MinusButton-UP"))
|
|
local n = ligne.plus:GetNormalTexture()
|
|
if n then
|
|
n:ClearAllPoints()
|
|
n:SetWidth(20)
|
|
n:SetHeight(20)
|
|
n:SetPoint("LEFT", ligne.plus, "LEFT", 3, 0)
|
|
end
|
|
ligne.niveau:Hide()
|
|
couleur(ligne.nom, COULEURS.entete)
|
|
else
|
|
ligne.plus:Hide()
|
|
ligne.isCollapsed = false
|
|
local minimum, maximum = info[3] or 0, info[4] or 0
|
|
if minimum == maximum then
|
|
ligne.niveau:SetText(format(txt("LFD_LEVEL_FORMAT_SINGLE"), minimum))
|
|
else
|
|
ligne.niveau:SetText(format(txt("LFD_LEVEL_FORMAT_RANGE"), minimum, maximum))
|
|
end
|
|
ligne.niveau:Show()
|
|
local joueur = UnitLevel("player")
|
|
local c = COULEURS.entree
|
|
if maximum ~= 0 and maximum < joueur then
|
|
c = COULEURS.facile
|
|
elseif minimum ~= 0 and minimum > joueur then
|
|
c = COULEURS.dur
|
|
end
|
|
couleur(ligne.niveau, c)
|
|
couleur(ligne.nom, fige and COULEURS.entete or c)
|
|
end
|
|
|
|
local plusieurs = src.plusieurs()
|
|
if src.verrou(id) then
|
|
ligne.case:Hide()
|
|
ligne.lockedIndicator:Show()
|
|
else
|
|
-- en groupe, un en-tete de raid n'a pas de bouton
|
|
if plusieurs or id >= 0 then ligne.case:Show() else ligne.case:Hide() end
|
|
ligne.lockedIndicator:Hide()
|
|
end
|
|
caseRadio(ligne.case, not plusieurs)
|
|
local etat = src.etat(id, mode)
|
|
if plusieurs and ligne.case.style == "camelot" then
|
|
ligne.case:SetChecked(etat and etat ~= 0)
|
|
elseif plusieurs then
|
|
if etat == 1 then
|
|
ligne.case:SetCheckedTexture(BOUTONS .. "UI-MultiCheck-Up")
|
|
ligne.case:SetDisabledCheckedTexture(BOUTONS .. "UI-MultiCheck-Disabled")
|
|
else
|
|
ligne.case:SetCheckedTexture(BOUTONS .. "UI-CheckBox-Check")
|
|
ligne.case:SetDisabledCheckedTexture(BOUTONS .. "UI-CheckBox-Check-Disabled")
|
|
end
|
|
ligne.case:SetChecked(etat and etat ~= 0)
|
|
else
|
|
ligne.case:SetChecked(etat)
|
|
end
|
|
if fige then ligne.case:Disable() else ligne.case:Enable() end
|
|
end
|
|
F.creerLigne = creerLigne
|
|
F.remplirLigne = remplirLigne
|
|
|
|
-- ------------------------------------------------------------ les recompenses
|
|
|
|
local OBJETS = "LFDQueueFrameRandomScrollFrameChildFrameItem"
|
|
|
|
local function creerObjet(parent, i)
|
|
local b = CreateFrame("Button", "ForeverUIGroupFinderReward" .. i, parent)
|
|
b:SetWidth(147)
|
|
b:SetHeight(41)
|
|
local icone = b:CreateTexture(nil, "BORDER")
|
|
icone:SetWidth(39)
|
|
icone:SetHeight(39)
|
|
icone:SetPoint("TOPLEFT", b, "TOPLEFT", 0, 0)
|
|
b.icone = icone
|
|
local cadreNom = b:CreateTexture(nil, "BACKGROUND")
|
|
cadreNom:SetTexture("Interface" .. SEP .. "QuestFrame" .. SEP .. "UI-QuestItemNameFrame")
|
|
cadreNom:SetWidth(128)
|
|
cadreNom:SetHeight(64)
|
|
cadreNom:SetPoint("LEFT", icone, "RIGHT", -10, 0)
|
|
local nom = b:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
|
|
nom:SetWidth(90)
|
|
nom:SetHeight(36)
|
|
nom:SetPoint("LEFT", icone, "RIGHT", 8, 0)
|
|
nom:SetJustifyH("LEFT")
|
|
b.nom = nom
|
|
local nombre = b:CreateFontString(nil, "OVERLAY", "NumberFontNormal")
|
|
nombre:SetPoint("BOTTOMRIGHT", icone, "BOTTOMRIGHT", -5, 2)
|
|
b.nombre = nombre
|
|
b:SetID(i)
|
|
-- LFDRandomDungeonLootTemplate
|
|
b:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetLFGDungeonReward(LFDQueueFrame.type, self:GetID())
|
|
GameTooltip:Show()
|
|
end)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
b:SetScript("OnClick", function(self)
|
|
HandleModifiedItemClick(GetLFGDungeonRewardLink(LFDQueueFrame.type, self:GetID()))
|
|
end)
|
|
return b
|
|
end
|
|
|
|
-- LES DETAILS : une zone qui defile sous le filet. Chaque piece est posee
|
|
-- a sa hauteur depuis le haut du contenu (et non d'une piece a l'autre) :
|
|
-- la hauteur totale en sort, et la barre la suit.
|
|
local function construireRecompenses(p)
|
|
local vue = CreateFrame("ScrollFrame", "ForeverUIGroupFinderDetails", p)
|
|
vue.decalage = 0
|
|
local r = CreateFrame("Frame", "ForeverUIGroupFinderRewards", vue)
|
|
r:SetWidth(G.largeur + G.detailsX2 - G.detailsX1)
|
|
r:SetHeight(1)
|
|
vue:SetScrollChild(r)
|
|
local largeur = G.largeur + G.detailsX2 - G.detailsX1
|
|
local function texte(police)
|
|
local fs = r:CreateFontString(nil, "ARTWORK", police)
|
|
fs:SetWidth(largeur)
|
|
fs:SetJustifyH("LEFT")
|
|
return fs
|
|
end
|
|
r.description = texte("GameFontHighlight")
|
|
r.etiquette = texte("GameFontNormalLarge")
|
|
r.etiquette:SetText(txt("LFD_REWARDS"))
|
|
r.explication = texte("GameFontHighlight")
|
|
r.pug = texte("GameFontHighlight")
|
|
-- l'argent : une case d'objet, sans infobulle ni lien
|
|
local argent = creerObjet(r, 0)
|
|
argent:SetScript("OnEnter", nil)
|
|
argent:SetScript("OnLeave", nil)
|
|
argent:SetScript("OnClick", nil)
|
|
argent.icone:SetTexture(G.pieces)
|
|
argent.nombre:Hide()
|
|
r.argent = argent
|
|
r.xp = texte("GameFontNormal")
|
|
r.objets = {}
|
|
F.recompenses = r
|
|
|
|
local barre = ForeverUI.CreateScrollBar("ForeverUIGroupFinderDetailsScrollBar", p, vue)
|
|
barre.surDefilement = function(nouveau)
|
|
vue.decalage = nouveau
|
|
vue:SetVerticalScroll(math.min(nouveau * G.cran, math.max(0, (vue.contenu or 0) - (vue.visible or 0))))
|
|
end
|
|
vue:EnableMouseWheel(true)
|
|
vue:SetScript("OnMouseWheel", function(self, sens)
|
|
barre:Deplacer(self.decalage - sens)
|
|
end)
|
|
vue.barre = barre
|
|
F.details = vue
|
|
|
|
-- LA SECONDE MESURE, a l'image suivante : du haut du contenu au bas de
|
|
-- sa derniere piece. Plus haute que la premiere, elle replace tout.
|
|
local remesure = CreateFrame("Frame")
|
|
remesure:Hide()
|
|
remesure:SetScript("OnUpdate", function(self)
|
|
self:Hide()
|
|
local piece = F.dernierePiece
|
|
if not (vue:IsShown() and piece and piece:IsShown()) then return end
|
|
local haut, bas = r:GetTop(), piece:GetBottom()
|
|
if not (haut and bas) then return end
|
|
local reel = haut - bas
|
|
if reel > (vue.contenu or 0) + 0.5 then F.poserContenu(reel) end
|
|
end)
|
|
F.remesure = remesure
|
|
end
|
|
|
|
-- LE FILET ET LES DETAILS. Les details finissent en bas de l'encadre ; le
|
|
-- filet se pose au-dessus de leur contenu, sans monter plus haut que
|
|
-- F.filetMax (6 sous le dernier bouton). Sans contenu, il reste la-haut.
|
|
local function placerFilet(contenu)
|
|
local y = F.filetMax or 0
|
|
if contenu and contenu > 0 then
|
|
local voulu = -(G.hauteur - G.detailsBas) + contenu + G.detailsAir + G.detailsEcart + G.regleH / 2
|
|
if voulu < y then y = voulu end
|
|
end
|
|
-- la hauteur visible des details, d'apres nos ecarts et non GetHeight
|
|
F.details.visible = (y - G.regleH / 2 - G.detailsEcart) + (G.hauteur - G.detailsBas)
|
|
F.regle:ClearAllPoints()
|
|
F.regle:SetPoint("LEFT", F.cadre, "TOPLEFT", G.listeX1, y)
|
|
F.regle:SetPoint("RIGHT", F.cadre, "TOPRIGHT", G.listeX2, y)
|
|
F.details:ClearAllPoints()
|
|
F.details:SetPoint("TOPLEFT", F.cadre, "TOPLEFT", G.detailsX1, y - G.regleH / 2 - G.detailsEcart)
|
|
F.details:SetPoint("BOTTOMRIGHT", F.cadre, "BOTTOMRIGHT", G.detailsX2, G.detailsBas)
|
|
-- les voiles des details partent du filet
|
|
F.hautDetails = y - G.regleH / 2 - G.encadreY1
|
|
end
|
|
|
|
-- la hauteur d'un texte replie sur sa largeur : GetHeight, comme
|
|
-- QuestInfo.lua du client
|
|
local function hauteur(fs)
|
|
local h = fs:GetHeight() or 0
|
|
if h <= 0 and fs.GetStringHeight then h = fs:GetStringHeight() or 0 end
|
|
return h
|
|
end
|
|
|
|
-- LFDQueueFrameRandom_UpdateFrame a pose les textes sur les regions du
|
|
-- client : on les reprend. Le titre n'est pas repris : le bouton choisi le
|
|
-- porte deja.
|
|
local function majRecompenses()
|
|
local r = F.recompenses
|
|
local vue = F.details
|
|
local client = LFDQueueFrameRandomScrollFrameChildFrame
|
|
local id = LFDQueueFrame.type
|
|
if not client or type(id) ~= "number" then
|
|
placerFilet(nil)
|
|
vue:Hide()
|
|
vue.barre:Hide()
|
|
return
|
|
end
|
|
vue:Show()
|
|
local y = 0
|
|
local dernier
|
|
local function poser(piece, x, ecart)
|
|
piece:ClearAllPoints()
|
|
piece:SetPoint("TOPLEFT", r, "TOPLEFT", x or 0, -(y + (ecart or 0)))
|
|
piece:Show()
|
|
y = y + (ecart or 0) + hauteur(piece)
|
|
dernier = piece
|
|
end
|
|
r.description:SetText(client.description:GetText() or "")
|
|
poser(r.description)
|
|
if client.rewardsLabel:IsShown() then
|
|
r.explication:SetText(client.rewardsDescription:GetText() or "")
|
|
poser(r.etiquette, 0, 10)
|
|
poser(r.explication, 0, 6)
|
|
else
|
|
r.etiquette:Hide()
|
|
r.explication:Hide()
|
|
end
|
|
local _, argentBase, argentVar, xpBase, xpVar, nombre = GetLFGDungeonRewards(id)
|
|
nombre = nombre or 0
|
|
-- l'argent et l'experience : le calcul de LFDQueueFrameRandom_UpdateFrame
|
|
local aleas = 4 - GetNumPartyMembers()
|
|
local argent = (argentBase or 0) + (argentVar or 0) * aleas
|
|
local xp = (xpBase or 0) + (xpVar or 0) * aleas
|
|
local haut = y + 8
|
|
local function case(b, i)
|
|
local rang, colonne = math.floor((i - 1) / 2), (i - 1) % 2
|
|
b:ClearAllPoints()
|
|
b:SetPoint("TOPLEFT", r, "TOPLEFT", colonne * 157, -(haut + rang * 44))
|
|
b:Show()
|
|
y = haut + rang * 44 + 41
|
|
dernier = b
|
|
end
|
|
for i = 1, nombre do
|
|
local b = r.objets[i] or creerObjet(r, i)
|
|
r.objets[i] = b
|
|
local nom, image, quantite = GetLFGDungeonRewardInfo(id, i)
|
|
b.nom:SetText(nom or "")
|
|
b.icone:SetTexture(image)
|
|
if quantite and quantite > 1 then b.nombre:SetText(quantite) b.nombre:Show() else b.nombre:Hide() end
|
|
case(b, i)
|
|
end
|
|
for i = nombre + 1, #r.objets do r.objets[i]:Hide() end
|
|
if argent > 0 then
|
|
r.argent.nom:SetText(GetCoinTextureString(argent))
|
|
case(r.argent, nombre + 1)
|
|
else
|
|
r.argent:Hide()
|
|
end
|
|
if client.pugDescription:IsShown() then
|
|
r.pug:SetText(client.pugDescription:GetText() or "")
|
|
poser(r.pug, 0, 5)
|
|
else
|
|
r.pug:Hide()
|
|
end
|
|
if xp > 0 then
|
|
r.xp:SetText(txt("EXPERIENCE_COLON") .. " |cffffffff" .. xp .. "|r")
|
|
poser(r.xp, 0, 8)
|
|
else
|
|
r.xp:Hide()
|
|
end
|
|
-- le filet descend sur le contenu ; puis la barre
|
|
F.dernierePiece = dernier
|
|
F.poserContenu(y)
|
|
-- la seconde mesure, une fois les textes poses par le client
|
|
F.remesure:Show()
|
|
end
|
|
|
|
function F.poserContenu(y)
|
|
local vue = F.details
|
|
F.recompenses:SetHeight(math.max(1, y))
|
|
vue.contenu = y
|
|
placerFilet(y)
|
|
local visible = vue.visible or 0
|
|
if visible <= 0 or y <= visible + G.tolerance then
|
|
vue.decalage = 0
|
|
vue:SetVerticalScroll(0)
|
|
vue.barre:Regler(0, 0, 0)
|
|
else
|
|
-- en crans de 20 : le dernier cran montre la fin du contenu
|
|
local total, visibles = math.ceil((y - visible) / G.cran) + 1, 1
|
|
vue.decalage = math.min(vue.decalage, total - visibles)
|
|
vue.barre:Regler(total, visibles, vue.decalage)
|
|
vue.barre.surDefilement(vue.decalage)
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ les voiles
|
|
-- Ceux de WotLK (330 x 257, noir a 0,93), poses sur l'encadre et dans le
|
|
-- meme ordre : l'attente (11), la reprise d'un groupe (14), "pas de donjon
|
|
-- pendant le raid" (16).
|
|
|
|
local function creerVoile(nom, niveau, page, encadre)
|
|
local v = CreateFrame("Frame", nom, page or F.pageDonjons)
|
|
v:SetFrameLevel((encadre or F.encadre):GetFrameLevel() + niveau)
|
|
v:EnableMouse(true)
|
|
local noir = v:CreateTexture(nil, "BACKGROUND")
|
|
noir:SetTexture(0, 0, 0, 0.93)
|
|
noir:SetAllPoints(v)
|
|
v.description = v:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
v.description:SetWidth(300)
|
|
v.description:SetPoint("TOP", v, "TOP", 0, -70)
|
|
v:Hide()
|
|
return v
|
|
end
|
|
F.creerVoile = creerVoile
|
|
|
|
local function construireVoiles()
|
|
local attente = creerVoile("ForeverUIGroupFinderCooldown", 11)
|
|
attente.temps = attente:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge")
|
|
attente.temps:SetPoint("TOP", attente.description, "BOTTOM", 0, -10)
|
|
attente.noms, attente.etats = {}, {}
|
|
for i = 1, 4 do
|
|
local n = attente:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
n:SetWidth(120)
|
|
n:SetJustifyH("LEFT")
|
|
if i == 1 then
|
|
n:SetPoint("TOPLEFT", attente.description, "BOTTOMLEFT", 25, -60)
|
|
else
|
|
n:SetPoint("TOP", attente.noms[i - 1], "BOTTOM", 0, -5)
|
|
end
|
|
local e = attente:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
e:SetWidth(110)
|
|
e:SetJustifyH("RIGHT")
|
|
e:SetPoint("TOPLEFT", n, "TOPRIGHT", 0, 0)
|
|
attente.noms[i], attente.etats[i] = n, e
|
|
end
|
|
-- le temps restant change a chaque image chez le client
|
|
attente:SetScript("OnUpdate", function(self)
|
|
local c = LFDQueueFrameCooldownFrame
|
|
if c and c.time then
|
|
self.temps:SetText(c.time:GetText() or "")
|
|
end
|
|
end)
|
|
F.attente = attente
|
|
|
|
local reprise = creerVoile("ForeverUIGroupFinderBackfill", 14)
|
|
reprise.oui = ForeverUI.CreatePanelButton(reprise, txt("YES"), 153, 22, nil, "GameFontNormal")
|
|
reprise.oui:SetPoint("TOPRIGHT", reprise.description, "BOTTOM", -5, -10)
|
|
reprise.oui:SetScript("OnClick", function()
|
|
if LFDQueueFramePartyBackfillBackfillButton then LFDQueueFramePartyBackfillBackfillButton:Click() end
|
|
end)
|
|
reprise.non = ForeverUI.CreatePanelButton(reprise, txt("HIDE"), 153, 22, nil, "GameFontNormal")
|
|
reprise.non:SetPoint("TOPLEFT", reprise.description, "BOTTOM", 5, -10)
|
|
reprise.non:SetScript("OnClick", function()
|
|
if LFDQueueFramePartyBackfillNoBackfillButton then LFDQueueFramePartyBackfillNoBackfillButton:Click() end
|
|
end)
|
|
F.reprise = reprise
|
|
|
|
local raid = creerVoile("ForeverUIGroupFinderNoLFDWhileLFR", 16)
|
|
raid.quitter = ForeverUI.CreatePanelButton(raid, "", 153, 22, nil, "GameFontNormal")
|
|
raid.quitter:SetPoint("TOP", raid.description, "BOTTOM", 0, -10)
|
|
raid.quitter:SetScript("OnClick", function()
|
|
if LFDQueueFrameNoLFDWhileLFRLeaveQueueButton then LFDQueueFrameNoLFDWhileLFRLeaveQueueButton:Click() end
|
|
end)
|
|
F.raid = raid
|
|
end
|
|
|
|
local function texteDe(nom)
|
|
local r = _G[nom]
|
|
return r and r.GetText and r:GetText() or ""
|
|
end
|
|
|
|
-- ce qu'ils couvrent : les details sous le filet, ou toute la liste
|
|
local function placerVoiles()
|
|
for _, v in ipairs({ F.attente, F.reprise, F.raid }) do
|
|
v:ClearAllPoints()
|
|
if F.vue == "liste" then
|
|
v:SetAllPoints(F.encadre)
|
|
else
|
|
v:SetPoint("TOPLEFT", F.encadre, "TOPLEFT", 0, F.hautDetails)
|
|
v:SetPoint("BOTTOMRIGHT", F.encadre, "BOTTOMRIGHT", 0, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function majVoiles()
|
|
placerVoiles()
|
|
-- l'attente : visible chez le client (son parent change selon la
|
|
-- desertion), textes recopies
|
|
local c = LFDQueueFrameCooldownFrame
|
|
if c and affiche(c) then
|
|
F.attente.description:SetText(c.description and c.description:GetText() or "")
|
|
F.attente.description:ClearAllPoints()
|
|
F.attente.description:SetPoint("TOP", F.attente, "TOP", 0, GetNumPartyMembers() == 0 and -85 or -30)
|
|
F.attente.temps:SetText(c.time and c.time:GetText() or "")
|
|
if c.time and c.time:IsShown() then F.attente.temps:Show() else F.attente.temps:Hide() end
|
|
for i = 1, 4 do
|
|
local n, e = _G["LFDQueueFrameCooldownFrameName" .. i], _G["LFDQueueFrameCooldownFrameStatus" .. i]
|
|
if n and n:IsShown() then
|
|
F.attente.noms[i]:SetText(n:GetText() or "")
|
|
F.attente.etats[i]:SetText(e and e:GetText() or "")
|
|
F.attente.noms[i]:Show()
|
|
F.attente.etats[i]:Show()
|
|
else
|
|
F.attente.noms[i]:Hide()
|
|
F.attente.etats[i]:Hide()
|
|
end
|
|
end
|
|
F.attente:Show()
|
|
else
|
|
F.attente:Hide()
|
|
end
|
|
|
|
local b = LFDQueueFramePartyBackfill
|
|
if b and affiche(b) then
|
|
F.reprise.description:SetText(texteDe("LFDQueueFramePartyBackfillDescription"))
|
|
F.reprise.oui:Activer(actif(LFDQueueFramePartyBackfillBackfillButton))
|
|
F.reprise:Show()
|
|
else
|
|
F.reprise:Hide()
|
|
end
|
|
|
|
local l = LFDQueueFrameNoLFDWhileLFR
|
|
if l and affiche(l) then
|
|
F.raid.description:SetText(texteDe("LFDQueueFrameNoLFDWhileLFRDescription"))
|
|
F.raid.quitter:SetText(texteDe("LFDQueueFrameNoLFDWhileLFRLeaveQueueButton"))
|
|
F.raid.quitter:Activer(actif(LFDQueueFrameNoLFDWhileLFRLeaveQueueButton))
|
|
F.raid:Show()
|
|
else
|
|
F.raid:Hide()
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ la page
|
|
|
|
-- LE BANDEAU DES ROLES d'une page : un cadre fils, au-dessus des stries
|
|
-- (camelot le pose en cadre fils, RolesSection), le bleu et les boutons
|
|
function F.construireBandeau(p, roles)
|
|
local f = F.cadre
|
|
local bandeau = CreateFrame("Frame", nil, p)
|
|
bandeau:SetAllPoints(f)
|
|
bandeau:SetFrameLevel(f:GetFrameLevel() + 1)
|
|
local bleu = bandeau:CreateTexture(nil, "BACKGROUND")
|
|
bleu:SetTexture(G.bleu)
|
|
bleu:SetPoint("TOPLEFT", f, "TOPLEFT", G.bleuX1, G.bleuY1)
|
|
bleu:SetPoint("BOTTOMRIGHT", f, "TOPRIGHT", G.bleuX2, G.bleuY2)
|
|
local l = {}
|
|
F.tousRoles = F.tousRoles or {}
|
|
for _, r in ipairs(roles) do
|
|
local b = creerRole(bandeau, r)
|
|
table.insert(l, b)
|
|
table.insert(F.tousRoles, b)
|
|
end
|
|
return bleu, l
|
|
end
|
|
|
|
-- L'ENCADRE d'une page, au-dessus du bandeau : sans marbre, le fond de
|
|
-- camelot a 3 du bord ; rogne en haut (0,093) sous un bandeau de roles, entier
|
|
-- sans (le parcours)
|
|
function F.construireEncadre(p, nom, haut, rogne, bas)
|
|
local f = F.cadre
|
|
local encadre = ForeverUI.CreateInset(p, nom)
|
|
encadre:SetFrameLevel(f:GetFrameLevel() + 2)
|
|
encadre:SetPoint("TOPLEFT", f, "TOPLEFT", G.encadreX1, haut)
|
|
encadre:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", G.encadreX2, bas or G.encadreY2)
|
|
encadre.fond:Hide()
|
|
local fond = encadre:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(fond, "groupfinder-background", true)
|
|
local e = ForeverUI.AtlasEntry("groupfinder-background")
|
|
if e and rogne then
|
|
fond:SetTexCoord(e[2], e[3], e[4] + (e[5] - e[4]) * G.fondHaut, e[5])
|
|
end
|
|
fond:SetPoint("TOPLEFT", encadre, "TOPLEFT", 3, -3)
|
|
fond:SetPoint("BOTTOMRIGHT", encadre, "BOTTOMRIGHT", -3, 3)
|
|
return encadre
|
|
end
|
|
|
|
local function construirePage(f)
|
|
local p = CreateFrame("Frame", "ForeverUIGroupFinderDungeons", f)
|
|
p:SetAllPoints(f)
|
|
F.pageDonjons = p
|
|
|
|
F.bleu, F.roles = F.construireBandeau(p, ROLES)
|
|
-- son fond de camelot couvre le bas du bleu comme dans la source
|
|
local encadre = F.construireEncadre(p, "ForeverUIGroupFinderInset", G.encadreY1, true)
|
|
F.encadre = encadre
|
|
|
|
local S = ForeverUI.Social
|
|
-- les categories : empilees depuis le haut, sans defilement ; le filet
|
|
-- et les details suivent le dernier bouton
|
|
local cats = CreateFrame("Frame", "ForeverUIGroupFinderCategories", p)
|
|
cats:SetFrameLevel(encadre:GetFrameLevel() + 1)
|
|
cats:SetPoint("TOPLEFT", f, "TOPLEFT", G.catX1, G.catY1)
|
|
cats:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", G.catX2, G.catY2)
|
|
cats.lignes = {}
|
|
F.categoriesVue = cats
|
|
local regle = cats:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(regle, "shop-list-rule", true)
|
|
regle:SetHeight(G.regleH)
|
|
F.regle = regle
|
|
|
|
-- la liste des donjons specifiques
|
|
local liste = S.creerListe(p, "ForeverUIGroupFinderList", G.ligne, creerLigne, remplirLigne)
|
|
liste.src = SOURCE_LFD
|
|
liste:SetFrameLevel(encadre:GetFrameLevel() + 1)
|
|
liste.barre:SetFrameLevel(encadre:GetFrameLevel() + 2)
|
|
liste:SuivreBarre({ "TOPLEFT", f, "TOPLEFT", G.listeX1 + G.marge, G.listeY1 - G.marge },
|
|
{ "BOTTOMRIGHT", f, "BOTTOMRIGHT", G.listeX2 + G.barreDroite - G.marge, G.listeY2 + G.marge },
|
|
G.listeX2 - G.marge)
|
|
-- la barre : TOPLEFT sur le TOPRIGHT de la liste (+13, -4) avec la marge
|
|
liste.barre:ClearAllPoints()
|
|
liste.barre:SetPoint("TOPLEFT", liste, "TOPRIGHT", 13 + G.marge, 0)
|
|
liste.barre:SetPoint("BOTTOMLEFT", liste, "BOTTOMRIGHT", 13 + G.marge, -2)
|
|
F.listeVue = liste
|
|
|
|
construireRecompenses(p)
|
|
F.details:SetFrameLevel(encadre:GetFrameLevel() + 1)
|
|
F.details.barre:SetFrameLevel(encadre:GetFrameLevel() + 2)
|
|
construireVoiles()
|
|
|
|
-- les boutons du bas
|
|
local retour = ForeverUI.CreatePanelButton(p, txt("BACK"), G.backL, G.boutonH, "ForeverUIGroupFinderBackButton", "GameFontNormal")
|
|
retour:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", G.boutonCote, G.boutonBas)
|
|
retour:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
F.vue = "categories"
|
|
F.maj()
|
|
end)
|
|
F.retour = retour
|
|
local chercher = ForeverUI.CreatePanelButton(p, txt("FIND_A_GROUP"), G.postL, G.boutonH, "ForeverUIGroupFinderFindButton", "GameFontNormal")
|
|
chercher:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -G.boutonCote, G.boutonBas)
|
|
-- le bouton du client : son OnClick choisit entre LeaveLFG et
|
|
-- LFDQueueFrame_Join
|
|
chercher:SetScript("OnClick", function()
|
|
if LFDQueueFrameFindGroupButton and actif(LFDQueueFrameFindGroupButton) then
|
|
LFDQueueFrameFindGroupButton:Click()
|
|
end
|
|
end)
|
|
F.chercher = chercher
|
|
end
|
|
|
|
-- ------------------------------------------------------------ la mise a jour
|
|
|
|
local function modeEnFile()
|
|
local mode = GetLFGMode()
|
|
return mode == "queued" or mode == "rolecheck" or mode == "proposal"
|
|
end
|
|
|
|
-- les boutons de categorie, le filet sous le dernier, les details dessous
|
|
local function poserCategories()
|
|
local cats = F.categoriesVue
|
|
local n = #F.liste_categories
|
|
for i = 1, n do
|
|
local l = cats.lignes[i]
|
|
if not l then
|
|
l = CreateFrame("Frame", nil, cats)
|
|
l:SetHeight(G.catH)
|
|
creerCategorie(l)
|
|
cats.lignes[i] = l
|
|
end
|
|
l:ClearAllPoints()
|
|
l:SetPoint("TOPLEFT", cats, "TOPLEFT", 0, G.catPremier - (i - 1) * G.catPas)
|
|
l:SetPoint("TOPRIGHT", cats, "TOPRIGHT", 0, G.catPremier - (i - 1) * G.catPas)
|
|
remplirCategorie(l, i)
|
|
l:Show()
|
|
end
|
|
for i = n + 1, #cats.lignes do cats.lignes[i]:Hide() end
|
|
-- le bas du dernier bouton, depuis le haut de la fenetre
|
|
local bas = G.catY1 + G.catPremier - (n - 1) * G.catPas - G.catH
|
|
F.filetMax = bas - G.regleEcart
|
|
placerFilet(nil)
|
|
end
|
|
|
|
local function majDonjons()
|
|
local vue = F.vue or "categories"
|
|
if vue == "liste" and LFDQueueFrame.type ~= "specific" then vue = "categories" end
|
|
F.vue = vue
|
|
|
|
F.liste_categories = F.categories()
|
|
poserCategories()
|
|
if vue == "categories" then
|
|
F.categoriesVue:Show()
|
|
majRecompenses()
|
|
else
|
|
F.categoriesVue:Hide()
|
|
F.details:Hide()
|
|
F.details.barre:Hide()
|
|
end
|
|
if vue == "liste" then
|
|
F.listeVue:Show()
|
|
F.listeVue:Maj(LFDDungeonList and #LFDDungeonList or 0)
|
|
else
|
|
F.listeVue:Hide()
|
|
F.listeVue.barre:Hide()
|
|
end
|
|
majVoiles()
|
|
|
|
-- Back n'existe que dans la liste de "Specific Dungeons" (demande du
|
|
-- 2026-09-26)
|
|
if vue == "liste" then F.retour:Show() else F.retour:Hide() end
|
|
local client = LFDQueueFrameFindGroupButton
|
|
if client then
|
|
F.chercher:SetText(client:GetText() or txt("FIND_A_GROUP"))
|
|
F.chercher:Activer(actif(client))
|
|
end
|
|
end
|
|
|
|
-- LES PAGES : une par onglet ; celle des donjons ici, celles du raid dans
|
|
-- GroupFinderRaid.lua (F.inscrirePage)
|
|
F.pages = {}
|
|
function F.inscrirePage(cle, cadre, maj)
|
|
F.pages[cle] = { cadre = cadre, maj = maj }
|
|
end
|
|
|
|
function F.maj()
|
|
if not F.cadre then return end
|
|
F.majRoles()
|
|
local pg = F.pages[F.onglet or "donjons"]
|
|
if pg then pg.maj() end
|
|
end
|
|
|
|
-- montrer une page : son onglet choisi, les autres pages cachees
|
|
function F.afficher(cle)
|
|
F.choisirOnglet(cle)
|
|
for k, pg in pairs(F.pages) do
|
|
if k == cle then pg.cadre:Show() else pg.cadre:Hide() end
|
|
end
|
|
F.maj()
|
|
end
|
|
|
|
-- plusieurs mises a jour du client dans la meme image n'en font qu'une chez
|
|
-- nous
|
|
local attendre = CreateFrame("Frame")
|
|
attendre:Hide()
|
|
attendre:SetScript("OnUpdate", function(self)
|
|
self:Hide()
|
|
F.maj()
|
|
end)
|
|
F.attendre = attendre
|
|
F.G, F.txt, F.actif, F.couleur, F.COULEURS, F.ROLES = G, txt, actif, couleur, COULEURS, ROLES
|
|
|
|
function F.demander()
|
|
if F.cadre and F.cadre:IsShown() then attendre:Show() end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ le panneau
|
|
|
|
-- Le panneau du client se tait : ses regions, ses cadres fils sauf son
|
|
-- contenu et notre fenetre ; il n'attrape plus la souris. Son contenu reste
|
|
-- affiche -- sa logique en depend -- mais transparent, et pose SOUS notre
|
|
-- fenetre : ses boutons invisibles ne peuvent rien attraper.
|
|
local function etoufferClient()
|
|
local p = LFDParentFrame
|
|
for _, r in ipairs({ p:GetRegions() }) do r:Hide() end
|
|
for _, c in ipairs({ p:GetChildren() }) do
|
|
if c ~= F.cadre and c ~= LFDQueueFrame then c:Hide() end
|
|
end
|
|
p:EnableMouse(false)
|
|
LFDQueueFrame:SetAlpha(0)
|
|
LFDQueueFrame:ClearAllPoints()
|
|
LFDQueueFrame:SetPoint("TOPLEFT", F.cadre, "TOPLEFT", 0, 0)
|
|
LFDQueueFrame:SetWidth(p:GetWidth())
|
|
LFDQueueFrame:SetHeight(p:GetHeight())
|
|
end
|
|
|
|
-- NOTRE FENETRE PASSE D'UN PANNEAU A L'AUTRE : fille de celui qui est
|
|
-- ouvert, au-dessus de son contenu ; a sa place retenue si on l'a deplacee,
|
|
-- sinon a celle du panneau.
|
|
function F.attacher(panneau)
|
|
local f = F.cadre
|
|
if f:GetParent() ~= panneau then f:SetParent(panneau) end
|
|
f:SetFrameLevel(panneau:GetFrameLevel() + 30)
|
|
local pos = ForeverUIDB and ForeverUIDB.positions and ForeverUIDB.positions.chercheur
|
|
if not pos then
|
|
f:ClearAllPoints()
|
|
f:SetPoint("TOPLEFT", panneau, "TOPLEFT", 0, 0)
|
|
end
|
|
end
|
|
|
|
-- UN ONGLET : son panneau du client s'ouvre, l'autre se ferme. Les donjons
|
|
-- restent fermes sous le niveau du client (SHOW_LFD_LEVEL, comme le
|
|
-- micro-bouton).
|
|
function F.allerA(cle)
|
|
if cle == "donjons" then
|
|
if UnitLevel("player") < (SHOW_LFD_LEVEL or 15) then return end
|
|
if LFRParentFrame and LFRParentFrame:IsShown() then HideUIPanel(LFRParentFrame) end
|
|
if not LFDParentFrame:IsShown() then ShowUIPanel(LFDParentFrame) end
|
|
elseif LFRParentFrame then
|
|
if LFDParentFrame:IsShown() then HideUIPanel(LFDParentFrame) end
|
|
if LFRParentFrame:IsShown() then F.afficher(cle) else ShowUIPanel(LFRParentFrame) end
|
|
end
|
|
end
|
|
|
|
local function ouvrir()
|
|
if LFRParentFrame and LFRParentFrame:IsShown() then HideUIPanel(LFRParentFrame) end
|
|
F.attacher(LFDParentFrame)
|
|
etoufferClient()
|
|
-- a l'ouverture, les categories ; en file pour des donjons choisis, leur
|
|
-- liste
|
|
if modeEnFile() and LFDQueueFrame.type == "specific" then
|
|
F.vue = "liste"
|
|
else
|
|
F.vue = "categories"
|
|
end
|
|
F.cadre:Show()
|
|
F.afficher("donjons")
|
|
end
|
|
|
|
local function construire()
|
|
if F.cadre or not LFDParentFrame or not LFDQueueFrame then return end
|
|
local f = CreateFrame("Frame", "ForeverUIGroupFinderFrame", LFDParentFrame)
|
|
f:SetWidth(G.largeur)
|
|
f:SetHeight(G.hauteur)
|
|
f:SetPoint("TOPLEFT", LFDParentFrame, "TOPLEFT", 0, 0)
|
|
-- au-dessus de tout le contenu du client (ses voiles montent a 16)
|
|
f:SetFrameLevel(LFDParentFrame:GetFrameLevel() + 30)
|
|
f:EnableMouse(true)
|
|
F.cadre = f
|
|
construireCadre(f)
|
|
construirePage(f)
|
|
|
|
F.inscrirePage("donjons", F.pageDonjons, majDonjons)
|
|
F.onglets = {}
|
|
local precedent
|
|
for n, def in ipairs(ONGLETS) do
|
|
if def.raid and not LFRParentFrame then break end
|
|
local o = creerOnglet(f, def, n)
|
|
if precedent then
|
|
o:SetPoint("TOPLEFT", precedent, "BOTTOMLEFT", 0, G.ongletEcart)
|
|
else
|
|
o:SetPoint("TOPLEFT", f, "TOPRIGHT", 0, G.ongletY)
|
|
end
|
|
F.onglets[n] = o
|
|
precedent = o
|
|
end
|
|
f:Hide()
|
|
end
|
|
|
|
construire()
|
|
|
|
if F.cadre then
|
|
LFDParentFrame:HookScript("OnShow", ouvrir)
|
|
LFDParentFrame:HookScript("OnHide", function()
|
|
if F.cadre:GetParent() == LFDParentFrame then F.cadre:Hide() end
|
|
end)
|
|
-- chaque mise a jour du client, et le changement de type (le PNJ d'une
|
|
-- conversation l'appelle aussi) : la vue suit le type choisi
|
|
for _, nom in ipairs({ "LFDQueueFrameSpecificList_Update", "LFDQueueFrameRandom_UpdateFrame",
|
|
"LFDQueueFrameFindGroupButton_Update", "LFG_UpdateRolesChangeable", "LFG_UpdateRoleCheckboxes",
|
|
"LFG_UpdateLockedOutPanels", "LFDFrame_UpdateBackfill", "LFDQueueFrameRandomCooldownFrame_Update" }) do
|
|
if _G[nom] then hooksecurefunc(nom, F.demander) end
|
|
end
|
|
if LFDQueueFrame_SetType then
|
|
hooksecurefunc("LFDQueueFrame_SetType", function(valeur)
|
|
F.vue = (valeur == "specific") and "liste" or "categories"
|
|
F.demander()
|
|
end)
|
|
end
|
|
local veilleur = CreateFrame("Frame")
|
|
for _, ev in ipairs({ "LFG_UPDATE", "LFG_ROLE_UPDATE", "LFG_LOCK_INFO_RECEIVED",
|
|
"LFG_UPDATE_RANDOM_INFO", "PARTY_MEMBERS_CHANGED" }) do
|
|
veilleur:RegisterEvent(ev)
|
|
end
|
|
veilleur:SetScript("OnEvent", F.demander)
|
|
-- deplacable par son titre ; devant quand on l'ouvre ou qu'on la clique
|
|
ForeverUI.Superposition.deplacable(F.cadre, F.cadre.bandeau, "chercheur")
|
|
ForeverUI.Superposition.inscrire("chercheur", LFDParentFrame, function()
|
|
local z = { F.cadre }
|
|
for _, o in ipairs(F.onglets) do z[#z + 1] = o end
|
|
return z
|
|
end)
|
|
end
|
|
|
|
-- TEMOIN -- /fui chercheur
|
|
function ForeverUI.GroupFinderDebug()
|
|
local dire = function(t) DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffForeverUI|r " .. t) end
|
|
if not F.cadre then
|
|
dire(L.GROUPFINDER_DEBUG_NOT_BUILT)
|
|
return
|
|
end
|
|
dire(string.format(L.GROUPFINDER_DEBUG_STATE,
|
|
tostring(F.vue), tostring(LFDQueueFrame.type), tostring(GetLFGMode()),
|
|
LFDDungeonList and #LFDDungeonList or 0, F.cadre:IsShown() and L.GROUPFINDER_DEBUG_SHOWN or L.GROUPFINDER_DEBUG_HIDDEN,
|
|
F.cadre:GetFrameLevel(), tostring(LFDQueueFrame:GetAlpha()), LFDQueueFrame:GetFrameLevel()))
|
|
-- le navigateur de raid : la recherche, et ce qui a ete releve pour
|
|
-- chacun de ses raids
|
|
local R = ForeverUI.GroupFinderRaid
|
|
if R and R.cache then
|
|
local r = R.recherche
|
|
dire(string.format(L.GROUPFINDER_DEBUG_RAID,
|
|
r and r.nom or L.GROUPFINDER_DEBUG_NONE, tostring(SearchLFGGetJoinedID and SearchLFGGetJoinedID())))
|
|
for _, id in ipairs(r and r.ids or {}) do
|
|
local info = LFGGetDungeonInfoByID and LFGGetDungeonInfoByID(id)
|
|
dire(string.format(L.GROUPFINDER_DEBUG_RAID_ENTRY, info and info[1] or "?", id,
|
|
R.cache[id] and #R.cache[id] or L.GROUPFINDER_DEBUG_NOTHING))
|
|
end
|
|
end
|
|
end
|