+local RegisterStateDriver = RegisterStateDriver;
+local CooldownFrame_Set, CooldownFrame_Clear = CooldownFrame_Set, CooldownFrame_Clear;
+local CTimerAfter = C_Timer.After;
+local GameTooltip = GameTooltip;
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor;
+local COOLDOWN_TYPE_LOSS_OF_CONTROL = COOLDOWN_TYPE_LOSS_OF_CONTROL;
+local COOLDOWN_TYPE_NORMAL = COOLDOWN_TYPE_NORMAL;
+local CDTexture = "Interface\\Cooldown\\edge";
+local locCDTexture = "Interface\\Cooldown\\edge-LoC";
+
+local BUTTONLOCK = true; -- change to lock button dragging
+
+local settings = {
+ ["Oma1"] = {
+ bar = 1,
+ start = 1,
+ length = 12,
+ columns = 4,
+ size = 40,
+ x = 580,
+ y = 300,
+ nomouse = true,
+ },
+ ["Oma2"] = {
+ bar = 2,
+ start = 13,
+ length = 12,
+ columns = 4,
+ size = 40,
+ x = 580,
+ y = 180,
+ nomouse = true,
+ },
+ ["Oma3"] = {
+ bar = 3,
+ start = 25,
+ length = 12,
+ columns = 3,
+ x = 1824,
+ y = 128,
+ flyout = "LEFT",
+ },
+ ["Oma4"] = {
+ bar = 4,
+ start = 37,
+ length = 12,
+ columns = 3,
+ x = 1824,
+ y = 256,
+ },
+ ["Oma5"] = {
+ bar = 5,
+ start = 49,
+ length = 12,
+ columns = 3,
+ x = 1000,
+ y = 840,
+ },
+ ["Oma6"] = {
+ bar = 6,
+ start = 61,
+ length = 12,
+ x = 1000,
+ y = 600,
+ },
+ -- used as bonus bars for some classes
+ ["Oma7"] = {
+ bar = 7,
+ start = 73,
+ length = 12,
+ x = 1000,
+ y = 760,
+ },
+ ["Oma8"] = {
+ bar = 8,
+ start = 85,
+ length = 12,
+ x = 1000,
+ y = 720,
+ },
+ ["Oma9"] = {
+ bar = 9,
+ start = 97,
+ length = 12,
+ x = 1000,
+ y = 680,
+ },
+ ["Oma10"] = {
+ bar = 10,
+ start = 109,
+ length = 12,
+ x = 1000,
+ y = 640,
+ },
+};
+
+local usingBonusbars = {
+ --["WARRIOR"] = {[7]=true, [8]=true, [9]=true}, -- not using stance separated actionbars
+ ["DRUID"] = {[7]=true, [8]=true, [9]=true}, -- moonkin form page is usable anyway
+ --["DRUID"] = {[7]=true, [8]=true, [9]=true,[10]=true},
+ ["ROGUE"] = {[7]=true},
+ --["PRIEST"] = {[7]=true}, -- shadowform doesn't change abilities
+};
+
+local chars = {
+ ["Stormreaver"] = {
+ ["Vildan"] = {1, 2, 3, 4,},
+ ["Gedren"] = {1, 2, 3, 4,},
+ ["Gazden"] = {1, 2, 3, 4,},
+ },
+};
+
+local buttons = {};
+local activeButtons = {};
+
+local ActionBars = CreateFrame("Frame", "OmaActionBars", UIParent);
+local inheritedFrames =
+"SecureActionButtonTemplate,SecureHandlerDragTemplate,SecureHandlerStateTemplate";
+
+local function showTooltip(secure)
+ GameTooltip_SetDefaultAnchor(GameTooltip, secure);
+ GameTooltip:SetAction(secure:GetAttribute("action"));
+end
+
+local function hideTooltip()
+ GameTooltip:Hide();
+end
+
+local numChargeCDs = 0;
+local function createChargeCD(parent)
+ numChargeCDs = numChargeCDs + 1;
+ local frame = CreateFrame("Cooldown", "OmaChargeCD"..numChargeCDs, parent, "CooldownFrameTemplate");
+ frame:SetHideCountdownNumbers(false);
+ frame:SetDrawSwipe(false);
+ frame:SetAllPoints(parent);
+ frame:SetFrameStrata("TOOLTIP");
+ return frame;
+end
+
+local function clearChargeCD(parent)
+ if parent.chargecd then CooldownFrame_Clear(parent.chargecd) end
+end
+
+local function startChargeCD(parent, start, duration, modrate)
+ if start == 0 then
+ return clearChargeCD(parent);
+ end
+ parent.chargecd = parent.chargecd or createChargeCD(parent);
+ CooldownFrame_Set(parent.chargecd, start, duration, true, true, modrate);
+end
+
+local redoCooldown;
+
+local function updateCooldown(button, slot)
+ -- CD update from FrameXML/ActionButton.lua
+ local locstart, locduration = GetActionLossOfControlCooldown(slot);
+ local start, duration, enable, modrate = GetActionCooldown(slot);
+ local charges, maxcharges, chargestart, chargeduration, chargemodrate = GetActionCharges(slot);
+ -- avoid as many updates as possible by checking if there's changes first
+ if button.prev and
+ button.prev[1] == locstart and button.prev[2] == locduration and
+ button.prev[3] == start and button.prev[4] == duration and
+ button.prev[5] == enable and button.prev[6] == modrate and
+ button.prev[7] == charges and button.prev[8] == maxcharges and
+ button.prev[9] == chargestart and button.prev[10] == chargeduration and
+ button.prev[11] == chargemodrate then
+ return;
+ end
+ button.prev = { locstart, locduration, start, duration, enable, modrate,
+ charges, maxcharges, chargestart, chargeduration, chargemodrate };
+ if (locstart + locduration) > (start + duration) then
+ if button.cd.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL then
+ button.cd:SetEdgeTexture(locCDTexture);
+ button.cd:SetSwipeColor(0.17, 0, 0);
+ button.cd:SetHideCountdownNumbers(true);
+ button.cd.currentCooldownType = COOLDOWN_TYPE_LOSS_OF_CONTROL;
+ end
+
+ CooldownFrame_Set(button.cd, locstart, locduration, true, true, modrate);
+ clearChargeCD(button);
+ else
+ if button.cd.currentCooldownType ~= COOLDOWN_TYPE_NORMAL then
+ button.cd:SetEdgeTexture(CDTexture);
+ button.cd:SetSwipeColor(0, 0, 0);
+ button.cd:SetHideCountdownNumbers(false);
+ button.cd.currentCooldownType = COOLDOWN_TYPE_NORMAL;
+ end
+
+ if locstart > 0 then
+ button.cd:SetScript("OnCooldownDone", redoCooldown);
+ end
+ if charges and maxcharges and maxcharges > 1 and charges < maxcharges then
+ startChargeCD(button, chargestart, chargeduration, chargemodrate);
+ else
+ clearChargeCD(button);
+ end
+ CooldownFrame_Set(button.cd, start, duration, enable, false, modrate);
+ end
+end
+
+local function redoCooldown(cd)
+ local button = cd:GetParent();
+ cd:SetScript("OnCooldownDone", nil);
+ updateCooldown(button, button.slot);
+end
+
+local function updateCount(button, slot)
+ if IsConsumableAction(slot) or IsStackableAction(slot) or
+ (not IsItemAction(slot) and GetActionCount(slot) > 0) then
+ local count = GetActionCount(slot);
+ if count > 99 then
+ button.count:SetText("*");
+ else
+ button.count:SetText(count);
+ end
+ button.count:Show();
+ else
+ local charges, maxcharges = GetActionCharges(slot);
+ if maxcharges > 1 then
+ button.count:SetText(charges);
+ button.count:Show();
+ else
+ button.count:Hide();
+ end
+ end
+end
+
+local function updateUsable(button, slot)
+ local isUsable, noMana = IsUsableAction(slot);
+ if isUsable then
+ button.icon:SetVertexColor(1, 1, 1);
+ elseif noMana then
+ button.icon:SetVertexColor(0, 0.5, 1);
+ else
+ button.icon:SetVertexColor(0.4, 0.4, 0.4);
+ end
+end
+
+local function updateState(button, slot)
+ button:SetChecked(IsCurrentAction(slot) or IsAutoRepeatAction(slot));
+end
+
+local function updateGlow(button, slot)
+ local stype, id, _ = GetActionInfo(slot);
+ if stype == "spell" and IsSpellOverlayed(id) then
+ button.glow:Show();
+ elseif stype == "macro" then
+ local _, _, macroid = GetMacroSpell(id);
+ if macroid and IsSpellOverlayed(macroid) then
+ button.glow:Show();
+ else
+ button.glow:Hide();
+ end
+ else -- TODO FlyoutHasSpell glow
+ button.glow:Hide();
+ end
+end
+
+local function startGlow(button, slot, spell)
+ local stype, id, _ = GetActionInfo(slot);
+ if stype == "spell" and id == spell then
+ button.glow:Show();
+ elseif stype == "macro" then
+ local _, _, macroid = GetMacroSpell(id);
+ if macroid and macroid == spell then
+ button.glow:Show();
+ end
+ end
+ -- TODO FlyoutHasSpell glow
+end
+
+local function stopGlow(button, slot, spell)
+ local stype, id, _ = GetActionInfo(slot);
+ if stype == "spell" and id == spell then
+ button.glow:Hide();
+ elseif stype == "macro" then
+ local _, _, macroid = GetMacroSpell(id);
+ if macroid and macroid == spell then
+ button.glow:Hide();
+ end
+ end
+ -- TODO FlyoutHasSpell glow
+end
+
+local function updateButton(button, slot)
+ if HasAction(slot) then
+ activeButtons[slot] = button;
+ button.base:Show();
+ button.icon:SetTexture(GetActionTexture(slot));
+ updateCooldown(button, slot);
+ updateUsable(button, slot);
+ updateState(button, slot);
+ updateCount(button, slot);
+ updateGlow(button, slot);
+ if not IsConsumableAction(slot) and not IsStackableAction(slot) then
+ button.text:SetText(ssub(GetActionText(slot) or "", 1, 4));
+ button.text:Show();
+ end
+ if button.hotkey.shown then button.hotkey:Show() end
+ else
+ activeButtons[slot] = nil;
+ if not button.grid then button.base:Hide() end
+ button.icon:SetTexture(nil);
+ button.cd:Hide();
+ button.count:Hide();
+ button.hotkey:Hide();
+ button.text:Hide();
+ button.glow:Hide();
+ button:SetChecked(false);
+ end
+end
+
+local function updateHotkeys(button)
+ local key = GetBindingKey(format("CLICK %s:LeftButton", button:GetName()));
+ if key and key ~= "" then
+ -- from LibKeyBound-1.0
+ key = key:upper();
+ key = key:gsub(" ", "");
+ key = key:gsub("ALT%-", "a");
+ key = key:gsub("CTRL%-", "c");
+ key = key:gsub("SHIFT%-", "s");
+ key = key:gsub("NUMPAD", "n");
+ button.hotkey:SetText(key);
+ button.hotkey.shown = true;
+ button.hotkey:Show();
+ else
+ button.hotkey.shown = nil;
+ button.hotkey:Hide();
+ end
+end
+
+local mainbartoggle = "[overridebar][possessbar][shapeshift]possess;";
+mainbartoggle = mainbartoggle.."[bonusbar:1,stealth:1]bonusbar2;"; -- prowl
+mainbartoggle = mainbartoggle.."[bonusbar:1]bonusbar1;[bonusbar:2]bonusbar2;"; -- cat form, unused
+mainbartoggle = mainbartoggle.."[bonusbar:3]bonusbar3;[bonusbar:4]bonusbar4;"; -- bear form, moonkin form
+mainbartoggle = mainbartoggle.."normal";
+local function setupSnippets(secure, slot)
+ -- FrameXML/SecureHandlers.lua has arguments and return value
+ -- args: self, button, kind, value, ... (kind, value, ... from GetCursorInfo())
+ -- returns: kind, target, detail
+ -- or: "clear", kind, target, detail
+ -- used for Pickup* functions
+ -- some of these snippets based on LibActionButton-1.0
+ secure:SetAttribute("_ondragstart", [=[
+ return "action", self:GetAttribute("action");
+ ]=]);
+ secure:SetAttribute("_onreceivedrag", [=[
+ if not kind or not value then return nil end
+ return "action", self:GetAttribute("action");
+ ]=]);
+ -- pre-wrapper can pass a message to post-wrapper
+ secure:WrapScript(secure, "OnDragStart", [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ return "message", format("%s|%s", tostring(kind), tostring(value));
+ ]=], [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ if message ~= format("%s|%s", tostring(kind), tostring(value)) then
+ self:CallMethod("ActionChanged");
+ end
+ ]=]);
+ secure:WrapScript(secure, "OnReceiveDrag", [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ return "message", format("%s|%s", tostring(kind), tostring(value));
+ ]=], [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ if message ~= format("%s|%s", tostring(kind), tostring(value)) then
+ self:CallMethod("ActionChanged");
+ end
+ ]=]);
+ function secure:UpdateState()
+ return updateState(self, self.slot);
+ end
+ secure:WrapScript(secure, "OnClick", [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ return nil, format("%s|%s", tostring(kind), tostring(value));
+ ]=], [=[
+ local kind, value = GetActionInfo(self:GetAttribute("action"));
+ if message ~= format("%s|%s", tostring(kind), tostring(value)) then
+ self:CallMethod("ActionChanged");