Files
moon-well-ui/data/addon/ForeverUI/SkillsTab.lua
T
Adrestie 1a71d63e40 SetFontObject efface la justification : elle se repose apres lui
Un objet de police porte la SIENNE. GameFontNormalLeft est a gauche ;
GameFontHighlight, NumberFontNormal et NumberFontNormalSmallGray n ont
aucun justifyH -- donc CENTRE, releve dans le FontStyles.xml du client.
Un SetJustifyH pose a la creation, ou avant SetFontObject, ne survit
donc pas.

Dans la reputation, le nom se retrouvait centre dans une boite dont la
largeur change d un gabarit a l autre : il se deplacait horizontalement
au fil du defilement, selon le role que la ligne reprenait. Meme faute
dans les competences et les monnaies, ou le compte d une monnaie a zero
passait de RIGHT a CENTER avec GameFontDisable.

Et sur les boutons d action, ou le raccourci et la quantite sont cales
a droite dans le code mais etaient centres a l ecran. C est du code
VALIDE : le geste ne change pas l intention, il la retablit.

camelot le fait exactement ainsi, et c est ce qui le trahit :
  <FontString inherits="GameFontHighlight" justifyH="LEFT">

Le faux du harnais ne touchait pas a justify : il est desormais fidele,
et c est lui qui a trouve la faute des boutons d action.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 16:27:06 +02:00

711 lines
23 KiB
Lua

