flickerstreak@25: --[[ flickerstreak@25: ReAction Configuration UI module flickerstreak@25: flickerstreak@33: Hooks into Blizzard Interface Options AddOns panel flickerstreak@25: --]] flickerstreak@25: flickerstreak@25: -- local imports flickerstreak@25: local ReAction = ReAction flickerstreak@25: local L = ReAction.L flickerstreak@51: local _G = _G flickerstreak@47: local AceConfigReg = LibStub("AceConfigRegistry-3.0") flickerstreak@47: local AceConfigDialog = LibStub("AceConfigDialog-3.0") flickerstreak@25: flickerstreak@51: -- some constants flickerstreak@51: local pointTable = { flickerstreak@51: CENTER = L["Center"], flickerstreak@51: LEFT = L["Left"], flickerstreak@51: RIGHT = L["Right"], flickerstreak@51: TOP = L["Top"], flickerstreak@51: BOTTOM = L["Bottom"], flickerstreak@51: TOPLEFT = L["Top Left"], flickerstreak@51: TOPRIGHT = L["Top Right"], flickerstreak@51: BOTTOMLEFT = L["Bottom Left"], flickerstreak@51: BOTTOMRIGHT = L["Bottom Right"], flickerstreak@51: } flickerstreak@51: flickerstreak@25: -- module declaration flickerstreak@25: local moduleID = "ConfigUI" flickerstreak@47: local module = ReAction:NewModule( moduleID, flickerstreak@47: "AceEvent-3.0" flickerstreak@47: ) flickerstreak@25: flickerstreak@25: -- module methods flickerstreak@25: function module:OnInitialize() flickerstreak@47: self.db = ReAction.db:RegisterNamespace( moduleID, flickerstreak@47: { flickerstreak@47: profile = { flickerstreak@47: closeOnLaunch = true, flickerstreak@47: editorCloseOnLaunch = true, flickerstreak@47: } flickerstreak@47: } flickerstreak@47: ) flickerstreak@47: flickerstreak@30: ReAction.RegisterCallback(self,"OnOptionsRegistered") flickerstreak@33: ReAction.RegisterCallback(self,"OnOptionsRefreshed") flickerstreak@47: ReAction.RegisterCallback(self,"OnCreateBar") flickerstreak@47: ReAction.RegisterCallback(self,"OnEraseBar") flickerstreak@47: ReAction.RegisterCallback(self,"OnRenameBar") flickerstreak@46: self:InitializeOptions() flickerstreak@47: self:RegisterEvent("PLAYER_REGEN_DISABLED") flickerstreak@25: end flickerstreak@25: flickerstreak@30: function module:OnOptionsRegistered(evt, context, module, opts) flickerstreak@46: local c = self.configOptions.args[context] flickerstreak@46: if c then flickerstreak@30: for k, v in pairs(opts) do flickerstreak@46: c.args[k] = v flickerstreak@30: end flickerstreak@47: elseif c == "bar" then flickerstreak@47: flickerstreak@30: end flickerstreak@25: end flickerstreak@25: flickerstreak@33: function module:OnOptionsRefreshed(evt) flickerstreak@48: AceConfigReg:NotifyChange("ReAction") flickerstreak@58: AceConfigReg:NotifyChange("ReAction-Editor") flickerstreak@25: end flickerstreak@25: flickerstreak@47: function module:OnCreateBar(evt, bar) flickerstreak@47: local name = bar:GetName() flickerstreak@47: -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be flickerstreak@47: -- unique strings. So generate a unique key (it can be whatever) for the bar flickerstreak@47: local key flickerstreak@47: local i = 1 flickerstreak@47: repeat flickerstreak@47: key = ("bar%s"):format(i) flickerstreak@47: i = i+1 flickerstreak@58: until self.editorOpts.args[key] == nil flickerstreak@47: self.barOptMap[name] = key flickerstreak@58: self.editorOpts.args[key] = { flickerstreak@47: type = "group", flickerstreak@47: name = name, flickerstreak@47: childGroups = "tab", flickerstreak@47: args = { flickerstreak@47: general = { flickerstreak@47: type = "group", flickerstreak@47: name = L["General"], flickerstreak@47: args = { flickerstreak@47: name = { flickerstreak@47: type = "input", flickerstreak@47: name = L["Rename Bar"], flickerstreak@47: get = function() return bar:GetName() end, flickerstreak@47: set = function(info, value) return ReAction:RenameBar(bar, value) end, flickerstreak@47: order = 1, flickerstreak@47: }, flickerstreak@47: delete = { flickerstreak@47: type = "execute", flickerstreak@47: name = L["Delete Bar"], flickerstreak@47: desc = function() return bar:GetName() end, flickerstreak@47: confirm = true, flickerstreak@47: func = function() ReAction:EraseBar(bar) end, flickerstreak@51: order = 2 flickerstreak@47: }, flickerstreak@51: anchor = { flickerstreak@51: type = "group", flickerstreak@51: name = L["Anchor"], flickerstreak@51: inline = true, flickerstreak@51: args = { flickerstreak@51: frame = { flickerstreak@51: type = "input", flickerstreak@51: name = L["Frame"], flickerstreak@51: desc = L["The frame that the bar is anchored to"], flickerstreak@51: get = function() local _, f = bar:GetAnchor(); return f end, flickerstreak@51: set = function(info, val) bar:SetAnchor(nil,val) end, flickerstreak@51: validate = function(info, name) flickerstreak@51: if name then flickerstreak@51: local f = ReAction:GetBar(name) flickerstreak@51: if f then flickerstreak@51: return true flickerstreak@51: else flickerstreak@51: f = _G[name] flickerstreak@51: if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then flickerstreak@51: return true flickerstreak@51: end flickerstreak@51: end flickerstreak@51: end flickerstreak@51: return false flickerstreak@51: end, flickerstreak@51: width = "double", flickerstreak@51: order = 1 flickerstreak@51: }, flickerstreak@51: point = { flickerstreak@51: type = "select", flickerstreak@51: name = L["Point"], flickerstreak@51: desc = L["Anchor point on the bar frame"], flickerstreak@51: style = "dropdown", flickerstreak@51: get = function() return bar:GetAnchor() end, flickerstreak@51: set = function(info, val) bar:SetAnchor(val) end, flickerstreak@51: values = pointTable, flickerstreak@51: order = 2, flickerstreak@51: }, flickerstreak@51: relativePoint = { flickerstreak@51: type = "select", flickerstreak@51: name = L["Relative Point"], flickerstreak@51: desc = L["Anchor point on the target frame"], flickerstreak@51: style = "dropdown", flickerstreak@51: get = function() local p,f,r = bar:GetAnchor(); return r end, flickerstreak@51: set = function(info, val) bar:SetAnchor(nil,nil,val) end, flickerstreak@51: values = pointTable, flickerstreak@51: order = 3, flickerstreak@51: }, flickerstreak@51: x = { flickerstreak@51: type = "input", flickerstreak@51: pattern = "\-?%d+", flickerstreak@51: name = L["X offset"], flickerstreak@52: get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end, flickerstreak@51: set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end, flickerstreak@51: order = 4 flickerstreak@51: }, flickerstreak@51: y = { flickerstreak@51: type = "input", flickerstreak@51: pattern = "\-?%d+", flickerstreak@51: name = L["Y offset"], flickerstreak@52: get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end, flickerstreak@51: set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end, flickerstreak@51: order = 5 flickerstreak@51: }, flickerstreak@51: }, flickerstreak@51: order = 3 flickerstreak@51: }, flickerstreak@51: }, flickerstreak@47: }, flickerstreak@47: }, flickerstreak@47: flickerstreak@47: } flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:OnEraseBar(evt, name) flickerstreak@47: local key = self.barOptMap[name] flickerstreak@47: self.barOptMap[name] = nil flickerstreak@47: if key then flickerstreak@58: self.editorOpts.args[key] = nil flickerstreak@58: self:RefreshBarEditor() flickerstreak@25: end flickerstreak@25: end flickerstreak@44: flickerstreak@47: function module:OnRenameBar(evt, oldname, newname) flickerstreak@47: local key = self.barOptMap[oldname] flickerstreak@47: self.barOptMap[oldname], self.barOptMap[newname] = nil, key flickerstreak@47: if key then flickerstreak@58: self.editorOpts.args[key].name = newname flickerstreak@58: self:RefreshBarEditor() flickerstreak@47: end flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:PLAYER_REGEN_DISABLED() flickerstreak@47: if self.editor then flickerstreak@47: self.editor:Hide() flickerstreak@47: end flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:UserError(msg) flickerstreak@47: -- any user errors should be flashed to the UIErrorsFrame flickerstreak@47: UIErrorsFrame:AddMessage(msg) flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:OpenConfig() flickerstreak@47: InterfaceOptionsFrame_OpenToFrame("ReAction") flickerstreak@47: end flickerstreak@47: flickerstreak@58: function module:LaunchBarEditor(bar) flickerstreak@47: if InCombatLockdown() then flickerstreak@47: self:UserError(L["ReAction config mode disabled during combat."]) flickerstreak@47: else flickerstreak@47: if not self.editor then flickerstreak@47: -- use a local container to work around AceConfigDialog closing flickerstreak@58: -- both the bar editor and the global options when interface options is closed flickerstreak@47: local ed = LibStub("AceGUI-3.0"):Create("Frame") flickerstreak@47: ed.frame:SetClampedToScreen(true) flickerstreak@47: local old_OnUpdate = ed.frame:GetScript("OnUpdate") flickerstreak@47: ed.frame:SetScript("OnUpdate", function(dt) flickerstreak@47: if old_OnUpdate then flickerstreak@47: old_OnUpdate(dt) flickerstreak@47: end flickerstreak@47: if ed.closePending then flickerstreak@47: InterfaceOptionsFrame:Hide() flickerstreak@47: ed.closePending = false flickerstreak@47: end flickerstreak@47: if ed.selfClosePending then flickerstreak@47: ed:Hide() flickerstreak@47: AceConfigReg:NotifyChange("ReAction") flickerstreak@47: ed.selfClosePending = false flickerstreak@47: end flickerstreak@47: end ) flickerstreak@47: ed:SetCallback("OnClose", flickerstreak@47: function() flickerstreak@47: ReAction:SetConfigMode(false) flickerstreak@47: end ) flickerstreak@47: self.editor = ed flickerstreak@58: AceConfigDialog:SetDefaultSize("ReAction-Editor", 640, 420) flickerstreak@47: end flickerstreak@47: flickerstreak@58: AceConfigDialog:Open("ReAction-Editor", self.editor) flickerstreak@47: ReAction:SetConfigMode(true) flickerstreak@47: end flickerstreak@47: end flickerstreak@47: flickerstreak@58: function module:RefreshBarEditor() flickerstreak@58: AceConfigReg:NotifyChange("ReAction-Editor") flickerstreak@47: if self.editor and self.editor.frame:IsShown() then flickerstreak@58: AceConfigDialog:Open("ReAction-Editor", self.editor) flickerstreak@47: end flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:GetBarTypes() flickerstreak@47: local opts = self.optBarTypes or { } flickerstreak@48: self.optBarTypes = { } flickerstreak@48: for k,v in pairs(opts) do flickerstreak@48: opts[k] = nil flickerstreak@48: end flickerstreak@48: for k in pairs(ReAction.defaultBarConfig) do flickerstreak@48: opts[k] = k flickerstreak@48: end flickerstreak@47: return opts flickerstreak@47: end flickerstreak@47: flickerstreak@47: function module:CreateBar() flickerstreak@50: if self.tmpBarName and self.tmpBarName ~= "" then flickerstreak@50: ReAction:CreateBar(self.tmpBarName, self.tmpBarType or ReAction.defaultBarConfigChoice, self.tmpBarRows, self.tmpBarCols, self.tmpBarSize, self.tmpBarSpacing) flickerstreak@48: self.tmpBarName = nil flickerstreak@48: end flickerstreak@47: end flickerstreak@47: flickerstreak@46: function module:InitializeOptions() flickerstreak@47: -- general config options flickerstreak@47: local opts = { flickerstreak@46: type = "group", flickerstreak@47: name = "ReAction", flickerstreak@46: childGroups = "tab", flickerstreak@46: args = { flickerstreak@47: _desc = { flickerstreak@47: type = "description", flickerstreak@47: name = L["Customizable replacement for Blizzard's Action Bars"], flickerstreak@47: order = 1, flickerstreak@47: }, flickerstreak@58: _launchEditor = { flickerstreak@47: type = "execute", flickerstreak@47: handler = self, flickerstreak@58: name = L["Edit Bars..."], flickerstreak@58: desc = L["Show the ReAction Bar Editor dialogue"], flickerstreak@47: func = function() flickerstreak@58: self:LaunchBarEditor() flickerstreak@47: -- you can't close a dialog in response to an options click, because the end of the flickerstreak@47: -- handler for all the button events calls lib:Open() flickerstreak@47: -- So, schedule a close on the next OnUpdate flickerstreak@47: if self.db.profile.closeOnLaunch then flickerstreak@47: self.editor.closePending = true flickerstreak@47: end flickerstreak@47: end, flickerstreak@47: order = 2, flickerstreak@47: }, flickerstreak@47: _closeThis = { flickerstreak@47: type = "toggle", flickerstreak@47: name = L["Close on Launch"], flickerstreak@58: desc = L["Close the Interface Options window when launching the ReAction Bar Editor"], flickerstreak@47: get = function() return self.db.profile.closeOnLaunch end, flickerstreak@47: set = function(info, val) self.db.profile.closeOnLaunch = val end, flickerstreak@47: order = 3, flickerstreak@47: }, flickerstreak@46: global = { flickerstreak@46: type = "group", flickerstreak@46: name = L["Global Settings"], flickerstreak@46: desc = L["Global configuration settings"], flickerstreak@46: args = { }, flickerstreak@47: order = 3, flickerstreak@46: }, flickerstreak@47: _profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(ReAction.db), flickerstreak@46: module = { flickerstreak@46: type = "group", flickerstreak@46: childGroups = "select", flickerstreak@46: name = L["Module Settings"], flickerstreak@46: desc = L["Configuration settings for each module"], flickerstreak@46: args = { }, flickerstreak@46: order = -1, flickerstreak@46: }, flickerstreak@46: }, flickerstreak@46: plugins = { } flickerstreak@46: } flickerstreak@47: self.configOptions = opts flickerstreak@47: opts.args._profile.order = -2 flickerstreak@47: AceConfigReg:RegisterOptionsTable("ReAction",opts) flickerstreak@47: self.frame = AceConfigDialog:AddToBlizOptions("ReAction", "ReAction") flickerstreak@47: self.frame.obj:SetCallback("default", flickerstreak@47: function() flickerstreak@47: ReAction.db:ResetProfile() flickerstreak@47: module:OpenConfig() flickerstreak@47: end ) flickerstreak@46: flickerstreak@47: -- import options from registered modules flickerstreak@47: for c, tbl in pairs(opts.args) do flickerstreak@46: for _, m in pairs(ReAction:GetOptions(c)) do flickerstreak@46: for k, v in pairs(m) do flickerstreak@46: tbl.args[k] = v flickerstreak@46: end flickerstreak@46: end flickerstreak@46: end flickerstreak@46: flickerstreak@46: ReAction:RegisterOptions("module",self, { flickerstreak@46: configUI = { flickerstreak@46: type = "group", flickerstreak@46: name = "Config UI", flickerstreak@46: desc = "description", flickerstreak@46: args = { flickerstreak@46: foo = { flickerstreak@46: type = "toggle", flickerstreak@46: handler = self, flickerstreak@46: name = "foo", flickerstreak@46: desc = "description", flickerstreak@46: get = function() return true end, flickerstreak@46: set = function() end, flickerstreak@46: } flickerstreak@46: } flickerstreak@46: }, flickerstreak@46: }) flickerstreak@46: flickerstreak@58: -- bar editor options flickerstreak@58: local editorOpts = { flickerstreak@47: type = "group", flickerstreak@58: name = ("ReAction - %s"):format(L["Bar Editor"]), flickerstreak@47: handler = self, flickerstreak@47: childGroups = "tree", flickerstreak@47: args = { flickerstreak@47: desc = { flickerstreak@47: type = "description", flickerstreak@47: name = L["Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality."], flickerstreak@47: order = 1 flickerstreak@47: }, flickerstreak@47: launchConfig = { flickerstreak@47: type = "execute", flickerstreak@47: name = L["Global Config"], flickerstreak@47: desc = L["Opens ReAction global configuration settings panel"], flickerstreak@47: func = function() flickerstreak@47: self:OpenConfig() flickerstreak@47: -- you can't close a dialog in response to an options click, because the end of the flickerstreak@47: -- handler for all the button events calls lib:Open() flickerstreak@48: -- So, schedule a close on the next OnUpdate flickerstreak@47: if self.db.profile.editorCloseOnLaunch then flickerstreak@47: self.editor.selfClosePending = true flickerstreak@47: end flickerstreak@47: end, flickerstreak@47: order = 2 flickerstreak@47: }, flickerstreak@48: closeThis = { flickerstreak@47: type = "toggle", flickerstreak@47: name = L["Close on Launch"], flickerstreak@58: desc = L["Close the Bar Editor when opening the ReAction global Interface Options"], flickerstreak@47: get = function() return self.db.profile.editorCloseOnLaunch end, flickerstreak@47: set = function(info, val) self.db.profile.editorCloseOnLaunch = val end, flickerstreak@47: order = 3, flickerstreak@47: }, flickerstreak@47: new = { flickerstreak@47: type = "group", flickerstreak@47: name = L["New Bar..."], flickerstreak@47: order = 4, flickerstreak@47: args = { flickerstreak@47: desc = { flickerstreak@47: type = "description", flickerstreak@47: name = L["Choose a name, type, and initial grid for your new action bar:"], flickerstreak@47: order = 1, flickerstreak@47: }, flickerstreak@47: name = { flickerstreak@47: type = "input", flickerstreak@47: name = L["Bar Name"], flickerstreak@47: desc = L["Enter a name for your new action bar"], flickerstreak@47: get = function() return self.tmpBarName or "" end, flickerstreak@47: set = function(info, val) self.tmpBarName = val end, flickerstreak@47: order = 2, flickerstreak@47: }, flickerstreak@47: type = { flickerstreak@47: type = "select", flickerstreak@47: name = L["Button Type"], flickerstreak@48: get = function() return self.tmpBarType or ReAction.defaultBarConfigChoice or "" end, flickerstreak@53: set = function(info, val) flickerstreak@53: local c = ReAction.defaultBarConfig[val] flickerstreak@53: self.tmpBarType = val flickerstreak@53: self.tmpBarSize = c.defaultButtonSize or self.tmpBarSize flickerstreak@53: self.tmpBarRows = c.defaultBarRows or self.tmpBarRows flickerstreak@53: self.tmpBarCols = c.defaultBarCols or self.tmpBarCols flickerstreak@53: self.tmpBarSpacing = c.defaultBarSpacing or self.tmpBarSpacing flickerstreak@53: end, flickerstreak@47: values = "GetBarTypes", flickerstreak@47: order = 3, flickerstreak@47: }, flickerstreak@47: grid = { flickerstreak@47: type = "group", flickerstreak@47: name = L["Button Grid"], flickerstreak@47: inline = true, flickerstreak@47: args = { flickerstreak@47: hdr = { flickerstreak@47: type = "header", flickerstreak@47: name = L["Button Grid"], flickerstreak@47: order = 1, flickerstreak@47: }, flickerstreak@47: rows = { flickerstreak@47: type = "range", flickerstreak@47: name = L["Rows"], flickerstreak@47: get = function() return self.tmpBarRows or 1 end, flickerstreak@47: set = function(info, val) self.tmpBarRows = val end, flickerstreak@47: width = "half", flickerstreak@47: min = 1, flickerstreak@47: max = 32, flickerstreak@47: step = 1, flickerstreak@47: order = 2, flickerstreak@47: }, flickerstreak@47: cols = { flickerstreak@47: type = "range", flickerstreak@47: name = L["Columns"], flickerstreak@47: get = function() return self.tmpBarCols or 12 end, flickerstreak@47: set = function(info, val) self.tmpBarCols = val end, flickerstreak@47: width = "half", flickerstreak@47: min = 1, flickerstreak@47: max = 32, flickerstreak@47: step = 1, flickerstreak@47: order = 3, flickerstreak@47: }, flickerstreak@47: sz = { flickerstreak@47: type = "range", flickerstreak@47: name = L["Size"], flickerstreak@47: get = function() return self.tmpBarSize or 36 end, flickerstreak@47: set = function(info, val) self.tmpBarSize = val end, flickerstreak@47: width = "half", flickerstreak@47: min = 10, flickerstreak@47: max = 72, flickerstreak@47: step = 1, flickerstreak@47: order = 4, flickerstreak@47: }, flickerstreak@47: spacing = { flickerstreak@47: type = "range", flickerstreak@47: name = L["Spacing"], flickerstreak@47: get = function() return self.tmpBarSpacing or 3 end, flickerstreak@47: set = function(info, val) self.tmpBarSpacing = val end, flickerstreak@47: width = "half", flickerstreak@47: min = 0, flickerstreak@47: max = 24, flickerstreak@47: step = 1, flickerstreak@47: order = 5, flickerstreak@47: } flickerstreak@47: }, flickerstreak@47: order = 4 flickerstreak@47: }, flickerstreak@47: spacer = { flickerstreak@47: type = "header", flickerstreak@47: name = "", flickerstreak@47: width = "full", flickerstreak@47: order = -2 flickerstreak@47: }, flickerstreak@47: go = { flickerstreak@47: type = "execute", flickerstreak@47: name = L["Create Bar"], flickerstreak@47: func = "CreateBar", flickerstreak@47: order = -1, flickerstreak@47: } flickerstreak@47: } flickerstreak@47: } flickerstreak@47: } flickerstreak@47: } flickerstreak@58: self.editorOpts = editorOpts flickerstreak@47: self.barOptMap = { } flickerstreak@58: AceConfigReg:RegisterOptionsTable("ReAction-Editor",editorOpts) flickerstreak@44: end flickerstreak@44: