a7709279b8
La fenêtre de butin reprend le LootFrame de camelot : panneau plat « Objets » de 220 de large et 290 de haut au plus, une carte par emplacement (fond teinté par la qualité, contour, étiquette de rareté, bouton d'objet de 37, nom), barre de défilement au-delà, place sous la souris ou à (16, -116). Le LootFrame du client reste l'hôte, invisible : événements, liste du butin de maître ancrée au bouton choisi, CloseLoot. Feuille interface/lootframe/lootframe.blp ajoutée. Animations à venir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
636 lines
23 KiB
Lua
636 lines
23 KiB
Lua
-- ForeverUI: drawing parts of atlas sheets.
|
|
-- A sheet stays one texture: only the rectangle read from it moves. A partial fill
|
|
-- (health bar at 40 %) crops that rectangle instead of stretching the image, which would
|
|
-- distort the art.
|
|
|
|
ForeverUI = ForeverUI or {}
|
|
|
|
-- Atlas entry { file, left, right, top, bottom, width, height }, or nil if unknown.
|
|
local function entry(name)
|
|
if not UIAtlas or not UIAtlas.data then
|
|
return nil
|
|
end
|
|
return UIAtlas.data[name]
|
|
end
|
|
|
|
ForeverUI.AtlasEntry = entry
|
|
|
|
-- Sets a texture to an atlas element. keepSize keeps the current size (when the frame
|
|
-- sets its own dimensions).
|
|
function ForeverUI.SetAtlas(texture, name, keepSize)
|
|
local e = entry(name)
|
|
if not e then
|
|
return false
|
|
end
|
|
|
|
texture:SetTexture(e[1])
|
|
texture:SetTexCoord(e[2], e[3], e[4], e[5])
|
|
|
|
if not keepSize then
|
|
texture:SetWidth(e[6])
|
|
texture:SetHeight(e[7])
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-- Left-to-right fill: the rectangle is cropped to the fraction. fullWidth: width at 100 %.
|
|
-- The client rejects a zero width, so the texture is hidden instead.
|
|
function ForeverUI.SetAtlasFill(texture, name, fraction, fullWidth)
|
|
local e = entry(name)
|
|
if not e then
|
|
texture:Hide()
|
|
return false
|
|
end
|
|
|
|
if not fraction or fraction ~= fraction or fraction < 0 then
|
|
fraction = 0
|
|
elseif fraction > 1 then
|
|
fraction = 1
|
|
end
|
|
|
|
local width = (fullWidth or e[6]) * fraction
|
|
if width < 1 then
|
|
texture:Hide()
|
|
return true
|
|
end
|
|
|
|
texture:SetTexture(e[1])
|
|
texture:SetTexCoord(e[2], e[2] + (e[3] - e[2]) * fraction, e[4], e[5])
|
|
texture:SetWidth(width)
|
|
texture:SetHeight(e[7])
|
|
texture:Show()
|
|
return true
|
|
end
|
|
|
|
-- Nine-slice cut of one atlas element.
|
|
-- mainline/MainActionBar.xml, camelot/MainMenuBarBagButtons.xml and MainMenuBarMicroMenu.xml
|
|
-- all frame their group with UI-HUD-ActionBar-Frame (TOPLEFT -6, 6; BOTTOMRIGHT 4, -5):
|
|
-- a 55 x 55 octagon (110 x 110 on a 2x sheet) with a bronze edge. The modern client
|
|
-- nine-slices it; stretched in one piece over 560 px, its bevels would become ramps.
|
|
-- options.name: atlas element; options.layer: draw layer (BACKGROUND by default);
|
|
-- options.imageMargin: corner size in the image, px; options.imageSize: image side, px;
|
|
-- options.margin: corner size on screen, px.
|
|
function ForeverUI.SetAtlasNineSlice(parent, options)
|
|
local e = entry(options.name)
|
|
if not e then
|
|
return nil
|
|
end
|
|
|
|
local layer = options.layer or "BACKGROUND"
|
|
local margin = options.margin
|
|
local fraction = options.imageMargin / options.imageSize
|
|
local du = (e[3] - e[2]) * fraction
|
|
local dv = (e[5] - e[4]) * fraction
|
|
local u = { e[2], e[2] + du, e[3] - du, e[3] }
|
|
local v = { e[4], e[4] + dv, e[5] - dv, e[5] }
|
|
|
|
local function piece(cu1, cu2, cv1, cv2)
|
|
local t = parent:CreateTexture(nil, layer)
|
|
t:SetTexture(e[1])
|
|
t:SetTexCoord(u[cu1], u[cu2], v[cv1], v[cv2])
|
|
return t
|
|
end
|
|
|
|
local p = {}
|
|
|
|
p.topLeftCorner = piece(1, 2, 1, 2)
|
|
p.topLeftCorner:SetWidth(margin)
|
|
p.topLeftCorner:SetHeight(margin)
|
|
p.topLeftCorner:SetPoint("TOPLEFT", parent, "TOPLEFT")
|
|
|
|
p.topRightCorner = piece(3, 4, 1, 2)
|
|
p.topRightCorner:SetWidth(margin)
|
|
p.topRightCorner:SetHeight(margin)
|
|
p.topRightCorner:SetPoint("TOPRIGHT", parent, "TOPRIGHT")
|
|
|
|
p.bottomLeftCorner = piece(1, 2, 3, 4)
|
|
p.bottomLeftCorner:SetWidth(margin)
|
|
p.bottomLeftCorner:SetHeight(margin)
|
|
p.bottomLeftCorner:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT")
|
|
|
|
p.bottomRightCorner = piece(3, 4, 3, 4)
|
|
p.bottomRightCorner:SetWidth(margin)
|
|
p.bottomRightCorner:SetHeight(margin)
|
|
p.bottomRightCorner:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT")
|
|
|
|
-- Edges and center are set by two opposite corners: no size to compute.
|
|
p.topEdge = piece(2, 3, 1, 2)
|
|
p.topEdge:SetPoint("TOPLEFT", p.topLeftCorner, "TOPRIGHT")
|
|
p.topEdge:SetPoint("BOTTOMRIGHT", p.topRightCorner, "BOTTOMLEFT")
|
|
|
|
p.bottomEdge = piece(2, 3, 3, 4)
|
|
p.bottomEdge:SetPoint("TOPLEFT", p.bottomLeftCorner, "TOPRIGHT")
|
|
p.bottomEdge:SetPoint("BOTTOMRIGHT", p.bottomRightCorner, "BOTTOMLEFT")
|
|
|
|
p.leftEdge = piece(1, 2, 2, 3)
|
|
p.leftEdge:SetPoint("TOPLEFT", p.topLeftCorner, "BOTTOMLEFT")
|
|
p.leftEdge:SetPoint("BOTTOMRIGHT", p.bottomLeftCorner, "TOPRIGHT")
|
|
|
|
p.rightEdge = piece(3, 4, 2, 3)
|
|
p.rightEdge:SetPoint("TOPLEFT", p.topRightCorner, "BOTTOMLEFT")
|
|
p.rightEdge:SetPoint("BOTTOMRIGHT", p.bottomRightCorner, "TOPRIGHT")
|
|
|
|
p.center = piece(2, 3, 2, 3)
|
|
p.center:SetPoint("TOPLEFT", p.topLeftCorner, "BOTTOMRIGHT")
|
|
p.center:SetPoint("BOTTOMRIGHT", p.bottomRightCorner, "TOPLEFT")
|
|
|
|
return p
|
|
end
|
|
|
|
-- Frame art shared by the three groups at the bottom of the screen.
|
|
-- The corner must hold the whole bevel: the image's top and left profiles only become
|
|
-- constant from pixel 19 of 110. A smaller cut stretches part of the diagonal along the
|
|
-- bar. So 20 (one pixel of margin), which is 10 px on screen on this 2x sheet.
|
|
function ForeverUI.SetBarFrameArt(frame, layer)
|
|
return ForeverUI.SetAtlasNineSlice(frame, {
|
|
name = "ui-hud-actionbar-frame",
|
|
layer = layer or "BACKGROUND",
|
|
imageMargin = 20,
|
|
imageSize = 110,
|
|
margin = 10,
|
|
})
|
|
end
|
|
|
|
-- Divider between two slots. mainline/MainActionBar.xml HorizontalDividerTemplate: 12 wide,
|
|
-- three vertical slices of ui-hud-actionbar-frame-divider. Heights 14 top, 16 center,
|
|
-- 15 bottom fit a 45 button.
|
|
function ForeverUI.CreateDivider(parent, level)
|
|
local frame = CreateFrame("Frame", nil, parent)
|
|
frame:SetWidth(12)
|
|
frame:SetFrameLevel(level or parent:GetFrameLevel())
|
|
|
|
local top = frame:CreateTexture(nil, "ARTWORK")
|
|
if not ForeverUI.SetAtlas(top, "ui-hud-actionbar-frame-divider-threeslice-edgetop", true) then
|
|
frame:Hide()
|
|
return frame
|
|
end
|
|
top:SetHeight(14)
|
|
top:SetPoint("TOPLEFT", frame, "TOPLEFT")
|
|
top:SetPoint("TOPRIGHT", frame, "TOPRIGHT")
|
|
|
|
local down = frame:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(down, "ui-hud-actionbar-frame-divider-threeslice-edgebottom", true)
|
|
down:SetHeight(15)
|
|
down:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT")
|
|
down:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT")
|
|
|
|
local center = frame:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(center, "!ui-hud-actionbar-frame-divider-threeslice-center", true)
|
|
center:SetPoint("TOPLEFT", top, "BOTTOMLEFT")
|
|
center:SetPoint("BOTTOMRIGHT", down, "TOPRIGHT")
|
|
|
|
frame.top, frame.center, frame.down = top, center, down
|
|
return frame
|
|
end
|
|
|
|
-- Panel art: mainline/SharedUIPanelTemplates.xml PortraitFrameFlatTemplate, two layers.
|
|
-- 1. Flat background (FlatPanelBackgroundTemplate), TOPLEFT (2, -20) to BOTTOMRIGHT (-2, 3):
|
|
-- two 16 x 16 rounded bottom corners, an edge between them, the rest flat, all tinted
|
|
-- by PANEL_BACKGROUND_COLOR.
|
|
-- 2. Metal nine-slice frame: HeldBagLayout (mainline/NineSliceLayouts.lua) with the fixes
|
|
-- of camelot/NineSliceLayoutOverrides.lua (top right corner x -2, bottom corners y -8).
|
|
-- PANEL_BACKGROUND_COLOR is not in the extracted code; measured on a real client capture
|
|
-- (docs/reference): (16, 14, 12), opaque. A translucent one turns bag slot gaps blue.
|
|
-- Edges are stretched, not tiled: a tiled atlas texture spreads the whole sheet.
|
|
local PANEL_BACKGROUND = { 16 / 255, 14 / 255, 12 / 255, 1 }
|
|
ForeverUI.PanelBackground = PANEL_BACKGROUND
|
|
|
|
-- HeldBagLayout (blizzard_sharedxml/mainline/nineslicelayouts.lua): the eight pieces are
|
|
-- OVERLAY and each corner has its offset, copied as is. In OVERLAY the metal covers every
|
|
-- region of the frame itself. The source puts title and portrait in child frames
|
|
-- (TitleContainer at frameLevel 510, PortraitContainer), which draw above their parent's
|
|
-- regions; callers must do the same for anything that must stay visible.
|
|
local PANEL_LAYER = "OVERLAY"
|
|
|
|
local PANEL_CORNERS = {
|
|
{ key = "topLeftCorner", name = "ui-frame-portraitmetal-cornertopleftsmall",
|
|
point = "TOPLEFT", x = -13, y = 16 },
|
|
{ key = "topRightCorner", name = "ui-frame-metal-cornertopright",
|
|
point = "TOPRIGHT", x = 4, y = 16 },
|
|
{ key = "bottomLeftCorner", name = "ui-frame-metal-cornerbottomleft",
|
|
point = "BOTTOMLEFT", x = -13, y = -3 },
|
|
{ key = "bottomRightCorner", name = "ui-frame-metal-cornerbottomright",
|
|
point = "BOTTOMRIGHT", x = 4, y = -3 },
|
|
}
|
|
|
|
-- options.topLeftCorner: top left corner atlas. HeldBagLayout uses ...CornerTopLeftSmall,
|
|
-- PortraitFrameTemplate ...CornerTopLeft (a wider ring for a 62 portrait).
|
|
-- options.corners: { key = { x =, y = } } overrides a corner offset, as
|
|
-- camelot/NineSliceLayoutOverrides.lua does on every layout (its art has other sizes).
|
|
-- options.level: puts the metal in a child frame this many levels above the frame. Needed
|
|
-- when the frame has other child frames, which would draw over the metal. The background
|
|
-- stays on the frame itself, behind all its child frames.
|
|
function ForeverUI.SetPanelArt(frame, options)
|
|
if frame.foreverPanel then
|
|
return frame.foreverPanel
|
|
end
|
|
|
|
options = options or {}
|
|
-- host: where the metal goes. The background stays on the frame, at the back.
|
|
local host = frame
|
|
if options.level then
|
|
host = CreateFrame("Frame", nil, frame)
|
|
host:SetAllPoints(frame)
|
|
host:SetFrameLevel(frame:GetFrameLevel() + options.level)
|
|
frame.foreverSkinLayer = host
|
|
end
|
|
|
|
local p = {}
|
|
|
|
-- 1. Flat background
|
|
local r, v, b, a = PANEL_BACKGROUND[1], PANEL_BACKGROUND[2], PANEL_BACKGROUND[3], PANEL_BACKGROUND[4]
|
|
|
|
local bottomLeft = frame:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(bottomLeft, "uiframebackground-nineslice-cornerbottomleft")
|
|
bottomLeft:SetVertexColor(r, v, b, a)
|
|
bottomLeft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 2, 3)
|
|
|
|
local bottomRight = frame:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(bottomRight, "uiframebackground-nineslice-cornerbottomright")
|
|
bottomRight:SetVertexColor(r, v, b, a)
|
|
bottomRight:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 3)
|
|
|
|
local bottomEdge = frame:CreateTexture(nil, "BACKGROUND")
|
|
bottomEdge:SetTexture(r, v, b, a)
|
|
bottomEdge:SetPoint("TOPLEFT", bottomLeft, "TOPRIGHT")
|
|
bottomEdge:SetPoint("BOTTOMRIGHT", bottomRight, "BOTTOMLEFT")
|
|
|
|
local body = frame:CreateTexture(nil, "BACKGROUND")
|
|
body:SetTexture(r, v, b, a)
|
|
body:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, -20)
|
|
body:SetPoint("BOTTOMRIGHT", bottomRight, "TOPRIGHT")
|
|
|
|
p.background = { bottomLeft, bottomRight, bottomEdge, body }
|
|
|
|
-- 2. Metal frame
|
|
for _, corner in ipairs(PANEL_CORNERS) do
|
|
local texture = host:CreateTexture(nil, PANEL_LAYER)
|
|
local atlasName = corner.name
|
|
if corner.key == "topLeftCorner" and options.topLeftCorner then
|
|
atlasName = options.topLeftCorner
|
|
end
|
|
if ForeverUI.SetAtlas(texture, atlasName) then
|
|
local x, y = corner.x, corner.y
|
|
local setting = options.corners and options.corners[corner.key]
|
|
if setting then
|
|
x = setting.x or x
|
|
y = setting.y or y
|
|
end
|
|
texture:SetPoint(corner.point, host, corner.point, x, y)
|
|
p[corner.key] = texture
|
|
p[corner.key .. "Atlas"] = atlasName
|
|
else
|
|
texture:Hide()
|
|
end
|
|
end
|
|
|
|
local function edge(name, point1, target1, relative1, point2, target2, relative2)
|
|
local texture = host:CreateTexture(nil, PANEL_LAYER)
|
|
if not ForeverUI.SetAtlas(texture, name) then
|
|
texture:Hide()
|
|
return nil
|
|
end
|
|
texture:SetPoint(point1, target1, relative1)
|
|
texture:SetPoint(point2, target2, relative2)
|
|
return texture
|
|
end
|
|
|
|
if p.topLeftCorner and p.topRightCorner then
|
|
p.topEdge = edge("_ui-frame-metal-edgetop",
|
|
"TOPLEFT", p.topLeftCorner, "TOPRIGHT",
|
|
"TOPRIGHT", p.topRightCorner, "TOPLEFT")
|
|
p.leftEdge = edge("!ui-frame-metal-edgeleft",
|
|
"TOPLEFT", p.topLeftCorner, "BOTTOMLEFT",
|
|
"BOTTOMLEFT", p.bottomLeftCorner, "TOPLEFT")
|
|
p.rightEdge = edge("!ui-frame-metal-edgeright",
|
|
"TOPRIGHT", p.topRightCorner, "BOTTOMRIGHT",
|
|
"BOTTOMRIGHT", p.bottomRightCorner, "TOPRIGHT")
|
|
p.bottomEdge = edge("_ui-frame-metal-edgebottom",
|
|
"BOTTOMLEFT", p.bottomLeftCorner, "BOTTOMRIGHT",
|
|
"BOTTOMRIGHT", p.bottomRightCorner, "BOTTOMLEFT")
|
|
end
|
|
|
|
frame.foreverPanel = p
|
|
ForeverUI.UpdatePanelCorners(frame)
|
|
return p
|
|
end
|
|
|
|
-- NineSliceUtil.UpdateCornerCropping and ClipNineSliceBottomCorner
|
|
-- (blizzard_sharedxml/nineslice.lua):
|
|
-- overhang = topCornerHeight + bottomCornerHeight - frameHeight
|
|
-- - topOffset - (-bottomOffset)
|
|
-- When a frame is shorter than its two corners stacked, the bottom corners are cropped from
|
|
-- the top by that overhang (texture coordinates and height). Otherwise the corners overlap
|
|
-- and the left edge between them is drawn upside down across the frame.
|
|
function ForeverUI.UpdatePanelCorners(frame)
|
|
local p = frame.foreverPanel
|
|
if not p then
|
|
return
|
|
end
|
|
|
|
local topLeft, bottomLeft
|
|
for _, corner in ipairs(PANEL_CORNERS) do
|
|
if corner.key == "topLeftCorner" then topLeft = corner end
|
|
if corner.key == "bottomLeftCorner" then bottomLeft = corner end
|
|
end
|
|
|
|
local topEntry = ForeverUI.AtlasEntry(p.topLeftCornerAtlas or topLeft.name)
|
|
local bottomEntry = ForeverUI.AtlasEntry(bottomLeft.name)
|
|
if not (topEntry and bottomEntry) then
|
|
return
|
|
end
|
|
|
|
local overhang = topEntry[7] + bottomEntry[7] - frame:GetHeight() - topLeft.y - (-bottomLeft.y)
|
|
|
|
for _, corner in ipairs(PANEL_CORNERS) do
|
|
if corner.point == "BOTTOMLEFT" or corner.point == "BOTTOMRIGHT" then
|
|
local texture = p[corner.key]
|
|
local e = ForeverUI.AtlasEntry(corner.name)
|
|
if texture and e then
|
|
local trim = math.max(0, math.min(overhang, e[7]))
|
|
local uvHeight = e[5] - e[4]
|
|
texture:SetTexCoord(e[2], e[3], e[4] + (trim / e[7]) * uvHeight, e[5])
|
|
texture:SetWidth(e[6])
|
|
texture:SetHeight(e[7] - trim)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- Vertical divider in three slices. common-framedivider (11 x 50) has a cap at each end;
|
|
-- stretched over a panel's height, the caps smear over dozens of pixels. So it is cut by
|
|
-- texture coordinates into top cap, stretched middle and bottom cap.
|
|
-- atlas: element; endCap: cap height in px (4 by default); level: frame level.
|
|
function ForeverUI.CreateVerticalDivider(parent, atlas, endCap, level)
|
|
local e = ForeverUI.AtlasEntry(atlas)
|
|
local frame = CreateFrame("Frame", nil, parent)
|
|
if not e then
|
|
frame:Hide()
|
|
return frame
|
|
end
|
|
|
|
endCap = endCap or 4
|
|
frame:SetWidth(e[6])
|
|
frame:SetFrameLevel(level or parent:GetFrameLevel())
|
|
|
|
local u1, u2, v1, v2, height = e[2], e[3], e[4], e[5], e[7]
|
|
local partV = (v2 - v1) * (endCap / height)
|
|
|
|
local top = frame:CreateTexture(nil, "OVERLAY")
|
|
top:SetTexture(e[1])
|
|
top:SetTexCoord(u1, u2, v1, v1 + partV)
|
|
top:SetHeight(endCap)
|
|
top:SetPoint("TOPLEFT", frame, "TOPLEFT")
|
|
top:SetPoint("TOPRIGHT", frame, "TOPRIGHT")
|
|
|
|
local down = frame:CreateTexture(nil, "OVERLAY")
|
|
down:SetTexture(e[1])
|
|
down:SetTexCoord(u1, u2, v2 - partV, v2)
|
|
down:SetHeight(endCap)
|
|
down:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT")
|
|
down:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT")
|
|
|
|
local middle = frame:CreateTexture(nil, "OVERLAY")
|
|
middle:SetTexture(e[1])
|
|
middle:SetTexCoord(u1, u2, v1 + partV, v2 - partV)
|
|
middle:SetPoint("TOPLEFT", top, "BOTTOMLEFT")
|
|
middle:SetPoint("BOTTOMRIGHT", down, "TOPRIGHT")
|
|
|
|
frame.top, frame.middle, frame.down = top, middle, down
|
|
return frame
|
|
end
|
|
|
|
-- Nine slices cut from one image. A panel image has a shadow and fixed-size rounded
|
|
-- corners; stretched whole, the shadow scales with it and the corners distort. Corners keep
|
|
-- their size, edges stretch one way, the center both.
|
|
-- corner: corner size in px; margins = { left, top, right, bottom }: how far the image
|
|
-- overhangs the frame (the shadow thickness measured on the image), so the image's rim
|
|
-- falls on the frame edge; level: draw layer (BACKGROUND by default).
|
|
function ForeverUI.CreateNineSlice(parent, atlas, corner, margins, level)
|
|
local e = ForeverUI.AtlasEntry(atlas)
|
|
if not e then
|
|
return nil
|
|
end
|
|
|
|
local path, u1, u2, v1, v2, width, height = e[1], e[2], e[3], e[4], e[5], e[6], e[7]
|
|
local du = (u2 - u1) * corner / width
|
|
local dv = (v2 - v1) * corner / height
|
|
local us = { u1, u1 + du, u2 - du, u2 }
|
|
local vs = { v1, v1 + dv, v2 - dv, v2 }
|
|
|
|
local slices = {}
|
|
local function slice(column, row)
|
|
local t = parent:CreateTexture(nil, level or "BACKGROUND")
|
|
t:SetTexture(path)
|
|
t:SetTexCoord(us[column], us[column + 1], vs[row], vs[row + 1])
|
|
slices[#slices + 1] = t
|
|
return t
|
|
end
|
|
|
|
local topLeft, topRight = slice(1, 1), slice(3, 1)
|
|
local bottomLeft, bottomRight = slice(1, 3), slice(3, 3)
|
|
local top, down = slice(2, 1), slice(2, 3)
|
|
local left, right = slice(1, 2), slice(3, 2)
|
|
local center = slice(2, 2)
|
|
|
|
for _, c in ipairs({ topLeft, topRight, bottomLeft, bottomRight }) do
|
|
c:SetWidth(corner)
|
|
c:SetHeight(corner)
|
|
end
|
|
top:SetHeight(corner)
|
|
down:SetHeight(corner)
|
|
left:SetWidth(corner)
|
|
right:SetWidth(corner)
|
|
|
|
local G, H, D, B = margins[1], margins[2], margins[3], margins[4]
|
|
topLeft:SetPoint("TOPLEFT", parent, "TOPLEFT", -G, H)
|
|
topRight:SetPoint("TOPRIGHT", parent, "TOPRIGHT", D, H)
|
|
bottomLeft:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", -G, -B)
|
|
bottomRight:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", D, -B)
|
|
|
|
top:SetPoint("TOPLEFT", topLeft, "TOPRIGHT")
|
|
top:SetPoint("TOPRIGHT", topRight, "TOPLEFT")
|
|
down:SetPoint("BOTTOMLEFT", bottomLeft, "BOTTOMRIGHT")
|
|
down:SetPoint("BOTTOMRIGHT", bottomRight, "BOTTOMLEFT")
|
|
left:SetPoint("TOPLEFT", topLeft, "BOTTOMLEFT")
|
|
left:SetPoint("BOTTOMRIGHT", bottomLeft, "TOPRIGHT")
|
|
right:SetPoint("TOPLEFT", topRight, "BOTTOMLEFT")
|
|
right:SetPoint("BOTTOMRIGHT", bottomRight, "TOPRIGHT")
|
|
center:SetPoint("TOPLEFT", topLeft, "BOTTOMRIGHT")
|
|
center:SetPoint("BOTTOMRIGHT", bottomRight, "TOPLEFT")
|
|
|
|
return slices
|
|
end
|
|
|
|
-- Tertiary button, two states: common-button-tertiary-normal / -pressed, 46 x 34 each, sheet
|
|
-- commonbuttontertiaryc60. The rounded end is 11 px (column profile constant from x = 11),
|
|
-- so the corner is 11 on both axes. Stretched instead of sliced, it squashes past 46 wide.
|
|
-- The button keeps its own textures at alpha 0: they still hold its state for the client,
|
|
-- and some functions read them.
|
|
-- auto: the pressed state follows the mouse button. Otherwise the caller drives it with
|
|
-- button.foreverPress(true or false), e.g. statistic selectors, pressed while their list
|
|
-- is open.
|
|
local TERTIARY_NORMAL = "common-button-tertiary-normal"
|
|
local TERTIARY_PRESSED = "common-button-tertiary-pressed"
|
|
local TERTIARY_CORNER = 11
|
|
local TERTIARY_MARGINS = { 0, 0, 0, 0 }
|
|
|
|
function ForeverUI.SkinTertiaryButton(button, auto)
|
|
if button.foreverPress then
|
|
return button
|
|
end
|
|
|
|
for _, method in ipairs({ "GetNormalTexture", "GetPushedTexture",
|
|
"GetHighlightTexture", "GetDisabledTexture" }) do
|
|
local texture = button[method] and button[method](button)
|
|
if texture then
|
|
texture:SetAlpha(0)
|
|
end
|
|
end
|
|
|
|
button.foreverNormal = ForeverUI.CreateNineSlice(button, TERTIARY_NORMAL,
|
|
TERTIARY_CORNER, TERTIARY_MARGINS, "BACKGROUND")
|
|
button.foreverPressed = ForeverUI.CreateNineSlice(button, TERTIARY_PRESSED,
|
|
TERTIARY_CORNER, TERTIARY_MARGINS, "BACKGROUND")
|
|
|
|
button.foreverPress = function(state)
|
|
for _, slice in ipairs(button.foreverPressed or {}) do
|
|
if state then slice:Show() else slice:Hide() end
|
|
end
|
|
for _, slice in ipairs(button.foreverNormal or {}) do
|
|
if state then slice:Hide() else slice:Show() end
|
|
end
|
|
end
|
|
button.foreverPress(false)
|
|
|
|
if auto then
|
|
button:HookScript("OnMouseDown", function() button.foreverPress(true) end)
|
|
button:HookScript("OnMouseUp", function() button.foreverPress(false) end)
|
|
end
|
|
|
|
return button
|
|
end
|
|
|
|
-- Camelot inset: InsetFrameTemplate (shareduipaneltemplates.xml, nineslicelayouts.lua).
|
|
-- Tiled UI-Background-Marble background; UI-Frame-InnerTopLeft / TopRight / BotLeftCorner /
|
|
-- BotRight corners (6 x 6, bottom ones at y = -1) joined by _UI-Frame-InnerTopTile / BotTile
|
|
-- and !UI-Frame-InnerLeftTile / RightTile (3 thick).
|
|
local MARBLE = "interface" .. string.char(92) .. "ForeverUI" .. string.char(92)
|
|
.. "framegeneral" .. string.char(92) .. "ui-background-marble"
|
|
|
|
function ForeverUI.CreateInset(parent, name)
|
|
return ForeverUI.DecorateInset(CreateFrame("Frame", name, parent))
|
|
end
|
|
|
|
-- Same art on an existing frame (e.g. the bank rights frame of the guild control window):
|
|
-- regions of its own, below its child frames.
|
|
function ForeverUI.DecorateInset(e)
|
|
local background = e:CreateTexture(nil, "BACKGROUND")
|
|
background:SetTexture(MARBLE, true)
|
|
if background.SetHorizTile then
|
|
background:SetHorizTile(true)
|
|
background:SetVertTile(true)
|
|
end
|
|
background:SetAllPoints(e)
|
|
e.background = background
|
|
|
|
local function corner(atlas, point, y)
|
|
local t = e:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(t, atlas)
|
|
t:SetPoint(point, e, point, 0, y or 0)
|
|
return t
|
|
end
|
|
local topLeft = corner("ui-frame-innertopleft", "TOPLEFT")
|
|
local topRight = corner("ui-frame-innertopright", "TOPRIGHT")
|
|
local bottomLeft = corner("ui-frame-innerbotleftcorner", "BOTTOMLEFT", -1)
|
|
local bottomRight = corner("ui-frame-innerbotright", "BOTTOMRIGHT", -1)
|
|
-- thickness from the element (3), length from the corners
|
|
local function edge(atlas, a1, c1, r1, a2, c2, r2)
|
|
local t = e:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(t, atlas, true)
|
|
t:SetPoint(a1, c1, r1)
|
|
t:SetPoint(a2, c2, r2)
|
|
return t
|
|
end
|
|
local top = edge("_ui-frame-innertoptile", "TOPLEFT", topLeft, "TOPRIGHT", "TOPRIGHT", topRight, "TOPLEFT")
|
|
top:SetHeight(3)
|
|
local down = edge("_ui-frame-innerbottile", "BOTTOMLEFT", bottomLeft, "BOTTOMRIGHT", "BOTTOMRIGHT", bottomRight, "BOTTOMLEFT")
|
|
down:SetHeight(3)
|
|
local left = edge("!ui-frame-innerlefttile", "TOPLEFT", topLeft, "BOTTOMLEFT", "BOTTOMLEFT", bottomLeft, "TOPLEFT")
|
|
left:SetWidth(3)
|
|
local right = edge("!ui-frame-innerrighttile", "TOPRIGHT", topRight, "BOTTOMRIGHT", "BOTTOMRIGHT", bottomRight, "TOPRIGHT")
|
|
right:SetWidth(3)
|
|
e.trim = { topLeft, topRight, bottomLeft, bottomRight, top, down, left, right }
|
|
return e
|
|
end
|
|
|
|
-- Camelot panel button, UIPanelButtonTemplate: three pieces of UI-Panel-Button-Up / -Down /
|
|
-- -Disabled (left 12, stretched middle, right 12; 0.6875 high), -Highlight in ADD.
|
|
-- b:Activate(yes): UIPanelButton_OnEnable / _OnDisable, -Disabled image and grey font.
|
|
-- font: font object name (GameFontNormalSmall by default); template: optional frame template.
|
|
local PANEL_BUTTON = "Interface" .. string.char(92) .. "Buttons" .. string.char(92) .. "UI-Panel-Button-"
|
|
|
|
function ForeverUI.CreatePanelButton(parent, buttonText, width, height, name, font, template)
|
|
local b = CreateFrame("Button", name, parent, template)
|
|
b:SetWidth(width)
|
|
b:SetHeight(height)
|
|
local function piece(u1, u2)
|
|
local t = b:CreateTexture(nil, "BACKGROUND")
|
|
t:SetTexCoord(u1, u2, 0, 0.6875)
|
|
return t
|
|
end
|
|
local g = piece(0, 0.09375)
|
|
g:SetWidth(12)
|
|
g:SetPoint("TOPLEFT", b, "TOPLEFT", 0, 0)
|
|
g:SetPoint("BOTTOMLEFT", b, "BOTTOMLEFT", 0, 0)
|
|
local d = piece(0.53125, 0.625)
|
|
d:SetWidth(12)
|
|
d:SetPoint("TOPRIGHT", b, "TOPRIGHT", 0, 0)
|
|
d:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 0, 0)
|
|
local m = piece(0.09375, 0.53125)
|
|
m:SetPoint("TOPLEFT", g, "TOPRIGHT", 0, 0)
|
|
m:SetPoint("BOTTOMRIGHT", d, "BOTTOMLEFT", 0, 0)
|
|
local pieces = { g, m, d }
|
|
local function state(suffix)
|
|
for _, t in ipairs(pieces) do
|
|
t:SetTexture(PANEL_BUTTON .. suffix)
|
|
end
|
|
end
|
|
state("Up")
|
|
local normalFont = font and _G[font .. ""] or GameFontNormalSmall
|
|
local hover = font and _G[(font == "GameFontNormal") and "GameFontHighlight" or "GameFontHighlightSmall"]
|
|
or GameFontHighlightSmall
|
|
local fs = b:CreateFontString(nil, "ARTWORK")
|
|
fs:SetFontObject(normalFont)
|
|
fs:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
b:SetFontString(fs)
|
|
b:SetNormalFontObject(normalFont)
|
|
b:SetHighlightFontObject(hover)
|
|
if b.SetDisabledFontObject then
|
|
b:SetDisabledFontObject((font == "GameFontNormal") and GameFontDisable or GameFontDisableSmall)
|
|
end
|
|
b:SetText(buttonText)
|
|
b:SetHighlightTexture(PANEL_BUTTON .. "Highlight")
|
|
local s = b:GetHighlightTexture()
|
|
if s then
|
|
s:SetTexCoord(0, 0.625, 0, 0.6875)
|
|
s:SetBlendMode("ADD")
|
|
end
|
|
b.active = true
|
|
b:SetScript("OnMouseDown", function(self) if self.active then state("Down") end end)
|
|
b:SetScript("OnMouseUp", function(self) if self.active then state("Up") end end)
|
|
function b:Activate(yes)
|
|
self.active = yes and true or false
|
|
if yes then
|
|
self:Enable()
|
|
state("Up")
|
|
else
|
|
self:Disable()
|
|
state("Disabled")
|
|
end
|
|
end
|
|
return b
|
|
end
|