flickerstreak@175: local addonName, addonTable = ... flickerstreak@175: local ReAction = addonTable.ReAction flickerstreak@109: local L = ReAction.L flickerstreak@109: local _G = _G flickerstreak@185: local wipe = wipe flickerstreak@185: flickerstreak@109: local AceConfigReg = LibStub("AceConfigRegistry-3.0") flickerstreak@109: local AceConfigDialog = LibStub("AceConfigDialog-3.0") flickerstreak@109: flickerstreak@109: flickerstreak@185: local pointTable = { flickerstreak@185: CENTER = L["Center"], flickerstreak@185: LEFT = L["Left"], flickerstreak@185: RIGHT = L["Right"], flickerstreak@185: TOP = L["Top"], flickerstreak@185: BOTTOM = L["Bottom"], flickerstreak@185: TOPLEFT = L["Top Left"], flickerstreak@185: TOPRIGHT = L["Top Right"], flickerstreak@185: BOTTOMLEFT = L["Bottom Left"], flickerstreak@185: BOTTOMRIGHT = L["Bottom Right"], flickerstreak@185: } flickerstreak@109: flickerstreak@185: local Editor = { } flickerstreak@109: flickerstreak@185: function Editor:New() flickerstreak@185: -- create new self flickerstreak@185: self = setmetatable( { }, { __index = self } ) flickerstreak@109: flickerstreak@185: self.barOptMap = setmetatable({},{__mode="v"}) flickerstreak@185: self.tmp = { } flickerstreak@185: self.configID = "ReAction-Editor" flickerstreak@109: flickerstreak@185: self.gui = LibStub("AceGUI-3.0"):Create("Frame") flickerstreak@185: flickerstreak@185: local frame = self.gui.frame flickerstreak@109: frame:SetClampedToScreen(true) flickerstreak@109: frame:Hide() flickerstreak@185: flickerstreak@185: frame:SetScript("OnHide", flickerstreak@185: function(...) flickerstreak@109: ReAction:SetConfigMode(false) flickerstreak@185: end) flickerstreak@109: flickerstreak@185: self.options = { flickerstreak@109: type = "group", flickerstreak@185: name = L["Select Bar:"], flickerstreak@185: desc = "foo foo foo", flickerstreak@185: handler = self, flickerstreak@185: childGroups = "select", flickerstreak@109: args = { flickerstreak@109: launchConfig = { flickerstreak@109: type = "execute", flickerstreak@109: name = L["Global Config"], flickerstreak@109: desc = L["Opens ReAction global configuration settings panel"], flickerstreak@109: func = function() flickerstreak@185: if ReAction.db.profile.editorCloseOnLaunch then flickerstreak@185: self:Close() flickerstreak@185: end flickerstreak@182: ReAction:ShowOptions() flickerstreak@109: end, flickerstreak@185: order = 1 flickerstreak@109: }, flickerstreak@109: closeThis = { flickerstreak@109: type = "toggle", flickerstreak@185: name = L["Close Editor"], flickerstreak@109: desc = L["Close the Bar Editor when opening the ReAction global Interface Options"], flickerstreak@185: get = function() return ReAction.db.profile.editorCloseOnLaunch end, flickerstreak@185: set = function(info, val) ReAction.db.profile.editorCloseOnLaunch = val end, flickerstreak@185: order = 2, flickerstreak@185: }, flickerstreak@185: hdr = { flickerstreak@185: type = "header", flickerstreak@185: name = "", flickerstreak@109: order = 3, flickerstreak@109: }, flickerstreak@185: desc = { flickerstreak@185: type = "description", flickerstreak@185: name = L["Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality."], flickerstreak@185: width = "double", flickerstreak@185: order = 4, flickerstreak@185: }, flickerstreak@185: _new = { flickerstreak@109: type = "group", flickerstreak@109: name = L["New Bar..."], flickerstreak@185: order = 5, flickerstreak@109: args = { flickerstreak@109: desc = { flickerstreak@109: type = "description", flickerstreak@109: name = L["Choose a name, type, and initial grid for your new action bar:"], flickerstreak@109: order = 1, flickerstreak@109: }, flickerstreak@109: name = { flickerstreak@109: type = "input", flickerstreak@109: name = L["Bar Name"], flickerstreak@109: desc = L["Enter a name for your new action bar"], flickerstreak@185: get = function() return self.tmp.barName or "" end, flickerstreak@185: set = function(info, val) self.tmp.barName = val end, flickerstreak@109: order = 2, flickerstreak@109: }, flickerstreak@109: type = { flickerstreak@109: type = "select", flickerstreak@109: name = L["Button Type"], flickerstreak@185: get = function() return self.tmp.barType or ReAction:GetDefaultBarType() or "" end, flickerstreak@109: set = function(info, val) flickerstreak@109: local c = ReAction:GetBarTypeConfig(val) flickerstreak@185: self.tmp.barType = val flickerstreak@185: self.tmp.barSize = c.defaultButtonSize or self.tmp.barSize flickerstreak@185: self.tmp.barRows = c.defaultBarRows or self.tmp.barRows flickerstreak@185: self.tmp.barCols = c.defaultBarCols or self.tmp.barCols flickerstreak@185: self.tmp.barSpacing = c.defaultBarSpacing or self.tmp.barSpacing flickerstreak@109: end, flickerstreak@109: values = "GetBarTypes", flickerstreak@109: order = 3, flickerstreak@109: }, flickerstreak@185: go = { flickerstreak@185: type = "execute", flickerstreak@185: name = L["Create Bar"], flickerstreak@185: func = "CreateBar", flickerstreak@185: order = 4, flickerstreak@185: }, flickerstreak@109: grid = { flickerstreak@109: type = "group", flickerstreak@109: name = L["Button Grid"], flickerstreak@109: inline = true, flickerstreak@185: order = 5, flickerstreak@109: args = { flickerstreak@109: rows = { flickerstreak@109: type = "range", flickerstreak@109: name = L["Rows"], flickerstreak@185: get = function() return self.tmp.barRows or 1 end, flickerstreak@185: set = function(info, val) self.tmp.barRows = val end, flickerstreak@185: width = "full", flickerstreak@109: min = 1, flickerstreak@109: max = 32, flickerstreak@109: step = 1, flickerstreak@109: order = 2, flickerstreak@109: }, flickerstreak@109: cols = { flickerstreak@109: type = "range", flickerstreak@109: name = L["Columns"], flickerstreak@185: get = function() return self.tmp.barCols or 12 end, flickerstreak@185: set = function(info, val) self.tmp.barCols = val end, flickerstreak@185: width = "full", flickerstreak@109: min = 1, flickerstreak@109: max = 32, flickerstreak@109: step = 1, flickerstreak@109: order = 3, flickerstreak@109: }, flickerstreak@109: sz = { flickerstreak@109: type = "range", flickerstreak@109: name = L["Size"], flickerstreak@185: get = function() return self.tmp.barSize or 36 end, flickerstreak@185: set = function(info, val) self.tmp.barSize = val end, flickerstreak@185: width = "full", flickerstreak@109: min = 10, flickerstreak@109: max = 72, flickerstreak@109: step = 1, flickerstreak@109: order = 4, flickerstreak@109: }, flickerstreak@109: spacing = { flickerstreak@109: type = "range", flickerstreak@109: name = L["Spacing"], flickerstreak@185: get = function() return self.tmp.barSpacing or 3 end, flickerstreak@185: set = function(info, val) self.tmp.barSpacing = val end, flickerstreak@185: width = "full", flickerstreak@109: min = 0, flickerstreak@109: max = 24, flickerstreak@109: step = 1, flickerstreak@109: order = 5, flickerstreak@109: } flickerstreak@109: }, flickerstreak@109: }, flickerstreak@109: } flickerstreak@109: } flickerstreak@185: }, flickerstreak@109: } flickerstreak@109: flickerstreak@185: self.title = ("%s - %s"):format(L["ReAction"],L["Bar Editor"]) flickerstreak@185: self.gui:SetTitle(self.title) flickerstreak@185: flickerstreak@185: self.gui:SetCallback("OnClose", flickerstreak@185: function() flickerstreak@185: ReAction:SetConfigMode(false) flickerstreak@185: end ) flickerstreak@185: flickerstreak@185: AceConfigReg:RegisterOptionsTable(self.configID, self.options) flickerstreak@185: AceConfigDialog:SetDefaultSize(self.configID, 700, 540) flickerstreak@185: flickerstreak@185: ReAction.RegisterCallback(self,"OnCreateBar") flickerstreak@185: ReAction.RegisterCallback(self,"OnDestroyBar") flickerstreak@185: ReAction.RegisterCallback(self,"OnEraseBar") flickerstreak@185: ReAction.RegisterCallback(self,"OnRenameBar") flickerstreak@185: flickerstreak@185: for name, bar in ReAction:IterateBars() do flickerstreak@185: self:CreateBarTree(bar) flickerstreak@109: end flickerstreak@109: flickerstreak@185: return self flickerstreak@109: end flickerstreak@109: flickerstreak@109: flickerstreak@185: function Editor:Open(bar, ...) flickerstreak@185: if bar then flickerstreak@185: AceConfigDialog:SelectGroup(self.configID, self.barOptMap[bar:GetName()], ...) flickerstreak@185: end flickerstreak@185: AceConfigDialog:Open(self.configID,self.gui) flickerstreak@185: self.gui:SetTitle(self.title) flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:Close() flickerstreak@185: if self.gui then flickerstreak@185: self.gui:ReleaseChildren() flickerstreak@185: self.gui:Hide() flickerstreak@109: end flickerstreak@109: end flickerstreak@109: flickerstreak@185: function Editor:Refresh() flickerstreak@185: AceConfigReg:NotifyChange(self.configID) flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:CreateBarTree(bar) flickerstreak@185: local name = bar:GetName() flickerstreak@185: -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be flickerstreak@185: -- unique strings. So generate a unique key (it can be whatever) for the bar flickerstreak@185: local args = self.options.args flickerstreak@185: local key flickerstreak@185: local i = 1 flickerstreak@185: repeat flickerstreak@185: key = ("bar%s"):format(i) flickerstreak@185: i = i+1 flickerstreak@185: until args[key] == nil flickerstreak@185: self.barOptMap[name] = key flickerstreak@185: args[key] = { flickerstreak@185: type = "group", flickerstreak@185: name = name, flickerstreak@185: childGroups = "tab", flickerstreak@185: order = i+100, flickerstreak@185: args = { flickerstreak@185: general = { flickerstreak@185: type = "group", flickerstreak@185: name = L["General"], flickerstreak@185: order = 1, flickerstreak@185: args = { flickerstreak@185: name = { flickerstreak@185: type = "input", flickerstreak@185: name = L["Rename Bar"], flickerstreak@185: get = function() return bar:GetName() end, flickerstreak@185: set = function(info, value) return ReAction:RenameBar(bar, value) end, flickerstreak@185: order = 1, flickerstreak@185: }, flickerstreak@185: delete = { flickerstreak@185: type = "execute", flickerstreak@185: name = L["Delete Bar"], flickerstreak@185: desc = function() return bar:GetName() end, flickerstreak@185: confirm = true, flickerstreak@185: func = function() ReAction:EraseBar(bar) end, flickerstreak@185: order = 2 flickerstreak@185: }, flickerstreak@185: anchor = { flickerstreak@185: type = "group", flickerstreak@185: name = L["Anchor"], flickerstreak@185: inline = true, flickerstreak@185: args = { flickerstreak@185: frame = { flickerstreak@185: type = "input", flickerstreak@185: name = L["Frame"], flickerstreak@185: desc = L["The frame that the bar is anchored to"], flickerstreak@185: get = function() local _, f = bar:GetAnchor(); return f end, flickerstreak@185: set = function(info, val) bar:SetAnchor(nil,val) end, flickerstreak@185: validate = function(info, name) flickerstreak@185: if name then flickerstreak@185: local f = ReAction:GetBar(name) flickerstreak@185: if f then flickerstreak@185: return true flickerstreak@185: else flickerstreak@185: f = _G[name] flickerstreak@185: if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then flickerstreak@185: local _, explicit = f:IsProtected() flickerstreak@185: return explicit flickerstreak@185: end flickerstreak@185: end flickerstreak@185: end flickerstreak@185: return false flickerstreak@185: end, flickerstreak@185: width = "double", flickerstreak@185: order = 1 flickerstreak@185: }, flickerstreak@185: point = { flickerstreak@185: type = "select", flickerstreak@185: name = L["Point"], flickerstreak@185: desc = L["Anchor point on the bar frame"], flickerstreak@185: style = "dropdown", flickerstreak@185: get = function() return bar:GetAnchor() end, flickerstreak@185: set = function(info, val) bar:SetAnchor(val) end, flickerstreak@185: values = pointTable, flickerstreak@185: order = 2, flickerstreak@185: }, flickerstreak@185: relativePoint = { flickerstreak@185: type = "select", flickerstreak@185: name = L["Relative Point"], flickerstreak@185: desc = L["Anchor point on the target frame"], flickerstreak@185: style = "dropdown", flickerstreak@185: get = function() local p,f,r = bar:GetAnchor(); return r end, flickerstreak@185: set = function(info, val) bar:SetAnchor(nil,nil,val) end, flickerstreak@185: values = pointTable, flickerstreak@185: order = 3, flickerstreak@185: }, flickerstreak@185: x = { flickerstreak@185: type = "input", flickerstreak@185: pattern = "\-?%d+", flickerstreak@185: name = L["X offset"], flickerstreak@185: get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end, flickerstreak@185: set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end, flickerstreak@185: order = 4 flickerstreak@185: }, flickerstreak@185: y = { flickerstreak@185: type = "input", flickerstreak@185: pattern = "\-?%d+", flickerstreak@185: name = L["Y offset"], flickerstreak@185: get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end, flickerstreak@185: set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end, flickerstreak@185: order = 5 flickerstreak@185: }, flickerstreak@185: }, flickerstreak@185: order = 3 flickerstreak@185: }, flickerstreak@185: alpha = { flickerstreak@185: type = "range", flickerstreak@185: name = L["Transparency"], flickerstreak@185: get = function() return bar:GetAlpha() end, flickerstreak@185: set = function(info, val) bar:SetAlpha(val) end, flickerstreak@185: min = 0, flickerstreak@185: max = 1, flickerstreak@185: isPercent = true, flickerstreak@185: step = 0.01, flickerstreak@185: bigStep = 0.05, flickerstreak@185: order = 4, flickerstreak@185: }, flickerstreak@185: }, flickerstreak@185: }, flickerstreak@185: } flickerstreak@185: } flickerstreak@185: self:RefreshBarOptions() flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:RefreshBarOptions() flickerstreak@185: for name, key in pairs(self.barOptMap) do flickerstreak@185: local bar = ReAction:GetBar(name) flickerstreak@185: if bar and key and self.options.args[key] then flickerstreak@185: self.options.args[key].plugins = self:GenerateBarOptionsTable(bar) flickerstreak@185: end flickerstreak@185: end flickerstreak@185: AceConfigReg:NotifyChange(self.configID) flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:OnCreateBar(evt, bar) flickerstreak@185: if not self.tmp.creating then flickerstreak@185: -- a bit of hack to work around OnCreateBar event handler ordering flickerstreak@185: self:CreateBarTree(bar) flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:OnDestroyBar(evt, bar, name) flickerstreak@185: local key = self.barOptMap[name] flickerstreak@185: if key then flickerstreak@185: self.options.args[key] = nil flickerstreak@185: end flickerstreak@185: self:Refresh() flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:OnEraseBar(evt, name) flickerstreak@185: local key = self.barOptMap[name] flickerstreak@185: self.barOptMap[name] = nil flickerstreak@185: if key then flickerstreak@185: self.options.args[key] = nil flickerstreak@185: self:Refresh() flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:OnRenameBar(evt, bar, oldname, newname) flickerstreak@185: local key = self.barOptMap[oldname] flickerstreak@185: self.barOptMap[oldname], self.barOptMap[newname] = nil, key flickerstreak@185: if key then flickerstreak@185: self.options.args[key].name = newname flickerstreak@185: self:Refresh() flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: local _scratch = { } flickerstreak@185: function Editor:GetBarTypes() flickerstreak@185: wipe(_scratch) flickerstreak@185: return ReAction:GetBarTypeOptions(_scratch) flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:CreateBar() flickerstreak@185: if self.tmp.barName and self.tmp.barName ~= "" then flickerstreak@185: self.tmp.creating = true flickerstreak@185: local bar = ReAction:CreateBar(self.tmp.barName, self.tmp.barType or ReAction:GetDefaultBarType(), self.tmp.barRows, self.tmp.barCols, self.tmp.barSize, self.tmp.barSpacing) flickerstreak@185: if bar then flickerstreak@185: self:CreateBarTree(bar) flickerstreak@185: AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName]) flickerstreak@185: self.tmp.barName = nil flickerstreak@185: end flickerstreak@185: self.tmp.creating = false flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:GenerateBarOptionsTable( bar ) flickerstreak@185: local opts = { } flickerstreak@185: if not ReAction.barOptionGenerators then flickerstreak@185: return flickerstreak@185: end flickerstreak@185: flickerstreak@185: for module, func in pairs(ReAction.barOptionGenerators) do flickerstreak@185: local success, r flickerstreak@185: if type(func) == "string" then flickerstreak@185: success, r = pcall(module[func], module, bar) flickerstreak@185: else flickerstreak@185: success, r = pcall(func, bar) flickerstreak@185: end flickerstreak@185: if success then flickerstreak@185: if r then flickerstreak@185: opts[module:GetName()] = { [module:GetName()] = r } flickerstreak@185: end flickerstreak@185: else flickerstreak@185: geterrorhandler()(r) flickerstreak@185: end flickerstreak@185: end flickerstreak@185: return opts flickerstreak@185: end flickerstreak@185: flickerstreak@185: flickerstreak@185: flickerstreak@185: ---- Export to ReAction ---- flickerstreak@185: function ReAction:ShowEditor(bar, ...) flickerstreak@185: if InCombatLockdown() then flickerstreak@185: self:UserError(L["ReAction config mode disabled during combat."]) flickerstreak@185: else flickerstreak@185: self.editor = self.editor or Editor:New() flickerstreak@185: self.editor:Open(bar, ...) flickerstreak@185: self:SetConfigMode(true) flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function ReAction:CloseEditor() flickerstreak@185: if self.editor then flickerstreak@185: self.editor:Close() flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function ReAction:RefreshEditor() flickerstreak@185: if self.editor then flickerstreak@185: self.editor:RefreshBarOptions() flickerstreak@185: end flickerstreak@185: end flickerstreak@185: flickerstreak@185: function ReAction:RegisterBarOptionGenerator( module, func ) flickerstreak@185: if not module or type(module) ~= "table" then -- doesn't need to be a proper module, strictly flickerstreak@185: error("ReAction:RegisterBarOptionGenerator() : Invalid module") flickerstreak@185: end flickerstreak@185: if type(func) == "string" then flickerstreak@185: if not module[func] then flickerstreak@185: error(("ReAction:RegisterBarOptionGenerator() : Invalid method '%s'"):format(func)) flickerstreak@185: end flickerstreak@185: elseif func and type(func) ~= "function" then flickerstreak@185: error("ReAction:RegisterBarOptionGenerator() : Invalid function") flickerstreak@185: end flickerstreak@185: self.barOptionGenerators = self.barOptionGenerators or { } flickerstreak@185: self.barOptionGenerators[module] = func flickerstreak@185: flickerstreak@185: if self.editor then flickerstreak@185: self.editor:RefreshBarOptions() flickerstreak@185: end flickerstreak@185: end flickerstreak@185: