29dc3dfe5b
- Mode agrandi (etape 4) : le plein ecran de WotLK habille a la camelot, carte seule. Cadre aux dimensions de UpdateMaximizedSize, pose en haut au centre dans l'unite de l'interface ; bordure sans portrait ; titre WORLD_MAP ; fil d'Ariane, filtres, etages, coordonnees, boutons rouges. La carte remplit le canevas par les constantes QUESTLIST / FULLMAP que WotLK lit pour la fleche et les reperes ; bordure, menus et liste des quetes du plein ecran de WotLK etouffes. - Petite fenetre et mode agrandi partagent le meme ancrage. - Selecteur d'etages : fond decoupe en trois (16 / 19), variante c60 ; nom elide ; la liste ne descend pas sous la largeur du selecteur. - Banc d'essai : plein ecran de WotLK et ses deux vues, essais du mode agrandi et du selecteur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
297 lines
12 KiB
Lua
297 lines
12 KiB
Lua
-- ForeverUI : les listes des menus deroulants.
|
|
--
|
|
-- CE QUE C'EST. Quand on clique sur un menu deroulant, 3.3.5 ouvre un cadre
|
|
-- global unique -- DropDownList1, et DropDownList2 pour un sous-menu. Tous
|
|
-- les menus du jeu passent par lui : celui des categories de statistiques
|
|
-- comme celui d'un clic droit sur un joueur. Le rhabiller les rhabille tous.
|
|
--
|
|
-- RELEVE -- CE QUE LE CLIENT CHARGE (patch-enUS-2 pour le .xml, patch-enUS-3
|
|
-- pour le .lua, le FrameXML d'origine).
|
|
-- UIDropDownListTemplate : un Button en strate DIALOG qui tient DEUX fonds
|
|
-- en cadres fils, montres l'un ou l'autre selon displayMode --
|
|
-- $parentBackdrop (UI-DialogBox-Background-Dark et UI-DialogBox-Border) et
|
|
-- $parentMenuBackdrop (UI-Tooltip-Background et UI-Tooltip-Border).
|
|
-- UIDropDownMenuButtonTemplate : 100 x 16, avec $parentHighlight
|
|
-- (UI-QuestTitleHighlight en ADD), $parentCheck (UI-CheckBox-Check, 18 x 18
|
|
-- a LEFT), $parentExpandArrow (ChatFrameExpandArrow) et $parentNormalText.
|
|
-- UIDROPDOWNMENU_BUTTON_HEIGHT 16, UIDROPDOWNMENU_BORDER_HEIGHT 15 :
|
|
-- une ligne se pose a -((rang - 1) x 16) - 15 et la liste fait
|
|
-- rangs x 16 + 15 x 2.
|
|
--
|
|
-- RELEVE -- CE QUE FAIT CAMELOT. Blizzard_Menu, MenuStyle1Mixin, que
|
|
-- MenuVariants.GetDefaultMenuMixin et GetDefaultContextMenuMixin rendent
|
|
-- tous deux -- donc le meme habillage pour un menu deroulant et pour un menu
|
|
-- contextuel.
|
|
--
|
|
-- Generate() fond common-dropdown-bg, TOPLEFT (-10, 3) et BOTTOMRIGHT
|
|
-- (10, -3), alpha 0,925 -- UNE texture etiree.
|
|
-- GetInset() gauche 8, haut 8, droite 8, bas 15.
|
|
-- ligne DarkMenuElementTemplate, 20 de haut.
|
|
-- police le compositeur pose GameFontHighlight, blanc, justifie a
|
|
-- gauche et centre verticalement.
|
|
-- largeur DropdownButtonMixin:RegisterMenu -- si la description du
|
|
-- menu n'impose rien, SetMinimumWidth(self:GetWidth()) : la
|
|
-- liste fait AU MOINS la largeur du bouton qui l'ouvre.
|
|
-- coche MenuVariants.CreateCheckbox : la CASE common-dropdown-
|
|
-- ticksquare a LEFT, toujours la, et la COCHE JAUNE
|
|
-- common-dropdown-icon-checkmark-yellow par-dessus, centree
|
|
-- a (2, 1), seulement quand la ligne est choisie.
|
|
-- surbrillance MenuVariants.CreateHighlight : UI-QuestTitleHighlight en
|
|
-- ADD sur toute la ligne -- DEJA CE QUE FAIT 3.3.5.
|
|
-- sous-menu MenuVariants.CreateSubmenuArrow : ChatFrameExpandArrow --
|
|
-- DEJA CE QUE FAIT 3.3.5.
|
|
--
|
|
-- QUELLE SAVEUR. Blizzard_Menu.toc charge Camelot\Menu.xml pour camelot,
|
|
-- mais ses gabarits viennent de [Family]\MenuTemplates : il n'y a pas de
|
|
-- camelot/, et entre les deux familles presentes la reponse se lit dans
|
|
-- l'art -- les atlas common-dropdown-classic-* n'existent NULLE PART dans ce
|
|
-- client, tandis que common-dropdown-* ont tous leur variante c60. C'est
|
|
-- donc la famille mainline, avec l'art c60.
|
|
--
|
|
-- CE QUI DIFFERE, ET POURQUOI.
|
|
-- Les marges de camelot sont dissymetriques (8 en haut, 15 en bas) ; 3.3.5
|
|
-- n'a qu'une constante pour les deux, UIDROPDOWNMENU_BORDER_HEIGHT, et la
|
|
-- sert deux fois. Elle reste a 15 : la tordre deplacerait toutes les
|
|
-- lignes de tous les menus du jeu pour trois pixels.
|
|
-- La case a cocher et la coche jaune n'ont PAS de variante c60 : leur art
|
|
-- de base est celui que camelot montre.
|
|
-- 3.3.5 ne distingue pas une case a cocher d'un bouton radio -- un menu
|
|
-- n'a que info.checked. La paire case + coche jaune sert donc partout, la
|
|
-- ou camelot choisirait le rond pour un choix unique.
|
|
|
|
ForeverUI = ForeverUI or {}
|
|
|
|
-- LE FOND, EN NEUF TRANCHES. Camelot etire une seule texture d'un bord a
|
|
-- l'autre. Mesure sur l'image -- common-dropdown-bg-c60, 68 x 68 -- le
|
|
-- panneau n'occupe que x 9..58 et y 6..55 : le reste est une OMBRE de 9 a
|
|
-- gauche et a droite, 6 en haut et 12 en bas, et les angles sont coupes sur
|
|
-- 6 pixels. L'etirer sur une liste de 200 x 130 multiplie cette ombre par
|
|
-- 3,3 en largeur et par 2 en hauteur : le filet dore rentre d'une vingtaine
|
|
-- de pixels de chaque cote, les angles s'ecrasent, et le bas du panneau
|
|
-- remonte au-dessus de la derniere ligne.
|
|
--
|
|
-- Les coins gardent donc leur taille et seuls les bords s'etirent. Le coin
|
|
-- vaut 18 : l'ombre la plus epaisse (12) plus le pan coupe (6), ce qui
|
|
-- laisse une bande centrale de 32 sur les 68.
|
|
--
|
|
-- Et les marges ne sont plus celles de camelot mais CELLES DE L'IMAGE :
|
|
-- donner l'epaisseur de l'ombre fait tomber le filet exactement sur le bord
|
|
-- du cadre, donc sur la largeur du menu deroulant.
|
|
local FOND_ATLAS = "common-dropdown-bg-c60"
|
|
local FOND_COIN = 18
|
|
local FOND_MARGES = { 9, 6, 9, 12 } -- gauche, haut, droite, bas
|
|
local FOND_ALPHA = 0.925
|
|
local LIGNE_HAUTEUR = 20
|
|
local CASE_ATLAS = "common-dropdown-ticksquare"
|
|
local CASE = 12
|
|
local COCHE_ATLAS = "common-dropdown-icon-checkmark-yellow"
|
|
local COCHE_L, COCHE_H = 15, 14
|
|
local COCHE_X, COCHE_Y = 2, 1
|
|
local FONDS = { "Backdrop", "MenuBackdrop" }
|
|
|
|
-- L'ecart que le client garde entre la liste et ses lignes : il pose la
|
|
-- liste a maxWidth + 25 et les lignes a maxWidth. On le garde tel quel pour
|
|
-- que la marge de droite ne bouge pas quand la liste s'elargit.
|
|
local LISTE_MARGE = 25
|
|
|
|
-- LA LARGEUR. Le client taille la liste sur son texte le plus long
|
|
-- (maxWidth + 25) ; camelot lui impose un PLANCHER, la largeur du bouton
|
|
-- qui l'ouvre (DropdownButtonMixin:RegisterMenu, SetMinimumWidth).
|
|
--
|
|
-- ECART ASSUME, sur demande : ici c'est une EGALITE, pas un plancher. La
|
|
-- liste prend exactement la largeur de son bouton, meme quand une entree
|
|
-- est plus longue -- auquel cas son texte se trouve serre.
|
|
--
|
|
-- Cela se joue a l'affichage de la liste : ToggleDropDownMenu retient le
|
|
-- menu ouvert (UIDROPDOWNMENU_OPEN_MENU) AVANT de la montrer, et ne verifie
|
|
-- qu'elle tient dans l'ecran qu'APRES -- la largeur doit donc etre acquise
|
|
-- a ce moment-la, sinon le recadrage se ferait sur l'ancienne.
|
|
--
|
|
-- Seul le premier niveau d'un MENU DEROULANT est concerne. Un menu
|
|
-- contextuel (displayMode "MENU" : clic droit, menus de la carte, du journal,
|
|
-- du suivi) n'a pas de bouton a epouser -- son ouvreur est un cadre
|
|
-- invisible de 40 de large -- et un sous-menu n'est ouvert par aucun bouton :
|
|
-- ceux-la prennent la largeur de leur CONTENU (corrige le 2026-09-25 : ils
|
|
-- etaient ecrases a 40).
|
|
--
|
|
-- LE CONTENU SE MESURE DANS LA POLICE AFFICHEE. Le client mesure chaque
|
|
-- ligne en GameFontHighlightSmallLeft, avant que nous passions a
|
|
-- GameFontHighlightLeft, plus grande : sa largeur (maxWidth) serait trop
|
|
-- courte. La mesure est refaite a chaque ligne posee (mesurerBouton) avec la
|
|
-- formule de UIDropDownMenu_AddButton.
|
|
local function fixerLargeur(liste, voulue)
|
|
if math.abs(liste:GetWidth() - voulue) < 0.5 then
|
|
return
|
|
end
|
|
liste:SetWidth(voulue)
|
|
for index = 1, (liste.numButtons or 0) do
|
|
local bouton = _G[liste:GetName() .. "Button" .. index]
|
|
if bouton then
|
|
bouton:SetWidth(voulue - LISTE_MARGE)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function ajusterLargeur(liste)
|
|
local ouvreur = UIDROPDOWNMENU_OPEN_MENU
|
|
local niveau = liste.foreverNiveau or liste:GetID()
|
|
if niveau ~= 1 or not ouvreur or not ouvreur.GetWidth or ouvreur.displayMode == "MENU" then
|
|
local contenu = liste.foreverContenu
|
|
if contenu and contenu > 0 then
|
|
-- un menu de ForeverUI peut demander un plancher : la largeur du
|
|
-- bouton qui l'ouvre, comme camelot (SetMinimumWidth)
|
|
local minimum = niveau == 1 and ouvreur and ouvreur.foreverMinimum or 0
|
|
fixerLargeur(liste, math.max(contenu + LISTE_MARGE, minimum))
|
|
end
|
|
return
|
|
end
|
|
|
|
local voulue = ouvreur:GetWidth()
|
|
if not voulue or voulue <= 0 then
|
|
return
|
|
end
|
|
fixerLargeur(liste, voulue)
|
|
end
|
|
|
|
-- La largeur d'une ligne, par la formule de UIDropDownMenu_AddButton : texte
|
|
-- + 40, + 10 pour une fleche ou un nuancier, - 30 sans case, + 10 pour une
|
|
-- icone, + le rembourrage demande.
|
|
local function mesurerBouton(liste, bouton, info)
|
|
if liste.numButtons == 1 then
|
|
liste.foreverContenu = 0
|
|
end
|
|
local texte = _G[bouton:GetName() .. "NormalText"]
|
|
if not (texte and info and info.text) then
|
|
return
|
|
end
|
|
local largeur = texte:GetStringWidth() + 40
|
|
if info.hasArrow or info.hasColorSwatch then largeur = largeur + 10 end
|
|
if info.notCheckable then largeur = largeur - 30 end
|
|
if info.icon then largeur = largeur + 10 end
|
|
if info.padding then largeur = largeur + info.padding end
|
|
if largeur > (liste.foreverContenu or 0) then
|
|
liste.foreverContenu = largeur
|
|
end
|
|
end
|
|
|
|
-- La liste perd ses deux fonds d'epoque et prend celui de camelot.
|
|
--
|
|
-- On RETIRE le fond au lieu de masquer le cadre : ToggleDropDownMenu montre
|
|
-- l'un ou l'autre a chaque ouverture, selon displayMode, et remettrait
|
|
-- debout ce qu'on aurait couche. Un cadre sans fond ne dessine rien.
|
|
local function habillerListe(liste)
|
|
if liste.foreverFond then
|
|
return
|
|
end
|
|
|
|
local nom = liste:GetName()
|
|
for _, suffixe in ipairs(FONDS) do
|
|
local cadre = nom and _G[nom .. suffixe]
|
|
if cadre and cadre.SetBackdrop then
|
|
cadre:SetBackdrop(nil)
|
|
end
|
|
end
|
|
|
|
local tranches = ForeverUI.CreateNineSlice(liste, FOND_ATLAS, FOND_COIN,
|
|
FOND_MARGES, "BACKGROUND")
|
|
if not tranches then
|
|
return
|
|
end
|
|
for _, tranche in ipairs(tranches) do
|
|
tranche:SetAlpha(FOND_ALPHA)
|
|
end
|
|
liste.foreverFond = tranches[1]
|
|
liste.foreverTranches = tranches
|
|
|
|
liste:HookScript("OnShow", ajusterLargeur)
|
|
end
|
|
|
|
-- La case et la coche. La case va en BORDER et la coche reste en ARTWORK :
|
|
-- 3.3.5 n'a pas de sous-niveau de calque, l'ordre vient donc du calque, et
|
|
-- la coche doit passer par-dessus sa case.
|
|
local function habillerBouton(bouton)
|
|
if bouton.foreverCase then
|
|
return
|
|
end
|
|
|
|
local case = bouton:CreateTexture(nil, "BORDER")
|
|
if not ForeverUI.SetAtlas(case, CASE_ATLAS, true) then
|
|
case:Hide()
|
|
end
|
|
case:SetWidth(CASE)
|
|
case:SetHeight(CASE)
|
|
case:SetPoint("LEFT", bouton, "LEFT", 0, 0)
|
|
case:Hide()
|
|
bouton.foreverCase = case
|
|
|
|
local coche = _G[bouton:GetName() .. "Check"]
|
|
if coche then
|
|
ForeverUI.SetAtlas(coche, COCHE_ATLAS, true)
|
|
coche:SetWidth(COCHE_L)
|
|
coche:SetHeight(COCHE_H)
|
|
coche:ClearAllPoints()
|
|
coche:SetPoint("CENTER", case, "CENTER", COCHE_X, COCHE_Y)
|
|
end
|
|
end
|
|
|
|
-- Ce qui se refait a chaque ligne posee : UIDropDownMenu_AddButton remet la
|
|
-- police a GameFontHighlightSmallLeft a chaque passage, et c'est elle qui
|
|
-- sait si la ligne porte une case (info.notCheckable).
|
|
local function reglerBouton(bouton)
|
|
bouton:SetHeight(LIGNE_HAUTEUR)
|
|
if GameFontHighlightLeft then
|
|
bouton:SetNormalFontObject(GameFontHighlightLeft)
|
|
bouton:SetHighlightFontObject(GameFontHighlightLeft)
|
|
end
|
|
|
|
if bouton.foreverCase then
|
|
if bouton.notCheckable then
|
|
bouton.foreverCase:Hide()
|
|
else
|
|
bouton.foreverCase:Show()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Le pas des lignes suit leur hauteur : le client le lit a chaque ligne
|
|
-- posee et a chaque calcul de hauteur de liste.
|
|
UIDROPDOWNMENU_BUTTON_HEIGHT = LIGNE_HAUTEUR
|
|
|
|
if hooksecurefunc and type(UIDropDownMenu_AddButton) == "function" then
|
|
hooksecurefunc("UIDropDownMenu_AddButton", function(info, level)
|
|
level = level or 1
|
|
local liste = _G["DropDownList" .. level]
|
|
if not liste then
|
|
return
|
|
end
|
|
|
|
liste.foreverNiveau = level
|
|
habillerListe(liste)
|
|
|
|
local bouton = _G[liste:GetName() .. "Button" .. (liste.numButtons or 1)]
|
|
if bouton then
|
|
habillerBouton(bouton)
|
|
reglerBouton(bouton)
|
|
mesurerBouton(liste, bouton, info)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- UIDropDownMenu_Refresh retaille la liste sur son texte (maxWidth + 25) et
|
|
-- effacerait la largeur voulue : on la repose derriere elle.
|
|
if hooksecurefunc and type(UIDropDownMenu_Refresh) == "function" then
|
|
hooksecurefunc("UIDropDownMenu_Refresh", function(cadre, valeur, niveau)
|
|
local liste = _G["DropDownList" .. (niveau or UIDROPDOWNMENU_MENU_LEVEL or 1)]
|
|
if liste and liste:IsShown() then
|
|
ajusterLargeur(liste)
|
|
end
|
|
end)
|
|
end
|
|
|
|
ForeverUI.DropDown = {
|
|
Skin = habillerListe,
|
|
SkinButton = habillerBouton,
|
|
Refresh = reglerBouton,
|
|
Fit = ajusterLargeur,
|
|
}
|