flickerstreak@54: --[[ flickerstreak@54: ReAction Possess Bar (Mind Control/etc) button module. flickerstreak@54: flickerstreak@54: Wraps the standard Action buttons 121-132 with an automatic show/hide flickerstreak@54: when mind control (etc) is active flickerstreak@54: flickerstreak@54: --]] flickerstreak@54: flickerstreak@54: -- local imports flickerstreak@54: local ReAction = ReAction flickerstreak@54: local L = ReAction.L flickerstreak@54: local _G = _G flickerstreak@54: local CreateFrame = CreateFrame flickerstreak@54: flickerstreak@54: -- module declaration flickerstreak@54: local moduleID = "PossessBar" flickerstreak@54: local module = ReAction:NewModule( moduleID ) flickerstreak@54: flickerstreak@54: -- module methods flickerstreak@54: function module:OnInitialize() flickerstreak@54: self.db = ReAction.db:RegisterNamespace( moduleID, flickerstreak@54: { flickerstreak@54: profile = { flickerstreak@54: buttons = { } flickerstreak@54: } flickerstreak@54: } flickerstreak@54: ) flickerstreak@54: self.buttons = { } flickerstreak@54: flickerstreak@54: ReAction:RegisterOptions("global", self, { flickerstreak@54: hideEmptyPossess = { flickerstreak@54: type = "toggle", flickerstreak@54: name = L["Hide Empty Possess Bar Buttons"], flickerstreak@54: get = function() return self.db.profile.hideEmptyButtons end, flickerstreak@54: set = function(info, val) module:SetHideEmptyButtons(val) end, flickerstreak@54: } flickerstreak@54: }) flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:OnEnable() flickerstreak@54: ReAction:RegisterBarType(L["Possess Bar"], flickerstreak@54: { flickerstreak@54: type = moduleID, flickerstreak@54: defaultButtonSize = 36, flickerstreak@54: defaultBarRows = 1, flickerstreak@54: defaultBarCols = 12, flickerstreak@54: defaultBarSpacing = 3 flickerstreak@54: }) flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:OnDisable() flickerstreak@54: ReAction:UnregisterBarType(L["Possess Bar"]) flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:ApplyToBar(bar) flickerstreak@54: if bar.config.type == moduleID then flickerstreak@54: bar:GetFrame():SetParent(PossessBarFrame) flickerstreak@54: bar.config.parent = "PossessBarFrame" flickerstreak@57: self:CreatePossessControlButtons(bar) flickerstreak@54: end flickerstreak@54: self:RefreshBar(bar) flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:RefreshBar(bar) flickerstreak@54: if bar.config.type == moduleID then flickerstreak@54: if self.buttons[bar] == nil then flickerstreak@54: self.buttons[bar] = { } flickerstreak@54: end flickerstreak@54: local btns = self.buttons[bar] flickerstreak@54: local profile = self.db.profile flickerstreak@54: local barName = bar:GetName() flickerstreak@54: if profile.buttons[barName] == nil then flickerstreak@54: profile.buttons[barName] = {} flickerstreak@54: end flickerstreak@54: local btnCfg = profile.buttons[barName] flickerstreak@54: flickerstreak@54: local r, c = bar:GetButtonGrid() flickerstreak@54: local n = r*c flickerstreak@54: for i = 1, n do flickerstreak@54: if btnCfg[i] == nil then flickerstreak@54: btnCfg[i] = {} flickerstreak@54: end flickerstreak@54: if btns[i] == nil then flickerstreak@54: local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) flickerstreak@54: if ok and b then flickerstreak@54: btns[i] = b flickerstreak@54: end flickerstreak@54: else flickerstreak@54: btns[i]:Refresh(bar,i) flickerstreak@54: end flickerstreak@54: end flickerstreak@54: for i = n+1, #btns do flickerstreak@54: if btns[i] then flickerstreak@54: btns[i] = btns[i]:Destroy() flickerstreak@54: if btnCfg[i] then flickerstreak@54: btnCfg[i] = nil flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:RemoveFromBar(bar) flickerstreak@54: if self.buttons[bar] then flickerstreak@54: local btns = self.buttons[bar] flickerstreak@54: for _,b in pairs(btns) do flickerstreak@54: if b then flickerstreak@54: b:Destroy() flickerstreak@54: end flickerstreak@54: end flickerstreak@54: self.buttons[bar] = nil flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:EraseBarConfig(barName) flickerstreak@54: self.db.profile.buttons[barName] = nil flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:RenameBarConfig(oldname, newname) flickerstreak@54: local b = self.db.profile.buttons flickerstreak@54: b[newname], b[oldname] = b[oldname], nil flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:SetHideEmptyButtons(hide) flickerstreak@54: if hide ~= self.db.profile.hideEmptyButtons then flickerstreak@54: for _, bar in pairs(self.buttons) do flickerstreak@54: for _, b in pairs(bar) do flickerstreak@54: if hide then flickerstreak@54: ActionButton_HideGrid(b.frame) flickerstreak@54: else flickerstreak@54: ActionButton_ShowGrid(b.frame) flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: self.db.profile.hideEmptyButtons = hide flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:ApplyConfigMode(mode,bars) flickerstreak@54: for _, bar in pairs(bars) do flickerstreak@54: if bar and self.buttons[bar] then flickerstreak@54: for _, b in pairs(self.buttons[bar]) do flickerstreak@54: if b then flickerstreak@54: if mode then flickerstreak@54: ActionButton_ShowGrid(b.frame) flickerstreak@54: self:showActionIDLabel(b) flickerstreak@54: else flickerstreak@54: ActionButton_HideGrid(b.frame) flickerstreak@54: self:hideActionIDLabel(b) flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: local f = bar:GetFrame() flickerstreak@54: if mode then flickerstreak@54: f:SetParent(UIParent) flickerstreak@54: f:Show() flickerstreak@54: else flickerstreak@54: f:SetParent(PossessBarFrame) flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:showActionIDLabel(button) flickerstreak@54: if not button.actionIDLabel and button:GetActionID() then flickerstreak@54: local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge") flickerstreak@54: label:SetAllPoints() flickerstreak@54: label:SetJustifyH("CENTER") flickerstreak@54: label:SetShadowColor(0,0,0,1) flickerstreak@54: label:SetShadowOffset(2,-2) flickerstreak@54: label:SetText(tostring(button:GetActionID())) flickerstreak@54: button.actionIDLabel = label flickerstreak@54: end flickerstreak@54: button.actionIDLabel:Show() flickerstreak@54: end flickerstreak@54: flickerstreak@54: function module:hideActionIDLabel(button) flickerstreak@54: if button.actionIDLabel then flickerstreak@54: button.actionIDLabel:Hide() flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: flickerstreak@57: -- possess-bar control buttons (shows buff, cancel buff) flickerstreak@57: function module:CreatePossessControlButton(bar,id,name) flickerstreak@57: -- guard against taint by reusing global variable frames flickerstreak@57: -- instead of nilling them out (e.g. create bar, delete bar, create bar with same name) flickerstreak@57: name = name or ("ReAction_%s_PossessCtrlButton%d"):format(bar:GetName(),id) flickerstreak@57: local b = name and _G[name] flickerstreak@57: if b then flickerstreak@57: b:SetParent(bar:GetFrame()) flickerstreak@57: else flickerstreak@57: b = CreateFrame("CheckButton", name, bar:GetFrame(), "PossessButtonTemplate") flickerstreak@57: end flickerstreak@57: b:SetID(id) flickerstreak@57: flickerstreak@57: b:RegisterEvent("PLAYER_AURAS_CHANGED"); flickerstreak@57: flickerstreak@57: local icon = _G[("%sIcon"):format(name)] flickerstreak@57: local cooldown = _G[("%sCooldown"):format(name)] flickerstreak@57: local nTex = _G[("%sNormalTexture"):format(name)] flickerstreak@57: nTex:SetWidth(54) flickerstreak@57: nTex:SetHeight(54) flickerstreak@57: flickerstreak@57: local function update() flickerstreak@57: local texture = GetPossessInfo(id); flickerstreak@57: icon:SetTexture(texture); flickerstreak@57: icon:Show() flickerstreak@57: cooldown:Hide(); flickerstreak@57: b:SetChecked(0); flickerstreak@57: icon:SetVertexColor(1.0, 1.0, 1.0); flickerstreak@57: end flickerstreak@57: update() flickerstreak@57: flickerstreak@57: b:HookScript("OnClick", function() b:SetChecked(0) end) flickerstreak@57: b:SetScript("OnEvent", update) flickerstreak@57: b:SetScript("OnShow", update) flickerstreak@57: flickerstreak@57: return b flickerstreak@57: end flickerstreak@57: flickerstreak@57: function module:CreatePossessControlButtons(bar) flickerstreak@57: if not bar.possessButtons then flickerstreak@57: bar.possessButtons = { } flickerstreak@57: bar.config.possessFrameNames = bar.config.possessFrameNames or { } flickerstreak@57: local previous flickerstreak@57: local n = NUM_POSSESS_SLOTS flickerstreak@57: for i = 1, n do flickerstreak@57: local name = bar.config.possessFrameNames[i] flickerstreak@57: local f = self:CreatePossessControlButton(bar,i,name) flickerstreak@57: bar.possessButtons[i] = f flickerstreak@57: bar.config.possessFrameNames[i] = f:GetName() flickerstreak@57: flickerstreak@57: local r, c, s = bar:GetButtonGrid() flickerstreak@57: local w, h = bar:GetButtonSize() flickerstreak@57: flickerstreak@57: local scale = ((h - (n-1)*s)/n)/30 flickerstreak@57: f:SetScale(scale) flickerstreak@57: flickerstreak@57: if previous then flickerstreak@57: f:SetPoint("TOP", previous, "BOTTOM", 0, -s/scale) flickerstreak@57: else flickerstreak@57: f:SetPoint("TOPRIGHT", bar:GetFrame(), "TOPLEFT", -s/scale, 0) flickerstreak@57: end flickerstreak@57: f:Show() flickerstreak@57: previous = f flickerstreak@57: end flickerstreak@57: end flickerstreak@57: end flickerstreak@57: flickerstreak@57: flickerstreak@54: flickerstreak@54: -- use-count of action IDs flickerstreak@54: local minActionID = 121 flickerstreak@54: local maxActionID = 132 flickerstreak@54: local ActionIDList = setmetatable( {}, { flickerstreak@54: __index = function(self, idx) flickerstreak@54: if idx == nil then flickerstreak@54: for i = minActionID, maxActionID do flickerstreak@54: if rawget(self,i) == nil then flickerstreak@54: rawset(self,i,1) flickerstreak@54: return i flickerstreak@54: end flickerstreak@54: end flickerstreak@54: error("ran out of action IDs") flickerstreak@54: else flickerstreak@54: local c = rawget(self,idx) or 0 flickerstreak@54: rawset(self,idx,c+1) flickerstreak@54: return idx flickerstreak@54: end flickerstreak@54: end, flickerstreak@54: __newindex = function(self,idx,value) flickerstreak@54: if value == nil then flickerstreak@54: value = rawget(self,idx) flickerstreak@54: if value == 1 then flickerstreak@54: value = nil flickerstreak@54: elseif value then flickerstreak@54: value = value - 1 flickerstreak@54: end flickerstreak@54: end flickerstreak@54: rawset(self,idx,value) flickerstreak@54: end flickerstreak@54: }) flickerstreak@54: flickerstreak@54: flickerstreak@54: flickerstreak@54: flickerstreak@54: ------ Button class ------ flickerstreak@54: local Button = { } flickerstreak@54: flickerstreak@54: local function Constructor( self, bar, idx, config ) flickerstreak@54: self.bar, self.idx, self.config = bar, idx, config flickerstreak@54: flickerstreak@54: local barFrame = bar:GetFrame() flickerstreak@54: flickerstreak@57: config.name = config.name or ("ReAction_%s_Possess_%d"):format(bar:GetName(),idx) flickerstreak@54: self.name = config.name flickerstreak@54: config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured flickerstreak@54: flickerstreak@54: local f = CreateFrame("CheckButton", self.name, barFrame, "BonusActionButtonTemplate") flickerstreak@54: flickerstreak@54: -- TODO: re-implement ActionButton event handlers that don't do secure stuff flickerstreak@54: flickerstreak@54: -- this will probably cause taint, using right now for display/debugging purposes flickerstreak@54: f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) flickerstreak@54: f:SetAttribute("action", config.actionID) flickerstreak@54: flickerstreak@54: barFrame:SetAttribute("addchild",f) flickerstreak@54: flickerstreak@54: self.frame = f flickerstreak@54: self:Refresh(bar,idx) flickerstreak@54: flickerstreak@54: if not module.db.profile.hideEmptyButtons then flickerstreak@54: ActionButton_ShowGrid(self.frame) flickerstreak@54: end flickerstreak@54: flickerstreak@54: if ReAction.configMode then flickerstreak@54: ActionButton_ShowGrid(self.frame) flickerstreak@54: module:showActionIDLabel(self) flickerstreak@54: end flickerstreak@54: end flickerstreak@54: flickerstreak@54: function Button:Destroy() flickerstreak@54: local f = self.frame flickerstreak@54: f:UnregisterAllEvents() flickerstreak@54: f:Hide() flickerstreak@54: f:SetParent(UIParent) flickerstreak@54: f:ClearAllPoints() flickerstreak@54: if self.name then flickerstreak@54: _G[self.name] = nil flickerstreak@54: end flickerstreak@54: if self.config.actionID then flickerstreak@54: ActionIDList[self.config.actionID] = nil flickerstreak@54: end flickerstreak@54: self.frame = nil flickerstreak@54: self.config = nil flickerstreak@54: self.bar = nil flickerstreak@54: end flickerstreak@54: flickerstreak@54: function Button:Refresh(bar,idx) flickerstreak@54: bar:PlaceButton(self.frame, idx, 36, 36) flickerstreak@54: end flickerstreak@54: flickerstreak@54: function Button:GetFrame() flickerstreak@54: return self.frame flickerstreak@54: end flickerstreak@54: flickerstreak@54: function Button:GetName() flickerstreak@54: return self.name flickerstreak@54: end flickerstreak@54: flickerstreak@54: function Button:GetActionID() flickerstreak@54: return self.config.actionID flickerstreak@54: end flickerstreak@54: flickerstreak@54: flickerstreak@54: -- export as a class-factory to module flickerstreak@54: module.BtnClass = { flickerstreak@54: new = function(self, ...) flickerstreak@54: local x = { } flickerstreak@54: for k,v in pairs(Button) do flickerstreak@54: x[k] = v flickerstreak@54: end flickerstreak@54: Constructor(x, ...) flickerstreak@54: return x flickerstreak@54: end flickerstreak@54: }