2c94ea6bc9
- PNJ (NpcDialog.lua, nouveau) : dialogue et quete, livres et lettres, petition, registre de guilde a la DA de camelot (parchemin QuestBG-Parchment, portrait, croix, places de camelot, contours de qualite des objets). - Barres de defilement : chacune cachee quand rien ne defile, et sans elle le contenu laisse a droite la marge qu'il a a gauche (courrier et papeterie, banque de guilde, hotel des ventes, reputation, competences, monnaies, contacts, guilde, macros, reglages, chercheur, dialogues des PNJ) ; ecrans d'accueil : selection des personnages (cartes centrees), royaumes, AddOns, creation. - Chercheur de donjon : la liste des donjons reprend la liste a categories des raids (en-tetes de la feuille, cases de camelot), l'en-tete gardant sa case "tout cocher". - Tabard : camera 1 et modele dans la moitie gauche de l'encadre, cadrage independant de la race (gnome). - Cabine : portrait a 48 (1, 1.5) ; README a jour (fenetres secondaires, commerce). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
264 lines
9.5 KiB
Lua
264 lines
9.5 KiB
Lua
-- ForeverUI : la barre de defilement de camelot, MinimalScrollBar.
|
|
--
|
|
-- RELEVE -- camelot/reputationframe.xml et blizzard_tokenui/camelot :
|
|
-- <EventFrame parentKey="ScrollBar" inherits="MinimalScrollBar">
|
|
-- TOPLEFT sur le TOPRIGHT du ScrollBox (5, -2)
|
|
-- BOTTOMLEFT sur le BOTTOMRIGHT du ScrollBox (5, 4)
|
|
--
|
|
-- MESURE SUR L'ART, et non d'apres les noms -- la regle vaut ici plus
|
|
-- qu'ailleurs, les noms de ces atlas ne disant pas ce qu'ils portent :
|
|
--
|
|
-- minimal-scrollbar-track-top / -bottom 8 x 8, noir a 60 % d'alpha,
|
|
-- le texel du bout transparent :
|
|
-- ce sont les deux embouts
|
|
-- arrondis de la glissiere
|
|
-- !minimal-scrollbar-track-middle 8 x 1, faite pour s'etirer
|
|
-- minimal-scrollbar-thumb-top 8 x 8, brun : l'embout du haut
|
|
-- minimal-scrollbar-thumb-middle 8 x 515, brun, etirable
|
|
-- minimal-scrollbar-thumb-bottom 8 x 36 -- et ce N'EST PAS un
|
|
-- embout : son alpha monte de 1 a
|
|
-- 255 sur les 36 pixels, donc son
|
|
-- HAUT est transparent. Posee au
|
|
-- bas du curseur, elle le faisait
|
|
-- fondre dans le noir de la
|
|
-- glissiere. ELLE N'EST PAS
|
|
-- EMPLOYEE.
|
|
-- minimal-scrollbar-arrow-top / -bottom 17 x 11, plus larges que la
|
|
-- barre : elles la debordent de
|
|
-- 4,5 de chaque cote
|
|
--
|
|
-- LES DEUX BOUTS DU CURSEUR SONT LE MEME MORCEAU, le second RETOURNE.
|
|
-- thumb-top est opaque d'un bord a l'autre, avec un filet clair sur son
|
|
-- premier texel : c'est un embout fini. On le pose en haut tel quel et en
|
|
-- bas retourne, et le milieu s'etire entre les deux -- le curseur est alors
|
|
-- plein jusqu'a ses extremites, ce que la demande veut. Ecart assume, et
|
|
-- mesure : garder le morceau nomme "bottom" donnait un degrade.
|
|
--
|
|
-- CE QUI DIFFERE, ET POURQUOI. 3.3.5 n'a pas MinimalScrollBar, ni le
|
|
-- ScrollBox qui le pilote : la barre est refaite en entier, et c'est
|
|
-- l'appelant qui lui dit combien de lignes existent, combien tiennent, et
|
|
-- ou il en est. Elle lui rend le nouveau decalage, rien de plus -- elle ne
|
|
-- touche a aucune liste.
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
|
|
local LARGEUR = 8
|
|
local FLECHE_L, FLECHE_H = 17, 11
|
|
local CURSEUR_BOUT = 8 -- minimal-scrollbar-thumb-top
|
|
local CURSEUR_MIN = 2 * CURSEUR_BOUT -- ses deux bouts, sans milieu
|
|
local TRACK_BOUT = 8
|
|
|
|
local ATLAS = {
|
|
trackHaut = "minimal-scrollbar-track-top-c60",
|
|
trackMilieu = "!minimal-scrollbar-track-middle-c60",
|
|
trackBas = "minimal-scrollbar-track-bottom-c60",
|
|
curseurBout = "minimal-scrollbar-thumb-top-c60",
|
|
curseurMilieu = "minimal-scrollbar-thumb-middle-c60",
|
|
flecheHaut = "minimal-scrollbar-arrow-top-c60",
|
|
flecheHautSurvol = "minimal-scrollbar-arrow-top-over-c60",
|
|
flecheBas = "minimal-scrollbar-arrow-bottom-c60",
|
|
flecheBasSurvol = "minimal-scrollbar-arrow-bottom-over-c60",
|
|
}
|
|
|
|
-- OU EN EST LA SOURIS, dans le repere d'un cadre. GetCursorPosition rend des
|
|
-- coordonnees d'ECRAN : il faut les ramener a l'echelle du cadre.
|
|
local function souris(cadre)
|
|
local _, y = GetCursorPosition()
|
|
return y / (cadre:GetEffectiveScale() or 1)
|
|
end
|
|
|
|
local function creerFleche(barre, nom, atlas, atlasSurvol, pas)
|
|
local bouton = CreateFrame("Button", nom, barre)
|
|
bouton:SetWidth(FLECHE_L)
|
|
bouton:SetHeight(FLECHE_H)
|
|
|
|
local image = bouton:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(image, atlas, true)
|
|
image:SetAllPoints(bouton)
|
|
bouton.image = image
|
|
|
|
bouton:SetScript("OnEnter", function(self)
|
|
ForeverUI.SetAtlas(self.image, atlasSurvol, true)
|
|
end)
|
|
bouton:SetScript("OnLeave", function(self)
|
|
ForeverUI.SetAtlas(self.image, atlas, true)
|
|
end)
|
|
bouton:SetScript("OnClick", function()
|
|
barre:Deplacer(barre.decalage + pas)
|
|
end)
|
|
|
|
return bouton
|
|
end
|
|
|
|
-- LA BARRE. `parent` la porte, `liste` est ce qu'elle fait defiler : on
|
|
-- s'ancre sur lui comme camelot le fait sur son ScrollBox.
|
|
function ForeverUI.CreateScrollBar(nom, parent, liste)
|
|
local barre = CreateFrame("Frame", nom, parent)
|
|
barre:SetWidth(LARGEUR)
|
|
barre:SetPoint("TOPLEFT", liste, "TOPRIGHT", 5, -2)
|
|
barre:SetPoint("BOTTOMLEFT", liste, "BOTTOMRIGHT", 5, 4)
|
|
|
|
barre.total = 0
|
|
barre.visibles = 0
|
|
barre.decalage = 0
|
|
|
|
local haut = creerFleche(barre, nom .. "Up", ATLAS.flecheHaut,
|
|
ATLAS.flecheHautSurvol, -1)
|
|
haut:SetPoint("TOP", barre, "TOP", 0, 0)
|
|
barre.flecheHaut = haut
|
|
|
|
local bas = creerFleche(barre, nom .. "Down", ATLAS.flecheBas,
|
|
ATLAS.flecheBasSurvol, 1)
|
|
bas:SetPoint("BOTTOM", barre, "BOTTOM", 0, 0)
|
|
barre.flecheBas = bas
|
|
|
|
-- LA GLISSIERE, entre les deux fleches : deux embouts et un milieu tendu.
|
|
local piste = CreateFrame("Frame", nil, barre)
|
|
piste:SetPoint("TOPLEFT", haut, "BOTTOMLEFT", 0, 0)
|
|
piste:SetPoint("BOTTOMRIGHT", bas, "TOPRIGHT", 0, 0)
|
|
piste:SetWidth(LARGEUR)
|
|
barre.piste = piste
|
|
|
|
local function tranche(cadre, atlas, couche)
|
|
local t = cadre:CreateTexture(nil, couche or "BACKGROUND")
|
|
ForeverUI.SetAtlas(t, atlas, true)
|
|
t:SetWidth(LARGEUR)
|
|
return t
|
|
end
|
|
|
|
local pisteHaut = tranche(piste, ATLAS.trackHaut)
|
|
pisteHaut:SetHeight(TRACK_BOUT)
|
|
pisteHaut:SetPoint("TOP", piste, "TOP", 0, 0)
|
|
local pisteBas = tranche(piste, ATLAS.trackBas)
|
|
pisteBas:SetHeight(TRACK_BOUT)
|
|
pisteBas:SetPoint("BOTTOM", piste, "BOTTOM", 0, 0)
|
|
local pisteMilieu = tranche(piste, ATLAS.trackMilieu)
|
|
pisteMilieu:SetPoint("TOPLEFT", pisteHaut, "BOTTOMLEFT", 0, 0)
|
|
pisteMilieu:SetPoint("BOTTOMRIGHT", pisteBas, "TOPRIGHT", 0, 0)
|
|
|
|
-- LE CURSEUR : ses trois tranches, dans un cadre qu'on deplace.
|
|
local curseur = CreateFrame("Frame", nom .. "Thumb", piste)
|
|
curseur:SetWidth(LARGEUR)
|
|
curseur:SetHeight(CURSEUR_MIN)
|
|
curseur:EnableMouse(true)
|
|
barre.curseur = curseur
|
|
|
|
local cHaut = tranche(curseur, ATLAS.curseurBout, "ARTWORK")
|
|
cHaut:SetHeight(CURSEUR_BOUT)
|
|
cHaut:SetPoint("TOP", curseur, "TOP", 0, 0)
|
|
|
|
-- LE MEME MORCEAU, RETOURNE : on echange le haut et le bas de son
|
|
-- rectangle d'atlas.
|
|
local cBas = tranche(curseur, ATLAS.curseurBout, "ARTWORK")
|
|
local e = ForeverUI.AtlasEntry(ATLAS.curseurBout)
|
|
if e then
|
|
cBas:SetTexCoord(e[2], e[3], e[5], e[4])
|
|
end
|
|
cBas:SetHeight(CURSEUR_BOUT)
|
|
cBas:SetPoint("BOTTOM", curseur, "BOTTOM", 0, 0)
|
|
|
|
local cMilieu = tranche(curseur, ATLAS.curseurMilieu, "ARTWORK")
|
|
cMilieu:SetPoint("TOPLEFT", cHaut, "BOTTOMLEFT", 0, 0)
|
|
cMilieu:SetPoint("BOTTOMRIGHT", cBas, "TOPRIGHT", 0, 0)
|
|
|
|
-- CE QUE LA BARRE SAIT FAIRE.
|
|
|
|
-- Deplacer d'un cran, en bornant : elle ne connait pas la liste, elle
|
|
-- ne connait que ses trois nombres.
|
|
function barre:Deplacer(vers)
|
|
local maximum = math.max(0, self.total - self.visibles)
|
|
vers = math.max(0, math.min(math.floor(vers + 0.5), maximum))
|
|
if vers == self.decalage then
|
|
return
|
|
end
|
|
self.decalage = vers
|
|
self:Repositionner()
|
|
if self.surDefilement then
|
|
self.surDefilement(vers)
|
|
end
|
|
end
|
|
|
|
-- Poser le curseur : sa hauteur dit la part visible, sa place le
|
|
-- decalage.
|
|
function barre:Repositionner()
|
|
local hauteur = self.piste:GetHeight() or 0
|
|
local maximum = math.max(0, self.total - self.visibles)
|
|
|
|
if hauteur <= 0 or maximum <= 0 then
|
|
self.curseur:Hide()
|
|
return
|
|
end
|
|
|
|
local part = self.visibles / self.total
|
|
local taille = math.max(CURSEUR_MIN, math.floor(hauteur * part + 0.5))
|
|
if taille > hauteur then
|
|
taille = hauteur
|
|
end
|
|
local course = hauteur - taille
|
|
|
|
self.curseur:SetHeight(taille)
|
|
self.curseur:ClearAllPoints()
|
|
self.curseur:SetPoint("TOP", self.piste, "TOP", 0,
|
|
-course * (self.decalage / maximum))
|
|
self.curseur:Show()
|
|
end
|
|
|
|
-- CE QUE L'APPELANT LUI DIT : combien de lignes, combien tiennent, ou il
|
|
-- en est. La barre s'efface quand tout tient. Quand elle parait ou
|
|
-- s'efface, `surVisibilite(avec)` le dit a l'appelant, dont le contenu
|
|
-- prend ou rend sa place (regle du 28/09).
|
|
function barre:Regler(total, visibles, decalage)
|
|
self.total = total or 0
|
|
self.visibles = visibles or 0
|
|
self.decalage = decalage or 0
|
|
local avec = self.total > self.visibles
|
|
if avec then
|
|
self:Show()
|
|
self:Repositionner()
|
|
else
|
|
self:Hide()
|
|
end
|
|
if avec ~= self.avecAvant then
|
|
self.avecAvant = avec
|
|
if self.surVisibilite then self.surVisibilite(avec) end
|
|
end
|
|
end
|
|
|
|
-- GLISSER LE CURSEUR. Un OnUpdate le suit tant que le bouton est tenu :
|
|
-- 3.3.5 n'a pas de suivi de souris sur un cadre.
|
|
curseur:SetScript("OnMouseDown", function(self)
|
|
self.prise = souris(self)
|
|
self.priseDecalage = barre.decalage
|
|
self:SetScript("OnUpdate", function(soi)
|
|
local hauteur = barre.piste:GetHeight() or 0
|
|
local course = hauteur - (soi:GetHeight() or 0)
|
|
local maximum = math.max(0, barre.total - barre.visibles)
|
|
if course <= 0 or maximum <= 0 then
|
|
return
|
|
end
|
|
local parcouru = soi.prise - souris(soi)
|
|
barre:Deplacer(soi.priseDecalage + parcouru / course * maximum)
|
|
end)
|
|
end)
|
|
curseur:SetScript("OnMouseUp", function(self)
|
|
self:SetScript("OnUpdate", nil)
|
|
end)
|
|
|
|
-- CLIQUER LA GLISSIERE saute d'une page, du cote ou l'on a clique.
|
|
piste:EnableMouse(true)
|
|
piste:SetScript("OnMouseDown", function(self)
|
|
local y = souris(self)
|
|
local dessus = barre.curseur:GetTop() or 0
|
|
local dessous = barre.curseur:GetBottom() or 0
|
|
if y > dessus then
|
|
barre:Deplacer(barre.decalage - barre.visibles)
|
|
elseif y < dessous then
|
|
barre:Deplacer(barre.decalage + barre.visibles)
|
|
end
|
|
end)
|
|
|
|
barre:Hide()
|
|
return barre
|
|
end
|