You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
13 KiB

local XLoot = select(2, ...)
local lib = {
skins = {},
masque_tweaks = {},
}
XLoot.Skin = lib
local L = XLoot.L
local print = print
-- Custom skins
-- To add your own, simply make XLoot a dependency then call XLoot:RegisterSkin(name, skin_table)
-- skin_table being a table with these keys:
-- [required] texture - Path to texture
-- [optional] name - Shown in UI, name provided to RegisterSkin used by default
-- [optional] size, size_highlight
-- [optional] row_spacing
-- [optional] frame_color_*, loot_color_* -- See above
-- [optional] color_mod - Multiplier for border quality colors
-- [optional] padding, padding_highlight - Padding refers to how far outward (or inward) the border should be offset from the frame
-- Tweaking Masque skins
-- To keep from having to change this file, call XLoot:RegisterMasqueTweak(skin_name, skin_table)
-- following the same rules as custom skins
-- Quick or temporary tweaks can be added to SKIN_TWEAKS.lua
-- Base skin template
lib.base = {
bar_texture = [[Interface\AddOns\XLoot\Textures\bar]],
color_mod = .75,
row_spacing = 2,
}
-- Skin registration
function XLoot:RegisterSkin(skin_name, skin_table)
setmetatable(skin_table, { __index = lib.base })
skin_table.key = skin_name
lib.skins[skin_name] = skin_table
end
-- Masque tweaks
function XLoot:RegisterMasqueTweak(masque_name, tweak_table)
lib.masque_tweaks[masque_name] = tweak_table
-- Apply to existing skins
if lib.skins[masque_name] then
for k, v in pairs(tweak_table) do
lib.skins[masque_name][k] = v
end
end
end
-- Skinning
local function subtable_insert(t, k, v)
if not t[k] then
t[k] = {}
end
table.insert(t[k], v)
end
do
local base = {
padding = 2,
size = 16,
layer = 'ARTWORK',
mode = 'BLEND',
r = 1,
g = 1,
b = 1,
a = 1
}
local types = {
highlight = {
mode = 'ADD',
layer = 'HIGHLIGHT',
texture = [[Interface\Buttons\ButtonHilight-Square]],
size = 8,
padding = 0,
r = .8,
g = .8,
b = .8,
a = .8
}
}
local mt = {
__index = function(t, k)
local ttype = rawget(t, 'type')
if ttype and types[ttype] and types[ttype][k] then
return types[ttype][k]
end
return base[k] or nil
end
}
local function meta(t)
return setmetatable(t, mt)
end
local function update_borders(frame, options, borders, r, g, b, a)
local padding = options.padding
local size = options.size/2
r = r or options.r
g = g or options.g
b = b or options.b
a = a or options.a
for pos, tex in ipairs(borders) do
-- Set texture options
tex:SetDrawLayer(options.layer)
tex:SetTexture(options.texture)
tex:SetBlendMode(options.mode)
tex:SetWidth(size)
tex:SetHeight(size)
tex:SetVertexColor(r, g, b, a)
-- Position texture
tex:ClearAllPoints()
if pos == 1 then
tex:SetTexCoord(0, 1/6, 0, 1/6)
tex:SetPoint("TOPLEFT", frame, "TOPLEFT", -padding, padding)
elseif pos == 2 then
tex:SetTexCoord(5/6, 1, 0, 1/6)
tex:SetPoint("TOPRIGHT", frame, "TOPRIGHT", padding, padding)
elseif pos == 3 then
tex:SetTexCoord(0, 1/6, 5/6, 1)
tex:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", -padding, -padding)
elseif pos == 4 then
tex:SetTexCoord(5/6, 1, 5/6, 1)
tex:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", padding, -padding)
elseif pos == 5 then
tex:SetTexCoord(1/6, 5/6, 0, 1/6)
tex:SetPoint("TOPLEFT", borders[1], "TOPRIGHT")
tex:SetPoint("TOPRIGHT", borders[2], "TOPLEFT")
elseif pos == 6 then
tex:SetTexCoord(1/6, 5/6, 5/6, 1)
tex:SetPoint("BOTTOMLEFT", borders[3], "BOTTOMRIGHT")
tex:SetPoint("BOTTOMRIGHT", borders[4], "BOTTOMLEFT")
elseif pos == 7 then
tex:SetTexCoord(0, 1/6, 1/6, 5/6)
tex:SetPoint("TOPLEFT", borders[1], "BOTTOMLEFT")
tex:SetPoint("BOTTOMLEFT", borders[3], "TOPLEFT")
elseif pos == 8 then
tex:SetTexCoord(5/6, 1, 1/6, 5/6)
tex:SetPoint("TOPRIGHT", borders[2], "BOTTOMRIGHT")
tex:SetPoint("BOTTOMRIGHT", borders[4], "TOPRIGHT")
end
end
end
local function create_borders(frame, options)
local borders = { }
for i = 1, 8 do
borders[i] = frame:CreateTexture()
end
update_borders(frame, options, borders)
return borders
end
local backdrop = {
bgFile = [[Interface\ChatFrame\ChatFrameBackground]], tile = true, tileSize = 16,
insets = {left = 3, right = 3, top = 3, bottom = 3},
}
local backdrop_empty = {
bgFile = ''
}
local bd_color = { 0, 0, 0, .9 }
local g_color = { .5, .5, .5, .6 }
-- Frame methods
-- https://www.wowace.com/projects/xloot/issues/205 is not reproducible, but user gets error reliably
local alphaworks = false
local function SetBorderColor(self, r, g, b, a)
for i, x in pairs(self._skin_borders) do
x:SetVertexColor(r, g, b, a or 1)
end
end
local function GetBorderColor(self)
return self._skin_borders[1]:GetVertexColor()
end
local function SetGradientColor(self, r, g, b, a)
self.gradient:SetGradient('VERTICAL', CreateColor(0.1, 0.1, 0.1, 0), CreateColor(r, g, b, a))
end
function lib:Gradient(frame)
local g = frame:CreateTexture(nil, 'BORDER')
frame.gradient = g
g:SetTexture([[Interface\ChatFrame\ChatFrameBackground]])
g:SetPoint('TOPLEFT', 3, -3)
g:SetPoint('BOTTOMRIGHT', -3, 3)
-- g:SetBlendMode'ADD'
frame.SetGradientColor = SetGradientColor
frame:SetGradientColor(unpack(g_color))
end
function lib:Backdrop(frame, opt_backdrop)
frame:SetBackdrop(opt_backdrop or backdrop)
frame:SetBackdropColor(unpack(bd_color))
end
-- Lib methods
-- Basic skin
function lib:Skin(frame, options)
-- Store options
frame._skin_options = meta(options)
-- Apply backdrop
if options.backdrop ~= false then
self:Backdrop(frame, type(options.backdrop) == 'table' and options.backdrop or nil)
end
-- Gradient
if options.gradient ~= false then
self:Gradient(frame)
end
-- Borders
frame._skin_borders = create_borders(frame, options)
frame.SetBorderColor = SetBorderColor
frame.GetBorderColor = GetBorderColor
end
function lib:SkinRaw(frame, options)
return create_borders(frame, meta(options)), SetBorderColor
end
function lib:UpdateSkin(frame, options, r, g, b, a)
frame._skin_options = meta(options)
update_borders(frame, options, frame._skin_borders, r, g, b, a)
end
-- Highlights
local function ShowHighlight(self, status)
for _, tex in ipairs(self._highlights) do
tex:Show()
end
end
local function HideHighlight(self)
for _, tex in ipairs(self._highlights) do
tex:Hide()
end
end
local function SetHighlightColor(self, r, g, b, a)
for _, tex in ipairs(self._highlights) do
tex:SetVertexColor(r, g, b, a)
end
end
local function GetHighlightColor(self)
return self._highlights[1]:GetVertexColor()
end
local highlight = { type = 'highlight' }
-- Add highlight borders to a frame
function lib:Highlight(frame, options)
-- Default options
options = meta(options or highlight)
frame._highlights = create_borders(frame, options)
frame._higlight_options = options
frame.ShowHighlight = ShowHighlight
frame.HideHighlight = HideHighlight
frame.SetHighlightColor = SetHighlightColor
frame.GetHighlightColor = GetHighlightColor
if options.layer ~= 'HIGHLIGHT' then
frame:HideHighlight()
end
end
function lib:UpdateHighlight(frame, options, r, g, b, a)
frame._higlight_options = meta(options)
update_borders(frame, options, frame._highlights, r, g, b, a)
end
end
-- Create a subset of skins to be applied
do
-- Merge current skin with set options
local function compile(data, name)
assert(data.sets[name], "Bad set name given to XLoot.Skin")
-- Return cached
if not data.compiled[name] then
data.compiled[name] = {}
elseif next(data.compiled[name]) then
return data.compiled[name]
end
-- Generate to cache
local out = data.compiled[name]
local skin = (data.SKIN and lib.skins[data.SKIN]) and lib.skins[data.SKIN] or lib.current
local set = data.sets[name]
-- Copy defaults
for k,v in pairs(lib.base) do
out[k] = v
end
-- Copy skin data
for k,v in pairs(skin) do
out[k] = v
end
-- Extract data for highlights
if skin.highlight
and set.type
and set.type == 'highlight'
and type(skin.highlight) == 'table' then
for k,v in pairs(skin.highlight) do
out[k] = v
end
-- Highlights shouldn't inherit default texture
if not skin.highlight.texture then
out.texture = nil
end
end
-- Apply set overrides
for k,v in pairs(set) do
out[k] = v
end
-- Apply metatable
setmetatable(out, getmetatable(skin))
return out
end
-- Re-compile and Re-apply all
local function Reskin(self)
local data = self._skin_data
-- Clear cache
for k,v in pairs(data.compiled) do
wipe(v)
end
-- Update skins
for set_name,frames in pairs(data.skinned) do
for i,frame in ipairs(frames) do
lib:UpdateSkin(frame, compile(data, set_name), frame:GetBorderColor())
end
end
-- Update highlights
for set_name,frames in pairs(data.highlighted) do
for i,frame in ipairs(frames) do
lib:UpdateHighlight(frame, compile(data, set_name), frame:GetHighlightColor())
end
end
return compile(data, data.default or next(data.sets))
end
local function Skin(self, frame, set_name)
local data = self._skin_data
set_name = set_name or data.default
local skin = compile(data, set_name)
lib:Skin(frame, skin)
subtable_insert(data.skinned, set_name, frame)
return skin
end
local function Highlight(self, frame, set_name)
local data = self._skin_data
set_name = set_name or data.default
lib:Highlight(frame, compile(data, set_name))
subtable_insert(data.highlighted, set_name, frame)
end
-- Embed required functions and create data set to skin multiple similar frames
XLoot.skinners = {}
function XLoot:MakeSkinner(target, sets, default_set)
if not default_set and not sets.default then
sets.default = {}
end
target._skin_data = {
skinned = {},
highlighted = {},
compiled = {},
sets = sets,
default = default_set or "default"
}
target.Reskin = Reskin
target.Skin = Skin
target.Highlight = Highlight
table.insert(XLoot.skinners, target)
return target
end
end
-------------------------------------------------------------------------------
-- Default skins
local svelte = {
name = ('|c2244dd22%s|r'):format(L.skin_svelte),
texture = [[Interface\AddOns\XLoot\Textures\border_svelte]],
}
local legacy = {
name = ('|c2244dd22%s|r'):format(L.skin_legacy),
row_spacing = 3,
texture = [[Interface\AddOns\XLoot\Textures\border_legacy]],
size = 16,
highlight = {
size = 12
},
color_mod = .85,
}
local smooth = {
name = ('|c2244dd22%s|r'):format(L.skin_smooth),
row_spacing = 3,
texture = [[Interface\AddOns\XLoot\Textures\border_smooth]],
size = 14,
padding = 1,
highlight = {
size = 6,
padding = -1
},
color_mod = .9,
}
-- Register default skins
XLoot:RegisterSkin('svelte', svelte)
XLoot:RegisterSkin('legacy', legacy)
XLoot:RegisterSkin('smooth', smooth)
-------------------------------------------------------------------------------
-- Index Masque skins later so we definitely catch all of them
function XLoot:SkinsOnInitialize()
-- Masque skins
local Masque = LibStub('Masque', true) or LibStub('LibButtonFacade', true)
if Masque and Masque.GetSkins then
-- Add available skins
local Masque_Skins = Masque:GetSkins()
if type(Masque_Skins) == 'table' then
for k, v in pairs(Masque_Skins) do
if k ~= 'Blizzard' and v.Normal.Texture then
local skin = { }
-- Guess at dimensions
if v.Icon.Height and v.Normal.Height then
skin.padding = (v.Normal.Height - v.Icon.Height) / 4
skin.row_spacing = v.Icon.Height / 16
skin.size = v.Icon.Height / 2
end
skin.texture = v.Normal.Texture
skin.name = ('|c22dddd22Masque:|r %s'):format(k)
-- Apply existing tweak
if lib.masque_tweaks[k] then
for mk,mv in pairs(lib.masque_tweaks[k]) do
skin[mk] = mv
end
end
-- Register
XLoot:RegisterSkin(k, skin)
end
end
else -- Warn about outdated Masque
print("XLoot: Use of masque skins requires the beta version of Masque.")
end
end
XLoot:ApplySkinTweaks()
-- Activate current skin
self:SetSkin(self.db.profile.skin)
end
-------------------------------------------------------------------------------
-- Skin access
function XLoot:SetSkin(name)
lib.current = lib.skins[lib.skins[name] and name or 'smooth']
end