flickerstreak@201: local addonName, addonTable = ... flickerstreak@205: local pcall = pcall flickerstreak@205: local pairs = pairs flickerstreak@205: local type = type flickerstreak@205: local geterrorhandler = geterrorhandler flickerstreak@184: local LKB = LibStub("LibKeyBound-1.0") flickerstreak@33: local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") flickerstreak@33: flickerstreak@205: ------ Utility ------ flickerstreak@205: local tcopy flickerstreak@28: do flickerstreak@205: function tcopy(x) flickerstreak@28: if type(x) ~= "table" then flickerstreak@28: return x flickerstreak@28: end flickerstreak@28: local r = {} flickerstreak@28: for k,v in pairs(x) do flickerstreak@205: r[k] = tcopy(v) flickerstreak@28: end flickerstreak@28: return r flickerstreak@28: end flickerstreak@28: end flickerstreak@28: flickerstreak@205: ------ Core ------ flickerstreak@205: local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction", flickerstreak@205: "AceEvent-3.0" flickerstreak@205: ) flickerstreak@205: addonTable.ReAction = ReAction flickerstreak@205: ReAction.version = "1.1" flickerstreak@205: ReAction.L = L flickerstreak@205: ReAction.LKB = LKB flickerstreak@28: flickerstreak@205: flickerstreak@205: ------ Handlers ------ flickerstreak@28: function ReAction:OnInitialize() flickerstreak@28: self.db = LibStub("AceDB-3.0"):New("ReAction_DB", flickerstreak@213: self.defaultProfile, flickerstreak@182: true -- use global 'Default' (locale-specific) flickerstreak@28: ) flickerstreak@205: flickerstreak@213: self:UpgradeProfile() flickerstreak@211: flickerstreak@205: self.bars = { } flickerstreak@218: self.barTypes = { } flickerstreak@205: flickerstreak@213: self.LBF = LibStub("LibButtonFacade",true) flickerstreak@213: if self.LBF then flickerstreak@213: self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self) flickerstreak@213: end flickerstreak@213: flickerstreak@211: -- It's fairly normal to use the Blizzard vehicle bar, and to have flickerstreak@211: -- your regular buttons in the same location. If you do this, and don't flickerstreak@211: -- bother to hide your buttons, they'll obscure some parts of the vehicle bar. flickerstreak@211: VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3) flickerstreak@211: flickerstreak@205: self.callbacks = LibStub("CallbackHandler-1.0"):New(self) flickerstreak@184: LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED") flickerstreak@184: LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED") flickerstreak@207: LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") flickerstreak@182: self:RegisterEvent("PLAYER_REGEN_DISABLED") flickerstreak@182: self:InitializeOptions() flickerstreak@28: end flickerstreak@28: flickerstreak@28: function ReAction:OnEnable() flickerstreak@205: self:InitializeBars() flickerstreak@28: end flickerstreak@28: flickerstreak@28: function ReAction:OnDisable() flickerstreak@205: self:TearDownBars() flickerstreak@28: end flickerstreak@28: flickerstreak@33: function ReAction:PLAYER_REGEN_DISABLED() flickerstreak@205: if self.configMode == true then flickerstreak@63: self:UserError(L["ReAction config mode disabled during combat."]) flickerstreak@33: self:SetConfigMode(false) flickerstreak@88: self:SetKeybindMode(false) flickerstreak@185: self:CloseEditor() flickerstreak@33: end flickerstreak@33: end flickerstreak@33: flickerstreak@88: function ReAction:LIBKEYBOUND_ENABLED( evt ) flickerstreak@88: self:SetKeybindMode(true) flickerstreak@88: end flickerstreak@88: flickerstreak@88: function ReAction:LIBKEYBOUND_DISABLED( evt ) flickerstreak@88: return self:SetKeybindMode(false) flickerstreak@88: end flickerstreak@88: flickerstreak@213: function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors ) flickerstreak@213: if group == nil then flickerstreak@213: -- don't store global flickerstreak@213: else flickerstreak@213: -- 'group' is the bar-name flickerstreak@213: local bar = self:GetBar(group) flickerstreak@213: if bar then flickerstreak@213: local c = bar:GetConfig().ButtonFacade flickerstreak@213: if c then flickerstreak@213: c.skinID = skinID flickerstreak@213: c.gloss = gloss flickerstreak@213: c.backdrop = backdrop flickerstreak@213: c.colors = colors flickerstreak@213: end flickerstreak@213: end flickerstreak@213: end flickerstreak@213: end flickerstreak@213: flickerstreak@33: flickerstreak@205: ------ Methods ------ flickerstreak@77: flickerstreak@61: function ReAction:UserError(msg) flickerstreak@61: UIErrorsFrame:AddMessage(msg) flickerstreak@61: end flickerstreak@61: flickerstreak@205: function ReAction:GetBar(arg) flickerstreak@205: if type(arg) == "string" then flickerstreak@205: return self.bars[arg], arg flickerstreak@205: elseif type(arg) == "table" then -- reverse lookup flickerstreak@205: for name, bar in pairs(self.bars) do flickerstreak@205: if arg == bar then flickerstreak@205: return bar, name flickerstreak@205: end flickerstreak@205: end flickerstreak@205: else flickerstreak@205: error("ReAction:GetBar() requires either a name or a bar table arg") flickerstreak@205: end flickerstreak@184: end flickerstreak@184: flickerstreak@205: function ReAction:IterateBars() flickerstreak@205: return pairs(self.bars) flickerstreak@205: end flickerstreak@184: flickerstreak@63: -- usage: flickerstreak@91: -- (1) ReAction:CreateBar(name, [cfgTable]) flickerstreak@63: -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing]) flickerstreak@91: function ReAction:CreateBar(name, config, ...) flickerstreak@91: local profile = self.db.profile flickerstreak@91: flickerstreak@217: name = tostring(name) flickerstreak@217: if not name or name == "" then flickerstreak@217: error("ReAction:CreateBar() - bar name string required") flickerstreak@217: elseif self.bars[name] then flickerstreak@217: self:UserError(format(L["ReAction: name '%s' already in use"],name)) flickerstreak@217: return nil flickerstreak@91: end flickerstreak@91: flickerstreak@91: if type(config) == "string" then flickerstreak@218: local class = self.barTypes[config] flickerstreak@218: if not class then flickerstreak@218: error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config)) flickerstreak@48: end flickerstreak@218: config = tcopy(class:GetDefaultBarConfig()) flickerstreak@218: config.btnRows = select(1,...) or config.btnRows flickerstreak@218: config.btnColumns = select(2,...) or config.btnColumns flickerstreak@218: config.btnWidth = select(3,...) or config.btnWidth flickerstreak@218: config.btnHeight = select(3,...) or config.btnHeight flickerstreak@218: config.spacing = select(4,...) or config.spacing flickerstreak@48: config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1 flickerstreak@48: config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1 flickerstreak@81: config.anchor = config.anchor or "UIParent" flickerstreak@81: config.point = config.point or "BOTTOM" flickerstreak@81: config.relpoint = config.relpoint or "BOTTOM" flickerstreak@48: config.y = config.y or 200 flickerstreak@48: config.x = config.x or 0 flickerstreak@48: end flickerstreak@211: config = config or profile.bars[name] or { } flickerstreak@91: flickerstreak@91: profile.bars[name] = config flickerstreak@91: local bar = self.Bar:New( name, config ) -- ReAction.Bar defined in Bar.lua flickerstreak@205: self.bars[name] = bar flickerstreak@205: self.callbacks:Fire("OnCreateBar", bar, name) flickerstreak@205: if self.configMode then flickerstreak@33: bar:ShowControls(true) flickerstreak@33: end flickerstreak@33: flickerstreak@28: return bar flickerstreak@28: end flickerstreak@28: flickerstreak@205: function ReAction:DestroyBar(x) flickerstreak@205: local bar, name = self:GetBar(x) flickerstreak@63: if bar and name then flickerstreak@205: self.bars[name] = nil flickerstreak@205: self.callbacks:Fire("OnDestroyBar", bar, name) flickerstreak@205: bar:Destroy() flickerstreak@28: end flickerstreak@28: end flickerstreak@28: flickerstreak@205: function ReAction:RefreshBar(x) flickerstreak@205: local bar, name = self:GetBar(x) flickerstreak@205: if bar and name then flickerstreak@205: self.callbacks:Fire("OnRefreshBar", bar, name) flickerstreak@205: end flickerstreak@63: end flickerstreak@63: flickerstreak@205: function ReAction:InitializeBars() flickerstreak@205: if not self.barsInitialized then flickerstreak@211: self:ManageBlizzardBars() flickerstreak@211: flickerstreak@205: for name, config in pairs(self.db.profile.bars) do flickerstreak@205: if config then flickerstreak@205: self:CreateBar(name, config) flickerstreak@205: end flickerstreak@205: end flickerstreak@205: -- re-anchor and refresh in case anchor order does not match init order flickerstreak@205: for name, bar in pairs(self.bars) do flickerstreak@205: bar:ApplyAnchor() flickerstreak@205: self.callbacks:Fire("OnRefreshBar", bar, name) flickerstreak@205: end flickerstreak@205: self.barsInitialized = true flickerstreak@205: end flickerstreak@205: end flickerstreak@205: flickerstreak@205: function ReAction:TearDownBars() flickerstreak@205: for name, bar in pairs(self.bars) do flickerstreak@205: if bar then flickerstreak@208: self.bars[name] = self:DestroyBar(bar) flickerstreak@205: end flickerstreak@205: end flickerstreak@205: self.barsInitialized = false flickerstreak@205: end flickerstreak@205: flickerstreak@205: function ReAction:RebuildAll() flickerstreak@205: self:TearDownBars() flickerstreak@205: self:InitializeBars() flickerstreak@28: end flickerstreak@28: flickerstreak@28: function ReAction:RenameBar(x, newname) flickerstreak@205: local bar, name = self:GetBar(x) flickerstreak@63: if type(newname) ~= "string" then flickerstreak@63: error("ReAction:RenameBar() - second argument must be a string") flickerstreak@63: end flickerstreak@63: if bar and name and #newname > 0 then flickerstreak@127: if newname == name then flickerstreak@127: return flickerstreak@127: end flickerstreak@205: if self.bars[newname] then flickerstreak@127: self:UserError(format(L["ReAction: name '%s' already in use"],newname)) flickerstreak@47: else flickerstreak@205: self.bars[newname], self.bars[name] = self.bars[name], nil flickerstreak@47: bar:SetName(newname or "") flickerstreak@47: local cfg = self.db.profile.bars flickerstreak@47: cfg[newname], cfg[name] = cfg[name], nil flickerstreak@205: self.callbacks:Fire("OnRenameBar", bar, name, newname) flickerstreak@28: end flickerstreak@28: end flickerstreak@28: end flickerstreak@28: flickerstreak@205: function ReAction:EraseBar(x) flickerstreak@205: local bar, name = self:GetBar(x) flickerstreak@63: if bar and name then flickerstreak@205: self.callbacks:Fire("OnEraseBar", bar, name) flickerstreak@208: self:DestroyBar(bar) flickerstreak@205: self.db.profile.bars[name] = nil flickerstreak@63: end flickerstreak@63: end flickerstreak@63: flickerstreak@211: local blizzFrames = { flickerstreak@211: MainMenuBar, flickerstreak@211: MultiBarLeft, flickerstreak@211: MultiBarRight, flickerstreak@211: MultiBarBottomLeft, flickerstreak@211: MultiBarBottomRight, flickerstreak@211: } flickerstreak@211: flickerstreak@211: local hideFrame = CreateFrame("Frame") flickerstreak@211: hideFrame:Hide() flickerstreak@211: local hiddenParents = { } flickerstreak@211: local function ManageBlizzFrame(f, hide) flickerstreak@211: if hide and not hiddenParents[f] then flickerstreak@211: hiddenParents[f] = f:GetParent() flickerstreak@211: f:SetParent(hideFrame) flickerstreak@211: elseif not hide and hiddenParents[f] then flickerstreak@211: f:SetParent(hiddenParents[f]) flickerstreak@211: hiddenParents[f] = nil flickerstreak@211: if f:IsShown() then flickerstreak@211: f:Show() -- refresh flickerstreak@211: end flickerstreak@211: end flickerstreak@211: end flickerstreak@211: flickerstreak@211: function ReAction:ManageBlizzardBars() flickerstreak@211: for _, f in pairs(blizzFrames) do flickerstreak@211: ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars) flickerstreak@211: end flickerstreak@211: ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar) flickerstreak@211: end flickerstreak@211: flickerstreak@218: function ReAction:RegisterBarType( class, isDefault ) flickerstreak@218: local name = class:GetBarType() flickerstreak@218: self.barTypes[name] = class flickerstreak@218: if isDefault then flickerstreak@218: self.defaultBarType = name flickerstreak@48: end flickerstreak@185: self:RefreshEditor() flickerstreak@48: end flickerstreak@48: flickerstreak@218: function ReAction:UnregisterBarType( class ) flickerstreak@218: local name = class:GetBarType() flickerstreak@218: self.barTypes[name] = nil flickerstreak@218: if self.defaultBarType == name then flickerstreak@218: self.defaultBarType = nil flickerstreak@48: end flickerstreak@185: self:RefreshEditor() flickerstreak@48: end flickerstreak@48: flickerstreak@63: function ReAction:IterateBarTypes() flickerstreak@218: return pairs(self.barTypes) flickerstreak@63: end flickerstreak@63: flickerstreak@218: function ReAction:GetDefaultBarConfig(barType) flickerstreak@218: if barType and self.barTypes[barType] then flickerstreak@218: return self.barTypes[barType]:GetDefaultBarConfig() flickerstreak@63: end flickerstreak@63: end flickerstreak@63: flickerstreak@63: function ReAction:GetBarTypeOptions( fill ) flickerstreak@63: fill = fill or { } flickerstreak@63: for k in self:IterateBarTypes() do flickerstreak@63: fill[k] = k flickerstreak@63: end flickerstreak@63: return fill flickerstreak@63: end flickerstreak@63: flickerstreak@63: function ReAction:GetDefaultBarType() flickerstreak@218: return self.defaultBarType flickerstreak@63: end flickerstreak@63: flickerstreak@33: function ReAction:SetConfigMode( mode ) flickerstreak@205: if mode ~= self.configMode then flickerstreak@207: if mode then flickerstreak@207: self:SetKeybindMode(false) flickerstreak@207: end flickerstreak@205: self.configMode = mode flickerstreak@205: self.callbacks:Fire("OnConfigModeChanged", mode) flickerstreak@77: end flickerstreak@63: end flickerstreak@63: flickerstreak@63: function ReAction:GetConfigMode() flickerstreak@205: return self.configMode flickerstreak@33: end flickerstreak@38: flickerstreak@88: function ReAction:SetKeybindMode( mode ) flickerstreak@205: if mode ~= self.kbMode then flickerstreak@88: if mode then flickerstreak@207: self:SetConfigMode(false) flickerstreak@184: LKB:Activate() flickerstreak@88: else flickerstreak@184: LKB:Deactivate() flickerstreak@88: end flickerstreak@207: for _, bar in self:IterateBars() do flickerstreak@207: bar:SetKeybindMode(mode) flickerstreak@207: end flickerstreak@205: self.kbMode = LKB:IsShown() or false flickerstreak@88: end flickerstreak@88: end flickerstreak@88: flickerstreak@88: function ReAction:GetKeybindMode( mode ) flickerstreak@205: return self.kbMode flickerstreak@88: end