a0c279f - Fix action button glow
[wowui.git] / OmaRF / Indicators.lua
1 -- Indicators.lua
2 local pairs, ipairs = pairs, ipairs;
3 local floor = math.floor;
4 local GetTime = GetTime;
5 local UnitAura = UnitAura;
6 local CreateFrame = CreateFrame;
7 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
8 local CTimerAfter = C_Timer.After;
9
10 local Settings = OmaRFSettings;
11 local majorAuras = Settings.MajorAuras;
12 local watchedAuras = {};
13
14 local updaters = {};
15 local updating = {};
16 local auraFilters = {"HELPFUL", "HARMFUL"};
17
18 local M = {};
19 OmaRFIndicators = M;
20 M.Class = {};
21
22 function M.SetupIndicators(frame, class)
23     frame.indBase = CreateFrame("Frame", nil, frame);
24     frame.indBase:SetAllPoints();
25     frame.indBase:Hide();
26     if M.Class[class] then
27         watchedAuras = M.Class[class].Auras;
28         frame.inds = M.Class[class].Setup(frame.indBase);
29     else
30         frame.inds = {};
31     end
32
33     frame.majorBase = CreateFrame("Frame", nil, frame);
34     frame.majorBase:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -10);
35     frame.majorBase:SetPoint("BOTTOMRIGHT");
36     frame.majors = {};
37     for i = 1,3 do
38         local tex = frame.majorBase:CreateTexture(nil, "OVERLAY");
39         tex = frame.majorBase:CreateTexture(nil, "OVERLAY");
40         if i == 1 then tex:SetPoint("TOPLEFT", frame.majorBase, "TOPLEFT");
41         else tex:SetPoint("TOPLEFT", frame.majors[i-1], "TOPRIGHT"); end
42         tex:SetWidth(20);
43         tex:SetHeight(20);
44         tex:Hide();
45         tex.text = frame.majorBase:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
46         tex.text:SetPoint("CENTER", tex, "BOTTOMRIGHT", -2, 2);
47         tex.text:Hide();
48         tex.stack = frame.majorBase:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
49         tex.stack:SetPoint("CENTER", tex, "TOPLEFT", 1, 0);
50         tex.stack:Hide();
51         tex.icon = true;
52         frame.majors[i] = tex;
53     end
54 end
55
56 local function remaining(text, expires, current)
57     if expires == 0 then
58         text:SetText("");
59         return false;
60     end
61     local remain = expires - current;
62     if remain > 8 then
63         text:SetText("");
64     else
65         text:SetText(floor(remain+0.5));
66     end
67     return true;
68 end
69
70 local function updateIndicators(frame)
71     local unit = frame.displayed;
72     if not frame:IsShown() or not UnitIsConnected(unit) or UnitIsDeadOrGhost(unit) then
73         updating[frame] = nil;
74         return;
75     end
76
77     local needUpdate = false;
78     local current = GetTime();
79     for _, ind in pairs(frame.inds) do
80         if ind.text and ind.text.expires ~= nil then
81             needUpdate = remaining(ind.text, ind.text.expires, current) or needUpdate;
82         end
83     end
84     for _, ind in pairs(frame.majors) do
85         if ind.text and ind.text.expires ~= nil then
86             needUpdate = remaining(ind.text, ind.text.expires, current) or needUpdate;
87         end
88     end
89     if needUpdate then
90         CTimerAfter(0.16, updaters[frame]);
91     else
92         updating[frame] = nil;
93     end
94 end
95
96 local function showInd(ind, expires, current, count, icon)
97     local needUpdate = false;
98     if ind.icon then
99         ind:SetTexture(icon);
100     end
101     if ind.text then
102         needUpdate = remaining(ind.text, expires, current);
103         ind.text.expires = expires;
104         ind.text:Show();
105     end
106     if ind.stack and count > 1 then
107         ind.stack:SetText(count);
108         ind.stack:Show();
109     end
110     ind:Show();
111     return needUpdate;
112 end
113
114 local function hideInd(ind)
115     if ind.text then
116         ind.text.expires = nil;
117         ind.text:Hide();
118     end
119     if ind.stack then ind.stack:Hide() end
120     ind:Hide();
121 end
122
123 function M.CheckIndicators(frame, unit)
124     for _, ind in pairs(frame.inds) do
125         hideInd(ind);
126     end
127     for _, ind in pairs(frame.majors) do
128         hideInd(ind);
129     end
130     local name, icon, count, expires, caster, id;
131     local showInds, showMajors, needUpdate = false, false, false;
132     local majorPos = 1;
133     local alert = false; -- color the whole bar
134     local current = GetTime();
135     for _, filter in ipairs(auraFilters) do
136         local i = 1;
137         while true do
138             name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter);
139             if not id then break end
140             local pos = watchedAuras[id] or watchedAuras[name];
141             if pos and caster == "player" then
142                 needUpdate = showInd(frame.inds[pos], expires, current, count, icon) or needUpdate;
143                 showInds = true;
144             end
145             local major = majorAuras[id] or majorAuras[name];
146             if major and majorPos <= 3 then
147                 needUpdate = showInd(frame.majors[majorPos], expires, current, count, icon) or needUpdate;
148                 if major.bar then alert = true end
149                 showMajors = true;
150                 majorPos = majorPos + 1;
151             end
152             i = i + 1;
153         end
154     end
155     if showInds or showMajors then
156         frame.indBase:Show();
157         frame.majorBase:Show();
158         if needUpdate and not updating[frame] then
159             updating[frame] = true; -- race?
160             -- create a function for updating the indicator
161             local func = updaters[frame];
162             if not func then
163                 func = function() updateIndicators(frame) end;
164                 updaters[frame] = func;
165             end
166             CTimerAfter(0.16, func);
167         end
168     else
169         frame.indBase:Hide();
170         frame.majorBase:Hide();
171     end
172
173     return alert;
174 end