Flick@276: local _, ns = ... Flick@276: local ReAction = ns.ReAction flickerstreak@109: local L = ReAction.L flickerstreak@109: local _G = _G flickerstreak@185: local wipe = wipe Flick@244: local format = string.format Flick@244: local InCombatLockdown = InCombatLockdown Flick@276: local tfetch = ns.tfetch Flick@276: local tbuild = ns.tbuild 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 = { Flick@244: NONE = " ", 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: Flick@237: local Editor = { Flick@237: buttonHandlers = { } Flick@237: } 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@195: self.title = ("%s - %s"):format(L["ReAction"],L["Bar Editor"]) flickerstreak@195: self.gui:SetTitle(self.title) flickerstreak@195: flickerstreak@185: self.options = { flickerstreak@109: type = "group", flickerstreak@195: name = self.title, 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"], Flick@250: func = function() Flick@250: -- AceConfigDialog calls :Open() after every selection, making it Flick@250: -- generally not possible to cleanly close from a menu item. Flick@250: -- If you don't use a custom frame, you can use ACD:Close(), but since Flick@250: -- we're using a custom frame, we have to do the work of closing later in an Flick@250: -- OnUpdate script. Flick@250: ReAction:ShowOptions(); Flick@250: frame:SetScript("OnUpdate", Flick@250: function() Flick@250: self:Close() Flick@250: frame:SetScript("OnUpdate",nil) Flick@250: end) Flick@250: end, flickerstreak@185: order = 1 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@195: order = 2, flickerstreak@195: }, flickerstreak@195: hdr = { flickerstreak@195: type = "header", flickerstreak@195: name = L["Select Bar"], flickerstreak@194: order = 3, flickerstreak@185: }, flickerstreak@185: _new = { flickerstreak@109: type = "group", flickerstreak@109: name = L["New Bar..."], flickerstreak@194: order = 4, 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@218: local c = ReAction:GetDefaultBarConfig(val) flickerstreak@185: self.tmp.barType = val flickerstreak@218: self.tmp.barSize = c.btnWidth or self.tmp.barSize flickerstreak@218: self.tmp.barRows = c.btnRows or self.tmp.barRows flickerstreak@218: self.tmp.barCols = c.btnColumns or self.tmp.barCols flickerstreak@218: self.tmp.barSpacing = c.spacing 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, Flick@269: width = "double", 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, Flick@269: width = "double", 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, Flick@269: width = "double", 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, Flick@269: width = "double", flickerstreak@109: min = 0, flickerstreak@109: max = 24, flickerstreak@109: step = 1, flickerstreak@109: order = 5, flickerstreak@109: } flickerstreak@195: } flickerstreak@195: } flickerstreak@109: } flickerstreak@109: } flickerstreak@195: } flickerstreak@109: } flickerstreak@109: 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,"OnRenameBar") flickerstreak@185: flickerstreak@216: self:RefreshBarOptions() 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@216: function Editor:UpdateBarOptions(bar) flickerstreak@185: local name = bar:GetName() flickerstreak@216: local key = self.barOptMap[name] flickerstreak@185: local args = self.options.args flickerstreak@216: flickerstreak@216: if not key then flickerstreak@216: -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be flickerstreak@216: -- unique strings. So generate a unique key (it can be whatever) for the bar flickerstreak@216: local i = 1 flickerstreak@216: repeat flickerstreak@216: key = ("bar%s"):format(i) flickerstreak@216: i = i+1 flickerstreak@216: until args[key] == nil flickerstreak@216: self.barOptMap[name] = key flickerstreak@216: flickerstreak@216: args[key] = { flickerstreak@216: type = "group", flickerstreak@216: name = name, flickerstreak@216: childGroups = "tab", flickerstreak@216: order = i+100, flickerstreak@216: args = { flickerstreak@216: general = { flickerstreak@216: type = "group", flickerstreak@216: name = L["General"], flickerstreak@216: order = 1, flickerstreak@216: args = { flickerstreak@216: name = { flickerstreak@216: type = "input", flickerstreak@216: name = L["Rename Bar"], flickerstreak@216: get = function() return bar:GetName() end, flickerstreak@216: set = function(info, value) return ReAction:RenameBar(bar, value) end, flickerstreak@216: order = 1, flickerstreak@216: }, flickerstreak@216: delete = { flickerstreak@216: type = "execute", flickerstreak@216: name = L["Delete Bar"], flickerstreak@216: desc = function() return bar:GetName() end, flickerstreak@216: confirm = true, flickerstreak@216: func = function() ReAction:EraseBar(bar) end, flickerstreak@216: order = 2 flickerstreak@216: }, Flick@269: optionsHdr = { Flick@269: type = "header", Flick@269: name = "", Flick@269: order = 3, Flick@269: }, Flick@259: clickDown = { Flick@259: type = "toggle", Flick@259: name = L["Activate on Down"], Flick@259: desc = L["Activate the button when the key or mouse button is pressed down instead of when it is released"], Flick@269: order = 4, Flick@269: width = "full", Flick@261: set = function(info, value) bar:GetConfig().clickDown = value; ReAction:RebuildAll() end, Flick@259: get = function() return bar:GetConfig().clickDown end, Flick@259: }, Flick@269: alpha = { Flick@269: type = "range", Flick@269: name = L["Transparency"], Flick@269: get = function() return bar:GetAlpha() end, Flick@269: set = function(info, val) bar:SetAlpha(val) end, Flick@269: min = 0, Flick@269: max = 1, Flick@269: isPercent = true, Flick@269: step = 0.01, Flick@269: bigStep = 0.05, Flick@269: order = 5, Flick@269: }, flickerstreak@216: anchor = { flickerstreak@216: type = "group", flickerstreak@216: name = L["Anchor"], flickerstreak@216: inline = true, Flick@269: order = 6, flickerstreak@216: args = { flickerstreak@216: frame = { flickerstreak@216: type = "input", flickerstreak@216: name = L["Frame"], flickerstreak@216: desc = L["The frame that the bar is anchored to"], flickerstreak@216: get = function() local _, f = bar:GetAnchor(); return f end, flickerstreak@216: set = function(info, val) bar:SetAnchor(nil,val) end, flickerstreak@216: validate = function(info, name) flickerstreak@216: if name then flickerstreak@216: local f = ReAction:GetBar(name) flickerstreak@216: if f then flickerstreak@216: return true flickerstreak@216: else flickerstreak@216: f = _G[name] flickerstreak@216: if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then flickerstreak@216: local _, explicit = f:IsProtected() flickerstreak@216: return explicit flickerstreak@216: end flickerstreak@185: end flickerstreak@185: end flickerstreak@216: return false flickerstreak@216: end, flickerstreak@216: width = "double", flickerstreak@216: order = 1 flickerstreak@216: }, flickerstreak@216: point = { flickerstreak@216: type = "select", flickerstreak@216: name = L["Point"], flickerstreak@216: desc = L["Anchor point on the bar frame"], flickerstreak@216: style = "dropdown", flickerstreak@216: get = function() return bar:GetAnchor() end, flickerstreak@216: set = function(info, val) bar:SetAnchor(val) end, flickerstreak@216: values = pointTable, flickerstreak@216: order = 2, flickerstreak@216: }, flickerstreak@216: relativePoint = { flickerstreak@216: type = "select", flickerstreak@216: name = L["Relative Point"], flickerstreak@216: desc = L["Anchor point on the target frame"], flickerstreak@216: style = "dropdown", flickerstreak@216: get = function() local p,f,r = bar:GetAnchor(); return r end, flickerstreak@216: set = function(info, val) bar:SetAnchor(nil,nil,val) end, flickerstreak@216: values = pointTable, flickerstreak@216: order = 3, flickerstreak@216: }, flickerstreak@216: x = { flickerstreak@216: type = "input", flickerstreak@216: pattern = "\-?%d+", flickerstreak@216: name = L["X offset"], flickerstreak@216: get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end, flickerstreak@216: set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end, flickerstreak@216: order = 4 flickerstreak@216: }, flickerstreak@216: y = { flickerstreak@216: type = "input", flickerstreak@216: pattern = "\-?%d+", flickerstreak@216: name = L["Y offset"], flickerstreak@216: get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end, flickerstreak@216: set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end, flickerstreak@216: order = 5 flickerstreak@216: }, flickerstreak@185: }, flickerstreak@185: }, flickerstreak@185: }, flickerstreak@185: }, Flick@244: buttonOpts = self:CreateButtonOptions(bar), Flick@244: stateOpts = self:CreateStateOptions(bar) Flick@244: } flickerstreak@185: } flickerstreak@216: end flickerstreak@216: flickerstreak@185: end flickerstreak@185: Flick@237: function Editor:CreateButtonOptions(bar) Flick@237: local buttonClass = bar:GetButtonClass() Flick@237: local classID = buttonClass:GetButtonTypeID() Flick@237: local handler = self.buttonHandlers[classID] Flick@237: Flick@237: if handler then Flick@237: local h = handler:New(bar) Flick@237: return h:GetOptions() Flick@237: end Flick@237: end Flick@237: flickerstreak@185: function Editor:RefreshBarOptions() flickerstreak@219: for name, key in pairs(self.barOptMap) do flickerstreak@216: if not ReAction:GetBar(name) then flickerstreak@219: self.barOptMap[name] = nil flickerstreak@219: self.options.args[key] = nil flickerstreak@185: end flickerstreak@185: end flickerstreak@216: for name, bar in ReAction:IterateBars() do flickerstreak@216: self:UpdateBarOptions(bar) flickerstreak@216: end flickerstreak@216: self:Refresh() flickerstreak@185: end flickerstreak@185: flickerstreak@185: function Editor:OnCreateBar(evt, bar) flickerstreak@216: self:UpdateBarOptions(bar) flickerstreak@216: self:Refresh() 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@216: self.barOptMap[name] = nil 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: if key then flickerstreak@216: self.barOptMap[oldname], self.barOptMap[newname] = nil, key 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: 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: AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName]) flickerstreak@185: self.tmp.barName = nil flickerstreak@185: end flickerstreak@185: end flickerstreak@185: end flickerstreak@185: Flick@237: ------------------------------- Flick@237: ---- Action button handler ---- Flick@237: ------------------------------- Flick@237: Flick@237: do Flick@237: local ActionHandler = { Flick@237: buttonClass = ReAction.Button.Action, Flick@237: options = { Flick@237: pages = { Flick@237: name = L["# Pages"], Flick@237: desc = L["Use the Dynamic State tab to specify page transitions"], Flick@269: order = 1, Flick@237: type = "range", Flick@237: min = 1, Flick@237: max = 10, Flick@237: step = 1, Flick@237: get = "GetNumPages", Flick@237: set = "SetNumPages", Flick@237: }, Flick@237: mindcontrol = { Flick@237: name = L["Mind Control Support"], Flick@237: desc = L["When possessing a target (e.g. via Mind Control), map the first 12 buttons of this bar to the possessed target's actions."], Flick@269: order = 2, Flick@237: type = "toggle", Flick@237: set = "SetMindControl", Flick@237: get = "GetMindControl", Flick@237: }, Flick@237: vehicle = { Flick@237: name = L["Vehicle Support"], Flick@237: desc = L["When on a vehicle, map the first 6 buttons of this bar to the vehicle actions. The vehicle-exit button is mapped to the 7th button. Pitch controls are not supported."], Flick@269: order = 3, Flick@237: type = "toggle", Flick@237: get = "GetVehicle", Flick@237: set = "SetVehicle", Flick@237: }, Flick@269: hideEmpty = { Flick@269: name = L["Hide Empty Buttons"], Flick@269: order = 4, Flick@269: type = "toggle", Flick@269: width = "full", Flick@269: get = "GetHideEmpty", Flick@269: set = "SetHideEmpty", Flick@269: }, Flick@269: lockButtons = { Flick@269: name = L["Lock Buttons"], Flick@269: desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"], Flick@269: order = 5, Flick@269: width = "full", Flick@269: type = "toggle", Flick@269: get = "GetLockButtons", Flick@269: set = "SetLockButtons", Flick@269: }, Flick@269: lockOnlyCombat = { Flick@269: name = L["Only in Combat"], Flick@269: desc = L["Only lock the buttons when in combat"], Flick@269: order = 6, Flick@269: width = "full", Flick@269: type = "toggle", Flick@269: disabled = "LockButtonsCombatDisabled", Flick@269: get = "GetLockButtonsCombat", Flick@269: set = "SetLockButtonsCombat", Flick@269: }, Flick@237: actions = { Flick@237: name = L["Edit Action IDs"], Flick@237: order = 7, Flick@237: type = "group", Flick@237: inline = true, Flick@237: args = { Flick@237: method = { Flick@237: name = L["Assign"], Flick@237: order = 1, Flick@237: type = "select", Flick@269: width = "full", Flick@237: values = { [0] = L["Choose Method..."], Flick@237: [1] = L["Individually"], Flick@237: [2] = L["All at Once"], }, Flick@237: get = "GetActionEditMethod", Flick@237: set = "SetActionEditMethod", Flick@237: }, Flick@237: rowSelect = { Flick@237: name = L["Row"], Flick@237: desc = L["Rows are numbered top to bottom"], Flick@237: order = 2, Flick@237: type = "select", Flick@237: width = "half", Flick@237: hidden = "IsButtonSelectHidden", Flick@237: values = "GetRowList", Flick@237: get = "GetSelectedRow", Flick@237: set = "SetSelectedRow", Flick@237: }, Flick@237: colSelect = { Flick@237: name = L["Col"], Flick@237: desc = L["Columns are numbered left to right"], Flick@237: order = 3, Flick@237: type = "select", Flick@237: width = "half", Flick@237: hidden = "IsButtonSelectHidden", Flick@237: values = "GetColumnList", Flick@237: get = "GetSelectedColumn", Flick@237: set = "SetSelectedColumn", Flick@237: }, Flick@237: pageSelect = { Flick@237: name = L["Page"], Flick@237: order = 4, Flick@237: type = "select", Flick@237: width = "half", Flick@237: hidden = "IsPageSelectHidden", Flick@237: values = "GetPageList", Flick@237: get = "GetSelectedPage", Flick@237: set = "SetSelectedPage", Flick@237: }, Flick@237: single = { Flick@237: name = L["Action ID"], Flick@237: usage = L["Specify ID 1-120"], Flick@237: order = 5, Flick@237: type = "input", Flick@237: width = "half", Flick@237: hidden = "IsButtonSelectHidden", Flick@237: get = "GetActionID", Flick@237: set = "SetActionID", Flick@237: validate = "ValidateActionID", Flick@237: }, Flick@237: multi = { Flick@237: name = L["ID List"], Flick@237: usage = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"], Flick@237: order = 6, Flick@237: type = "input", Flick@237: multiline = true, Flick@237: width = "double", Flick@237: hidden = "IsMultiIDHidden", Flick@237: get = "GetMultiID", Flick@237: set = "SetMultiID", Flick@237: validate = "ValidateMultiID", Flick@237: }, Flick@237: }, Flick@237: }, Flick@237: } Flick@237: } Flick@237: Flick@237: Editor.buttonHandlers[ActionHandler.buttonClass:GetButtonTypeID()] = ActionHandler Flick@237: Flick@237: local meta = { __index = ActionHandler } Flick@237: Flick@237: function ActionHandler:New( bar ) Flick@237: return setmetatable( Flick@237: { Flick@237: bar = bar, Flick@237: config = bar:GetConfig(), Flick@237: }, Flick@237: meta) Flick@237: end Flick@237: Flick@237: function ActionHandler:Refresh() Flick@237: self.buttonClass:SetupBar(self.bar) Flick@237: end Flick@237: Flick@237: function ActionHandler:UpdateButtonLock() Flick@237: self.buttonClass:SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat) Flick@237: end Flick@237: Flick@237: function ActionHandler:GetLastButton() Flick@237: return self.bar:GetButton(self.bar:GetNumButtons()) Flick@237: end Flick@237: Flick@237: -- options handlers Flick@237: function ActionHandler:GetOptions() Flick@237: return { Flick@237: type = "group", Flick@237: name = L["Action Buttons"], Flick@237: handler = self, Flick@237: order = 2, Flick@237: args = self.options Flick@237: } Flick@237: end Flick@237: Flick@237: function ActionHandler:SetHideEmpty(info, value) Flick@237: if value ~= self.config.hideEmpty then Flick@237: self.config.hideEmpty = value Flick@237: for _, b in self.bar:IterateButtons() do Flick@237: b:ShowGrid(not value) Flick@237: end Flick@237: end Flick@237: end Flick@237: Flick@237: function ActionHandler:GetHideEmpty() Flick@237: return self.config.hideEmpty Flick@237: end Flick@237: Flick@237: function ActionHandler:GetLockButtons() Flick@237: return self.config.lockButtons Flick@237: end Flick@237: Flick@237: function ActionHandler:SetLockButtons(info, value) Flick@237: self.config.lockButtons = value Flick@237: self:UpdateButtonLock() Flick@237: end Flick@237: Flick@237: function ActionHandler:GetLockButtonsCombat() Flick@237: return self.config.lockButtonsCombat Flick@237: end Flick@237: Flick@237: function ActionHandler:SetLockButtonsCombat(info, value) Flick@237: self.config.lockButtonsCombat = value Flick@237: self:UpdateButtonLock() Flick@237: end Flick@237: Flick@237: function ActionHandler:LockButtonsCombatDisabled() Flick@237: return not self.config.lockButtons Flick@237: end Flick@237: Flick@237: function ActionHandler:GetNumPages() Flick@237: return self.config.nPages Flick@237: end Flick@237: Flick@237: function ActionHandler:SetNumPages(info, value) Flick@237: self.config.nPages = value Flick@237: self:Refresh() Flick@237: end Flick@237: Flick@237: function ActionHandler:GetMindControl() Flick@237: return self.config.mindcontrol Flick@237: end Flick@237: Flick@237: function ActionHandler:SetMindControl(info, value) Flick@237: self.config.mindcontrol = value Flick@237: self:Refresh() Flick@237: end Flick@237: Flick@237: function ActionHandler:GetVehicle() Flick@237: return self.config.vehicle Flick@237: end Flick@237: Flick@237: function ActionHandler:SetVehicle(info, value) Flick@237: self.config.vehicle = value Flick@237: self:Refresh() Flick@237: end Flick@237: Flick@237: function ActionHandler:GetActionEditMethod() Flick@237: return self.editMethod or 0 Flick@237: end Flick@237: Flick@237: function ActionHandler:SetActionEditMethod(info, value) Flick@237: self.editMethod = value Flick@237: end Flick@237: Flick@237: function ActionHandler:IsButtonSelectHidden() Flick@237: return self.editMethod ~= 1 Flick@237: end Flick@237: Flick@237: function ActionHandler:GetRowList() Flick@237: local r,c = self.bar:GetButtonGrid() Flick@237: if self.rowList == nil or #self.rowList ~= r then Flick@237: local list = { } Flick@237: for i = 1, r do Flick@237: table.insert(list,i) Flick@237: end Flick@237: self.rowList = list Flick@237: end Flick@237: return self.rowList Flick@237: end Flick@237: Flick@237: function ActionHandler:GetSelectedRow() Flick@237: local r, c = self.bar:GetButtonGrid() Flick@237: local row = self.selectedRow or 1 Flick@237: if row > r then Flick@237: row = 1 Flick@237: end Flick@237: self.selectedRow = row Flick@237: return row Flick@237: end Flick@237: Flick@237: function ActionHandler:SetSelectedRow(info, value) Flick@237: self.selectedRow = value Flick@237: end Flick@237: Flick@237: function ActionHandler:GetColumnList() Flick@237: local r,c = self.bar:GetButtonGrid() Flick@237: if self.columnList == nil or #self.columnList ~= c then Flick@237: local list = { } Flick@237: for i = 1, c do Flick@237: table.insert(list,i) Flick@237: end Flick@237: self.columnList = list Flick@237: end Flick@237: return self.columnList Flick@237: end Flick@237: Flick@237: function ActionHandler:GetSelectedColumn() Flick@237: local r, c = self.bar:GetButtonGrid() Flick@237: local col = self.selectedColumn or 1 Flick@237: if col > c then Flick@237: col = 1 Flick@237: end Flick@237: self.selectedColumn = col Flick@237: return col Flick@237: end Flick@237: Flick@237: function ActionHandler:SetSelectedColumn(info, value) Flick@237: self.selectedColumn = value Flick@237: end Flick@237: Flick@237: function ActionHandler:IsPageSelectHidden() Flick@237: return self.editMethod ~= 1 or (self.config.nPages or 1) < 2 Flick@237: end Flick@237: Flick@237: function ActionHandler:GetPageList() Flick@237: local n = self.config.nPages or 1 Flick@237: if self.pageList == nil or #self.pageList ~= n then Flick@237: local p = { } Flick@237: for i = 1, n do Flick@237: table.insert(p,i) Flick@237: end Flick@237: self.pageList = p Flick@237: end Flick@237: return self.pageList Flick@237: end Flick@237: Flick@237: function ActionHandler:GetSelectedPage() Flick@237: local p = self.selectedPage or 1 Flick@237: if p > (self.config.nPages or 1) then Flick@237: p = 1 Flick@237: end Flick@237: self.selectedPage = p Flick@237: return p Flick@237: end Flick@237: Flick@237: function ActionHandler:SetSelectedPage(info, value) Flick@237: self.selectedPage = value Flick@237: end Flick@237: Flick@237: function ActionHandler:GetActionID() Flick@237: local row = self.selectedRow or 1 Flick@237: local col = self.selectedColumn or 1 Flick@237: local r, c = self.bar:GetButtonGrid() Flick@237: local n = (row-1) * c + col Flick@237: local btn = self.bar:GetButton(n) Flick@237: if btn then Flick@237: return tostring(btn:GetActionID(self.selectedPage or 1)) Flick@237: end Flick@237: end Flick@237: Flick@237: function ActionHandler:SetActionID(info, value) Flick@237: local row = self.selectedRow or 1 Flick@237: local col = self.selectedColumn or 1 Flick@237: local r, c = self.bar:GetButtonGrid() Flick@237: local n = (row-1) * c + col Flick@237: local btn = self.bar:GetButton(n) Flick@237: if btn then Flick@237: btn:SetActionID(tonumber(value), self.selectedPage or 1) Flick@237: end Flick@237: end Flick@237: Flick@237: function ActionHandler:ValidateActionID(info, value) Flick@237: value = tonumber(value) Flick@237: if value == nil or value < 1 or value > 120 then Flick@237: return L["Specify ID 1-120"] Flick@237: end Flick@237: return true Flick@237: end Flick@237: Flick@237: function ActionHandler:IsMultiIDHidden() Flick@237: return self.editMethod ~= 2 Flick@237: end Flick@237: Flick@237: function ActionHandler:GetMultiID() Flick@237: local p = { } Flick@237: for i = 1, self.config.nPages or 1 do Flick@237: local b = { } Flick@237: for _, btn in self.bar:IterateButtons() do Flick@237: table.insert(b, btn:GetActionID(i)) Flick@237: end Flick@237: table.insert(p, table.concat(b,",")) Flick@237: end Flick@237: return table.concat(p,";\n") Flick@237: end Flick@237: Flick@237: Flick@237: local function ParseMultiID(nBtns, nPages, s) Flick@237: if s:match("[^%d%s,;]") then Flick@237: return nil Flick@237: end Flick@237: local p = { } Flick@237: for list in s:gmatch("[^;]+") do Flick@237: local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns)) Flick@237: local ids = { list:match(pattern) } Flick@237: if #ids ~= nBtns then Flick@237: return nil Flick@237: end Flick@237: table.insert(p,ids) Flick@237: end Flick@237: if #p ~= nPages then Flick@237: return nil Flick@237: end Flick@237: return p Flick@237: end Flick@237: Flick@237: function ActionHandler:SetMultiID(info, value) Flick@237: local p = ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value) Flick@237: for page, b in ipairs(p) do Flick@237: for button, id in ipairs(b) do Flick@237: self.bar:GetButton(button):SetActionID(id, page) Flick@237: end Flick@237: end Flick@237: end Flick@237: Flick@237: function ActionHandler:ValidateMultiID(info, value) Flick@237: local bad = L["Invalid action ID list string"] Flick@237: if value == nil or ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value) == nil then Flick@237: return bad Flick@237: end Flick@237: return true Flick@237: end Flick@237: end Flick@237: Flick@237: Flick@237: ---------------------------------- Flick@237: ---- PetAction button handler ---- Flick@237: ---------------------------------- Flick@237: Flick@237: do Flick@237: local PetHandler = { Flick@237: buttonClass = ReAction.Button.PetAction, Flick@237: } Flick@237: Flick@237: Editor.buttonHandlers[PetHandler.buttonClass:GetButtonTypeID()] = PetHandler Flick@237: Flick@237: local meta = { __index = PetHandler } Flick@237: Flick@237: function PetHandler:New(bar) Flick@237: return setmetatable( Flick@237: { Flick@237: bar = bar, Flick@237: config = bar.config Flick@237: }, meta) Flick@237: end Flick@237: Flick@237: function PetHandler:GetLockButtons() Flick@237: return self.config.lockButtons Flick@237: end Flick@237: Flick@237: function PetHandler:SetLockButtons(info, value) Flick@237: self.config.lockButtons = value Flick@237: self.buttonClass:UpdateButtonLock(self.bar) Flick@237: end Flick@237: Flick@237: function PetHandler:GetLockButtonsCombat() Flick@237: return self.config.lockButtonsCombat Flick@237: end Flick@237: Flick@237: function PetHandler:SetLockButtonsCombat(info, value) Flick@237: self.config.lockButtonsCombat = value Flick@237: self.buttonClass:UpdateButtonLock(self.bar) Flick@237: end Flick@237: Flick@237: function PetHandler:LockButtonsCombatDisabled() Flick@237: return not self.config.lockButtons Flick@237: end Flick@237: Flick@237: function PetHandler:GetOptions() Flick@237: return { Flick@237: type = "group", Flick@237: name = L["Pet Buttons"], Flick@237: handler = self, Flick@237: order = 2, Flick@237: args = { Flick@237: lockButtons = { Flick@237: name = L["Lock Buttons"], Flick@237: desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"], Flick@237: order = 2, Flick@237: type = "toggle", Flick@237: get = "GetLockButtons", Flick@237: set = "SetLockButtons", Flick@237: }, Flick@237: lockOnlyCombat = { Flick@237: name = L["Only in Combat"], Flick@237: desc = L["Only lock the buttons when in combat"], Flick@237: order = 3, Flick@237: type = "toggle", Flick@237: disabled = "LockButtonsCombatDisabled", Flick@237: get = "GetLockButtonsCombat", Flick@237: set = "SetLockButtonsCombat", Flick@237: }, Flick@237: } Flick@237: } Flick@237: end Flick@237: end Flick@237: Flick@237: Flick@237: ------------------------------------- Flick@237: ---- Vehicle Exit button handler ---- Flick@237: ------------------------------------- Flick@237: Flick@237: do Flick@237: local VExitHandler = { Flick@237: buttonClass = ReAction.Button.VehicleExit, Flick@237: } Flick@237: Flick@237: Editor.buttonHandlers[VExitHandler.buttonClass:GetButtonTypeID()] = VExitHandler Flick@237: Flick@237: local meta = { __index = VExitHandler } Flick@237: Flick@237: function VExitHandler:New(bar) Flick@237: return setmetatable( Flick@237: { Flick@237: bar = bar, Flick@237: }, meta) Flick@237: end Flick@237: Flick@237: function VExitHandler:GetConfig() Flick@237: return self.bar:GetConfig() Flick@237: end Flick@237: Flick@237: function VExitHandler:GetPassengerOnly() Flick@237: return not self:GetConfig().withControls Flick@237: end Flick@237: Flick@237: function VExitHandler:SetPassengerOnly(info, value) Flick@237: self:GetConfig().withControls = not value Flick@237: self.buttonClass:UpdateRegistration(self.bar) Flick@237: end Flick@237: Flick@237: Flick@237: function VExitHandler:GetOptions() Flick@237: return { Flick@237: type = "group", Flick@237: name = L["Exit Vehicle"], Flick@237: handler = self, Flick@237: args = { Flick@237: passengerOnly = { Flick@237: name = L["Show only when passenger"], Flick@237: desc = L["Only show the button when riding as a passenger in a vehicle (no vehicle controls)"], Flick@237: order = 2, Flick@237: width = "double", Flick@237: type = "toggle", Flick@237: get = "GetPassengerOnly", Flick@237: set = "SetPassengerOnly", Flick@237: }, Flick@237: } Flick@237: } Flick@237: end Flick@237: end Flick@237: flickerstreak@185: Flick@244: ------------------------------ Flick@244: --- Dynamic State options ---- Flick@244: ------------------------------ Flick@244: do Flick@244: local ApplyStates = ReAction.Bar.ApplyStates Flick@244: local CleanupStates = ReAction.Bar.CleanupStates Flick@244: local SetProperty = ReAction.Bar.SetStateProperty Flick@244: local GetProperty = ReAction.Bar.GetStateProperty Flick@244: Flick@244: -- pre-sorted by the order they should appear in Flick@244: local rules = { Flick@244: -- rule fields Flick@244: { "stance", { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } }, Flick@244: { "form", { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } }, Flick@244: { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]}, {shadowdance = L["Shadow Dance"]} } }, Flick@244: { "shadow", { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } }, Flick@244: { "demon", { {demon = L["Demon Form"]}, {nodemon = L["No Demon Form"]} } }, Flick@244: { "pet", { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } }, Flick@244: { "target", { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } }, Flick@244: { "focus", { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } }, Flick@244: { "possess", { {possess = L["Mind Control"]} } }, Flick@244: { "vehicle", { {vehicle = L["In a Vehicle"]} } }, Flick@244: { "group", { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } }, Flick@244: { "combat", { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } }, Flick@244: } Flick@244: Flick@244: local ruleSelect = { } Flick@244: local ruleMap = { } Flick@244: local optionMap = setmetatable({},{__mode="k"}) Flick@244: Flick@244: Flick@244: -- unpack rules table into ruleSelect and ruleMap Flick@244: for _, c in ipairs(rules) do Flick@244: local rule, fields = unpack(c) Flick@244: for _, field in ipairs(fields) do Flick@244: local key, label = next(field) Flick@244: table.insert(ruleSelect, label) Flick@244: table.insert(ruleMap, key) Flick@244: end Flick@244: end Flick@244: Flick@244: local stateOptions = { Flick@244: ordering = { Flick@244: name = L["Info"], Flick@244: order = 1, Flick@244: type = "group", Flick@244: args = { Flick@244: rename = { Flick@244: name = L["Name"], Flick@244: order = 1, Flick@244: type = "input", Flick@244: get = "GetName", Flick@244: set = "SetStateName", Flick@244: pattern = "^%w*$", Flick@244: usage = L["State names must be alphanumeric without spaces"], Flick@244: }, Flick@269: delete = { Flick@269: name = L["Delete this State"], Flick@269: order = 2, Flick@269: type = "execute", Flick@269: func = "DeleteState", Flick@269: confirm = true, Flick@269: }, Flick@244: ordering = { Flick@244: name = L["Evaluation Order"], Flick@256: desc = L["State transitions are evaluated in the order listed: Move a state up or down to change the order"], Flick@269: order = 3, Flick@244: type = "group", Flick@244: inline = true, Flick@244: args = { Flick@244: up = { Flick@244: name = L["Up"], Flick@244: order = 1, Flick@244: type = "execute", Flick@244: width = "half", Flick@244: func = "MoveStateUp", Flick@244: }, Flick@244: down = { Flick@244: name = L["Down"], Flick@244: order = 2, Flick@244: type = "execute", Flick@244: width = "half", Flick@244: func = "MoveStateDown", Flick@244: } Flick@244: } Flick@244: } Flick@244: } Flick@244: }, Flick@244: properties = { Flick@244: name = L["Properties"], Flick@244: order = 2, Flick@244: type = "group", Flick@244: args = { Flick@244: desc = { Flick@244: name = L["Set the properties for the bar when in this state"], Flick@244: order = 1, Flick@244: type = "description" Flick@244: }, Flick@244: page = { Flick@244: name = L["Show Page #"], Flick@244: order = 11, Flick@244: type = "select", Flick@244: width = "half", Flick@244: disabled = "IsPageDisabled", Flick@244: hidden = "IsPageHidden", Flick@244: values = "GetPageValues", Flick@244: set = "SetProp", Flick@244: get = "GetPage", Flick@244: }, Flick@244: hide = { Flick@244: name = L["Hide Bar"], Flick@244: order = 90, Flick@269: width = "full", Flick@244: type = "toggle", Flick@244: set = "SetProp", Flick@244: get = "GetProp", Flick@244: }, Flick@244: --[[ BROKEN Flick@244: keybindState = { Flick@244: name = L["Override Keybinds"], Flick@244: desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], Flick@244: order = 91, Flick@244: type = "toggle", Flick@244: set = "SetProp", Flick@244: get = "GetProp", Flick@244: }, ]] Flick@269: Flick@269: anchorEnable = { Flick@269: name = L["Reposition"], Flick@269: order = 111, Flick@269: type = "toggle", Flick@269: set = "SetProp", Flick@269: get = "GetProp", Flick@269: }, Flick@269: anchorGroup = { Flick@244: name = L["Position"], Flick@269: order = 112, Flick@244: type = "group", Flick@244: inline = true, Flick@269: disabled = "GetAnchorDisabled", Flick@244: args = { Flick@244: anchorFrame = { Flick@244: name = L["Anchor Frame"], Flick@269: order = 1, Flick@244: type = "select", Flick@244: values = "GetAnchorFrames", Flick@244: set = "SetAnchorFrame", Flick@244: get = "GetAnchorFrame", Flick@244: }, Flick@244: anchorPoint = { Flick@244: name = L["Point"], Flick@269: order = 2, Flick@269: type = "select", Flick@269: values = pointTable, Flick@269: set = "SetAnchorPointProp", Flick@269: get = "GetAnchorPointProp", Flick@269: }, Flick@269: anchorRelPoint = { Flick@269: name = L["Relative Point"], Flick@244: order = 3, Flick@244: type = "select", Flick@244: values = pointTable, Flick@244: set = "SetAnchorPointProp", Flick@244: get = "GetAnchorPointProp", Flick@244: }, Flick@244: anchorX = { Flick@244: name = L["X Offset"], Flick@269: order = 4, Flick@269: type = "range", Flick@269: min = -100, Flick@269: max = 100, Flick@269: step = 1, Flick@269: set = "SetProp", Flick@269: get = "GetProp", Flick@269: }, Flick@269: anchorY = { Flick@269: name = L["Y Offset"], Flick@244: order = 5, Flick@244: type = "range", Flick@244: min = -100, Flick@244: max = 100, Flick@244: step = 1, Flick@244: set = "SetProp", Flick@244: get = "GetProp", Flick@244: }, Flick@244: }, Flick@244: }, Flick@269: Flick@269: enableScale = { Flick@269: name = L["Set New Scale"], Flick@269: order = 121, Flick@269: type = "toggle", Flick@269: set = "SetProp", Flick@269: get = "GetProp", Flick@269: }, Flick@269: scaleGroup = { Flick@244: name = L["Scale"], Flick@269: order = 122, Flick@244: type = "group", Flick@244: inline = true, Flick@269: disabled = "GetScaleDisabled", Flick@244: args = { Flick@244: scale = { Flick@244: name = L["Scale"], Flick@269: order = 1, Flick@244: type = "range", Flick@244: min = 0.25, Flick@244: max = 2.5, Flick@244: step = 0.05, Flick@244: isPercent = true, Flick@244: set = "SetProp", Flick@244: get = "GetScale", Flick@244: }, Flick@244: }, Flick@244: }, Flick@269: Flick@269: enableAlpha = { Flick@269: name = L["Set Transparency"], Flick@269: order = 131, Flick@269: type = "toggle", Flick@269: set = "SetProp", Flick@269: get = "GetProp", Flick@269: }, Flick@269: alphaGroup = { Flick@244: name = L["Transparency"], Flick@269: order = 132, Flick@244: type = "group", Flick@244: inline = true, Flick@269: disabled = "GetAlphaDisabled", Flick@244: args = { Flick@244: alpha = { Flick@244: name = L["Transparency"], Flick@269: order = 1, Flick@244: type = "range", Flick@244: min = 0, Flick@244: max = 1, Flick@244: step = 0.01, Flick@244: bigStep = 0.05, Flick@244: isPercent = true, Flick@244: set = "SetProp", Flick@244: get = "GetAlpha", Flick@244: }, Flick@244: }, Flick@244: }, Flick@244: }, Flick@244: plugins = { } Flick@244: }, Flick@244: rules = { Flick@244: name = L["Rule"], Flick@244: order = 3, Flick@244: type = "group", Flick@244: args = { Flick@244: mode = { Flick@244: name = L["Select this state"], Flick@244: order = 2, Flick@244: type = "select", Flick@269: style = "dropdown", Flick@244: values = { Flick@244: default = L["by default"], Flick@244: any = L["when ANY of these"], Flick@244: all = L["when ALL of these"], Flick@244: custom = L["via custom rule"], Flick@244: keybind = L["via keybinding"], Flick@244: }, Flick@244: set = "SetType", Flick@244: get = "GetType", Flick@244: }, Flick@244: clear = { Flick@244: name = L["Clear All"], Flick@244: order = 3, Flick@244: type = "execute", Flick@244: hidden = "GetClearAllDisabled", Flick@244: disabled = "GetClearAllDisabled", Flick@244: func = "ClearAllConditions", Flick@244: }, Flick@244: inputs = { Flick@244: name = L["Conditions"], Flick@244: order = 4, Flick@244: type = "multiselect", Flick@244: hidden = "GetConditionsDisabled", Flick@244: disabled = "GetConditionsDisabled", Flick@244: values = ruleSelect, Flick@244: set = "SetCondition", Flick@244: get = "GetCondition", Flick@244: }, Flick@244: custom = { Flick@244: name = L["Custom Rule"], Flick@244: order = 5, Flick@244: type = "input", Flick@244: multiline = true, Flick@244: hidden = "GetCustomDisabled", Flick@244: disabled = "GetCustomDisabled", Flick@244: desc = L["Syntax like macro rules: see preset rules for examples"], Flick@244: set = "SetCustomRule", Flick@244: get = "GetCustomRule", Flick@244: validate = "ValidateCustomRule", Flick@244: }, Flick@244: keybind = { Flick@244: name = L["Keybinding"], Flick@244: order = 6, Flick@244: inline = true, Flick@244: hidden = "GetKeybindDisabled", Flick@244: disabled = "GetKeybindDisabled", Flick@244: type = "group", Flick@244: args = { Flick@244: desc = { Flick@244: name = L["Invoking a state keybind toggles an override of all other transition rules."], Flick@244: order = 1, Flick@244: type = "description", Flick@244: }, Flick@244: keybind = { Flick@244: name = L["State Hotkey"], Flick@244: desc = L["Define an override toggle keybind"], Flick@244: order = 2, Flick@244: type = "keybinding", Flick@244: set = "SetKeybind", Flick@244: get = "GetKeybind", Flick@244: }, Flick@244: }, Flick@244: }, Flick@244: }, Flick@244: }, Flick@244: } Flick@244: Flick@244: local StateHandler = { } Flick@244: local meta = { __index = StateHandler } Flick@244: Flick@244: function StateHandler:New( bar, opts ) Flick@244: local self = setmetatable( Flick@244: { Flick@244: bar = bar Flick@244: }, Flick@244: meta ) Flick@244: Flick@244: function self:GetName() Flick@244: return opts.name Flick@244: end Flick@244: Flick@244: function self:SetName(name) Flick@244: opts.name = name Flick@244: end Flick@244: Flick@244: function self:GetOrder() Flick@244: return opts.order Flick@244: end Flick@244: Flick@244: -- get reference to states table: even if the bar Flick@244: -- name changes the states table ref won't Flick@244: self.states = tbuild(bar:GetConfig(), "states") Flick@244: self.state = tbuild(self.states, opts.name) Flick@244: Flick@244: opts.order = self:GetRuleField("order") Flick@244: if opts.order == nil then Flick@244: -- add after the highest Flick@244: opts.order = 100 Flick@244: for _, state in pairs(self.states) do Flick@244: local x = tonumber(tfetch(state, "rule", "order")) Flick@244: if x and x >= opts.order then Flick@244: opts.order = x + 1 Flick@244: end Flick@244: end Flick@244: self:SetRuleField("order",opts.order) Flick@244: end Flick@244: Flick@244: return self Flick@244: end Flick@244: Flick@244: -- helper methods Flick@244: Flick@244: function StateHandler:SetRuleField( key, value, ... ) Flick@244: tbuild(self.state, "rule", ...)[key] = value Flick@244: end Flick@244: Flick@244: function StateHandler:GetRuleField( ... ) Flick@244: return tfetch(self.state, "rule", ...) Flick@244: end Flick@244: Flick@244: function StateHandler:FixAll( setkey ) Flick@244: -- if multiple selections in the same group are chosen when 'all' is selected, Flick@244: -- keep only one of them. If changing the mode, the first in the fields list will Flick@244: -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, Flick@244: -- it will be retained. Flick@244: local notified = false Flick@244: if self:GetRuleField("type") == "all" then Flick@244: for _, c in ipairs(rules) do Flick@244: local rule, fields = unpack(c) Flick@244: local once = false Flick@244: if setkey then Flick@244: for idx, field in ipairs(fields) do Flick@244: if next(field) == setkey then Flick@244: once = true Flick@244: end Flick@244: end Flick@244: end Flick@244: for idx, field in ipairs(fields) do Flick@244: local key = next(field) Flick@244: if self:GetRuleField("values",key) then Flick@244: if once and key ~= setkey then Flick@244: self:SetRuleField(key,false,"values") Flick@244: if not setkey and not notified then Flick@244: ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) Flick@244: notified = true Flick@244: end Flick@244: end Flick@244: once = true Flick@244: end Flick@244: end Flick@244: end Flick@244: end Flick@244: end Flick@244: Flick@244: function StateHandler:GetNeighbors() Flick@244: local before, after Flick@244: for k, v in pairs(self.states) do Flick@244: local o = tonumber(tfetch(v, "rule", "order")) Flick@244: if o and k ~= self:GetName() then Flick@244: local obefore = tfetch(self.states,before,"rule","order") Flick@244: local oafter = tfetch(self.states,after,"rule","order") Flick@244: if o < self:GetOrder() and (not obefore or obefore < o) then Flick@244: before = k Flick@244: end Flick@244: if o > self:GetOrder() and (not oafter or oafter > o) then Flick@244: after = k Flick@244: end Flick@244: end Flick@244: end Flick@244: return before, after Flick@244: end Flick@244: Flick@244: function StateHandler:SwapOrder( a, b ) Flick@244: -- do options table Flick@244: local args = optionMap[self.bar].args Flick@244: args[a].order, args[b].order = args[b].order, args[a].order Flick@244: -- do profile Flick@244: a = tbuild(self.states, a, "rule") Flick@244: b = tbuild(self.states, b, "rule") Flick@244: a.order, b.order = b.order, a.order Flick@244: end Flick@244: Flick@244: -- handler methods Flick@244: Flick@244: function StateHandler:GetProp( info ) Flick@244: -- gets property of the same name as the options arg Flick@244: return GetProperty(self.bar, self:GetName(), info[#info]) Flick@244: end Flick@244: Flick@244: function StateHandler:SetProp( info, value ) Flick@244: -- sets property of the same name as the options arg Flick@244: SetProperty(self.bar, self:GetName(), info[#info], value) Flick@244: end Flick@244: Flick@244: function StateHandler:DeleteState() Flick@244: if self.states[self:GetName()] then Flick@244: self.states[self:GetName()] = nil Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: optionMap[self.bar].args[self:GetName()] = nil Flick@244: end Flick@244: Flick@244: function StateHandler:SetStateName(info, value) Flick@244: -- check for existing state name Flick@244: if self.states[value] then Flick@244: ReAction:UserError(format(L["State named '%s' already exists"],value)) Flick@244: return Flick@244: end Flick@244: local args = optionMap[self.bar].args Flick@244: local name = self:GetName() Flick@244: self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil Flick@244: self:SetName(value) Flick@244: ApplyStates(self.bar) Flick@244: ReAction:ShowEditor(self.bar, moduleID, value) Flick@244: end Flick@244: Flick@244: function StateHandler:MoveStateUp() Flick@244: local before, after = self:GetNeighbors() Flick@244: if before then Flick@244: self:SwapOrder(before, self:GetName()) Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: end Flick@244: Flick@244: function StateHandler:MoveStateDown() Flick@244: local before, after = self:GetNeighbors() Flick@244: if after then Flick@244: self:SwapOrder(self:GetName(), after) Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: end Flick@244: Flick@244: function StateHandler:GetAnchorDisabled() Flick@244: return not GetProperty(self.bar, self:GetName(), "anchorEnable") Flick@244: end Flick@244: Flick@244: function StateHandler:IsPageDisabled() Flick@244: local n = self.bar:GetConfig().nPages or 1 Flick@244: return not (n > 1) Flick@244: end Flick@244: Flick@244: function StateHandler:IsPageHidden() Flick@244: return not self.bar:GetConfig().nPages Flick@244: end Flick@244: Flick@244: function StateHandler:GetPageValues() Flick@244: if not self._pagevalues then Flick@244: self._pagevalues = { } Flick@244: end Flick@244: local n = self.bar:GetConfig().nPages Flick@244: -- cache the results Flick@244: if self._npages ~= n then Flick@244: self._npages = n Flick@244: wipe(self._pagevalues) Flick@244: for i = 1, n do Flick@244: self._pagevalues["page"..i] = i Flick@244: end Flick@244: end Flick@244: return self._pagevalues Flick@244: end Flick@244: Flick@244: function StateHandler:GetPage(info) Flick@244: return self:GetProp(info) or 1 Flick@244: end Flick@244: Flick@244: function StateHandler:GetAnchorFrames(info) Flick@244: self._anchorframes = self._anchorframes or { } Flick@244: table.wipe(self._anchorframes) Flick@244: Flick@244: table.insert(self._anchorframes, "UIParent") Flick@244: for name, bar in ReAction:IterateBars() do Flick@244: table.insert(self._anchorframes, bar:GetFrame():GetName()) Flick@244: end Flick@244: return self._anchorframes Flick@244: end Flick@244: Flick@244: function StateHandler:GetAnchorFrame(info) Flick@244: local value = self:GetProp(info) Flick@244: for k,v in pairs(self._anchorframes) do Flick@244: if v == value then Flick@244: return k Flick@244: end Flick@244: end Flick@244: end Flick@244: Flick@244: function StateHandler:SetAnchorFrame(info, value) Flick@244: local f = _G[self._anchorframes[value]] Flick@244: if f then Flick@244: self.bar:SetFrameRef("anchor-"..self:GetName(), f) Flick@244: self:SetProp(info, f:GetName()) Flick@244: end Flick@244: end Flick@244: Flick@244: function StateHandler:SetAnchorPointProp(info, value) Flick@244: self:SetProp(info, value ~= "NONE" and value or nil) Flick@244: end Flick@244: Flick@244: function StateHandler:GetAnchorPointProp(info) Flick@244: return self:GetProp(info) or "NONE" Flick@244: end Flick@244: Flick@244: function StateHandler:GetScale(info) Flick@244: return self:GetProp(info) or 1.0 Flick@244: end Flick@244: Flick@244: function StateHandler:GetScaleDisabled() Flick@244: return not GetProperty(self.bar, self:GetName(), "enableScale") Flick@244: end Flick@244: Flick@244: function StateHandler:GetAlpha(info) Flick@244: return self:GetProp(info) or 1.0 Flick@244: end Flick@244: Flick@244: function StateHandler:GetAlphaDisabled() Flick@244: return not GetProperty(self.bar, self:GetName(), "enableAlpha") Flick@244: end Flick@244: Flick@244: function StateHandler:SetType(info, value) Flick@244: self:SetRuleField("type", value) Flick@244: self:FixAll() Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: Flick@244: function StateHandler:GetType() Flick@244: return self:GetRuleField("type") Flick@244: end Flick@244: Flick@244: function StateHandler:GetClearAllDisabled() Flick@244: local t = self:GetRuleField("type") Flick@244: return not( t == "any" or t == "all" or t == "custom") Flick@244: end Flick@244: Flick@244: function StateHandler:ClearAllConditions() Flick@244: local t = self:GetRuleField("type") Flick@244: if t == "custom" then Flick@244: self:SetRuleField("custom","") Flick@244: elseif t == "any" or t == "all" then Flick@244: self:SetRuleField("values", {}) Flick@244: end Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: Flick@244: function StateHandler:GetConditionsDisabled() Flick@244: local t = self:GetRuleField("type") Flick@244: return not( t == "any" or t == "all") Flick@244: end Flick@244: Flick@244: function StateHandler:SetCondition(info, key, value) Flick@244: self:SetRuleField(ruleMap[key], value or nil, "values") Flick@244: if value then Flick@244: self:FixAll(ruleMap[key]) Flick@244: end Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: Flick@244: function StateHandler:GetCondition(info, key) Flick@244: return self:GetRuleField("values", ruleMap[key]) or false Flick@244: end Flick@244: Flick@244: function StateHandler:GetCustomDisabled() Flick@244: return self:GetRuleField("type") ~= "custom" Flick@244: end Flick@244: Flick@244: function StateHandler:SetCustomRule(info, value) Flick@244: self:SetRuleField("custom",value) Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: Flick@244: function StateHandler:GetCustomRule() Flick@244: return self:GetRuleField("custom") or "" Flick@244: end Flick@244: Flick@244: function StateHandler:ValidateCustomRule(info, value) Flick@244: local s = value:gsub("%s","") -- remove all spaces Flick@244: -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler Flick@244: repeat Flick@244: if s == "" then Flick@244: return true Flick@244: end Flick@244: local c, r = s:match("(%b[])(.*)") Flick@244: if c == nil and s and #s > 0 then Flick@244: return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "") Flick@244: end Flick@244: s = r Flick@244: until c == nil Flick@244: return true Flick@244: end Flick@244: Flick@244: function StateHandler:GetKeybindDisabled() Flick@244: return self:GetRuleField("type") ~= "keybind" Flick@244: end Flick@244: Flick@244: function StateHandler:GetKeybind() Flick@244: return self:GetRuleField("keybind") Flick@244: end Flick@244: Flick@244: function StateHandler:SetKeybind(info, value) Flick@244: if value and #value == 0 then Flick@244: value = nil Flick@244: end Flick@244: self:SetRuleField("keybind",value) Flick@244: ApplyStates(self.bar) Flick@244: end Flick@244: Flick@244: local function CreateStateOptions(bar, name) Flick@244: local opts = { Flick@244: type = "group", Flick@244: name = name, Flick@244: childGroups = "tab", Flick@244: args = stateOptions Flick@244: } Flick@244: Flick@244: opts.handler = StateHandler:New(bar,opts) Flick@244: Flick@244: return opts Flick@244: end Flick@244: Flick@244: function Editor:CreateStateOptions(bar) Flick@244: local private = { } Flick@244: local states = tbuild(bar:GetConfig(), "states") Flick@244: local options = { Flick@244: name = L["Dynamic State"], Flick@244: type = "group", Flick@244: order = -1, Flick@244: childGroups = "tree", Flick@244: disabled = InCombatLockdown, Flick@244: args = { Flick@244: __desc__ = { Flick@244: name = L["States are evaluated in the order they are listed"], Flick@244: order = 1, Flick@244: type = "description", Flick@244: }, Flick@244: __new__ = { Flick@244: name = L["New State..."], Flick@244: order = 2, Flick@244: type = "group", Flick@244: args = { Flick@244: name = { Flick@244: name = L["State Name"], Flick@244: desc = L["Set a name for the new state"], Flick@244: order = 1, Flick@244: type = "input", Flick@244: get = function() return private.newstatename or "" end, Flick@244: set = function(info,value) private.newstatename = value end, Flick@244: pattern = "^%w*$", Flick@244: usage = L["State names must be alphanumeric without spaces"], Flick@244: }, Flick@244: create = { Flick@244: name = L["Create State"], Flick@244: order = 2, Flick@244: type = "execute", Flick@244: func = function () Flick@244: local name = private.newstatename Flick@244: if states[name] then Flick@244: ReAction:UserError(format(L["State named '%s' already exists"],name)) Flick@244: else Flick@244: -- TODO: select default state options and pass as final argument Flick@244: states[name] = { } Flick@244: optionMap[bar].args[name] = CreateStateOptions(bar,name) Flick@269: ReAction:ShowEditor(bar, "stateOpts", name) Flick@244: private.newstatename = "" Flick@244: end Flick@244: end, Flick@244: disabled = function() Flick@244: local name = private.newstatename or "" Flick@244: return #name == 0 or name:find("%W") Flick@244: end, Flick@244: } Flick@244: } Flick@244: } Flick@244: } Flick@244: } Flick@244: for name, config in pairs(states) do Flick@244: options.args[name] = CreateStateOptions(bar,name) Flick@244: end Flick@244: optionMap[bar] = options Flick@244: return options Flick@244: end Flick@244: end Flick@244: 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: