--[[ This library contains work of Hendrick "nevcairiel" Leppkes https://www.wowace.com/projects/libbuttonglow-1-0 ]] -- luacheck: globals CreateFromMixins ObjectPoolMixin CreateTexturePool CreateFramePool local MAJOR_VERSION = "LibCustomGlow-1.0" local MINOR_VERSION = 21 if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end local lib, oldversion = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) if not lib then return end local pairs, ipairs = pairs, ipairs local ceil, floor, min, mod = math.ceil, math.floor, math.min, mod local tinsert, tremove = table.insert, table.remove -- =============================================================================== -- !!! IMPORTANT: CHANGE `texturePath` BELOW TO POINT TO YOUR ADDON'S FILE LOCATION !!! -- DON'T FORGET THE BACKSLASH AT THE END (\)! -- Example: local texturePath = [[Interface\AddOns\YourAddon\Libs\]] -- =============================================================================== -- This is the path to the texture files used by this library. local texturePath = [[Interface\AddOns\WeakAuras\Libs\]] local textureList = { ["empty"] = texturePath .. [[LibCustomGlow-1.0\AM_29]], ["white"] = [[Interface\BUTTONS\WHITE8X8]], ["shine"] = texturePath .. [[LibCustomGlow-1.0\Artifacts]] } function lib.RegisterTextures(texture, id) textureList[id] = texture end lib.glowList = {} lib.startList = {} lib.stopList = {} local GlowParent = UIParent local TexPoolResetter = function(pool, tex) tex:Hide() tex:ClearAllPoints() end local GlowTexPool = CreateTexturePool(GlowParent, "ARTWORK", nil, TexPoolResetter) lib.GlowTexPool = GlowTexPool local FramePoolResetter = function(framePool, frame) frame:SetScript("OnSizeChanged", nil) frame:SetScript("OnUpdate", nil) local parent = frame:GetParent() if parent[frame.name] then parent[frame.name] = nil end if frame.textures then for _, texture in ipairs(frame.textures) do GlowTexPool:Release(texture) end end frame.textures = {} frame.info = {} frame.name = nil frame.timer = nil frame:Hide() frame:ClearAllPoints() end local GlowFramePool = CreateFramePool("Frame", GlowParent, "", FramePoolResetter) lib.GlowFramePool = GlowFramePool local function addFrameAndTex(r, color, name, key, N, xOffset, yOffset, texture, texCoord, desaturated, frameLevel) key = key or "" frameLevel = frameLevel or 8 if not r[name..key] then r[name..key] = GlowFramePool:Acquire() r[name..key]:SetParent(r) r[name..key].name = name..key end local f = r[name..key] f:SetFrameLevel(r:GetFrameLevel() + frameLevel) f:SetPoint("TOPLEFT", r, "TOPLEFT", -xOffset, yOffset) f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", xOffset, -yOffset) f:Show() if not f.textures then f.textures = {} end for i = 1, N do if not f.textures[i] then f.textures[i] = GlowTexPool:Acquire() f.textures[i]:SetTexture(texture) f.textures[i]:SetTexCoord(texCoord[1], texCoord[2], texCoord[3], texCoord[4]) f.textures[i]:SetParent(f) end f.textures[i]:SetVertexColor(color[1], color[2], color[3], color[4]) f.textures[i]:Show() end while #f.textures > N do GlowTexPool:Release(f.textures[#f.textures]) tremove(f.textures) end end --Pixel Glow Functions-- local pPoint = { ["BOTTOMLEFT"] = "BOTTOMRIGHT", ["BOTTOMRIGHT"] = "TOPRIGHT", ["TOPRIGHT"] = "TOPLEFT", ["TOPLEFT"] = "BOTTOMLEFT", } local function pWidth(position, width, length, thickness, line1, line2, point) line1:ClearAllPoints() line1:SetPoint(pPoint[point], point == "BOTTOMLEFT" and -position or position, 0) position = width - position if position > length then line1:SetSize(length, thickness) line2:Hide() else line2:ClearAllPoints() line2:SetPoint(point) line2:Show() line1:SetSize(position, thickness) line2:SetSize(thickness, length - position) end end local function pHeight(position, height, length, thickness, line1, line2, point) line1:ClearAllPoints() line1:SetPoint(pPoint[point], 0, point == "BOTTOMRIGHT" and -position or position) position = height - position if position > length then line1:SetSize(thickness, length) line2:Hide() else line2:ClearAllPoints() line2:SetPoint(point) line2:Show() line1:SetSize(thickness, position) line2:SetSize(length - position, thickness) end end --[[ local function pSize(position, size, length, thickness, line1, line2, point, left) line1:ClearAllPoints() line1:SetPoint(pPoint[point], not left and (point == "BOTTOMLEFT" and -position or position) or 0, left and (point == "BOTTOMRIGHT" and -position or position) or 0) position = size - position if position > length then line1:SetSize(left and thickness or length, left and length or thickness) line2:Hide() else line2:ClearAllPoints() line2:SetPoint(point) line2:Show() line1:SetSize(left and thickness or position, left and position or thickness) line2:SetSize(left and (length - position) or thickness, not left and (length - position) or thickness) end end ]] local function pSizeChanged(self, width, height) if not (width or height) then width, height = self:GetSize() end if width ~= self.info.width or height ~= self.info.height then self.info.width = width self.info.height = height self.info.perimeter = 2 * (width + height) self.info.bottomlim = height * 2 + width self.info.rightlim = height + width self.info.space = self.info.perimeter / self.info.N end end local function pUpdate(self, elapsed) self.timer = self.timer + elapsed / self.info.period if self.timer > 1 or self.timer < -1 then self.timer = self.timer % 1 end local info = self.info for i = 1, info.N do local position = (info.space * i + info.perimeter * self.timer) % info.perimeter if position > info.bottomlim then -- BOTTOM pWidth(position - info.bottomlim, info.width, info.length, info.th, self.textures[i], self.textures[info.N + i], "BOTTOMLEFT") elseif position > info.rightlim then -- RIGHT pHeight(position - info.rightlim, info.height, info.length, info.th, self.textures[i], self.textures[info.N + i], "BOTTOMRIGHT") elseif position > info.height then -- TOP pWidth(position - info.height, info.width, info.length, info.th, self.textures[i], self.textures[info.N + i], "TOPRIGHT") else -- LEFT pHeight(position, info.height, info.length, info.th, self.textures[i], self.textures[info.N + i], "TOPLEFT") end end end function lib.PixelGlow_Start(r, color, N, frequency, length, th, xOffset, yOffset, border, key, frameLevel) if not r then return end if not N or N <= 0 then N = 8 end local width, height = r:GetSize() length = length or floor((width + height) * (2 / N - 0.1)) length = min(length, min(width, height)) key = key or "" addFrameAndTex(r, color or {.95, .95, .32, 1}, "_PixelGlow", key, N * 2, xOffset or 0, yOffset or 0, textureList.white, {0, 1, 0, 1}, nil, frameLevel) local f = r["_PixelGlow"..key] f.timer = f.timer or 0 f.info = f.info or {} f.info.N = N f.info.period = (not frequency or frequency == 0) and 4 or (1 / frequency) f.info.th = th or 1 if f.info.length ~= length then f.info.width = nil f.info.length = length end pSizeChanged(f) f:SetScript("OnSizeChanged", pSizeChanged) pUpdate(f, 0) f:SetScript("OnUpdate", pUpdate) end function lib.PixelGlow_Stop(r, key) if not r then return end key = key or "" if not r["_PixelGlow"..key] then return false else GlowFramePool:Release(r["_PixelGlow"..key]) end end tinsert(lib.glowList, "Pixel Glow") lib.startList["Pixel Glow"] = lib.PixelGlow_Start lib.stopList["Pixel Glow"] = lib.PixelGlow_Stop --Autocast Glow Funcitons-- local acSizes = {7, 6, 5, 4} local function acSizeChanged(self, width, height) if not (width or height) then width, height = self:GetSize() end if width ~= self.info.width or height ~= self.info.height then if width*height == 0 then return end self.info.width = width self.info.height = height self.info.perimeter = 2 * (width + height) self.info.bottomlim = height * 2 + width self.info.rightlim = height + width self.info.space = self.info.perimeter / self.info.N end end local function acUpdate(self, elapsed) local texIndex, info = 0, self.info for k = 1, 4 do self.timer[k] = self.timer[k] + elapsed / (info.period * k) if self.timer[k] > 1 or self.timer[k] < -1 then self.timer[k] = self.timer[k] % 1 end for i = 1, info.N do texIndex = texIndex + 1 local position = (info.space * i + info.perimeter * self.timer[k]) % info.perimeter if position > info.bottomlim then self.textures[texIndex]:SetPoint("CENTER", self, "BOTTOMRIGHT", -position + info.bottomlim, 0) elseif position > info.rightlim then self.textures[texIndex]:SetPoint("CENTER", self, "TOPRIGHT", 0, -position + info.rightlim) elseif position > info.height then self.textures[texIndex]:SetPoint("CENTER", self, "TOPLEFT", position - info.height, 0) else self.textures[texIndex]:SetPoint("CENTER", self, "BOTTOMLEFT", 0, position) end end end end function lib.AutoCastGlow_Start(r, color, N, frequency, scale, xOffset, yOffset, key, frameLevel) if not r then return end if not (N and N > 0) then N = 4 end scale = scale or 1 xOffset = xOffset or 0 yOffset = yOffset or 0 key = key or "" addFrameAndTex(r, color or {.95, .95, .32, 1}, "_AutoCastGlow", key, N * 4, xOffset, yOffset, textureList.shine, {0.8115234375, 0.9169921875, 0.8798828125, 0.9853515625}, true, frameLevel) local f = r["_AutoCastGlow"..key] for k, size in pairs(acSizes) do for i = 1, N do f.textures[i + N * (k - 1)]:SetSize(size * scale, size * scale) end end f.timer = f.timer or {0, 0, 0, 0} f.info = f.info or {} f.info.N = N f.info.period = (not frequency or frequency == 0) and 4 or (1 / frequency) acSizeChanged(f) f:SetScript("OnSizeChanged", acSizeChanged) f:SetScript("OnUpdate", acUpdate) acUpdate(f, 0) end function lib.AutoCastGlow_Stop(r, key) if not r then return end key = key or "" if not r["_AutoCastGlow"..key] then return false else GlowFramePool:Release(r["_AutoCastGlow"..key]) end end tinsert(lib.glowList, "Autocast Shine") lib.startList["Autocast Shine"] = lib.AutoCastGlow_Start lib.stopList["Autocast Shine"] = lib.AutoCastGlow_Stop -- Animation Functions local function InitAlphaAnimation(self) self.target = self.target or self:GetRegionParent() self.change = self.change or 0 self.frameAlpha = self.target:GetAlpha() self.alphaFactor = self.frameAlpha + self.change - self.frameAlpha end local function TidyAlphaAnimation(self) self.alphaFactor = nil self.frameAlpha = nil end local function AlphaAnimation_OnUpdate(self, elapsed) local progress = self:GetSmoothProgress() if progress ~= 0 then if not self.played then InitAlphaAnimation(self) self.played = 1 end if self.frameAlpha then self.target:SetAlpha(self.frameAlpha + self.alphaFactor * progress) if progress == 1 then TidyAlphaAnimation(self) end end end end local function AlphaAnimation_OnStop(self) if self.frameAlpha then TidyAlphaAnimation(self) end self.played = nil end local function CreateAlphaAnim(group, target, order, duration, change, delay, onPlay, onFinished) local alpha = group:CreateAnimation() if target then alpha.target = alpha:GetRegionParent()[target] end if order then alpha:SetOrder(order) end alpha:SetDuration(duration) alpha.change = change if delay then alpha:SetStartDelay(delay) end if onPlay then alpha:SetScript("OnPlay", onPlay) end alpha:SetScript("OnUpdate", AlphaAnimation_OnUpdate) alpha:SetScript("OnStop", AlphaAnimation_OnStop) alpha:SetScript("OnFinished", onFinished or AlphaAnimation_OnStop) end local function InitScaleAnimation(self) self.target = self.target or self:GetRegionParent() self.scaleX = self.scaleX or 0 self.scaleY = self.scaleY or 0 local _, _, width, height = self.target:GetRect() if not width then return end self.frameWidth = width self.frameHeight = height self.widthFactor = width * self.scaleX - width self.heightFactor = height * self.scaleY - height local setCenter local parent = self.target:GetParent() local numPoints = self.target:GetNumPoints() if numPoints > 0 then local point, relativeTo, relativePoint, xOffset, yOffset = self.target:GetPoint(1) if numPoints == 1 and point == "CENTER" then setCenter = false else local i = 1 while true do if relativeTo ~= parent and yOffset then local j = #self + 1 self[j], self[j + 1], self[j + 2], self[j + 3], self[j + 4] = point, relativeTo, relativePoint, xOffset, yOffset end i = i + 1 if numPoints >= i then point, relativeTo, relativePoint, xOffset, yOffset = self.target:GetPoint(i) else break end end setCenter = true end else setCenter = true end if setCenter then local x, y = self.target:GetCenter() local parentX, parentY = parent:GetCenter() self.target:ClearAllPoints() self.target:SetPoint("CENTER", x - parentX, y - parentY) end return 1 end local function TidyScaleAnimation(self) local target = self.target if #self ~= 0 then target:ClearAllPoints() for i = 1, #self, 5 do target:SetPoint(self[i], self[i + 1], self[i + 2], self[i + 3], self[i + 4]) self[i] = nil self[i + 1] = nil self[i + 2] = nil self[i + 3] = nil self[i + 4] = nil end end self.widthFactor = nil self.heightFactor = nil self.frameWidth = nil self.frameHeight = nil end local function ScaleAnimation_OnUpdate(self, elapsed) local progress = self:GetSmoothProgress() if progress ~= 0 then if not self.played then if InitScaleAnimation(self) then self.played = 1 end end if self.frameWidth then self.target:SetSize(self.frameWidth + self.widthFactor * progress, self.frameHeight + self.heightFactor * progress) if progress == 1 then TidyScaleAnimation(self) end end end end local function ScaleAnimation_OnStop(self) if self.frameWidth then TidyScaleAnimation(self) end self.played = nil end local function CreateScaleAnim(group, target, order, duration, x, y, delay, smoothing, onPlay) local scale = group:CreateAnimation() if target then scale.target = scale:GetRegionParent()[target] end scale:SetOrder(order) scale:SetDuration(duration) scale.scaleX, scale.scaleY = x, y if delay then scale:SetStartDelay(delay) end if smoothing then scale:SetSmoothing(smoothing) end if onPlay then scale:SetScript("OnPlay", onPlay) end scale:SetScript("OnUpdate", ScaleAnimation_OnUpdate) scale:SetScript("OnStop", ScaleAnimation_OnStop) scale:SetScript("OnFinished", ScaleAnimation_OnStop) end local function AnimateTexCoords(texture, textureWidth, textureHeight, frameWidth, frameHeight, numFrames, elapsed, throttle) if not texture.frame then texture.frame = 1 texture.throttle = throttle texture.numColumns = floor(textureWidth / frameWidth) texture.numRows = floor(textureHeight / frameHeight) texture.columnWidth = frameWidth / textureWidth texture.rowHeight = frameHeight / textureHeight end if not texture.throttle or texture.throttle > throttle then local frame = texture.frame local framesToAdvance = floor(texture.throttle / throttle) while frame + framesToAdvance > numFrames do frame = frame - numFrames end frame = frame + framesToAdvance texture.throttle = 0 local left = mod(frame - 1, texture.numColumns) * texture.columnWidth local right = left + texture.columnWidth local bottom = ceil(frame / texture.numColumns) * texture.rowHeight local top = bottom - texture.rowHeight texture:SetTexCoord(left, right, top, bottom) texture.frame = frame else texture.throttle = texture.throttle + elapsed end end --Action Button Glow-- local function ButtonGlowResetter(framePool,frame) -- frame:SetScript("OnUpdate",nil) local parent = frame:GetParent() if parent._ButtonGlow then parent._ButtonGlow = nil end frame:Hide() frame:ClearAllPoints() end local ButtonGlowPool = CreateFramePool("Frame", GlowParent, "", ButtonGlowResetter) lib.ButtonGlowPool = ButtonGlowPool local function AnimIn_OnPlay(anim) local frame = anim:GetRegionParent() local frameWidth, frameHeight = frame:GetSize() frame.spark:SetSize(frameWidth, frameHeight) frame.spark:SetAlpha(not (frame.color) and 1 or 0.3 * frame.color[4]) frame.innerGlow:SetSize(frameWidth / 2, frameHeight / 2) frame.innerGlow:SetAlpha(not (frame.color) and 1 or frame.color[4]) frame.innerGlowOver:SetAlpha(not (frame.color) and 1 or frame.color[4]) frame.outerGlow:SetSize(frameWidth * 2, frameHeight * 2) frame.outerGlow:SetAlpha(not (frame.color) and 1 or frame.color[4]) frame.outerGlowOver:SetAlpha(not (frame.color) and 1 or frame.color[4]) frame.ants:SetSize(frameWidth * 0.85, frameHeight * 0.85) frame.ants:SetAlpha(0) frame:Show() end local function AnimIn_OnFinished(group) local frame = group:GetParent() local frameWidth, frameHeight = frame:GetSize() frame.spark:SetAlpha(0) frame.innerGlow:SetAlpha(0) frame.innerGlow:SetSize(frameWidth, frameHeight) frame.innerGlowOver:SetAlpha(0) frame.outerGlow:SetSize(frameWidth, frameHeight) frame.outerGlowOver:SetAlpha(0) frame.outerGlowOver:SetSize(frameWidth, frameHeight) frame.ants:SetAlpha(not (frame.color) and 1 or frame.color[4]) end local function AnimIn_OnStop(group) local frame = group:GetParent() frame.spark:SetAlpha(0) frame.innerGlow:SetAlpha(0) frame.innerGlowOver:SetAlpha(0) frame.outerGlowOver:SetAlpha(0) end local function bgHide(self) if self.animOut:IsPlaying() then self.animOut:Stop() ButtonGlowPool:Release(self) end end local function bgUpdate(self, elapsed) AnimateTexCoords(self.ants, 256, 256, 48, 48, 22, elapsed, self.throttle) end local function IsAnimPlaying(self) return self.isPlaying end local function configureButtonGlow(f, alpha) f.spark = f:CreateTexture(nil, "BACKGROUND") f.spark:SetPoint("CENTER") f.spark:SetAlpha(0) f.spark:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlert]]) f.spark:SetTexCoord(0.00781250, 0.61718750, 0.00390625, 0.26953125) -- inner glow f.innerGlow = f:CreateTexture() f.innerGlow:SetPoint("CENTER") f.innerGlow:SetAlpha(0) f.innerGlow:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlert]]) f.innerGlow:SetTexCoord(0.00781250, 0.50781250, 0.27734375, 0.52734375) f.innerGlow:Show() -- inner glow over f.innerGlowOver = f:CreateTexture() f.innerGlowOver:SetPoint("TOPLEFT", f.innerGlow, "TOPLEFT") f.innerGlowOver:SetPoint("BOTTOMRIGHT", f.innerGlow, "BOTTOMRIGHT") f.innerGlowOver:SetAlpha(0) f.innerGlowOver:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlert]]) f.innerGlowOver:SetTexCoord(0.00781250, 0.50781250, 0.53515625, 0.78515625) -- outer glow f.outerGlow = f:CreateTexture() f.outerGlow:SetPoint("CENTER") f.outerGlow:SetAlpha(0) f.outerGlow:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlert]]) f.outerGlow:SetTexCoord(0.00781250, 0.50781250, 0.27734375, 0.52734375) -- outer glow over f.outerGlowOver = f:CreateTexture() f.outerGlowOver:SetPoint("TOPLEFT", f.outerGlow, "TOPLEFT") f.outerGlowOver:SetPoint("BOTTOMRIGHT", f.outerGlow, "BOTTOMRIGHT") f.outerGlowOver:SetAlpha(0) f.outerGlowOver:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlert]]) f.outerGlowOver:SetTexCoord(0.00781250, 0.50781250, 0.53515625, 0.78515625) -- ants f.ants = f:CreateTexture(nil, "OVERLAY") f.ants:SetPoint("CENTER") f.ants:SetAlpha(0) f.ants:SetTexture(texturePath .. [[LibCustomGlow-1.0\IconAlertAnts]]) f.animIn = f:CreateAnimationGroup() f.animIn.appear = {} f.animIn.fade = {} CreateScaleAnim(f.animIn, "spark", 1, 0.2, 1.5, 1.5, nil, nil, AnimIn_OnPlay) CreateAlphaAnim(f.animIn, "spark", 1, 0.2, alpha, nil, nil, nil, true) CreateScaleAnim(f.animIn, "innerGlow", 1, 0.3, 2, 2) CreateScaleAnim(f.animIn, "innerGlowOver", 1, 0.3, 2, 2) CreateAlphaAnim(f.animIn, "innerGlowOver", 1, 0.3, alpha, nil, nil, nil, false) CreateScaleAnim(f.animIn, "outerGlow", 1, 0.3, 0.5, 0.5) CreateScaleAnim(f.animIn, "outerGlowOver", 1, 0.3, 0.5, 0.5) CreateAlphaAnim(f.animIn, "outerGlowOver", 1, 0.3, alpha, nil, nil, nil, false) CreateScaleAnim(f.animIn, "spark", 1, 0.2, 0.666666, 0.666666, 0.2) CreateAlphaAnim(f.animIn, "spark", 1, 0.2, alpha, 0.2, nil, nil, false) CreateAlphaAnim(f.animIn, "innerGlow", 1, 0.2, alpha, 0.3, nil, nil, false) CreateAlphaAnim(f.animIn, "ants", 1, 0.2, alpha, 0.3, nil, nil, true) f.animIn:SetScript("OnStop", AnimIn_OnStop) f.animIn:SetScript("OnFinished", AnimIn_OnFinished) f.animOut = f:CreateAnimationGroup() f.animOut.appear = {} f.animOut.fade = {} CreateAlphaAnim(f.animOut, "outerGlowOver", 1, 0.2, alpha, nil, nil, nil, true) CreateAlphaAnim(f.animOut, "ants", 1, 0.2, alpha, nil, nil, nil, false) CreateAlphaAnim(f.animOut, "outerGlowOver", 2, 0.2, alpha, nil, nil, nil, false) CreateAlphaAnim(f.animOut, "outerGlow", 2, 0.2, alpha, nil, nil, nil, false) f.animOut:SetScript("OnPlay", function(self) self.isPlaying = true; end) f.animOut:SetScript("OnStop", function(self) self.isPlaying = false; end) f.animOut:SetScript("OnFinished", function(self) self.isPlaying = false; ButtonGlowPool:Release(f) end) f.animOut.isPlaying = false f.animOut.IsPlaying = IsAnimPlaying f:SetScript("OnHide", bgHide) end local function updateAlphaAnim(f,alpha) for _,anim in pairs(f.animIn.appear) do anim.change = alpha end for _,anim in pairs(f.animIn.fade) do anim.change = -alpha end for _,anim in pairs(f.animOut.appear) do anim.change = alpha end for _,anim in pairs(f.animOut.fade) do anim.change = -alpha end end local ButtonGlowTextures = {["spark"] = true, ["innerGlow"] = true, ["innerGlowOver"] = true, ["outerGlow"] = true, ["outerGlowOver"] = true, ["ants"] = true} local function noZero(num) if num == 0 then return 0.001 else return num end end function lib.ButtonGlow_Start(r, color, frequency, frameLevel) if not r then return end frameLevel = frameLevel or 8; local throttle = frequency and frequency > 0 and 0.25 / frequency * 0.01 or 0.01 if r._ButtonGlow then local f = r._ButtonGlow local width, height = r:GetSize() f:SetFrameLevel(r:GetFrameLevel() + frameLevel) f:SetSize(width * 1.4 , height * 1.4) f:SetPoint("TOPLEFT", r, "TOPLEFT", -width * 0.2, height * 0.2) f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", width * 0.2, -height * 0.2) f.ants:SetSize(width * 1.4 * 0.85, height * 1.4 * 0.85) AnimIn_OnFinished(f.animIn) if f.animOut:IsPlaying() then f.animOut:Stop() f.animIn:Play() end if not color then for texture in pairs(ButtonGlowTextures) do f[texture]:SetVertexColor(1, 1, 1) local alpha = math.min(f[texture]:GetAlpha()/noZero(f.color and f.color[4] or 1), 1) f[texture]:SetAlpha(alpha) updateAlphaAnim(f, 1) end f.color = false else for texture in pairs(ButtonGlowTextures) do f[texture]:SetVertexColor(color[1], color[2], color[3]) local alpha = math.min(f[texture]:GetAlpha()/noZero(f.color and f.color[4] or 1)*color[4], 1) f[texture]:SetAlpha(alpha) updateAlphaAnim(f,color and color[4] or 1) end f.color = color end f.throttle = throttle else local f, new = ButtonGlowPool:Acquire() if new then configureButtonGlow(f,color and color[4] or 1) else updateAlphaAnim(f,color and color[4] or 1) end r._ButtonGlow = f local width, height = r:GetSize() f:SetParent(r) f:SetFrameLevel(r:GetFrameLevel() + frameLevel) f:SetSize(width * 1.4, height * 1.4) f:SetPoint("TOPLEFT", r, "TOPLEFT", -width * 0.2, height * 0.2) f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", width * 0.2, -height * 0.2) if not color then f.color = false for texture in pairs(ButtonGlowTextures) do f[texture]:SetVertexColor(1, 1, 1) end else f.color = color for texture in pairs(ButtonGlowTextures) do f[texture]:SetVertexColor(color[1], color[2], color[3]) end end f.throttle = throttle f:SetScript("OnUpdate", bgUpdate) f.animIn:Play() end end function lib.ButtonGlow_Stop(r) if r._ButtonGlow then if r._ButtonGlow.animOut:IsPlaying() then -- Do nothing the animOut finishing will release elseif r._ButtonGlow.animIn:IsPlaying() then r._ButtonGlow.animIn:Stop() ButtonGlowPool:Release(r._ButtonGlow) elseif r:IsVisible() then r._ButtonGlow.animOut:Play() else ButtonGlowPool:Release(r._ButtonGlow) end end end tinsert(lib.glowList, "Action Button Glow") lib.startList["Action Button Glow"] = lib.ButtonGlow_Start lib.stopList["Action Button Glow"] = lib.ButtonGlow_Stop -- ProcGlow local BaseTexCoord = { ["Loop"] = {0.412598, 0.575195, 0.000976562, 0.391602}, ["Start"] = {0.000488281, 0.411621, 0.000976562, 0.987305}, } local function SetTile(texture, frame, rows, columns, frameScaleW, frameScaleH, key) frame = frame - 1 local row = math.floor(frame / columns) local column = frame % columns local leftStart, rightEnd, topStart, bottomEnd = BaseTexCoord[key][1], BaseTexCoord[key][2], BaseTexCoord[key][3], BaseTexCoord[key][4] local fullWidth = rightEnd - leftStart local fullHeight = bottomEnd - topStart local baseDeltaX = fullWidth / columns local baseDeltaY = fullHeight / rows local deltaX = baseDeltaX * frameScaleW local deltaY = baseDeltaY * frameScaleH local left = leftStart + baseDeltaX * column + (baseDeltaX - deltaX) / 2 local right = left + deltaX local top = topStart + baseDeltaY * row + (baseDeltaY - deltaY) / 2 local bottom = top + deltaY pcall(function() texture:SetTexCoord(left, right, top, bottom) end) end local StartFlipbook local FlipbookAnimation_OnUpdate FlipbookAnimation_OnUpdate = function(self, elapsed) local data = self.flipbookData if not data then return end if data.animElapsed then data.animElapsed = data.animElapsed + elapsed if data.animElapsed >= 0.7 then if self:IsShown() then StartFlipbook(self, self.ProcLoop, 6, 5, 30, ((data.animOptions and (30 / data.animOptions)) or 30), nil, nil, "Loop") end data.animElapsed = nil data.animOptions = nil end end data.elapsedTime = data.elapsedTime + elapsed local frameDuration = 1 / data.frameRate if data.elapsedTime >= frameDuration then data.elapsedTime = data.elapsedTime - frameDuration data.currentFrame = data.currentFrame + 1 if data.currentFrame > data.totalFrames then data.currentFrame = 1 end SetTile(data.texture, data.currentFrame, data.rows, data.columns, 1, 1, data.key) end end local function StopFlipbook(f) f:SetScript("OnUpdate", nil) if f.flipbookData and f.flipbookData.texture then f.flipbookData.texture:Hide() end f.flipbookData = nil end StartFlipbook = function(f, texture, rows, columns, totalFrames, frameRate, startAnim, startOptionsDur, key) StopFlipbook(f) f.flipbookData = { key = key, texture = texture, rows = rows, columns = columns, totalFrames = totalFrames, frameRate = frameRate, currentFrame = 1, elapsedTime = 0, animElapsed = startAnim, animOptions = startOptionsDur, } texture:Show() f:SetScript("OnUpdate", FlipbookAnimation_OnUpdate) end local function ProcGlowResetter(framePool, frame) frame:Hide() frame:ClearAllPoints() frame:SetScript("OnShow", nil) frame:SetScript("OnHide", nil) frame:SetScript("OnUpdate", nil) local parent = frame:GetParent() if frame.name and parent[frame.name] then parent[frame.name] = nil end end local ProcGlowPool = CreateFramePool("Frame", GlowParent, "", ProcGlowResetter) lib.ProcGlowPool = ProcGlowPool local function InitProcGlow(f) -- Start-Flipbook f.ProcStart = f:CreateTexture(nil, "ARTWORK") f.ProcStart:SetBlendMode("ADD") f.ProcStart:SetTexture(texturePath .. [[LibCustomGlow-1.0\UIActionBarFX]]) f.ProcStart:SetTexCoord(0.0827148248, 0.1649413686, 0.000976562, 0.165364635) -- First Frame f.ProcStart:SetAlpha(1) f.ProcStart:SetSize(150, 150) f.ProcStart:SetPoint("CENTER") f.ProcStart:Hide() -- Loop-Flipbook f.ProcLoop = f:CreateTexture(nil, "ARTWORK") f.ProcLoop:SetTexture(texturePath .. [[LibCustomGlow-1.0\UIActionBarFX]]) f.ProcLoop:SetTexCoord(0.412598, 0.4451174, 0.000976562, 0.066080801666667) -- First Frame f.ProcLoop:SetAlpha(1) f.ProcLoop:SetAllPoints() f.ProcLoop:Hide() end local function SetupProcGlow(f, options) f.name = "_ProcGlow" .. options.key f:SetScript("OnHide", function(self) StopFlipbook(self) end) f:SetScript("OnShow", function(self) StopFlipbook(self) if self.startAnim then local width, height = self:GetSize() self.ProcStart:SetSize((width / 42 * 150) / 1.4, (height / 42 * 150) / 1.4) StartFlipbook(self, self.ProcStart, 6, 5, 30, 30, 0, options.duration, "Start") else StartFlipbook(self, self.ProcLoop , 6, 5, 30, (30 / options.duration), nil, nil, "Loop") end end) local color = options.color or {1, 1, 1, 1} f.ProcStart:SetVertexColor(unpack(color)) f.ProcLoop:SetVertexColor(unpack(color)) f.startAnim = options.startAnim end local ProcGlowDefaults = { frameLevel = 8, color = nil, startAnim = true, xOffset = 0, yOffset = 0, duration = 1, key = "" } function lib.ProcGlow_Start(r, options) if not r then return end options = options or {} setmetatable(options, { __index = ProcGlowDefaults }) local key = "_ProcGlow" .. options.key local f, new if r[key] then f = r[key] else f, new = ProcGlowPool:Acquire() if new then InitProcGlow(f) end r[key] = f end f:SetParent(r) f:SetFrameLevel(r:GetFrameLevel() + options.frameLevel) local width, height = r:GetSize() local xOffset = options.xOffset + width * 0.2 local yOffset = options.yOffset + height * 0.2 f:SetPoint("TOPLEFT", r, "TOPLEFT", -xOffset, yOffset) f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", xOffset, -yOffset) SetupProcGlow(f, options) f:Show() end function lib.ProcGlow_Stop(r, key) key = key or "" local f = r["_ProcGlow" .. key] if f then ProcGlowPool:Release(f) end end table.insert(lib.glowList, "Proc Glow") lib.startList["Proc Glow"] = lib.ProcGlow_Start lib.stopList["Proc Glow"] = lib.ProcGlow_Stop