Compare commits
7 Commits
d2005c4725
...
13f36e7817
| Author | SHA1 | Date | |
|---|---|---|---|
| 13f36e7817 | |||
| 919feed322 | |||
| d2e55eb3cb | |||
| cddfc7e7af | |||
| 58fae4418a | |||
| cc6cd4028b | |||
| 6bf3864891 |
+44
-25
@@ -1,13 +1,18 @@
|
|||||||
local E, L, V, P, G = unpack(ElvUI)
|
local E, L, V, P, G = unpack(ElvUI)
|
||||||
local CoA = E:GetModule("CoA")
|
local CoA = E:GetModule("CoA")
|
||||||
|
|
||||||
|
-- defaultY staggers the movers' first-run default position (LEFT of screen,
|
||||||
|
-- spaced vertically) so they don't stack on top of each other before the
|
||||||
|
-- player has ever dragged them.
|
||||||
local FRAMES = {
|
local FRAMES = {
|
||||||
{name = "CoAResourceSegmentBar", moverText = "Resource Segment Bar", hideKey = "hideResourceSegmentBar"},
|
{name = "CoAResourceSegmentBar", moverText = "Resource Segment Bar", hideKey = "hideResourceSegmentBar", defaultY = 40},
|
||||||
{name = "CoAResourceOrb", moverText = "Resource Orb", hideKey = "hideResourceOrb"},
|
{name = "CoAResourceOrb", moverText = "Resource Orb", hideKey = "hideResourceOrb", defaultY = 100},
|
||||||
{name = "CoAResourceBar", moverText = "Resource Bar", hideKey = "hideResourceBar"},
|
{name = "CoAResourceBar", moverText = "Resource Bar", hideKey = "hideResourceBar", defaultY = 160},
|
||||||
{name = "CoAMultiCastActionBarFrame", moverText = "Multi Cast Action Bar", hideKey = "hideMultiCastActionBar"},
|
{name = "CoAMultiCastActionBarFrame", moverText = "Multi Cast Action Bar", hideKey = "hideMultiCastActionBar", defaultY = 220},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local DEFAULT_WIDTH, DEFAULT_HEIGHT = 150, 30
|
||||||
|
|
||||||
local FRAME_NAMES = {}
|
local FRAME_NAMES = {}
|
||||||
for _, def in ipairs(FRAMES) do
|
for _, def in ipairs(FRAMES) do
|
||||||
FRAME_NAMES[def.name] = true
|
FRAME_NAMES[def.name] = true
|
||||||
@@ -179,30 +184,42 @@ local function LockPosition(frame, holder)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SetupMover(frame, name, moverText)
|
-- Created eagerly (independent of the native frame ever showing up -- several
|
||||||
if frame.CoAMoverCreated then return true end
|
-- of these are class-specific and may never appear for a given character) so
|
||||||
|
-- every mover always appears in Toggle Anchors. The default point is only
|
||||||
|
-- used until the player drags it once; after that E:CreateMover restores the
|
||||||
|
-- saved position from E.db.movers.
|
||||||
|
local function CreateMoverHolder(def)
|
||||||
|
if CoA.classResourceMoversCreated and CoA.classResourceMoversCreated[def.name] then return end
|
||||||
|
CoA.classResourceMoversCreated = CoA.classResourceMoversCreated or {}
|
||||||
|
CoA.classResourceMoversCreated[def.name] = true
|
||||||
|
|
||||||
|
local holder = CreateFrame("Frame", "CoA_"..def.name.."Holder", E.UIParent)
|
||||||
|
holder:Size(DEFAULT_WIDTH, DEFAULT_HEIGHT)
|
||||||
|
holder:Point("LEFT", E.UIParent, "LEFT", 150, def.defaultY)
|
||||||
|
|
||||||
|
E:CreateMover(holder, "CoA_"..def.name.."Mover", def.moverText, nil, nil, nil, "ALL,COA", nil, "CoA,classResources")
|
||||||
|
holder:SetAllPoints(_G["CoA_"..def.name.."Mover"])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SyncHolderSize(frame, name)
|
||||||
|
local holder = _G["CoA_"..name.."Holder"]
|
||||||
|
if not holder then return end
|
||||||
|
|
||||||
local width, height = frame:GetSize()
|
local width, height = frame:GetSize()
|
||||||
if width == 0 or height == 0 then return false end
|
if width > 0 and height > 0 then
|
||||||
|
holder:Size(width, height)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local left, bottom = frame:GetLeft(), frame:GetBottom()
|
local function AnchorFrame(frame, name)
|
||||||
if not left or not bottom then return false end
|
local holder = _G["CoA_"..name.."Holder"]
|
||||||
|
if not holder then return end
|
||||||
frame.CoAMoverCreated = true
|
|
||||||
|
|
||||||
local holder = CreateFrame("Frame", "CoA_"..name.."Holder", E.UIParent)
|
|
||||||
holder:Size(width, height)
|
|
||||||
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom)
|
|
||||||
|
|
||||||
E:CreateMover(holder, "CoA_"..name.."Mover", moverText, nil, nil, nil, "ALL,COA", nil, "CoA,skin,classResources")
|
|
||||||
holder:SetAllPoints(_G["CoA_"..name.."Mover"])
|
|
||||||
|
|
||||||
QueueAnchor(function()
|
QueueAnchor(function()
|
||||||
AnchorToHolder(frame, holder)
|
AnchorToHolder(frame, holder)
|
||||||
LockPosition(frame, holder)
|
LockPosition(frame, holder)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The server never Show()s a frame the current class doesn't use, so its
|
-- The server never Show()s a frame the current class doesn't use, so its
|
||||||
@@ -259,12 +276,10 @@ local function TryHookAll()
|
|||||||
DisableDrag(frame)
|
DisableDrag(frame)
|
||||||
SetupVisibility(frame, def.hideKey)
|
SetupVisibility(frame, def.hideKey)
|
||||||
FixTooltip(frame)
|
FixTooltip(frame)
|
||||||
|
SyncHolderSize(frame, def.name)
|
||||||
|
AnchorFrame(frame, def.name)
|
||||||
|
|
||||||
if SetupMover(frame, def.name, def.moverText) then
|
hooked[def.name] = true
|
||||||
hooked[def.name] = true
|
|
||||||
else
|
|
||||||
allHooked = false
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
allHooked = false
|
allHooked = false
|
||||||
end
|
end
|
||||||
@@ -275,6 +290,10 @@ local function TryHookAll()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CoA:InitializeClassResources()
|
function CoA:InitializeClassResources()
|
||||||
|
for _, def in ipairs(FRAMES) do
|
||||||
|
CreateMoverHolder(def)
|
||||||
|
end
|
||||||
|
|
||||||
if TryHookAll() then return end
|
if TryHookAll() then return end
|
||||||
|
|
||||||
self.classResourcesTimer = self:ScheduleRepeatingTimer(function()
|
self.classResourcesTimer = self:ScheduleRepeatingTimer(function()
|
||||||
|
|||||||
+56
-16
@@ -22,9 +22,9 @@ local CLASS_DISPEL_TYPES = {
|
|||||||
-- every class tree, so querying one from a class that can't take it simply
|
-- every class tree, so querying one from a class that can't take it simply
|
||||||
-- reports rank 0 rather than erroring.
|
-- reports rank 0 rather than erroring.
|
||||||
local TALENT_DISPEL_TYPES = {
|
local TALENT_DISPEL_TYPES = {
|
||||||
PROPHET = {talentID = 6324, types = {Curse = true}}, -- Blight Antidote
|
PROPHET = {talentID = 6324, talentName = "Blight Antidote", types = {Curse = true}},
|
||||||
CULTIST = {talentID = 12982, types = {Curse = true}}, -- Devour Curse
|
CULTIST = {talentID = 12982, talentName = "Devour Curse", types = {Curse = true}},
|
||||||
PYROMANCER = {talentID = 31276, types = {Magic = true, Disease = true, Bleed = true}}, -- Burn Impurities
|
PYROMANCER = {talentID = 31276, talentName = "Burn Impurities", types = {Magic = true, Disease = true, Bleed = true}},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Cached result of the talent lookup for the player's current build.
|
-- Cached result of the talent lookup for the player's current build.
|
||||||
@@ -35,20 +35,45 @@ local hasTalentDispel = false
|
|||||||
-- C_CharacterAdvancement is a server addition with no API documentation, so
|
-- C_CharacterAdvancement is a server addition with no API documentation, so
|
||||||
-- every entry point is guarded and a failed call reads as "talent not taken",
|
-- every entry point is guarded and a failed call reads as "talent not taken",
|
||||||
-- which degrades to the same behaviour as before auto-detection existed.
|
-- which degrades to the same behaviour as before auto-detection existed.
|
||||||
local function HasTalent(talentID)
|
local function HasTalent(talent)
|
||||||
local api = C_CharacterAdvancement
|
local api = C_CharacterAdvancement
|
||||||
if not (api and type(api.GetTalentRankByID) == "function") then return false end
|
if not api then return false end
|
||||||
|
|
||||||
local ok, rank = pcall(api.GetTalentRankByID, talentID)
|
if type(api.GetTalentRankByID) == "function" then
|
||||||
|
local ok, rank = pcall(api.GetTalentRankByID, talent.talentID)
|
||||||
|
if ok and type(rank) == "number" and rank > 0 then return true end
|
||||||
|
end
|
||||||
|
|
||||||
return ok and type(rank) == "number" and rank > 0
|
-- Fall back to matching the talent by name, so an entry ID gone stale after
|
||||||
|
-- a server rebalance doesn't silently switch the feature off. Names are the
|
||||||
|
-- more fragile key of the two, but GetKnownTalentEntries only ever lists
|
||||||
|
-- entries the player has actually learned, which makes this a genuinely
|
||||||
|
-- independent check rather than a second opinion on the same ID. The list
|
||||||
|
-- has been seen with holes in it, so it's walked with pairs.
|
||||||
|
if type(api.GetKnownTalentEntries) == "function" then
|
||||||
|
local ok, entries = pcall(api.GetKnownTalentEntries)
|
||||||
|
if ok and type(entries) == "table" then
|
||||||
|
for _, entry in pairs(entries) do
|
||||||
|
if type(entry) == "table" and entry.Name == talent.talentName then return true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns whether the talent state actually moved, so callers reacting to the
|
||||||
|
-- chattier advancement events can skip the unitframe rebuild when it didn't.
|
||||||
local function RefreshTalentState()
|
local function RefreshTalentState()
|
||||||
local _, class = UnitClass("player")
|
local _, class = UnitClass("player")
|
||||||
local talent = TALENT_DISPEL_TYPES[class]
|
local talent = TALENT_DISPEL_TYPES[class]
|
||||||
|
local hasTalent = (talent and HasTalent(talent)) or false
|
||||||
|
|
||||||
hasTalentDispel = (talent and HasTalent(talent.talentID)) or false
|
if hasTalent == hasTalentDispel then return false end
|
||||||
|
|
||||||
|
hasTalentDispel = hasTalent
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function CoA:CanDispel(debuffType)
|
function CoA:CanDispel(debuffType)
|
||||||
@@ -100,6 +125,12 @@ function CoA:UpdateDispelHighlight()
|
|||||||
UF:Update_AllFrames()
|
UF:Update_AllFrames()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function CoA:RefreshDispelTalents()
|
||||||
|
if RefreshTalentState() then
|
||||||
|
UF:Update_AllFrames()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- On Ascension, UnitClass("player")'s second return only reliably reports the
|
-- On Ascension, UnitClass("player")'s second return only reliably reports the
|
||||||
-- real custom class (CULTIST, PYROMANCER, ...) a short while after login --
|
-- real custom class (CULTIST, PYROMANCER, ...) a short while after login --
|
||||||
-- immediately at ADDON_LOADED/PLAYER_LOGIN it can still read back the generic
|
-- immediately at ADDON_LOADED/PLAYER_LOGIN it can still read back the generic
|
||||||
@@ -109,17 +140,26 @@ end
|
|||||||
-- next aura change. Force one extra refresh shortly after entering the world
|
-- next aura change. Force one extra refresh shortly after entering the world
|
||||||
-- so the very first debuff isn't judged too early.
|
-- so the very first debuff isn't judged too early.
|
||||||
--
|
--
|
||||||
-- CHARACTER_ADVANCEMENT_UPDATE_ENTRIES_RESULT fires when a build is confirmed,
|
-- CHARACTER_ADVANCEMENT_UPDATE_ENTRIES_RESULT fires when a build is confirmed
|
||||||
-- which is the point the talent ranks actually change. The advancement UI also
|
-- in the talent UI, but switching to another saved specialization doesn't
|
||||||
-- fires CHARACTER_ADVANCEMENT_PENDING_BUILD_UPDATED while talents are being
|
-- confirm anything -- that path only fires PENDING_BUILD_UPDATED and
|
||||||
-- clicked around, but ranks don't move until the build is saved, so listening
|
-- SUGGESTIONS_UPDATED, so both are needed or the ranks read stale for the rest
|
||||||
-- to it would only cost refreshes that read back the unchanged state.
|
-- of the session. PENDING_BUILD_UPDATED also fires on every click inside the
|
||||||
|
-- talent UI and SUGGESTIONS_UPDATED is only incidentally related, which is why
|
||||||
|
-- they go through RefreshDispelTalents: it costs one rank lookup and rebuilds
|
||||||
|
-- the unitframes only when the answer changed.
|
||||||
function CoA:InitializeDispelHighlight()
|
function CoA:InitializeDispelHighlight()
|
||||||
CoA:RegisterEvent("PLAYER_ENTERING_WORLD", function()
|
CoA:RegisterEvent("PLAYER_ENTERING_WORLD", function()
|
||||||
CoA:ScheduleTimer("UpdateDispelHighlight", 2)
|
CoA:ScheduleTimer("UpdateDispelHighlight", 2)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
CoA:RegisterEvent("CHARACTER_ADVANCEMENT_UPDATE_ENTRIES_RESULT", function()
|
for _, event in ipairs({
|
||||||
CoA:UpdateDispelHighlight()
|
"CHARACTER_ADVANCEMENT_UPDATE_ENTRIES_RESULT",
|
||||||
end)
|
"CHARACTER_ADVANCEMENT_PENDING_BUILD_UPDATED",
|
||||||
|
"CHARACTER_ADVANCEMENT_SUGGESTIONS_UPDATED",
|
||||||
|
}) do
|
||||||
|
CoA:RegisterEvent(event, function()
|
||||||
|
CoA:RefreshDispelTalents()
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+33
-18
@@ -53,6 +53,11 @@ end
|
|||||||
|
|
||||||
function CoA:UpdateExtraActionButtonSize()
|
function CoA:UpdateExtraActionButtonSize()
|
||||||
UpdateSize()
|
UpdateSize()
|
||||||
|
|
||||||
|
local holder = _G["CoA_ExtraActionBarHolder"]
|
||||||
|
if holder then
|
||||||
|
holder:Size(CoA.db.profile.extraActionButtonSize or 52)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function UpdateHotkeyText(button)
|
local function UpdateHotkeyText(button)
|
||||||
@@ -157,26 +162,34 @@ local function SkinButton(button, container)
|
|||||||
SkinGlow(button, name)
|
SkinGlow(button, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SetupMover(container, button)
|
-- Created eagerly (independent of the native ExtraActionBar ever showing up)
|
||||||
if CoA.extraActionBarMoverCreated then return true end
|
-- so the mover always appears in Toggle Anchors. The default point below is
|
||||||
|
-- only used until the player drags it once; after that E:CreateMover restores
|
||||||
local width, height = button:GetSize()
|
-- the saved position from E.db.movers.
|
||||||
if width == 0 or height == 0 then return false end
|
local function CreateMoverHolder()
|
||||||
|
if CoA.extraActionBarMoverCreated then return end
|
||||||
local left, bottom = button:GetLeft(), button:GetBottom()
|
|
||||||
if not left or not bottom then return false end
|
|
||||||
|
|
||||||
CoA.extraActionBarMoverCreated = true
|
CoA.extraActionBarMoverCreated = true
|
||||||
|
|
||||||
|
local size = CoA.db.profile.extraActionButtonSize or 52
|
||||||
|
local holder = CreateFrame("Frame", "CoA_ExtraActionBarHolder", E.UIParent)
|
||||||
|
holder:Size(size, size)
|
||||||
|
holder:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 260)
|
||||||
|
|
||||||
|
E:CreateMover(holder, "CoA_ExtraActionBarMover", "Extra Action Bar", nil, nil, nil, "ALL,COA", nil, "CoA,skins,extraActionButton")
|
||||||
|
holder:SetAllPoints(_G["CoA_ExtraActionBarMover"])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SetupContainer(container)
|
||||||
|
if container.CoAContainerSetup then return end
|
||||||
|
container.CoAContainerSetup = true
|
||||||
|
|
||||||
container:StripTextures(true)
|
container:StripTextures(true)
|
||||||
container:EnableMouse(false)
|
container:EnableMouse(false)
|
||||||
|
end
|
||||||
|
|
||||||
local holder = CreateFrame("Frame", "CoA_ExtraActionBarHolder", E.UIParent)
|
local function AnchorContainer(container)
|
||||||
holder:Size(width, height)
|
local holder = _G["CoA_ExtraActionBarHolder"]
|
||||||
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom)
|
if not holder then return end
|
||||||
|
|
||||||
E:CreateMover(holder, "CoA_ExtraActionBarMover", "Extra Action Bar", nil, nil, nil, "ALL,COA", nil, "CoA,skin,extraActionBar")
|
|
||||||
holder:SetAllPoints(_G["CoA_ExtraActionBarMover"])
|
|
||||||
|
|
||||||
local function Anchor()
|
local function Anchor()
|
||||||
container:ClearAllPoints()
|
container:ClearAllPoints()
|
||||||
@@ -191,8 +204,6 @@ local function SetupMover(container, button)
|
|||||||
else
|
else
|
||||||
Anchor()
|
Anchor()
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function TryHook()
|
local function TryHook()
|
||||||
@@ -201,13 +212,17 @@ local function TryHook()
|
|||||||
|
|
||||||
if container and button then
|
if container and button then
|
||||||
SkinButton(button, container)
|
SkinButton(button, container)
|
||||||
return SetupMover(container, button)
|
SetupContainer(container)
|
||||||
|
AnchorContainer(container)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function CoA:InitializeExtraActionBar()
|
function CoA:InitializeExtraActionBar()
|
||||||
|
CreateMoverHolder()
|
||||||
|
|
||||||
if TryHook() then return end
|
if TryHook() then return end
|
||||||
|
|
||||||
self.extraActionBarTimer = self:ScheduleRepeatingTimer(function()
|
self.extraActionBarTimer = self:ScheduleRepeatingTimer(function()
|
||||||
|
|||||||
+28
-15
@@ -19,8 +19,17 @@ local function UpdateFont(button)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function SyncHolderSize(button)
|
||||||
|
local holder = _G["CoA_LayerPickerHolder"]
|
||||||
|
button = button or _G[BUTTON_NAME]
|
||||||
|
if holder and button then
|
||||||
|
holder:Size(button:GetSize())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function CoA:UpdateInstanceButtonFont()
|
function CoA:UpdateInstanceButtonFont()
|
||||||
UpdateFont()
|
UpdateFont()
|
||||||
|
SyncHolderSize()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Hooked at file scope, so unlike the rest of the skin it stays live even when
|
-- Hooked at file scope, so unlike the rest of the skin it stays live even when
|
||||||
@@ -69,24 +78,26 @@ local function DisableDrag(button)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SetupMover(button)
|
-- Created eagerly (independent of the native LayerPickerFrame ever showing
|
||||||
if CoA.layerPickerMoverCreated then return true end
|
-- up) so the mover always appears in Toggle Anchors. The default point below
|
||||||
|
-- is only used until the player drags it once; after that E:CreateMover
|
||||||
local width, height = button:GetSize()
|
-- restores the saved position from E.db.movers.
|
||||||
if width == 0 or height == 0 then return false end
|
local function CreateMoverHolder()
|
||||||
|
if CoA.layerPickerMoverCreated then return end
|
||||||
local left, bottom = button:GetLeft(), button:GetBottom()
|
|
||||||
if not left or not bottom then return false end
|
|
||||||
|
|
||||||
CoA.layerPickerMoverCreated = true
|
CoA.layerPickerMoverCreated = true
|
||||||
|
|
||||||
local holder = CreateFrame("Frame", "CoA_LayerPickerHolder", E.UIParent)
|
local holder = CreateFrame("Frame", "CoA_LayerPickerHolder", E.UIParent)
|
||||||
holder:Size(width, height)
|
holder:Size(MIN_WIDTH, MIN_HEIGHT)
|
||||||
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom)
|
holder:Point("TOPLEFT", E.UIParent, "TOPLEFT", 250, -250)
|
||||||
|
|
||||||
E:CreateMover(holder, "CoA_LayerPickerMover", "Instance", nil, nil, nil, "ALL,COA", nil, "CoA,skin,instance")
|
E:CreateMover(holder, "CoA_LayerPickerMover", "Instance", nil, nil, nil, "ALL,COA", nil, "CoA,skins,instanceSwap")
|
||||||
holder:SetAllPoints(_G["CoA_LayerPickerMover"])
|
holder:SetAllPoints(_G["CoA_LayerPickerMover"])
|
||||||
_G["CoA_LayerPickerMover"]:SetFrameStrata("FULLSCREEN")
|
_G["CoA_LayerPickerMover"]:SetFrameStrata("FULLSCREEN")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function AnchorButton(button)
|
||||||
|
local holder = _G["CoA_LayerPickerHolder"]
|
||||||
|
if not holder then return end
|
||||||
|
|
||||||
local function Anchor()
|
local function Anchor()
|
||||||
button:ClearAllPoints()
|
button:ClearAllPoints()
|
||||||
@@ -101,8 +112,6 @@ local function SetupMover(button)
|
|||||||
else
|
else
|
||||||
Anchor()
|
Anchor()
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SkinButton(button)
|
local function SkinButton(button)
|
||||||
@@ -122,13 +131,17 @@ local function TryHook()
|
|||||||
if button then
|
if button then
|
||||||
DisableDrag(button)
|
DisableDrag(button)
|
||||||
SkinButton(button)
|
SkinButton(button)
|
||||||
return SetupMover(button)
|
SyncHolderSize(button)
|
||||||
|
AnchorButton(button)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function CoA:InitializeLayerPicker()
|
function CoA:InitializeLayerPicker()
|
||||||
|
CreateMoverHolder()
|
||||||
|
|
||||||
if TryHook() then return end
|
if TryHook() then return end
|
||||||
|
|
||||||
self.layerPickerTimer = self:ScheduleRepeatingTimer(function()
|
self.layerPickerTimer = self:ScheduleRepeatingTimer(function()
|
||||||
|
|||||||
+135
-17
@@ -138,31 +138,149 @@ function Skin:HideArt(frame)
|
|||||||
frame:Hide()
|
frame:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The dropdown pills on the vanity and wardrobe frames are the same widget:
|
-- Buttons ---------------------------------------------------------------------
|
||||||
-- nine anonymous "Silver-Button" slices rather than the named Left/Middle/Right
|
|
||||||
-- fields or the Normal/Pushed/Disabled set S:HandleButton knows how to clear,
|
|
||||||
-- so its own clearing can't reach them -- and a blind StripTextures would take
|
|
||||||
-- the caret and the label with them.
|
|
||||||
--
|
--
|
||||||
-- The native mouse-down handler re-arts one of these regions with a pressed
|
-- IsEnabled hands back 0 and 1 on this client rather than false and true
|
||||||
-- variant of the same file on every click, which is why the pill came back
|
-- (probed), and 0 is truthy in Lua, so every enabled check has to normalise
|
||||||
-- skinless while held. SetTexture is noop'd per region after clearing.
|
-- what it gets back before comparing it.
|
||||||
local DROPDOWN_ART = "Silver%-Button"
|
function Skin:IsEnabled(button)
|
||||||
local CARET_ART = "ChatFrameExpandArrow"
|
local state = button.IsEnabled and button:IsEnabled()
|
||||||
local CARET_SIZE = 14
|
|
||||||
|
|
||||||
local function StripDropdownArt(dropdown)
|
return state ~= nil and state ~= false and state ~= 0
|
||||||
for i = 1, dropdown:GetNumRegions() do
|
end
|
||||||
local region = select(i, dropdown:GetRegions())
|
|
||||||
|
-- The target is resolved the way ElvUI's own SetModifiedBackdrop and
|
||||||
|
-- SetOriginalBackdrop resolve it -- the backdrop when the button has one, the
|
||||||
|
-- button itself otherwise -- or the colour lands on something that isn't the
|
||||||
|
-- object drawing the border.
|
||||||
|
local function SetButtonBorder(button, lit)
|
||||||
|
local backdrop = button.backdrop or button
|
||||||
|
if not backdrop.SetBackdropBorderColor then return end
|
||||||
|
|
||||||
|
backdrop:SetBackdropBorderColor(unpack(lit and E.media.rgbvaluecolor or E.media.bordercolor))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- S:HandleButton ends with an unconditional pair of OnEnter/OnLeave hooks that
|
||||||
|
-- swap the border to the value colour and back, and neither of them looks at
|
||||||
|
-- IsEnabled. A disabled button still fires both scripts on this client, so a
|
||||||
|
-- dead button lights up under the cursor and reads as clickable -- the greyed
|
||||||
|
-- Activate button, Save changes with nothing pending, Purchase with nothing
|
||||||
|
-- selected. HookScript can't be undone, but handlers fire in registration
|
||||||
|
-- order, so a hook registered after HandleButton runs last and has the final
|
||||||
|
-- say on the colour.
|
||||||
|
--
|
||||||
|
-- This one deliberately doesn't consult IsMouseOver: OnEnter can fire a pixel
|
||||||
|
-- before IsMouseOver turns true (ElvUI's own aura code pads around the same
|
||||||
|
-- quirk), and reading it here would drop the highlight off a live button.
|
||||||
|
local function OnButtonEnter(button)
|
||||||
|
if Skin:IsEnabled(button) then return end
|
||||||
|
|
||||||
|
SetButtonBorder(button, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For a button that can be disabled while the cursor is already on it: OnEnter
|
||||||
|
-- has been and gone by then, so nothing corrects the border until the pointer
|
||||||
|
-- leaves. Only worth wiring up where something already watches the button's
|
||||||
|
-- state -- it does not justify an OnUpdate of its own.
|
||||||
|
function Skin:RefreshButtonBorder(button)
|
||||||
|
SetButtonBorder(button, self:IsEnabled(button) and button:IsMouseOver())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Every S:HandleButton call site in the plugin goes through here, so the
|
||||||
|
-- disabled-hover correction is inherited rather than repeated per module. The
|
||||||
|
-- extra arguments are HandleButton's own (strip, isDeclineButton,
|
||||||
|
-- useCreateBackdrop, noSetTemplate) and are passed straight through.
|
||||||
|
function Skin:Button(button, ...)
|
||||||
|
if not button then return end
|
||||||
|
|
||||||
|
S:HandleButton(button, ...)
|
||||||
|
|
||||||
|
-- Unguarded: a pass over a handful of regions is cheap, and re-running it
|
||||||
|
-- catches a region added to the button after the first skin pass.
|
||||||
|
self:StripHighlightArt(button)
|
||||||
|
|
||||||
|
-- Guarded separately from HandleButton's own isSkinned flag: these frames
|
||||||
|
-- re-run their skin pass on every show, and HookScript stacks handlers
|
||||||
|
-- rather than replacing them, so an unguarded re-hook adds another copy
|
||||||
|
-- per show for the life of the session.
|
||||||
|
if not button.CoAButtonSkinned then
|
||||||
|
button.CoAButtonSkinned = true
|
||||||
|
|
||||||
|
button:HookScript("OnEnter", OnButtonEnter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Several of these controls draw their art as anonymous regions of one atlas
|
||||||
|
-- file rather than through the named Left/Middle/Right fields or the Normal/
|
||||||
|
-- Pushed/Disabled set S:HandleButton knows how to clear, so its own clearing
|
||||||
|
-- can't reach them -- and a blind StripTextures would take the caret or the
|
||||||
|
-- label with it. Those are cleared by file instead.
|
||||||
|
--
|
||||||
|
-- SetTexture is noop'd per region rather than just cleared: whatever re-arts
|
||||||
|
-- the control on a state change (a mouse-down swapping in the pressed variant,
|
||||||
|
-- a tex coord swap between two variants of the same file) is free to re-set the
|
||||||
|
-- file as well, and a cleared texture would come straight back.
|
||||||
|
function Skin:StripArtByFile(frame, pattern)
|
||||||
|
if not frame then return end
|
||||||
|
|
||||||
|
for i = 1, frame:GetNumRegions() do
|
||||||
|
local region = select(i, frame:GetRegions())
|
||||||
local texture = region.GetTexture and region:GetTexture()
|
local texture = region.GetTexture and region:GetTexture()
|
||||||
|
|
||||||
if texture and tostring(texture):find(DROPDOWN_ART) then
|
if texture and tostring(texture):find(pattern) then
|
||||||
region:SetTexture(nil)
|
region:SetTexture(nil)
|
||||||
region.SetTexture = E.noop
|
region.SetTexture = E.noop
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- S:HandleButton clears the button's own Normal/Highlight/Pushed/Disabled
|
||||||
|
-- textures and the named Left/Middle/Right pieces, and nothing else -- so a
|
||||||
|
-- native highlight drawn as a plain region of the button survives it and lights
|
||||||
|
-- up under the cursor against the flat ElvUI backdrop. That was the wardrobe
|
||||||
|
-- Cancel button's red glow, and clearing it by file there fixed exactly that
|
||||||
|
-- one button: probing the layer across everything the plugin skins turned up
|
||||||
|
-- the Save outfit button wearing the same red file, and Disable transmog and
|
||||||
|
-- Disable spell visuals wearing the dialog-box glow, none of which any
|
||||||
|
-- clear-by-file call site was ever going to reach.
|
||||||
|
--
|
||||||
|
-- The whole layer goes rather than named files, because on these frames it only
|
||||||
|
-- ever carries native hover art. Every button probed has exactly one HIGHLIGHT
|
||||||
|
-- region, and on the ones that already looked right it is blank -- so there is
|
||||||
|
-- nothing else living there to lose. ElvUI's own hover treatment isn't caught:
|
||||||
|
-- it's the backdrop border swap HandleButton hooks, and a backdrop is drawn
|
||||||
|
-- through SetBackdrop plus two child border frames, not as a region of the
|
||||||
|
-- button at all.
|
||||||
|
--
|
||||||
|
-- Noop'd rather than only cleared, as in StripArtByFile: a state change that
|
||||||
|
-- re-arts the button would otherwise bring the glow straight back.
|
||||||
|
function Skin:StripHighlightArt(frame)
|
||||||
|
if not frame then return end
|
||||||
|
|
||||||
|
for i = 1, frame:GetNumRegions() do
|
||||||
|
local region = select(i, frame:GetRegions())
|
||||||
|
|
||||||
|
if region:GetObjectType() == "Texture" and region:GetDrawLayer() == "HIGHLIGHT" then
|
||||||
|
region:SetTexture(nil)
|
||||||
|
region.SetTexture = E.noop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The pill behind the talent frame's Activate button and the wardrobe's Apply
|
||||||
|
-- and Cancel buttons. Two files rather than one: "128GoldRedButton" carries the
|
||||||
|
-- green and grey variants as tex coords, and Cancel alone is drawn from
|
||||||
|
-- "128RedButton" (probed). The shared suffix matches both, and nothing else on
|
||||||
|
-- these frames uses either. Only the pill itself is this pattern's job now --
|
||||||
|
-- the hover art on both files goes with the rest of the HIGHLIGHT layer.
|
||||||
|
Skin.RedButtonArt = "RedButton"
|
||||||
|
|
||||||
|
-- The dropdown pills on the vanity and wardrobe frames are the same widget:
|
||||||
|
-- nine anonymous "Silver-Button" slices.
|
||||||
|
local DROPDOWN_ART = "Silver%-Button"
|
||||||
|
local CARET_ART = "ChatFrameExpandArrow"
|
||||||
|
local CARET_SIZE = 14
|
||||||
|
|
||||||
-- The caret is retextured after HandleButton, not before: HandleButton strips
|
-- The caret is retextured after HandleButton, not before: HandleButton strips
|
||||||
-- the pill, and a caret replaced ahead of that gets cleared straight back off.
|
-- the pill, and a caret replaced ahead of that gets cleared straight back off.
|
||||||
local function SkinDropdownCaret(dropdown)
|
local function SkinDropdownCaret(dropdown)
|
||||||
@@ -191,8 +309,8 @@ function Skin:Dropdown(dropdown, menu)
|
|||||||
if not dropdown or dropdown.CoASkinned then return end
|
if not dropdown or dropdown.CoASkinned then return end
|
||||||
dropdown.CoASkinned = true
|
dropdown.CoASkinned = true
|
||||||
|
|
||||||
StripDropdownArt(dropdown)
|
self:StripArtByFile(dropdown, DROPDOWN_ART)
|
||||||
S:HandleButton(dropdown)
|
self:Button(dropdown)
|
||||||
SkinDropdownCaret(dropdown)
|
SkinDropdownCaret(dropdown)
|
||||||
|
|
||||||
self:Panel(menu)
|
self:Panel(menu)
|
||||||
|
|||||||
+109
-3
@@ -56,7 +56,7 @@ function SkinChildren(frame, depth)
|
|||||||
-- "...MenuClose", and it was coming out of the walk as an
|
-- "...MenuClose", and it was coming out of the walk as an
|
||||||
-- ordinary templated square with the X stripped off it.
|
-- ordinary templated square with the X stripped off it.
|
||||||
if not (name and name:find("Close")) then
|
if not (name and name:find("Close")) then
|
||||||
S:HandleButton(child)
|
Skin:Button(child)
|
||||||
end
|
end
|
||||||
elseif objType == "Frame" then
|
elseif objType == "Frame" then
|
||||||
if IsDropDown(child, name) then
|
if IsDropDown(child, name) then
|
||||||
@@ -311,6 +311,111 @@ function SkinMenuRow(row)
|
|||||||
UpdateRowSelection(row)
|
UpdateRowSelection(row)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- The Activate button inside an expanded specialization row draws its pill from
|
||||||
|
-- a single atlas across three BACKGROUND regions plus a HIGHLIGHT one, and
|
||||||
|
-- switches between the green and the grey variant by tex coord. There are no
|
||||||
|
-- Normal/Pushed/Disabled textures for HandleButton to clear (probed: both come
|
||||||
|
-- back nil, and every region's vertex colour is white in either state), so the
|
||||||
|
-- art is cleared by file the way the dropdown pills are (Skin:StripArtByFile,
|
||||||
|
-- which noops SetTexture per region as well -- whatever swaps the tex coord on
|
||||||
|
-- a state change is free to re-art the region), and the enabled/disabled
|
||||||
|
-- distinction the atlas was carrying has to be re-created on the label.
|
||||||
|
|
||||||
|
-- GetFontString covers the templated case; the scan is for a label that was
|
||||||
|
-- added as a plain region rather than set as the button's own font string.
|
||||||
|
local function ActivateLabel(button)
|
||||||
|
if button.CoALabel then return button.CoALabel end
|
||||||
|
|
||||||
|
local text = button.GetFontString and button:GetFontString()
|
||||||
|
|
||||||
|
if not text then
|
||||||
|
for i = 1, button:GetNumRegions() do
|
||||||
|
local region = select(i, button:GetRegions())
|
||||||
|
|
||||||
|
if region:GetObjectType() == "FontString" then
|
||||||
|
text = region
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
button.CoALabel = text
|
||||||
|
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Yellow live, grey dead: the same pair ElvUI's own templated buttons use, so
|
||||||
|
-- these read as buttons rather than as labels on a panel.
|
||||||
|
local ACTIVATE_COLOR = {1, 0.82, 0}
|
||||||
|
local ACTIVATE_DISABLED_COLOR = {0.55, 0.55, 0.55}
|
||||||
|
|
||||||
|
-- The active spec's button is disabled, and with the pill gone nothing else
|
||||||
|
-- says so -- the ElvUI panel is drawn the same either way. The label is greyed
|
||||||
|
-- instead, which is how ElvUI marks a dead button everywhere else.
|
||||||
|
--
|
||||||
|
-- The enabled state is compared against the cached one rather than written
|
||||||
|
-- blind because this runs from the button's update: there's no event for a spec
|
||||||
|
-- becoming active. Skin:IsEnabled does the 0/1-to-boolean normalisation this
|
||||||
|
-- client needs (see Skinning.lua).
|
||||||
|
local function UpdateActivateState(button)
|
||||||
|
local enabled = Skin:IsEnabled(button)
|
||||||
|
|
||||||
|
if enabled == button.CoAActivateEnabled then return end
|
||||||
|
button.CoAActivateEnabled = enabled
|
||||||
|
|
||||||
|
-- Activating a spec disables this button under the very cursor that just
|
||||||
|
-- clicked it, so its hover border would stay lit until the pointer moved
|
||||||
|
-- off. This update already watches the state, so it carries the border too.
|
||||||
|
Skin:RefreshButtonBorder(button)
|
||||||
|
|
||||||
|
local text = ActivateLabel(button)
|
||||||
|
if not text then return end
|
||||||
|
|
||||||
|
text:SetTextColor(unpack(enabled and ACTIVATE_COLOR or ACTIVATE_DISABLED_COLOR))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Stripped before templating, as with the dropdown pills: HandleButton adds its
|
||||||
|
-- backdrop as regions of this same button, so a strip afterwards takes the
|
||||||
|
-- backdrop with the pill.
|
||||||
|
local function SkinActivateButton(button)
|
||||||
|
if not button then return end
|
||||||
|
|
||||||
|
if not button.CoASkinned then
|
||||||
|
button.CoASkinned = true
|
||||||
|
|
||||||
|
Skin:StripArtByFile(button, Skin.RedButtonArt)
|
||||||
|
Skin:Button(button)
|
||||||
|
|
||||||
|
button:HookScript("OnUpdate", UpdateActivateState)
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdateActivateState(button)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Unlike the row's icon these are named without a literal dot
|
||||||
|
-- ("Button1ExpandedContent", "...ExpandedContentActivateButton"), read off the
|
||||||
|
-- frame stack.
|
||||||
|
--
|
||||||
|
-- The expanded content exists from the moment the menu is built rather than
|
||||||
|
-- being created when its row is expanded (probed: present, hidden, before any
|
||||||
|
-- row had been opened), so it's picked up with the rest of the row. The show
|
||||||
|
-- hook is there for a row whose content is filled in later than this first pass.
|
||||||
|
local function SkinRowExpansion(rowName)
|
||||||
|
local content = _G[rowName.."ExpandedContent"]
|
||||||
|
if not content then return end
|
||||||
|
|
||||||
|
local buttonName = rowName.."ExpandedContentActivateButton"
|
||||||
|
|
||||||
|
SkinActivateButton(_G[buttonName])
|
||||||
|
|
||||||
|
if content.CoASkinned then return end
|
||||||
|
content.CoASkinned = true
|
||||||
|
|
||||||
|
content:HookScript("OnShow", function()
|
||||||
|
SkinActivateButton(_G[buttonName])
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- These children are named with a literal dot ("Button1.SpecIcon"), so they
|
-- These children are named with a literal dot ("Button1.SpecIcon"), so they
|
||||||
-- only come out of _G by string key, never as plain identifiers.
|
-- only come out of _G by string key, never as plain identifiers.
|
||||||
local function SkinMenuRows(listName)
|
local function SkinMenuRows(listName)
|
||||||
@@ -321,6 +426,7 @@ local function SkinMenuRows(listName)
|
|||||||
|
|
||||||
SkinMenuRow(row)
|
SkinMenuRow(row)
|
||||||
SkinMenuRowIcon(_G[rowName..".SpecIcon"])
|
SkinMenuRowIcon(_G[rowName..".SpecIcon"])
|
||||||
|
SkinRowExpansion(rowName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -499,7 +605,7 @@ local function SkinBottomBar()
|
|||||||
-- stopped at the arrow, and the dead space to its right is taken out
|
-- stopped at the arrow, and the dead space to its right is taken out
|
||||||
-- of the hit rect so it can't swallow clicks meant for those icons.
|
-- of the hit rect so it can't swallow clicks meant for those icons.
|
||||||
if dropdown and arrow then
|
if dropdown and arrow then
|
||||||
S:HandleButton(dropdown, nil, nil, true)
|
Skin:Button(dropdown, nil, nil, true)
|
||||||
|
|
||||||
if dropdown.backdrop then
|
if dropdown.backdrop then
|
||||||
dropdown.backdrop:ClearAllPoints()
|
dropdown.backdrop:ClearAllPoints()
|
||||||
@@ -617,7 +723,7 @@ local function SkinSpecChoices()
|
|||||||
local cardName = SPEC_CHOICE:format(i)
|
local cardName = SPEC_CHOICE:format(i)
|
||||||
if not _G[cardName] then break end
|
if not _G[cardName] then break end
|
||||||
|
|
||||||
S:HandleButton(_G[cardName.."SelectButton"], true)
|
Skin:Button(_G[cardName.."SelectButton"], true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ local FRAME_NAME = "StoreCollectionFrame"
|
|||||||
-- Highlight textures), confirmed by probe -- S:HandleButton's own texture
|
-- Highlight textures), confirmed by probe -- S:HandleButton's own texture
|
||||||
-- clearing handles these directly, no manual stripping needed.
|
-- clearing handles these directly, no manual stripping needed.
|
||||||
local function SkinActionButtons()
|
local function SkinActionButtons()
|
||||||
S:HandleButton(_G[FRAME_NAME.."ActivateStoreButton"])
|
Skin:Button(_G[FRAME_NAME.."ActivateStoreButton"])
|
||||||
S:HandleButton(_G[FRAME_NAME.."BuyStoreButton"])
|
Skin:Button(_G[FRAME_NAME.."BuyStoreButton"])
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SkinSearchBox()
|
local function SkinSearchBox()
|
||||||
|
|||||||
@@ -8,9 +8,94 @@ local FRAME_NAME = "AppearanceWardrobeFrame"
|
|||||||
-- Standard UIPanelButtonTemplate art, same as Vanity's action buttons --
|
-- Standard UIPanelButtonTemplate art, same as Vanity's action buttons --
|
||||||
-- S:HandleButton's own texture clearing handles these directly.
|
-- S:HandleButton's own texture clearing handles these directly.
|
||||||
local function SkinActionButtons()
|
local function SkinActionButtons()
|
||||||
S:HandleButton(_G[FRAME_NAME.."PlayerModelSaveOutfitButton"])
|
Skin:Button(_G[FRAME_NAME.."PlayerModelSaveOutfitButton"])
|
||||||
S:HandleButton(_G[FRAME_NAME.."DisableTransmogButton"])
|
Skin:Button(_G[FRAME_NAME.."DisableTransmogButton"])
|
||||||
S:HandleButton(_G[FRAME_NAME.."DisableSpellVisualsButton"])
|
Skin:Button(_G[FRAME_NAME.."DisableSpellVisualsButton"])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply, Cancel and Clear invalid slots only exist while a transmog change is
|
||||||
|
-- pending, which is why they were missed for so long -- but they exist from the
|
||||||
|
-- start rather than being created on the first change (probed: they are
|
||||||
|
-- Buttons, hidden, with nothing pending), so the normal skin pass reaches them.
|
||||||
|
--
|
||||||
|
-- Same widget as the talent frame's Activate button: the pill is drawn across
|
||||||
|
-- plain regions, with no Normal/Pushed texture for HandleButton to clear
|
||||||
|
-- (probed: they come back nil). Apply and Clear invalid slots take the green
|
||||||
|
-- variant of the gold atlas, Cancel is drawn from the red file instead --
|
||||||
|
-- Skin.RedButtonArt matches both files, and Cancel's HIGHLIGHT region goes with
|
||||||
|
-- the rest of its art.
|
||||||
|
--
|
||||||
|
-- The labels don't carry the atlas's green/red split over: the buttons sit in a
|
||||||
|
-- row and read apart by their text, and they take the same yellow every other
|
||||||
|
-- templated button on these frames uses -- the talent frame's live Activate
|
||||||
|
-- label included -- so a pending change doesn't get its own colour scheme. The
|
||||||
|
-- grey is the disabled half of that same pair.
|
||||||
|
local LABEL_COLOR = {1, 0.82, 0}
|
||||||
|
local DISABLED_LABEL_COLOR = {0.55, 0.55, 0.55}
|
||||||
|
|
||||||
|
-- Apply is disabled for as long as an invalid slot is pending, and with the
|
||||||
|
-- pill gone nothing else says so -- the ElvUI panel is drawn the same either
|
||||||
|
-- way. The label is greyed instead, exactly as the talent frame does it for the
|
||||||
|
-- active spec's Activate button.
|
||||||
|
--
|
||||||
|
-- Driven from the button's update because there's no event for the state
|
||||||
|
-- change: clearing the invalid slots enables Apply on the spot. The cached
|
||||||
|
-- state is what keeps that cheap -- the colours are only written when the state
|
||||||
|
-- actually flips.
|
||||||
|
local function UpdatePendingButtonState(button)
|
||||||
|
local enabled = Skin:IsEnabled(button)
|
||||||
|
|
||||||
|
if enabled == button.CoAPendingEnabled then return end
|
||||||
|
button.CoAPendingEnabled = enabled
|
||||||
|
|
||||||
|
-- Clearing the invalid slots enables Apply under the very cursor that just
|
||||||
|
-- clicked Clear invalid slots, so its hover border would stay dark until
|
||||||
|
-- the pointer moved off. This update already watches the state, so it
|
||||||
|
-- carries the border too.
|
||||||
|
Skin:RefreshButtonBorder(button)
|
||||||
|
|
||||||
|
local text = button.GetFontString and button:GetFontString()
|
||||||
|
if text then text:SetTextColor(unpack(enabled and LABEL_COLOR or DISABLED_LABEL_COLOR)) end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The strip runs on every pass rather than once behind the skinned guard: the
|
||||||
|
-- art is only there to be cleared once a change is pending, and nothing fires
|
||||||
|
-- the frame's OnShow at that point -- the window is already open. The buttons'
|
||||||
|
-- own OnShow is what catches it, since that is exactly when they appear.
|
||||||
|
local function SkinPendingButton(name)
|
||||||
|
local button = _G[name]
|
||||||
|
if not button then return end
|
||||||
|
|
||||||
|
Skin:StripArtByFile(button, Skin.RedButtonArt)
|
||||||
|
|
||||||
|
if not button.CoASkinned then
|
||||||
|
button.CoASkinned = true
|
||||||
|
|
||||||
|
-- Stripped before templating: HandleButton adds its backdrop as regions
|
||||||
|
-- of this same button, so a strip afterwards takes the backdrop with the
|
||||||
|
-- pill.
|
||||||
|
Skin:Button(button)
|
||||||
|
|
||||||
|
button:HookScript("OnShow", function(self)
|
||||||
|
Skin:StripArtByFile(self, Skin.RedButtonArt)
|
||||||
|
end)
|
||||||
|
|
||||||
|
button:HookScript("OnUpdate", UpdatePendingButtonState)
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdatePendingButtonState(button)
|
||||||
|
end
|
||||||
|
|
||||||
|
local PENDING_BUTTONS = {
|
||||||
|
"PlayerModelApplyButton",
|
||||||
|
"PlayerModelCancelButton",
|
||||||
|
"PlayerModelClearInvalidButton",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function SkinPendingButtons()
|
||||||
|
for _, suffix in ipairs(PENDING_BUTTONS) do
|
||||||
|
SkinPendingButton(FRAME_NAME..suffix)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SkinSearchBox()
|
local function SkinSearchBox()
|
||||||
@@ -59,6 +144,7 @@ local function SkinContents()
|
|||||||
Skin:Title(_G[FRAME_NAME.."TitleText"])
|
Skin:Title(_G[FRAME_NAME.."TitleText"])
|
||||||
Skin:CloseButton(_G[FRAME_NAME.."CloseButton"])
|
Skin:CloseButton(_G[FRAME_NAME.."CloseButton"])
|
||||||
SkinActionButtons()
|
SkinActionButtons()
|
||||||
|
SkinPendingButtons()
|
||||||
SkinSearchBox()
|
SkinSearchBox()
|
||||||
SkinCollectionDropdown("Filter")
|
SkinCollectionDropdown("Filter")
|
||||||
SkinCollectionDropdown("Sorting")
|
SkinCollectionDropdown("Sorting")
|
||||||
|
|||||||
Reference in New Issue
Block a user