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