c6843f3 - Refactor updateIndicators to get auras when they're applied
[wowui.git] / OmaRF / Indicators.lua
1 local f = OmaRF.frames;
2 local majorFrames = OmaRF.majorFrames;
3 local positions = OmaRF.positions;
4 local pad = 2;
5 local paddings = {
6     TOPLEFT = {pad, -pad},
7     TOPRIGHT = {-pad, -pad},
8     CENTER = {0, 0},
9     BOTTOMLEFT = {pad, pad},
10     BOTTOMRIGHT = {-pad, pad}
11 };
12 local watchedAuras;
13 local majorAuras;
14 local majorMax;
15 local auraFilters = {"HELPFUL", "HARMFUL"};
16 local DEFAULT_ICON = "Interface\\AddOns\\OmaRF\\images\\rhomb";
17 local _;
18
19 -- global functions used every update
20 local C_TimerAfter = C_Timer.After;
21 local GetTime = GetTime;
22 local UnitAura = UnitAura;
23 local UnitIsPlayer = UnitIsPlayer;
24 local UnitIsConnected = UnitIsConnected;
25 local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
26 local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyToFrames;
27 local format = string.format;
28 local unpack = unpack;
29 local floor = floor;
30 local ceil = ceil;
31
32 -- update current auras
33 hooksecurefunc("CompactUnitFrame_UpdateAuras", function(frame)
34     local frameName = frame:GetName();
35     if f[frameName] then
36         for _, ind in pairs(f[frameName]) do ind.expires = nil end
37         for _, ind in ipairs(majorFrames[frameName]) do ind.expires = nil end
38
39         local name, icon, count, expires, caster, id;
40         local unit = frame.displayedUnit;
41         local majorI = 1;
42         for _, filter in ipairs(auraFilters) do
43             local i = 1;
44             while true do
45                 name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter);
46                 if not id then break end
47                 local pos = watchedAuras[id] or watchedAuras[name];
48                 if pos then
49                     local ind = f[frameName][pos];
50                     local config = OmaRF.db.profile.indicators[pos];
51                     if not config.mine or UnitIsPlayer(caster) then
52                         if config.useDefaultIcon then
53                             ind.icon:SetTexture(DEFAULT_ICON);
54                         else
55                             ind.icon:SetTexture(icon);
56                         end
57                         ind.expires = expires;
58                     end
59                 end
60
61                 if (majorAuras[id] or majorAuras[name]) and majorI <= majorMax then
62                     local ind = majorFrames[frameName][majorI];
63                     ind.icon:SetTexture(icon);
64                     ind.expires = expires;
65                     if count > 1 then
66                         ind.stackText:SetText(count);
67                     end
68                     majorI = majorI + 1;
69                 end
70                 i = i + 1;
71             end
72         end
73     end
74 end);
75
76 local function configureIndicators(frame, name)
77     local frameName = name or frame:GetName();
78     if not f[frameName] then return end
79
80     local config = OmaRF.db.profile.indicators;
81     for pos, ind in pairs(f[frameName]) do
82         ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]);
83         ind.text:SetTextColor(unpack(config[pos]["textColor"]));
84         ind.icon:SetWidth(config[pos]["iconSize"]);
85         ind.icon:SetHeight(config[pos]["iconSize"]);
86         ind.icon:SetTexture(DEFAULT_ICON);
87         ind.icon:SetVertexColor(unpack(config[pos]["iconColor"]));
88     end
89
90     config = OmaRF.db.profile.majorAuras;
91     for i, ind in ipairs(majorFrames[frameName]) do
92         if i == 1 then
93             ind.icon:ClearAllPoints();
94             ind.icon:SetPoint("CENTER", frame, "CENTER", -config.iconSize, 0);
95         end
96         ind.icon:SetWidth(config.iconSize);
97         ind.icon:SetHeight(config.iconSize);
98         ind.expireText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
99         ind.stackText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
100     end
101 end
102
103 -- Create the FontStrings used for indicators
104 local function setupCompactUnitFrame(frame, name)
105     f[name] = {};
106     for _, pos in ipairs(positions) do
107         f[name][pos] = {};
108         f[name][pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
109         f[name][pos].text:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
110         f[name][pos].icon = frame:CreateTexture(nil, "OVERLAY");
111         f[name][pos].icon:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
112     end
113
114     local config = OmaRF.db.profile.majorAuras;
115     majorFrames[name] = {};
116     for i = 1, config.max do
117         majorFrames[name][i] = {};
118         majorFrames[name][i].icon = frame:CreateTexture(nil, "OVERLAY");
119         if i > 1 then
120             majorFrames[name][i].icon:SetPoint("TOPLEFT", majorFrames[name][i-1].icon, "TOPRIGHT");
121         end
122         majorFrames[name][i].expireText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
123         majorFrames[name][i].expireText:SetPoint("BOTTOMRIGHT", majorFrames[name][i].icon, "BOTTOMRIGHT");
124         majorFrames[name][i].stackText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
125         majorFrames[name][i].stackText:SetPoint("TOPLEFT", majorFrames[name][i].icon, "TOPLEFT");
126     end
127
128     configureIndicators(frame, name);
129 end
130
131 local function remaining(expires, current)
132     if expires == 0 then return "" end
133     local remain = expires - current;
134     if remain > 60 then
135         return format("%dm", ceil(remain/60));
136     end
137     return floor(remain+0.5);
138 end
139
140 local function hide(frameName)
141     for _, ind in pairs(f[frameName]) do
142         ind.text:Hide();
143         ind.icon:Hide();
144     end
145     for _, ind in ipairs(majorFrames[frameName]) do
146         ind.icon:Hide();
147         ind.expireText:Hide();
148         ind.stackText:Hide();
149     end
150 end
151
152 -- Check the indicators on a frame and update the times on them
153 local function updateIndicators(frame)
154     local frameName = frame:GetName();
155     local unit = frame.unit;
156     if not unit then return end -- possible if the frame is just being hidden
157
158     -- Create indicators if needed, out of combat if forbidden
159     if not f[frameName] then
160         if frame:IsForbidden() then
161             if not OmaRF.ooc_queue[frameName] then
162                 OmaRF.ooc_queue[frameName] = {
163                     func = setupCompactUnitFrame,
164                     args = { frame, frameName }
165                 };
166             end
167             return;
168         else
169             setupCompactUnitFrame(frame, frameName);
170         end
171     end
172     -- Reset current
173     hide(frameName);
174     -- Hide if unit is dead/disconnected
175     if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then
176         return;
177     end
178
179     local current = GetTime();
180     for pos, ind in pairs(f[frameName]) do
181         if ind.expires ~= nil then
182             local config = OmaRF.db.profile.indicators[pos];
183             if config.showIcon then
184                 ind.icon:Show();
185             end
186             if config.showText then
187                 ind.text:SetText(remaining(ind.expires, current));
188                 ind.text:Show();
189             end
190         end
191     end
192     for _, ind in ipairs(majorFrames[frameName]) do
193         if ind.expires ~= nil then
194             ind.icon:Show();
195             ind.expireText:SetText(remaining(ind.expires, current));
196             ind.expireText:Show();
197             ind.stackText:Show();
198         end
199     end
200 end
201
202 -- Update all indicators
203 function OmaRF:UpdateAllIndicators()
204     CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators);
205     if OmaRF.running then
206         C_TimerAfter(0.15, OmaRF.UpdateAllIndicators);
207     end
208 end
209
210 -- Used to update everything that is affected by the configuration
211 function OmaRF:RefreshConfig()
212     self:OnDisable(); -- clear everything
213     if self.db.profile.enabled then
214         CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators);
215         watchedAuras = {};
216         for _, pos in ipairs(positions) do
217             for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do
218                 watchedAuras[aura] = pos; -- TODO single aura only in one position
219             end
220         end
221         majorAuras = {};
222         for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do
223             majorAuras[aura] = true;
224         end
225         majorMax = OmaRF.db.profile.majorAuras["max"];
226
227         if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then
228             self.running = true;
229             C_TimerAfter(0.15, self.UpdateAllIndicators);
230         end
231     end
232 end