-- ForeverUI : l'onglet des competences.
--
-- RELEVE -- camelot/SkillsFrame.xml et skillsframe.lua, lus en entier. C'est
-- le meme ecran que la reputation, aux differences pres notees ci-dessous.
--
-- SkillsFrame setAllPoints, parent CharacterFrame, useParentLevel
-- ScrollBox TOPLEFT sur CharacterFrameLeftPaneHost (10, -40)
-- BOTTOMRIGHT sur le meme (-25, 15), avec les deux
-- traits UI-Character-Info-ScrollLine-Long centres sur
-- son TOP et son BOTTOM
-- ScrollBar MinimalScrollBar, TOPLEFT sur le TOPRIGHT du
-- ScrollBox (5, -2), BOTTOMLEFT sur son BOTTOMRIGHT
-- (5, 4)
-- SkillDetailFrame CharacterFrameSidePaneTemplate, plus un RankBar
--
-- SetElementIndentCalculator et SetPadding : identiques a la reputation --
-- retraits 0 / 46 / 2, marges de 10, ecart de 3.
--
-- SkillsHeaderTemplate, hauteur 26 -- et non 28 comme la reputation :
-- fond common-button-list-collapseExpand, etire sur la ligne
-- StateIcon common-button-list-plus ou -minus, RIGHT (-8, -1)
-- nom GameFontNormalLeft, hauteur 15, LEFT x = 10
--
-- SkillsSubHeaderTemplate, hauteur 22 :
-- son bouton 20 x 20, LEFT x = 2 -- et non ancre a une AccountWideIcon
-- comme celui de la reputation
-- nom a +4 du bouton, jusqu'au LEFT de la barre moins 10
--
-- SkillsEntryTemplate, hauteur 30 :
-- barre SkillsBarTemplate, RIGHT x = -3
-- nom GameFontHighlight, hauteur 15, LEFT x = 2 -- il n'y a pas
-- d'AccountWideIcon ici, donc pas le 15 de la reputation
-- survol les memes trois tranches, aux alphas de
-- RefreshBackgroundHighlightOpacity : 0 / 0,10 / 0,20. Pas de
-- cas "en guerre" : la teinte est toujours blanche.
--
-- SkillsBarTemplate, 160 x 29, herite de ColoredProgressBarTemplate :
-- InitializeBarForStandardSkill pose SetFillTextureByColorType(Blue) puis
-- UpdateBarColor(WHITE_FONT_COLOR). LA BARRE EST DONC BLEUE PAR SON
-- SPRITE, common-stat-bar-blue, et non par une teinte -- c'est tout ce qui
-- la distingue de celle de la reputation.
-- Son texte est TOUJOURS la progression : "rang / maximum", ou
-- "rang (+bonus) / maximum" quand il y a un bonus, celui-ci en vert.
-- TryShowBarProgressText est appele des l'initialisation, pas seulement au
-- survol.
--
-- SkillDetailFrameMixin : titre = le nom de la competence, RankBar de
-- 180 x 29 au TOP du BOTTOM du separateur (y = -6), et la description
-- reancree au TOP du BOTTOM du RankBar avec y = -8 -- et non -6 comme la
-- reputation. Sans competence choisie, le volet affiche
-- SKILL_DETAIL_SELECT_PROMPT.
--
-- SelectFirstSkillIfNoneSelected : a l'ouverture, si rien n'est choisi, la
-- premiere competence qui n'est pas un en-tete l'est -- "opening the tab
-- with an empty detail pane reads as broken", dit le commentaire de la
-- source.
--
-- CE QUE 3.3.5 DONNE. GetNumSkillLines et GetSkillLineInfo, qui rend treize
-- valeurs : nom, en-tete, deplie, rang, points temporaires, bonus, rang
-- maximal, abandonnable, cout d'un pas, cout d'un rang, niveau minimal, type
-- de cout, DESCRIPTION. ExpandSkillHeader et CollapseSkillHeader replient,
-- SetSelectedSkill et GetSelectedSkill choisissent.
--
-- CE QUI DIFFERE, ET POURQUOI :
-- * PAS DE SOUS-EN-TETE. GetSkillLineInfo ne rend pas d'indicateur
-- d'enfant : la hierarchie de 3.3.5 n'a qu'un niveau. Le gabarit existe
-- donc dans le releve mais ne sert pas ici.
-- * LES LIGNES D'ARMES ne sont pas detaillees. camelot ajoute au volet
-- droit le calcul des chances de toucher, de critique et de coup
-- glancant face a un boss ; il demande des chaines --
-- WEAPON_SKILL_DETAIL_* -- que ce client n'a pas. A faire si besoin.
-- * La description ne defile pas : ScrollingFontTemplate n'existe pas.
-- * La barre de defilement est celle de camelot, MinimalScrollBar, refaite
-- dans ScrollBar.lua : 3.3.5 n'a ni ce gabarit ni le ScrollBox qui le
-- pilote.
local ForeverUI = ForeverUI or {}
_G.ForeverUI = ForeverUI
local LISTE_X, LISTE_Y = 10, -40
local LISTE_X2, LISTE_Y2 = -25, 15
local ENTREE_H = 30 -- SkillsEntryTemplate
local ENTETE_H = 26 -- SkillsHeaderTemplate
local MARGE = 10 -- SetPadding
local ECART = 3 -- elementSpacing
local RETRAIT_ENTETE = 0
local RETRAIT_AUTRE = 2
local BARRE_L, BARRE_H = 160, 29
local BARRE_X = -3
local REMPLISSAGE_H = 15
local NOM_H = 15
local NOM_X = 2 -- SkillsEntryTemplate
local NOM_ECART = -10
local ENTETE_NOM_X = 10
local FLECHE_X, FLECHE_Y = -8, -1
local FLECHE_PLACE = 16
local COTE = 6
local PLAQUE_COIN = 12 -- le meme que la reputation
local JAUGE_COIN = 10
local ATLAS_BARRE_FOND = "common-stat-bar-bg"
local ATLAS_ENTETE = "common-button-list-collapseexpand"
local ATLAS_PLUS = "common-button-list-plus"
local ATLAS_MOINS = "common-button-list-minus"
local ATLAS_TRAIT = "ui-character-info-scrollline-long"
local ATLAS_SURVOL_COTE = "charactercreate-customize-dropdown-linemouseover-side"
local ATLAS_SURVOL_MILIEU = "charactercreate-customize-dropdown-linemouseover-middle"
local ATLAS_SEPARATEUR = "ui-character-info-scrollline"
-- LE REMPLISSAGE BLEU, cuit au masque comme le blanc de la reputation :
-- meme decoupe que le fond, pour que les contours se superposent.
local CHEMIN_REMPLISSAGE = "Interface\\ForeverUI\\Bars\\statbarfillblue"
-- Le volet droit, CharacterFrameSidePaneTemplate.
local VOLET_DROIT_X, VOLET_DROIT_Y = 16, -14
local VOLET_DROIT_X2, VOLET_DROIT_Y2 = -12, 14
local TITRE_L = 195
local SOUS_TITRE_Y = -3
local SEPARATEUR_Y = -4
local RANG_L, RANG_H = 180, 29
local RANG_Y = -6
local DESCRIPTION_Y = -8 -- et non -6 : SkillDetailFrameMixin
local DESCRIPTION_X2 = -14
local DESCRIPTION_Y2 = 6
-- La taille du volet, par construction.
local VOLET_L, VOLET_H = 398, 464
local lignes = {}
local panneau, decalage = nil, 0
local visibles = 0
local choisie -- le NOM, seule cle stable
local detail, dernieresDonnees
-- --------------------------------------------------------------- les donnees
-- GetSkillLineInfo, dans l'ordre : nom, en-tete, deplie, rang, points
-- temporaires, bonus, rang maximal, abandonnable, cout d'un pas, cout d'un
-- rang, niveau minimal, type de cout, description.
local function lireCompetence(rang)
local nom, entete, deplie, valeur, temporaires, bonus, maximum, _, _, _,
_, _, description = GetSkillLineInfo(rang)
if not nom or nom == "" then
return nil
end
valeur = (valeur or 0) + (temporaires or 0)
bonus = bonus or 0
maximum = maximum or 0
-- InitializeBarForStandardSkill : "rang / maximum", ou "rang (+bonus) /
-- maximum" quand il y a un bonus, celui-ci en vert.
local texte
if bonus == 0 then
texte = tostring(valeur) .. " / " .. tostring(maximum)
else
texte = tostring(valeur) .. " |cff00ff00(+" .. tostring(bonus)
.. ")|r / " .. tostring(maximum)
end
return {
index = rang,
nom = nom,
entete = entete,
replie = (entete and not deplie) or false,
valeur = valeur,
maximum = maximum,
texte = texte,
description = description or "",
}
end
local function indiceDe(nom)
if not nom then
return nil
end
for rang = 1, (GetNumSkillLines and GetNumSkillLines()) or 0 do
if GetSkillLineInfo(rang) == nom then
return rang
end
end
return nil
end
-- --------------------------------------------------------------- une ligne
local function creerLigne(index, largeur)
local ligne = CreateFrame("Button", "ForeverUISkillRow" .. index, panneau)
ligne:SetWidth(largeur)
ligne:SetHeight(ENTREE_H)
ligne.plaque = ForeverUI.CreateNineSlice(ligne, ATLAS_ENTETE, PLAQUE_COIN,
{ 0, 0, 0, 0 }, "BACKGROUND") or {}
for _, tranche in ipairs(ligne.plaque) do
tranche:Hide()
end
local survol = CreateFrame("Frame", nil, ligne)
survol:SetAllPoints(ligne)
survol:SetAlpha(0)
ligne.survol = survol
local gauche = survol:CreateTexture(nil, "BACKGROUND")
ForeverUI.SetAtlas(gauche, ATLAS_SURVOL_COTE, true)
gauche:SetWidth(COTE)
gauche:SetPoint("TOPLEFT", survol, "TOPLEFT", 0, 0)
gauche:SetPoint("BOTTOMLEFT", survol, "BOTTOMLEFT", 0, 0)
local droite = survol:CreateTexture(nil, "BACKGROUND")
if ForeverUI.SetAtlas(droite, ATLAS_SURVOL_COTE, true) then
local e = ForeverUI.AtlasEntry(ATLAS_SURVOL_COTE)
droite:SetTexCoord(e[3], e[2], e[4], e[5])
end
droite:SetWidth(COTE)
droite:SetPoint("TOPRIGHT", survol, "TOPRIGHT", 0, 0)
droite:SetPoint("BOTTOMRIGHT", survol, "BOTTOMRIGHT", 0, 0)
local milieu = survol:CreateTexture(nil, "BACKGROUND")
ForeverUI.SetAtlas(milieu, ATLAS_SURVOL_MILIEU, true)
milieu:SetPoint("TOPLEFT", gauche, "TOPRIGHT", 0, 0)
milieu:SetPoint("BOTTOMRIGHT", droite, "BOTTOMLEFT", 0, 0)
local barre = CreateFrame("Frame", nil, ligne)
barre:SetWidth(BARRE_L)
barre:SetHeight(BARRE_H)
barre:SetPoint("RIGHT", ligne, "RIGHT", BARRE_X, 0)
ligne.barre = barre
ForeverUI.CreateNineSlice(barre, ATLAS_BARRE_FOND, JAUGE_COIN,
{ 0, 0, 0, 0 }, "BACKGROUND")
barre.remplissage = barre:CreateTexture(nil, "BORDER")
barre.remplissage:SetPoint("LEFT", barre, "LEFT", 0, 0)
barre.texte = barre:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
barre.texte:SetPoint("LEFT", barre, "LEFT", 0, 0)
barre.texte:SetPoint("RIGHT", barre, "RIGHT", 0, 0)
barre.texte:SetJustifyH("CENTER")
local nom = ligne:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
nom:SetHeight(NOM_H)
nom:SetJustifyH("LEFT")
ligne.nom = nom
local fleche = ligne:CreateTexture(nil, "OVERLAY")
fleche:SetPoint("RIGHT", ligne, "RIGHT", FLECHE_X, FLECHE_Y)
fleche:Hide()
ligne.fleche = fleche
ligne:RegisterForClicks("LeftButtonUp")
return ligne
end
-- ----------------------------------------------------------- le remplissage
-- SetFillPercent : largeur = fraction x largeur de barre, et la texture
-- rognee d'autant.
local function poserBarreDans(barre, donnees, largeur)
local fraction = 0
if donnees.maximum and donnees.maximum > 0 then
fraction = donnees.valeur / donnees.maximum
end
if fraction < 0 then
fraction = 0
elseif fraction > 1 then
fraction = 1
end
if fraction * largeur < 1 then
barre.remplissage:Hide()
else
barre.remplissage:SetTexture(CHEMIN_REMPLISSAGE)
barre.remplissage:SetTexCoord(0, fraction, 0, 1)
barre.remplissage:SetWidth(largeur * fraction)
barre.remplissage:SetHeight(REMPLISSAGE_H)
barre.remplissage:Show()
end
barre.texte:SetText(donnees.texte or "")
end
-- RefreshBackgroundHighlightOpacity : ici sans le cas "en guerre", et la
-- teinte est toujours blanche.
local function poserSurvol(ligne)
if ligne.entete then
ligne.survol:SetAlpha(0)
return
end
local dessus = ligne:IsMouseOver()
ligne.survol:SetAlpha((ligne.choisie and 0.20) or (dessus and 0.10) or 0)
end
-- SetFontObject EFFACE LA JUSTIFICATION, ET IL FAUT LA REPOSER.
--
-- Un objet de police porte la SIENNE : GameFontNormalLeft est a gauche,
-- GameFontHighlight n'a aucun justifyH -- donc CENTRE, releve dans le
-- FontStyles.xml du client. SetJustifyH pose a la creation ne survit donc
-- pas au premier SetFontObject, et le nom se retrouvait centre dans sa
-- boite. Comme la boite change de largeur d'un gabarit a l'autre, le nom
-- se deplacait horizontalement au fil du defilement, selon le role que la
-- ligne reprenait.
--
-- camelot le fait exactement ainsi, et c'est ce qui le trahit :
-- <FontString parentKey="Name" inherits="GameFontHighlight" justifyH="LEFT">
-- La justification est posee PAR-DESSUS l'objet de police.
local function remplirLigne(ligne, donnees)
ligne.skillIndex = donnees.index
ligne.skillNom = donnees.nom
ligne.entete = donnees.entete
ligne.replie = donnees.replie
ligne.nom:SetText(donnees.nom or "")
ligne.nom:ClearAllPoints()
for _, tranche in ipairs(ligne.plaque) do
if donnees.entete then tranche:Show() else tranche:Hide() end
end
if donnees.entete then
ligne:SetHeight(ENTETE_H)
ligne.barre:Hide()
ligne.nom:SetFontObject(GameFontNormalLeft or GameFontNormal)
ligne.nom:SetJustifyH("LEFT")
ligne.nom:SetPoint("LEFT", ligne, "LEFT", ENTETE_NOM_X, 0)
ligne.nom:SetPoint("RIGHT", ligne, "RIGHT", FLECHE_X - FLECHE_PLACE, 0)
ForeverUI.SetAtlas(ligne.fleche, donnees.replie and ATLAS_PLUS or ATLAS_MOINS)
ligne.fleche:Show()
else
ligne:SetHeight(ENTREE_H)
ligne.barre:Show()
ligne.fleche:Hide()
ligne.nom:SetFontObject(GameFontHighlight or GameFontNormal)
ligne.nom:SetJustifyH("LEFT")
ligne.nom:SetPoint("LEFT", ligne, "LEFT", NOM_X, 0)
ligne.nom:SetPoint("RIGHT", ligne.barre, "LEFT", NOM_ECART, 0)
poserBarreDans(ligne.barre, donnees, BARRE_L)
end
ligne.choisie = (choisie ~= nil and choisie == donnees.nom)
poserSurvol(ligne)
ligne:Show()
end
-- ------------------------------------------------------------- la mise en place
local function retraitDe(donnees)
return donnees.entete and RETRAIT_ENTETE or RETRAIT_AUTRE
end
local function hauteurDe(donnees)
return donnees.entete and ENTETE_H or ENTREE_H
end
-- L'ECRAN DU CLIENT SE TAIT EN ENTIER, A CHAQUE PASSAGE.
--
-- Il ne s'agit pas que de ses lignes. SkillFrame declare aussi un bouton de
-- tri, un bouton "tout replier", son cadre de depliage et ses trois tuiles,
-- deux boutons accepter / annuler, sa liste a ascenseur, et tout un cadre de
-- detail -- ScrollFrame, ScrollChildFrame, StatusBar. Les enumerer serait
-- une liste a tenir a jour et a oublier.
--
-- On masque donc TOUT ce que ce cadre porte et qui n'est pas a nous : ses
-- regions, et ses cadres fils sauf notre panneau. GetRegions ne rend que les
-- premieres, GetChildren que les seconds -- il faut les deux.
--
-- Et a chaque passage, parce que SkillFrame_UpdateSkills remontre les
-- siennes : les masquer une fois ne tient pas.
local function etoufferEcranDuClient()
local cadre = _G["SkillFrame"]
if not cadre then
return
end
for _, region in ipairs({ cadre:GetRegions() }) do
if region.Hide then
region:Hide()
end
end
if cadre.GetChildren then
for _, fils in ipairs({ cadre:GetChildren() }) do
if fils ~= panneau and fils.Hide then
fils:Hide()
end
end
end
end
local function disposer()
local total = (GetNumSkillLines and GetNumSkillLines()) or 0
local hauteurUtile = (panneau:GetHeight() or 0)
if hauteurUtile < 50 then
hauteurUtile = VOLET_H + LISTE_Y - LISTE_Y2
end
local largeurUtile = (panneau:GetWidth() or 0)
if largeurUtile < 50 then
largeurUtile = VOLET_L + LISTE_X2 - LISTE_X
end
local y = MARGE
local posees = 0
for rang, ligne in ipairs(lignes) do
local index = decalage + rang
local donnees = (index <= total) and lireCompetence(index) or nil
local hauteur = donnees and hauteurDe(donnees) or 0
if donnees and y + hauteur <= hauteurUtile - MARGE then
local retrait = retraitDe(donnees)
ligne:SetWidth(largeurUtile - 2 * MARGE - retrait)
remplirLigne(ligne, donnees)
ligne:ClearAllPoints()
ligne:SetPoint("TOPLEFT", panneau, "TOPLEFT", MARGE + retrait, -y)
y = y + hauteur + ECART
posees = posees + 1
else
ligne:Hide()
end
end
return posees
end
local function poserListe()
if not panneau then
return
end
etoufferEcranDuClient()
local total = (GetNumSkillLines and GetNumSkillLines()) or 0
local posees = disposer()
if decalage > 0 and decalage + posees > total then
decalage = math.max(0, total - posees)
posees = disposer()
end
visibles = posees
if panneau.barre then
panneau.barre:Regler(total, posees, decalage)
end
if ForeverUI.SkillsDetail then
ForeverUI.SkillsDetail()
end
end
ForeverUI.SkillsLayout = poserListe
-- --------------------------------------------------------------- le detail
local function viderDetail()
detail.titre:SetText("")
detail.sousTitre:SetText("")
-- SKILL_DETAIL_SELECT_PROMPT n'existe pas en 3.3.5 : on laisse vide.
detail.description:SetText("")
detail.separateur:Hide()
detail.jauge:Hide()
end
local function majDetail()
if not detail then
return
end
if not choisie then
dernieresDonnees = nil
viderDetail()
return
end
local index = indiceDe(choisie)
local donnees
if index then
if SetSelectedSkill and GetSelectedSkill and GetSelectedSkill() ~= index then
SetSelectedSkill(index)
end
donnees = lireCompetence(index)
dernieresDonnees = donnees
else
donnees = dernieresDonnees
end
if not donnees or donnees.entete then
viderDetail()
return
end
detail.titre:SetText(donnees.nom or "")
detail.sousTitre:SetText("")
detail.separateur:Show()
detail.jauge:Show()
poserBarreDans(detail.jauge, donnees, RANG_L)
detail.description:SetText(donnees.description or "")
end
ForeverUI.SkillsDetail = majDetail
local function choisir(nom)
choisie = nom
local index = indiceDe(nom)
if index and SetSelectedSkill then
SetSelectedSkill(index)
end
poserListe()
end
ForeverUI.SkillsSelect = choisir
-- SelectFirstSkillIfNoneSelected : a l'ouverture, la premiere competence qui
-- n'est pas un en-tete est choisie -- un volet droit vide "reads as broken",
-- dit la source.
local function choisirLaPremiere()
if choisie then
return
end
for rang = 1, (GetNumSkillLines and GetNumSkillLines()) or 0 do
local donnees = lireCompetence(rang)
if donnees and not donnees.entete then
choisir(donnees.nom)
return
end
end
end
local function monterDetail(hote)
if detail then
return detail, {}
end
local cadre = CreateFrame("Frame", "ForeverUISkillDetail", hote)
cadre:SetPoint("TOPLEFT", hote, "TOPLEFT", VOLET_DROIT_X, VOLET_DROIT_Y)
cadre:SetPoint("BOTTOMRIGHT", hote, "BOTTOMRIGHT", VOLET_DROIT_X2, VOLET_DROIT_Y2)
detail = cadre
detail.titre = cadre:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
detail.titre:SetWidth(TITRE_L)
detail.titre:SetJustifyH("CENTER")
detail.titre:SetPoint("TOP", cadre, "TOP", 0, 0)
detail.sousTitre = cadre:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
detail.sousTitre:SetWidth(TITRE_L)
detail.sousTitre:SetJustifyH("CENTER")
detail.sousTitre:SetPoint("TOP", detail.titre, "BOTTOM", 0, SOUS_TITRE_Y)
detail.separateur = cadre:CreateTexture(nil, "BORDER")
ForeverUI.SetAtlas(detail.separateur, ATLAS_SEPARATEUR)
detail.separateur:SetPoint("TOP", detail.sousTitre, "BOTTOM", 0, SEPARATEUR_Y)
local jauge = CreateFrame("Frame", "ForeverUISkillRank", cadre)
jauge:SetWidth(RANG_L)
jauge:SetHeight(RANG_H)
jauge:SetPoint("TOP", detail.separateur, "BOTTOM", 0, RANG_Y)
ForeverUI.CreateNineSlice(jauge, ATLAS_BARRE_FOND, JAUGE_COIN,
{ 0, 0, 0, 0 }, "BACKGROUND")
jauge.remplissage = jauge:CreateTexture(nil, "BORDER")
jauge.remplissage:SetPoint("LEFT", jauge, "LEFT", 0, 0)
jauge.texte = jauge:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
jauge.texte:SetPoint("LEFT", jauge, "LEFT", 0, 0)
jauge.texte:SetPoint("RIGHT", jauge, "RIGHT", 0, 0)
jauge.texte:SetJustifyH("CENTER")
detail.jauge = jauge
-- La description, dans une boite : sans bas, un texte long disparait.
detail.description = cadre:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
detail.description:SetPoint("TOPLEFT", jauge, "BOTTOMLEFT", 0, DESCRIPTION_Y)
detail.description:SetPoint("TOPRIGHT", jauge, "BOTTOMRIGHT", 0, DESCRIPTION_Y)
detail.description:SetPoint("BOTTOMLEFT", cadre, "BOTTOMLEFT", 0, DESCRIPTION_Y2)
detail.description:SetPoint("BOTTOMRIGHT", cadre, "BOTTOMRIGHT",
DESCRIPTION_X2, DESCRIPTION_Y2)
detail.description:SetJustifyH("LEFT")
detail.description:SetJustifyV("TOP")
if detail.description.SetWordWrap then
detail.description:SetWordWrap(true)
end
majDetail()
return cadre, {}
end
-- --------------------------------------------------------- la construction
local function suivreSurvol()
for _, ligne in ipairs(lignes) do
if ligne:IsShown() and not ligne.entete then
poserSurvol(ligne)
end
end
end
local function monter(hote)
local cadre = _G["SkillFrame"]
if not cadre or not hote then
return nil, {}
end
cadre:ClearAllPoints()
cadre:SetPoint("TOPLEFT", hote, "TOPLEFT", 0, 0)
cadre:SetPoint("BOTTOMRIGHT", hote, "BOTTOMRIGHT", 0, 0)
if panneau then
choisirLaPremiere()
return nil, { cadre }
end
-- L'art et les lignes de 3.3.5 s'en vont : on ne garde que le cadre.
if cadre.SetBackdrop then
cadre:SetBackdrop(nil)
end
local hauteur = hote:GetHeight() or 0
if hauteur < 100 then
hauteur = VOLET_H
end
local largeur = hote:GetWidth() or 0
if largeur < 100 then
largeur = VOLET_L
end
largeur = largeur + LISTE_X2 - LISTE_X
panneau = CreateFrame("Frame", "ForeverUISkillList", cadre)
panneau:SetPoint("TOPLEFT", hote, "TOPLEFT", LISTE_X, LISTE_Y)
panneau:SetPoint("BOTTOMRIGHT", hote, "BOTTOMRIGHT", LISTE_X2, LISTE_Y2)
panneau:SetWidth(largeur)
local place = math.floor((hauteur + LISTE_Y - LISTE_Y2) / (ENTETE_H + ECART))
if place < 1 then
place = 1
end
for index = 1, place do
local ligne = creerLigne(index, largeur)
ligne:SetScript("OnClick", function(self)
if not self.skillIndex then
return
end
if self.entete then
if self.replie then
ExpandSkillHeader(self.skillIndex)
else
CollapseSkillHeader(self.skillIndex)
end
poserListe()
else
ForeverUI.SkillsSelect(self.skillNom)
end
end)
lignes[index] = ligne
end
-- LES DEUX TRAITS VIVENT SUR NOTRE PANNEAU, et non sur le cadre du
-- client : celui-ci voit toutes ses regions masquees a chaque passage,
-- sans condition, et les notres y auraient disparu avec.
local haut = panneau:CreateTexture(nil, "ARTWORK")
ForeverUI.SetAtlas(haut, ATLAS_TRAIT)
haut:SetPoint("CENTER", panneau, "TOP", 0, 0)
local bas = panneau:CreateTexture(nil, "ARTWORK")
ForeverUI.SetAtlas(bas, ATLAS_TRAIT)
bas:SetPoint("CENTER", panneau, "BOTTOM", 0, 0)
-- LA BARRE DE DEFILEMENT de camelot, a droite de la liste. La meme que
-- la reputation : elle ne connait pas la liste, on lui donne trois
-- nombres et elle rend le nouveau decalage.
panneau.barre = ForeverUI.CreateScrollBar("ForeverUISkillsScrollBar",
cadre, panneau)
panneau.barre.surDefilement = function(nouveau)
decalage = nouveau
poserListe()
end
panneau:SetScript("OnUpdate", suivreSurvol)
panneau:EnableMouseWheel(true)
panneau:SetScript("OnMouseWheel", function(self, sens)
local total = (GetNumSkillLines and GetNumSkillLines()) or 0
decalage = math.max(0, math.min(decalage - sens, total - visibles))
poserListe()
end)
poserListe()
choisirLaPremiere()
return nil, { cadre }
end
ForeverUI.SkillsTab = { Build = monter, BuildRight = monterDetail, Rows = lignes }
-- TEMOIN -- /fui skills.
function ForeverUI.SkillsDebug()
local dire = function(texte)
DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffForeverUI|r " .. texte)
end
local total = (GetNumSkillLines and GetNumSkillLines()) or 0
dire(string.format("competences : %d lignes du client, decalage %d, %d posees, choisie=%s",
total, decalage, visibles, tostring(choisie)))
for rang = 1, total do
local d = lireCompetence(rang)
if d then
DEFAULT_CHAT_FRAME:AddMessage(string.format(
" %2d %-28s entete=%-5s replie=%-5s %s",
rang, d.nom, tostring(d.entete), tostring(d.replie), d.texte))
end
end
end
-- Le client refait sa liste dans SkillFrame_UpdateSkills : on passe apres.
if hooksecurefunc and type(_G["SkillFrame_UpdateSkills"]) == "function" then
hooksecurefunc("SkillFrame_UpdateSkills", poserListe)
end