e3460edf60222d10c7e405c9b9a24c7fa718066b
[wowui.git] / OmaAB / ActionBars.lua
1 -- ActionBars.lua
2 local _;
3 local pairs = pairs;
4 local GetActionTexture = GetActionTexture;
5 local GetActionLossOfControlCooldown = GetActionLossOfControlCooldown;
6 local GetActionCooldown, GetActionCharges = GetActionCooldown, GetActionCharges;
7 local IsConsumableAction, IsStackableAction = IsConsumableAction, IsStackableAction;
8 local IsItemAction, GetActionCount = IsItemAction, GetActionCount;
9 local CooldownFrame_Set, CooldownFrame_Clear = CooldownFrame_Set, CooldownFrame_Clear;
10 local GameTooltip = nil;
11 local COOLDOWN_TYPE_LOSS_OF_CONTROL = COOLDOWN_TYPE_LOSS_OF_CONTROL;
12 local COOLDOWN_TYPE_NORMAL = COOLDOWN_TYPE_NORMAL;
13 local CDTexture = "Interface\\Cooldown\\edge";
14 local locCDTexture = "Interface\\Cooldown\\edge-LoC";
15
16 local BUTTONLOCK = false; -- change to lock button dragging
17
18 local settings = {
19     ["OmaBT1"] = {
20         start = 1,
21         length = 12,
22         x = 1000,
23         y = 1000,
24     },
25     ["OmaBT2"] = {
26         start = 13,
27         length = 12,
28         x = 1000,
29         y = 960,
30     },
31     ["OmaBT3"] = {
32         start = 25,
33         length = 12,
34         x = 1000,
35         y = 920,
36     },
37     ["OmaBT4"] = {
38         start = 37,
39         length = 12,
40         x = 1000,
41         y = 880,
42     },
43     ["OmaBT5"] = {
44         start = 49,
45         length = 12,
46         x = 1000,
47         y = 840,
48     },
49     ["OmaBT6"] = {
50         start = 61,
51         length = 12,
52         x = 1000,
53         y = 800,
54     },
55     -- bogus data past this
56     --["OmaBT7"] = {
57     --    start = 73,
58     --    length = 12,
59     --    x = 1000,
60     --    y = 760,
61     --},
62     --["OmaBT8"] = {
63     --    start = 85,
64     --    length = 12,
65     --    x = 1000,
66     --    y = 760,
67     --},
68     --["OmaBT9"] = {
69     --    start = 97,
70     --    length = 12,
71     --    x = 1000,
72     --    y = 760,
73     --},
74     --["OmaBT10"] = {
75     --    start = 109,
76     --    length = 12,
77     --    x = 1000,
78     --    y = 760,
79     --},
80 };
81
82 local buttons = {};
83
84 local ActionBars = CreateFrame("Frame", "OmaActionBars", UIParent);
85 local inheritedFrames = "SecureActionButtonTemplate,SecureHandlerDragTemplate";
86
87 local numChargeCDs = 0;
88 local function createChargeCD(parent)
89     numChargeCDs = numChargeCDs + 1;
90     local frame = CreateFrame("Cooldown", "OmaChargeCD"..numChargeCDs, parent, "CooldownFrameTemplate");
91     frame:SetHideCountdownNumbers(false);
92     frame:SetDrawSwipe(false);
93     frame:SetAllPoints(parent);
94     frame:SetFrameStrata("TOOLTIP");
95     return frame;
96 end
97
98 local function clearChargeCD(parent)
99     if parent.chargecd then CooldownFrame_Clear(parent.chargecd) end
100 end
101
102 local function startChargeCD(parent, start, duration, modrate)
103     if start == 0 then
104         return clearChargeCD(parent);
105     end
106     parent.chargecd = parent.chargecd or createChargeCD(parent);
107     CooldownFrame_Set(parent.chargecd, start, duration, true, true, modrate);
108 end
109
110 local redoCooldown;
111
112 local function updateCooldown(button, slot)
113     -- CD update from FrameXML/ActionButton.lua
114     -- TODO charges
115     local locstart, locduration = GetActionLossOfControlCooldown(slot);
116     local start, duration, enable, modrate = GetActionCooldown(slot);
117     local charges, maxcharges, chargestart, chargeduration, chargemodrate = GetActionCharges(slot);
118     if (locstart + locduration) > (start + duration) then
119         if button.cd.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL then
120             button.cd:SetEdgeTexture(locCDTexture);
121             button.cd:SetSwipeColor(0.17, 0, 0);
122             button.cd:SetHideCountdownNumbers(true);
123             button.cd.currentCooldownType = COOLDOWN_TYPE_LOSS_OF_CONTROL;
124         end
125
126         CooldownFrame_Set(button.cd, locstart, locduration, true, true, modrate);
127         clearChargeCD(button);
128     else
129         if button.cd.currentCooldownType ~= COOLDOWN_TYPE_NORMAL then
130             button.cd:SetEdgeTexture(CDTexture);
131             button.cd:SetSwipeColor(0, 0, 0);
132             button.cd:SetHideCountdownNumbers(false);
133             button.cd.currentCooldownType = COOLDOWN_TYPE_NORMAL;
134         end
135
136         if locstart > 0 then
137             button.cd:SetScript("OnCooldownDone", redoCooldown);
138         end
139         if charges and maxcharges and maxcharges > 1 and charges < maxcharges then
140             startChargeCD(button, chargestart, chargeduration, chargemodrate);
141         else
142             clearChargeCD(button);
143         end
144         CooldownFrame_Set(button.cd, start, duration, enable, false, modrate);
145     end
146 end
147
148 local function redoCooldown(cd)
149     local button = cd:GetParent();
150     cd:SetScript("OnCooldownDone", nil);
151     updateCooldown(button, button.slot);
152 end
153
154 local function updateCount(button, slot)
155     if IsConsumableAction(slot) or IsStackableAction(slot) or
156             (not IsItemAction(slot) and GetActionCount(slot) > 0) then
157         local count = GetActionCount(slot);
158         if count > 99 then
159             button.count:SetText("*");
160         else
161             button.count:SetText(count);
162         end
163     else
164         local charges, maxcharges = GetActionCharges(slot);
165         if maxcharges > 1 then
166             button.count:SetText(charges);
167         else
168             button.count:SetText("");
169         end
170     end
171 end
172
173 local function updateButton(button, slot)
174     local texture = GetActionTexture(slot);
175     if texture then
176         button.hasaction = true;
177         button.base:Show();
178         button.icon:SetTexture(texture);
179         updateCount(button, slot);
180         updateCooldown(button, slot);
181     else
182         button.hasaction = nil;
183         if not button.grid then button.base:Hide() end
184         button.icon:SetTexture(nil);
185     end
186 end
187
188 local function createActionBar(parent, name, config)
189     local prev;
190     for slot = config.start, config.start+config.length-1 do
191         local secure = CreateFrame("Button", name..slot, parent, inheritedFrames);
192         secure.slot = slot;
193         if slot == config.start then
194             secure:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y);
195         else
196             secure:SetPoint("TOPLEFT", prev, "TOPRIGHT");
197         end
198         secure:RegisterForClicks("AnyUp");
199         if not BUTTONLOCK then
200             secure:RegisterForDrag("LeftButton", "RightButton");
201         end
202         secure:SetWidth(32);
203         secure:SetHeight(32);
204         secure.base = secure:CreateTexture(nil, "BACKGROUND");
205         secure.base:SetAllPoints();
206         secure.base:SetColorTexture(0, 0, 0, 0.5);
207         secure.iconbase = secure:CreateTexture(nil, "BORDER");
208         secure.iconbase:SetPoint("TOPLEFT", secure.base, "TOPLEFT", 1, -1);
209         secure.iconbase:SetPoint("BOTTOMRIGHT", secure.base, "BOTTOMRIGHT", -1, 1);
210         secure.iconbase:SetColorTexture(0, 0, 0, 0.5);
211         secure.iconbase:Hide();
212         secure.icon = secure:CreateTexture(nil, "ARTWORK");
213         secure.icon:SetPoint("TOPLEFT", secure.iconbase, "TOPLEFT");
214         secure.icon:SetPoint("BOTTOMRIGHT", secure.iconbase, "BOTTOMRIGHT");
215         secure.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
216         secure.hotkey = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormalGray");
217         secure.hotkey:SetPoint("TOPRIGHT", secure, "TOPRIGHT", 2, -1);
218         secure.count = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormal");
219         secure.count:SetPoint("BOTTOMRIGHT", secure, "BOTTOMRIGHT", 2, -1);
220         secure.cd = CreateFrame("Cooldown", name..slot.."CD", secure, "CooldownFrameTemplate");
221         secure.cd:SetAllPoints();
222         secure:SetAttribute("type", "action");
223         secure:SetAttribute("action", slot);
224         function secure:ActionChanged()
225             return updateButton(self, slot);
226         end
227         secure:ActionChanged(); -- initial update
228         -- FrameXML/SecureHandlers.lua has arguments and return value
229         -- args: self, button, kind, value, ... (kind, value, ... from GetCursorInfo())
230         -- returns: kind, target, detail
231         -- or: "clear", kind, target, detail
232         -- used for Pickup* functions
233         -- some of these snippets based on LibActionButton-1.0
234         secure:SetAttribute("_ondragstart", [=[
235             return "action", self:GetAttribute("action");
236         ]=]);
237         secure:SetAttribute("_onreceivedrag", [=[
238             if not kind or not value then return nil end
239             return "action", self:GetAttribute("action");
240         ]=]);
241         -- pre-wrapper can pass a message to post-wrapper
242         secure:WrapScript(secure, "OnDragStart", [=[
243             local kind, value = GetActionInfo(self:GetAttribute("action"));
244             return "message", format("%s|%s", tostring(kind), tostring(value));
245         ]=], [=[
246             local kind, value = GetActionInfo(self:GetAttribute("action"));
247             if message ~= format("%s|%s", tostring(kind), tostring(value)) then
248                 self:CallMethod("ActionChanged");
249             end
250         ]=]);
251         secure:WrapScript(secure, "OnReceiveDrag", [=[
252             local kind, value = GetActionInfo(self:GetAttribute("action"));
253             return "message", format("%s|%s", tostring(kind), tostring(value));
254         ]=], [=[
255             local kind, value = GetActionInfo(self:GetAttribute("action"));
256             if message ~= format("%s|%s", tostring(kind), tostring(value)) then
257                 self:CallMethod("ActionChanged");
258             end
259         ]=]);
260         secure:WrapScript(secure, "OnClick", [=[
261             local kind, value = GetActionInfo(self:GetAttribute("action"));
262             return nil, format("%s|%s", tostring(kind), tostring(value));
263         ]=], [=[
264             local kind, value = GetActionInfo(self:GetAttribute("action"));
265             if message ~= format("%s|%s", tostring(kind), tostring(value)) then
266                 self:CallMethod("ActionChanged");
267             end
268         ]=]);
269         buttons[slot] = secure;
270         prev = secure;
271     end
272 end
273
274 local function initialize()
275     ActionBars:SetFrameStrata("LOW");
276     ActionBars:SetPoint("BOTTOMLEFT");
277     ActionBars:SetWidth(1);
278     ActionBars:SetHeight(1);
279     for name, config in pairs(settings) do
280         createActionBar(ActionBars, name, config);
281     end
282 end
283
284 local events = {
285     ["ACTIONBAR_UPDATE_COOLDOWN"] = function()
286         for _, button in pairs(buttons) do
287             updateCooldown(button, button.slot);
288         end
289     end,
290     ["SPELL_UPDATE_CHARGES"] = function()
291         for _, button in pairs(buttons) do
292             updateCount(button, button.slot);
293         end
294     end,
295     ["ACTIONBAR_SLOT_CHANGED"] = function(slot)
296         if buttons[slot] then buttons[slot]:ActionChanged() end
297     end,
298     ["ACTIONBAR_SHOWGRID"] = function()
299         for _, button in pairs(buttons) do
300             button.grid = true;
301             button.iconbase:Show();
302             if not button.hasaction then button.base:Show() end
303         end
304     end,
305     ["ACTIONBAR_HIDEGRID"] = function()
306         for _, button in pairs(buttons) do
307             button.grid = nil;
308             button.iconbase:Hide();
309             if not button.hasaction then button.base:Hide() end
310         end
311     end,
312     ["UPDATE_ALL_BUTTONS"] = function()
313         for _, button in pairs(buttons) do
314             updateButton(button, button.slot);
315         end
316     end,
317     ["UPDATE_BINDINGS"] = function()
318     end,
319     ["PLAYER_LOGIN"] = function()
320         GameTooltip = _G["GameTooltip"];
321         initialize();
322     end,
323 };
324 events["LOSS_OF_CONTROL_ADDED"] = events["ACTIONBAR_UPDATE_COOLDOWN"];
325 events["LOSS_OF_CONTROL_UPDATE"] = events["ACTIONBAR_UPDATE_COOLDOWN"]; -- TODO might change once tooltips are in
326 events["SPELL_UPDATE_ICON"] = events["UPDATE_ALL_BUTTONS"];
327 events["PET_STABLE_UPDATE"] = events["UPDATE_ALL_BUTTONS"];
328 events["PET_STABLE_SHOW"] = events["UPDATE_ALL_BUTTONS"];
329 -- TODO overlay glow ? don't exactly know what it does
330 -- autorepeat, tooltips
331
332 ActionBars:RegisterEvent("PLAYER_LOGIN");
333 ActionBars:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
334 ActionBars:RegisterEvent("SPELL_UPDATE_CHARGES");
335 ActionBars:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
336 ActionBars:RegisterEvent("ACTIONBAR_SHOWGRID");
337 ActionBars:RegisterEvent("ACTIONBAR_HIDEGRID");
338 ActionBars:SetScript("OnEvent", function(self, event, arg1)
339     events[event](arg1);
340 end);