From 7e6c1d434fe52c3063869a11146763d2ccc5ded9 Mon Sep 17 00:00:00 2001 From: Aleksi Blinnikka Date: Sat, 13 Jan 2018 01:05:14 +0200 Subject: [PATCH 1/1] Detach indicators from protected frames --- OmaRF/Core.lua | 20 +-- OmaRF/Indicators.lua | 232 -------------------------------- OmaRF/LayoutFramesHook.lua | 9 +- OmaRF/NewIndicators.lua | 268 +++++++++++++++++++++++++++++++++++++ OmaRF/OmaRF.toc | 2 +- OmaRF/UpdateNameHook.lua | 9 +- 6 files changed, 285 insertions(+), 255 deletions(-) delete mode 100644 OmaRF/Indicators.lua create mode 100644 OmaRF/NewIndicators.lua diff --git a/OmaRF/Core.lua b/OmaRF/Core.lua index d39b6e6..e0ecbd1 100644 --- a/OmaRF/Core.lua +++ b/OmaRF/Core.lua @@ -1,8 +1,4 @@ -local unpack = unpack; -local wipe = wipe; -local next = next; -local pairs = pairs; -local ipairs = ipairs; +local unpack, wipe, next, pairs, ipairs = unpack, wipe, next, pairs, ipairs; OmaRF = CreateFrame("Frame"); @@ -10,8 +6,6 @@ OmaRF.normalBarColor = CreateColor(0.3, 0.3, 0.3); OmaRF.dispelBarColor = CreateColor(1, 0.5, 0); OmaRF.normalBackColor = {0.7, 0.7, 0.7}; OmaRF.dispelBackColor = {0.5, 0.2, 0}; -OmaRF.frames = {}; -OmaRF.majorFrames = {}; OmaRF.positions = { "TOPLEFT", "TOPRIGHT", "CENTER", "BOTTOMLEFT", "BOTTOMRIGHT" }; @@ -57,17 +51,7 @@ end function OmaRF:OnDisable() self.running = false; - for name, frame in pairs(self.frames) do - for _, ind in pairs(frame) do - ind.text:Hide(); - ind.icon:Hide(); - end - for _, ind in ipairs(self.majorFrames[name]) do - ind.icon:Hide(); - ind.expireText:Hide(); - ind.stackText:Hide(); - end - end + self.frameBase:Hide(); end local function onEvent(self, event, ...) diff --git a/OmaRF/Indicators.lua b/OmaRF/Indicators.lua deleted file mode 100644 index 9557258..0000000 --- a/OmaRF/Indicators.lua +++ /dev/null @@ -1,232 +0,0 @@ -local f = OmaRF.frames; -local majorFrames = OmaRF.majorFrames; -local positions = OmaRF.positions; -local pad = 2; -local paddings = { - TOPLEFT = {pad, -pad}, - TOPRIGHT = {-pad, -pad}, - CENTER = {0, 0}, - BOTTOMLEFT = {pad, pad}, - BOTTOMRIGHT = {-pad, pad} -}; -local watchedAuras; -local majorAuras; -local majorMax; -local auraFilters = {"HELPFUL", "HARMFUL"}; -local DEFAULT_ICON = "Interface\\AddOns\\OmaRF\\images\\rhomb"; -local _; - --- global functions used every update -local C_TimerAfter = C_Timer.After; -local GetTime = GetTime; -local UnitAura = UnitAura; -local UnitIsPlayer = UnitIsPlayer; -local UnitIsConnected = UnitIsConnected; -local UnitIsDeadOrGhost = UnitIsDeadOrGhost; -local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyToFrames; -local format = string.format; -local unpack = unpack; -local floor = floor; -local ceil = ceil; - --- update current auras -hooksecurefunc("CompactUnitFrame_UpdateAuras", function(frame) - local frameName = frame:GetName(); - if f[frameName] then - for _, ind in pairs(f[frameName]) do ind.expires = nil end - for _, ind in ipairs(majorFrames[frameName]) do ind.expires = nil end - - local name, icon, count, expires, caster, id; - local unit = frame.displayedUnit; - local majorI = 1; - for _, filter in ipairs(auraFilters) do - local i = 1; - while true do - name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter); - if not id then break end - local pos = watchedAuras[id] or watchedAuras[name]; - if pos then - local ind = f[frameName][pos]; - local config = OmaRF.db.profile.indicators[pos]; - if not config.mine or UnitIsPlayer(caster) then - if config.useDefaultIcon then - ind.icon:SetTexture(DEFAULT_ICON); - else - ind.icon:SetTexture(icon); - end - ind.expires = expires; - end - end - - if (majorAuras[id] or majorAuras[name]) and majorI <= majorMax then - local ind = majorFrames[frameName][majorI]; - ind.icon:SetTexture(icon); - ind.expires = expires; - if count > 1 then - ind.stackText:SetText(count); - end - majorI = majorI + 1; - end - i = i + 1; - end - end - end -end); - -local function configureIndicators(frame, name) - local frameName = name or frame:GetName(); - if not f[frameName] then return end - - local config = OmaRF.db.profile.indicators; - for pos, ind in pairs(f[frameName]) do - ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]); - ind.text:SetTextColor(unpack(config[pos]["textColor"])); - ind.icon:SetWidth(config[pos]["iconSize"]); - ind.icon:SetHeight(config[pos]["iconSize"]); - ind.icon:SetTexture(DEFAULT_ICON); - ind.icon:SetVertexColor(unpack(config[pos]["iconColor"])); - end - - config = OmaRF.db.profile.majorAuras; - for i, ind in ipairs(majorFrames[frameName]) do - if i == 1 then - ind.icon:ClearAllPoints(); - ind.icon:SetPoint("CENTER", frame, "CENTER", -config.iconSize, 0); - end - ind.icon:SetWidth(config.iconSize); - ind.icon:SetHeight(config.iconSize); - ind.expireText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); - ind.stackText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); - end -end - --- Create the FontStrings used for indicators -local function setupCompactUnitFrame(frame, name) - f[name] = {}; - for _, pos in ipairs(positions) do - f[name][pos] = {}; - f[name][pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); - f[name][pos].text:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]); - f[name][pos].icon = frame:CreateTexture(nil, "OVERLAY"); - f[name][pos].icon:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]); - end - - local config = OmaRF.db.profile.majorAuras; - majorFrames[name] = {}; - for i = 1, config.max do - majorFrames[name][i] = {}; - majorFrames[name][i].icon = frame:CreateTexture(nil, "OVERLAY"); - if i > 1 then - majorFrames[name][i].icon:SetPoint("TOPLEFT", majorFrames[name][i-1].icon, "TOPRIGHT"); - end - majorFrames[name][i].expireText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); - majorFrames[name][i].expireText:SetPoint("BOTTOMRIGHT", majorFrames[name][i].icon, "BOTTOMRIGHT"); - majorFrames[name][i].stackText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); - majorFrames[name][i].stackText:SetPoint("TOPLEFT", majorFrames[name][i].icon, "TOPLEFT"); - end - - configureIndicators(frame, name); -end - -local function remaining(expires, current) - if expires == 0 then return "" end - local remain = expires - current; - if remain > 60 then - return format("%dm", ceil(remain/60)); - end - return floor(remain+0.5); -end - -local function hide(frameName) - for _, ind in pairs(f[frameName]) do - ind.text:Hide(); - ind.icon:Hide(); - end - for _, ind in ipairs(majorFrames[frameName]) do - ind.icon:Hide(); - ind.expireText:Hide(); - ind.stackText:Hide(); - end -end - --- Check the indicators on a frame and update the times on them -local function updateIndicators(frame) - local frameName = frame:GetName(); - local unit = frame.unit; - if not unit then return end -- possible if the frame is just being hidden - - -- Create indicators if needed, out of combat if forbidden - if not f[frameName] then - if frame:IsForbidden() then - if not OmaRF.ooc_queue[frameName] then - OmaRF.ooc_queue[frameName] = { - func = setupCompactUnitFrame, - args = { frame, frameName } - }; - end - return; - else - setupCompactUnitFrame(frame, frameName); - end - end - -- Reset current - hide(frameName); - -- Hide if unit is dead/disconnected - if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then - return; - end - - local current = GetTime(); - for pos, ind in pairs(f[frameName]) do - if ind.expires ~= nil then - local config = OmaRF.db.profile.indicators[pos]; - if config.showIcon then - ind.icon:Show(); - end - if config.showText then - ind.text:SetText(remaining(ind.expires, current)); - ind.text:Show(); - end - end - end - for _, ind in ipairs(majorFrames[frameName]) do - if ind.expires ~= nil then - ind.icon:Show(); - ind.expireText:SetText(remaining(ind.expires, current)); - ind.expireText:Show(); - ind.stackText:Show(); - end - end -end - --- Update all indicators -function OmaRF:UpdateAllIndicators() - CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators); - if OmaRF.running then - C_TimerAfter(0.15, OmaRF.UpdateAllIndicators); - end -end - --- Used to update everything that is affected by the configuration -function OmaRF:RefreshConfig() - self:OnDisable(); -- clear everything - if self.db.profile.enabled then - CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators); - watchedAuras = {}; - for _, pos in ipairs(positions) do - for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do - watchedAuras[aura] = pos; -- TODO single aura only in one position - end - end - majorAuras = {}; - for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do - majorAuras[aura] = true; - end - majorMax = OmaRF.db.profile.majorAuras["max"]; - - if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then - self.running = true; - C_TimerAfter(0.15, self.UpdateAllIndicators); - end - end -end diff --git a/OmaRF/LayoutFramesHook.lua b/OmaRF/LayoutFramesHook.lua index a4d729a..168891c 100644 --- a/OmaRF/LayoutFramesHook.lua +++ b/OmaRF/LayoutFramesHook.lua @@ -6,7 +6,11 @@ local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyT local unpack = unpack; -- TODO remove 1px border -hooksecurefunc("CompactRaidFrameContainer_LayoutFrames", function(frame) +local function layoutHook(frame) + if InCombatLockdown() then + OmaRF.ooc_queue["layoutHook"] = {func = layoutHook, args = {frame}}; + return; + end CompactRaidFrameContainer_ApplyToFrames(frame, "normal", function(frame) -- Health bar color -- -- used in CompactUnitFrame_UpdateHealthColor, might not be set prior @@ -20,4 +24,5 @@ hooksecurefunc("CompactRaidFrameContainer_LayoutFrames", function(frame) frame.powerBar:Hide(); end end); -end); +end +hooksecurefunc("CompactRaidFrameContainer_LayoutFrames", layoutHook); diff --git a/OmaRF/NewIndicators.lua b/OmaRF/NewIndicators.lua new file mode 100644 index 0000000..01c1ae9 --- /dev/null +++ b/OmaRF/NewIndicators.lua @@ -0,0 +1,268 @@ +-- Indicators.lua +local unpack, ipairs, pairs, ceil, floor = unpack, ipairs, pairs, ceil, floor; +local UnitIsConnected, UnitIsDeadOrGhost = UnitIsConnected, UnitIsDeadOrGhost; +local UnitAura, UnitIsPlayer, GetTime = UnitAura, UnitIsPlayer, GetTime; +local C_TimerAfter = C_Timer.After; +local format = string.format; + +local positions = OmaRF.positions; +local auraFilters = {"HELPFUL", "HARMFUL"}; +local DEFAULT_ICON = "Interface\\AddOns\\OmaRF\\images\\rhomb"; +local _; + +local frameBase; +local frames = {}; +local watchedAuras = {}; +local majorAuras = {}; +local majorMax; + +local function remaining(expires, current) + if expires == 0 then return "" end + local remain = expires - current; + if remain > 60 then + return format("%dm", ceil(remain/60)); + end + return floor(remain+0.5); +end + +local function showIndicator(ind, icon, caster, expires, current, config) + if not config.mine or UnitIsPlayer(caster) then + if config.showIcon then + if config.useDefaultIcon then + ind.icon:SetTexture(DEFAULT_ICON); + else + ind.icon:SetTexture(icon); + end + if not ind.icon:IsShown() then ind.icon:Show() end + end + ind.expires = expires; + if config.showText then + ind.text:SetText(remaining(expires, current)); + if not ind.text:IsShown() then ind.text:Show() end + end + end +end + +local function showMajorIndicator(ind, icon, count, expires, current) + ind.icon:SetTexture(icon); + ind.expires = expires; + ind.expireText:SetText(remaining(expires, current)); + if count > 1 then + ind.stackText:SetText(count); + if not ind.stackText:IsShown() then ind.stackText:Show() end + else + if ind.stackText:IsShown() then ind.stackText:Hide() end + end + if not ind.icon:IsShown() then ind.icon:Show() end + if not ind.expireText:IsShown() then ind.expireText:Show() end +end + +-- update current auras +hooksecurefunc("CompactUnitFrame_UpdateAuras", function(unitFrame) + local frameName = unitFrame:GetName(); + if frames[frameName] then + local frame = frames[frameName]; + for _, ind in pairs(frame.inds) do ind.expires = nil end + for _, ind in ipairs(frame.majorInds) do ind.expires = nil end + + local name, icon, count, expires, caster, id; + local unit = unitFrame.displayedUnit; + local majorPos = 1; + local current = GetTime(); + for _, filter in ipairs(auraFilters) do + local i = 1; + while true do + name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter); + if not id then break end + local pos = watchedAuras[id] or watchedAuras[name]; + if pos then + showIndicator( + frame.inds[pos], icon, caster, expires, current, + OmaRF.db.profile.indicators[pos] + ); + end + if (majorAuras[id] or majorAuras[name]) and majorPos <= majorMax then + showMajorIndicator(frame.majorInds[majorPos], icon, count, expires, current); + majorPos = majorPos + 1; + end + i = i + 1; + end + end + end +end); + +-- Check the indicators on a frame and update the times on them +local function updateIndicators(frame, name) + local unitFrame = _G[name]; -- has to always reference global + if unitFrame == nil then + return; + elseif not unitFrame:IsVisible() then + if frame:IsShown() then frame:Hide() end + return; + end + + local unit = unitFrame.unit; + local displayedUnit = unitFrame.displayedUnit; + if not unit or not UnitIsConnected(unit) or UnitIsDeadOrGhost(displayedUnit) then + if frame:IsShown() then frame:Hide() end + return; + end + if not frame:IsShown() then frame:Show() end + + local current = GetTime(); + for pos, ind in pairs(frame.inds) do + if ind.expires ~= nil then + if OmaRF.db.profile.indicators[pos].showText then + ind.text:SetText(remaining(ind.expires, current)); + end + else + if ind.icon:IsShown() then ind.icon:Hide() end + if ind.text:IsShown() then ind.text:Hide() end + end + end + for _, ind in ipairs(frame.majorInds) do + if ind.expires ~= nil then + ind.expireText:SetText(remaining(ind.expires, current)); + else + if ind.icon:IsShown() then ind.icon:Hide() end + if ind.expireText:IsShown() then ind.expireText:Hide() end + if ind.stackText:IsShown() then ind.stackText:Hide() end + end + end +end + +local function configureIndicators(frame) + local config = OmaRF.db.profile.indicators; + for pos, ind in pairs(frame.inds) do + ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]); + ind.text:SetTextColor(unpack(config[pos]["textColor"])); + ind.icon:SetWidth(config[pos]["iconSize"]); + ind.icon:SetHeight(config[pos]["iconSize"]); + ind.icon:SetTexture(DEFAULT_ICON); + ind.icon:SetVertexColor(unpack(config[pos]["iconColor"])); + end + + config = OmaRF.db.profile.majorAuras; + for i, ind in ipairs(frame.majorInds) do + if i == 1 then + ind.icon:ClearAllPoints(); + ind.icon:SetPoint("CENTER", frame, "CENTER", -config["iconSize"], 0); + end + ind.icon:SetWidth(config["iconSize"]); + ind.icon:SetHeight(config["iconSize"]); + ind.expireText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); + ind.stackText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); + end +end + +local function createIndicators(frame) + frame.inds = {}; + for _, pos in ipairs(positions) do + frame.inds[pos] = {}; + frame.inds[pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); + frame.inds[pos].text:SetPoint(pos, frame, pos); + frame.inds[pos].icon = frame:CreateTexture(nil, "OVERLAY"); + frame.inds[pos].icon:SetPoint(pos, frame, pos); + end + + frame.majorInds = {}; + majorMax = OmaRF.db.profile.majorAuras.max; + for i = 1, majorMax do + frame.majorInds[i] = {}; + local ind = frame.majorInds[i]; + ind.icon = frame:CreateTexture(nil, "OVERLAY"); + if i > 1 then + ind.icon:SetPoint("TOPLEFT", frame.majorInds[i-1].icon, "TOPRIGHT"); + end + ind.expireText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); + ind.expireText:SetPoint("BOTTOMRIGHT", ind.icon, "BOTTOMRIGHT"); + ind.stackText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); + ind.stackText:SetPoint("TOPLEFT", ind.icon, "TOPLEFT"); + end + + configureIndicators(frame); +end + +-- Update all indicators +local function updateAllIndicators() + for name, frame in pairs(frames) do updateIndicators(frame, name) end + if OmaRF.running then C_TimerAfter(0.15, updateAllIndicators) end +end + +-- Used to update everything that is affected by the configuration +function OmaRF:RefreshConfig() + self:OnDisable(); -- clear everything + if self.db.profile.enabled then + for _, f in pairs(frames) do configureIndicators(f) end + + watchedAuras = {}; + for _, pos in ipairs(positions) do + for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do + watchedAuras[aura] = pos; -- TODO single aura only in one position + end + end + majorAuras = {}; + for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do + majorAuras[aura] = true; + end + + if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then + frameBase:Show(); + self.running = true; + C_TimerAfter(0.15, updateAllIndicators); + end + end +end + +local function updateFrames() + for name, frame in pairs(frames) do + local unitFrame = _G[name]; + if unitFrame then + if not frame.pointsSet then + frame:SetAllPoints(unitFrame); + frame.pointsSet = true; + end + end + end +end + +local function initialize(frame) + local name = "CompactRaidFrame1"; + frames[name] = CreateFrame("Frame", "OmaRF1", frameBase); + frames[name]:SetAllPoints(name); + frames[name]:Hide(); + createIndicators(frames[name]); + local i = 2; + for y = 2,5 do + local name = "CompactRaidFrame"..i; + frames[name] = CreateFrame("Frame", "OmaRF"..i, frameBase); + frames[name]:Hide(); + createIndicators(frames[name]); + i = i + 1; + end + for x = 1,7 do + for y = 1,5 do + local name = "CompactRaidFrame"..i; + frames[name] = CreateFrame("Frame", "OmaRF"..i, frameBase); + frames[name]:Hide(); + createIndicators(frames[name]); + i = i + 1; + end + end +end + +local function onEvent(self, event, ...) + if event == "GROUP_ROSTER_UPDATE" then + -- not sure if fired before LayoutFrames, wait a bit + C_TimerAfter(0.01, updateFrames); + elseif event == "PLAYER_LOGIN" then + initialize(); + end +end + +frameBase = CreateFrame("Frame", nil, UIParent); +frameBase:SetFrameStrata("HIGH"); +frameBase:RegisterEvent("PLAYER_LOGIN"); +frameBase:RegisterEvent("GROUP_ROSTER_UPDATE"); +frameBase:SetScript("OnEvent", onEvent); +OmaRF.frameBase = frameBase; diff --git a/OmaRF/OmaRF.toc b/OmaRF/OmaRF.toc index 1d83617..9e4a6aa 100644 --- a/OmaRF/OmaRF.toc +++ b/OmaRF/OmaRF.toc @@ -8,7 +8,7 @@ embeds.xml Core.lua -Indicators.lua +NewIndicators.lua UnitFrameSetupHook.lua UpdateNameHook.lua UpdateStatusTextHook.lua diff --git a/OmaRF/UpdateNameHook.lua b/OmaRF/UpdateNameHook.lua index 293d8c0..8165c7d 100644 --- a/OmaRF/UpdateNameHook.lua +++ b/OmaRF/UpdateNameHook.lua @@ -1,6 +1,10 @@ local UnitName = UnitName; -hooksecurefunc("CompactUnitFrame_UpdateName", function(frame) +local function nameHook(frame) + if InCombatLockdown() then + table.insert(OmaRF.ooc_queue, {func = nameHook, args = {frame}}); + return; + end -- allowClassColorsForNPCs only in regular raid frames, -- match only to them if frame.optionTable.allowClassColorsForNPCs ~= nil then @@ -11,4 +15,5 @@ hooksecurefunc("CompactUnitFrame_UpdateName", function(frame) frame.name:SetText(name); end end -end); +end +hooksecurefunc("CompactUnitFrame_UpdateName", nameHook); -- 2.39.5