-- ActionBars.lua local _; local pairs = pairs; local GetActionTexture = GetActionTexture; local GetActionLossOfControlCooldown = GetActionLossOfControlCooldown; local GetActionCooldown, GetActionCharges = GetActionCooldown, GetActionCharges; local IsConsumableAction, IsStackableAction = IsConsumableAction, IsStackableAction; local IsItemAction, GetActionCount = IsItemAction, GetActionCount; local CooldownFrame_Set, CooldownFrame_Clear = CooldownFrame_Set, CooldownFrame_Clear; local GameTooltip = nil; 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 = false; -- change to lock button dragging local settings = { ["OmaBT1"] = { start = 1, length = 12, x = 1000, y = 1000, }, ["OmaBT2"] = { start = 13, length = 12, x = 1000, y = 960, }, ["OmaBT3"] = { start = 25, length = 12, x = 1000, y = 920, }, ["OmaBT4"] = { start = 37, length = 12, x = 1000, y = 880, }, ["OmaBT5"] = { start = 49, length = 12, x = 1000, y = 840, }, ["OmaBT6"] = { start = 61, length = 12, x = 1000, y = 800, }, -- bogus data past this --["OmaBT7"] = { -- start = 73, -- length = 12, -- x = 1000, -- y = 760, --}, --["OmaBT8"] = { -- start = 85, -- length = 12, -- x = 1000, -- y = 760, --}, --["OmaBT9"] = { -- start = 97, -- length = 12, -- x = 1000, -- y = 760, --}, --["OmaBT10"] = { -- start = 109, -- length = 12, -- x = 1000, -- y = 760, --}, }; local buttons = {}; local ActionBars = CreateFrame("Frame", "OmaActionBars", UIParent); local inheritedFrames = "SecureActionButtonTemplate,SecureHandlerDragTemplate"; 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 -- TODO charges local locstart, locduration = GetActionLossOfControlCooldown(slot); local start, duration, enable, modrate = GetActionCooldown(slot); local charges, maxcharges, chargestart, chargeduration, chargemodrate = GetActionCharges(slot); 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 else local charges, maxcharges = GetActionCharges(slot); if maxcharges > 1 then button.count:SetText(charges); else button.count:SetText(""); end end end local function updateButton(button, slot) local texture = GetActionTexture(slot); if texture then button.hasaction = true; button.base:Show(); button.icon:SetTexture(texture); updateCount(button, slot); updateCooldown(button, slot); else button.hasaction = nil; if not button.grid then button.base:Hide() end button.icon:SetTexture(nil); end end local function createActionBar(parent, name, config) local prev; for slot = config.start, config.start+config.length-1 do local secure = CreateFrame("Button", name..slot, parent, inheritedFrames); secure.slot = slot; if slot == config.start then secure:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y); else secure:SetPoint("TOPLEFT", prev, "TOPRIGHT"); end secure:RegisterForClicks("AnyUp"); if not BUTTONLOCK then secure:RegisterForDrag("LeftButton", "RightButton"); end secure:SetWidth(32); secure:SetHeight(32); secure.base = secure:CreateTexture(nil, "BACKGROUND"); secure.base:SetAllPoints(); secure.base:SetColorTexture(0, 0, 0, 0.5); secure.iconbase = secure:CreateTexture(nil, "BORDER"); secure.iconbase:SetPoint("TOPLEFT", secure.base, "TOPLEFT", 1, -1); secure.iconbase:SetPoint("BOTTOMRIGHT", secure.base, "BOTTOMRIGHT", -1, 1); secure.iconbase:SetColorTexture(0, 0, 0, 0.5); secure.iconbase:Hide(); secure.icon = secure:CreateTexture(nil, "ARTWORK"); secure.icon:SetPoint("TOPLEFT", secure.iconbase, "TOPLEFT"); secure.icon:SetPoint("BOTTOMRIGHT", secure.iconbase, "BOTTOMRIGHT"); secure.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93); secure.hotkey = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormalGray"); secure.hotkey:SetPoint("TOPRIGHT", secure, "TOPRIGHT", 2, -1); secure.count = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormal"); secure.count:SetPoint("BOTTOMRIGHT", secure, "BOTTOMRIGHT", 2, -1); secure.cd = CreateFrame("Cooldown", name..slot.."CD", secure, "CooldownFrameTemplate"); secure.cd:SetAllPoints(); secure:SetAttribute("type", "action"); secure:SetAttribute("action", slot); function secure:ActionChanged() return updateButton(self, slot); end secure:ActionChanged(); -- initial update -- 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 ]=]); 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"); end ]=]); buttons[slot] = secure; prev = secure; end end local function initialize() ActionBars:SetFrameStrata("LOW"); ActionBars:SetPoint("BOTTOMLEFT"); ActionBars:SetWidth(1); ActionBars:SetHeight(1); for name, config in pairs(settings) do createActionBar(ActionBars, name, config); end end local events = { ["ACTIONBAR_UPDATE_COOLDOWN"] = function() for _, button in pairs(buttons) do updateCooldown(button, button.slot); end end, ["SPELL_UPDATE_CHARGES"] = function() for _, button in pairs(buttons) do updateCount(button, button.slot); end end, ["ACTIONBAR_SLOT_CHANGED"] = function(slot) if buttons[slot] then buttons[slot]:ActionChanged() end end, ["ACTIONBAR_SHOWGRID"] = function() for _, button in pairs(buttons) do button.grid = true; button.iconbase:Show(); if not button.hasaction then button.base:Show() end end end, ["ACTIONBAR_HIDEGRID"] = function() for _, button in pairs(buttons) do button.grid = nil; button.iconbase:Hide(); if not button.hasaction then button.base:Hide() end end end, ["UPDATE_ALL_BUTTONS"] = function() for _, button in pairs(buttons) do updateButton(button, button.slot); end end, ["UPDATE_BINDINGS"] = function() end, ["PLAYER_LOGIN"] = function() GameTooltip = _G["GameTooltip"]; initialize(); end, }; events["LOSS_OF_CONTROL_ADDED"] = events["ACTIONBAR_UPDATE_COOLDOWN"]; events["LOSS_OF_CONTROL_UPDATE"] = events["ACTIONBAR_UPDATE_COOLDOWN"]; -- TODO might change once tooltips are in events["SPELL_UPDATE_ICON"] = events["UPDATE_ALL_BUTTONS"]; events["PET_STABLE_UPDATE"] = events["UPDATE_ALL_BUTTONS"]; events["PET_STABLE_SHOW"] = events["UPDATE_ALL_BUTTONS"]; -- TODO overlay glow ? don't exactly know what it does -- autorepeat, tooltips ActionBars:RegisterEvent("PLAYER_LOGIN"); ActionBars:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN"); ActionBars:RegisterEvent("SPELL_UPDATE_CHARGES"); ActionBars:RegisterEvent("ACTIONBAR_SLOT_CHANGED"); ActionBars:RegisterEvent("ACTIONBAR_SHOWGRID"); ActionBars:RegisterEvent("ACTIONBAR_HIDEGRID"); ActionBars:SetScript("OnEvent", function(self, event, arg1) events[event](arg1); end);