36d03cca89345f0606edaa3848d591a971055972
[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 local function configureIndicators(frame, name)
33     local frameName = name or frame:GetName();
34     if not f[frameName] then return end
35
36     local config = OmaRF.db.profile.indicators;
37     for pos, ind in pairs(f[frameName]) do
38         ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]);
39         ind.text:SetTextColor(unpack(config[pos]["textColor"]));
40         ind.icon:SetWidth(config[pos]["iconSize"]);
41         ind.icon:SetHeight(config[pos]["iconSize"]);
42         ind.icon:SetTexture(DEFAULT_ICON);
43         ind.icon:SetVertexColor(unpack(config[pos]["iconColor"]));
44     end
45
46     config = OmaRF.db.profile.majorAuras;
47     for i, ind in ipairs(majorFrames[frameName]) do
48         if i == 1 then
49             ind.icon:ClearAllPoints();
50             ind.icon:SetPoint("CENTER", frame, "CENTER", -config.iconSize, 0);
51         end
52         ind.icon:SetWidth(config.iconSize);
53         ind.icon:SetHeight(config.iconSize);
54         ind.expire:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
55         ind.stack:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
56     end
57 end
58
59 -- Create the FontStrings used for indicators
60 local function setupCompactUnitFrame(frame, name)
61     f[name] = {};
62     for _, pos in ipairs(positions) do
63         f[name][pos] = {};
64         f[name][pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
65         f[name][pos].text:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
66         f[name][pos].icon = frame:CreateTexture(nil, "OVERLAY");
67         f[name][pos].icon:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
68     end
69
70     local config = OmaRF.db.profile.majorAuras;
71     majorFrames[name] = {};
72     for i = 1, config.max do
73         majorFrames[name][i] = {};
74         majorFrames[name][i].icon = frame:CreateTexture(nil, "OVERLAY");
75         if i > 1 then
76             majorFrames[name][i].icon:SetPoint("TOPLEFT", majorFrames[name][i-1].icon, "TOPRIGHT");
77         end
78         majorFrames[name][i].expire = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
79         majorFrames[name][i].expire:SetPoint("BOTTOMRIGHT", majorFrames[name][i].icon, "BOTTOMRIGHT");
80         majorFrames[name][i].stack = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
81         majorFrames[name][i].stack:SetPoint("TOPLEFT", majorFrames[name][i].icon, "TOPLEFT");
82     end
83
84     configureIndicators(frame, name);
85 end
86
87 local function remaining(expires, current)
88     local remain = expires - current;
89     if remain > 60 then
90         return format("%dm", ceil(remain/60));
91     end
92     return floor(remain+0.5);
93 end
94
95 -- Check the indicators on a frame and update the times on them
96 local function updateIndicators(frame)
97     local frameName = frame:GetName();
98     local unit = frame.unit;
99     if not unit then return end -- possible if the frame is just being hidden
100
101     -- Create indicators if needed
102     if not f[frameName] then setupCompactUnitFrame(frame, frameName) end
103     -- Reset current
104     for _, ind in pairs(f[frameName]) do
105         ind.text:Hide();
106         ind.icon:Hide();
107     end
108     for _, ind in ipairs(majorFrames[frameName]) do
109         ind.icon:Hide();
110         ind.expire:Hide();
111         ind.stack:Hide();
112     end
113     -- Hide if unit is dead/disconnected
114     if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then
115         return;
116     end
117
118     local name, icon, count, expires, caster, id;
119     local current = GetTime();
120     local majorI = 1;
121     for _, filter in ipairs(auraFilters) do
122         local i = 1;
123         while true do
124             name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter);
125             if not id then break end
126             local pos = watchedAuras[id] or watchedAuras[name];
127             if pos then
128                 local ind = f[frameName][pos];
129                 local config = OmaRF.db.profile.indicators[pos];
130                 if not config.mine or UnitIsPlayer(caster) then
131                     if config.showIcon then
132                         -- show icon
133                         if config.useDefaultIcon then
134                             ind.icon:SetTexture(DEFAULT_ICON);
135                         else
136                             ind.icon:SetTexture(icon);
137                         end
138                         ind.icon:Show()
139                     end
140                     if config.showText then
141                         -- show text
142                         ind.text:SetText(remaining(expires, current));
143                         ind.text:Show();
144                     end
145                 end
146             end
147
148             if (majorAuras[id] or majorAuras[name]) and majorI <= majorMax then
149                 local ind = majorFrames[frameName][majorI];
150                 ind.icon:SetTexture(icon);
151                 ind.icon:Show();
152                 ind.expire:SetText(remaining(expires, current));
153                 ind.expire:Show();
154                 if count > 1 then
155                     ind.stack:SetText(count);
156                     ind.stack:Show();
157                 end
158                 majorI = majorI + 1;
159             end
160             i = i + 1;
161         end
162     end
163 end
164
165 -- Update all indicators
166 function OmaRF:UpdateAllIndicators()
167     CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators);
168     if OmaRF.running then
169         C_TimerAfter(0.15, OmaRF.UpdateAllIndicators);
170     end
171 end
172
173 -- Used to update everything that is affected by the configuration
174 function OmaRF:RefreshConfig()
175     self:OnDisable(); -- clear everything
176     if self.db.profile.enabled then
177         CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators);
178         watchedAuras = {};
179         for _, pos in ipairs(positions) do
180             for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do
181                 watchedAuras[aura] = pos; -- TODO single aura only in one position
182             end
183         end
184         majorAuras = {};
185         for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do
186             majorAuras[aura] = true;
187         end
188         majorMax = OmaRF.db.profile.majorAuras["max"];
189
190         if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then
191             self.running = true;
192             C_TimerAfter(0.15, self.UpdateAllIndicators);
193         end
194     end
195 end