view Editor.lua @ 237:704f4a05a1d7

Demodulificate all bar options (except state options)
author Flick
date Thu, 24 Mar 2011 13:11:30 -0700
parents a5d91d7fd485
children f255cd69e890
line wrap: on
line source
local addonName, addonTable = ...
local ReAction = addonTable.ReAction
local L = ReAction.L
local _G = _G
local wipe = wipe

local AceConfigReg = LibStub("AceConfigRegistry-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")


local pointTable = {
  CENTER      = L["Center"], 
  LEFT        = L["Left"],
  RIGHT       = L["Right"],
  TOP         = L["Top"],
  BOTTOM      = L["Bottom"],
  TOPLEFT     = L["Top Left"],
  TOPRIGHT    = L["Top Right"],
  BOTTOMLEFT  = L["Bottom Left"],
  BOTTOMRIGHT = L["Bottom Right"],
}

local Editor = { 
  buttonHandlers = { }
}

function Editor:New()
  -- create new self
  self = setmetatable( { }, { __index = self } )

  self.barOptMap = setmetatable({},{__mode="v"})
  self.tmp = { }
  self.configID = "ReAction-Editor"

  self.gui = LibStub("AceGUI-3.0"):Create("Frame")
  
  local frame = self.gui.frame
  frame:SetClampedToScreen(true)
  frame:Hide()

  frame:SetScript("OnHide", 
    function(...)
      ReAction:SetConfigMode(false)
    end)

  self.title = ("%s - %s"):format(L["ReAction"],L["Bar Editor"])
  self.gui:SetTitle(self.title)

  self.options = {
    type = "group",
    name = self.title,
    handler = self,
    childGroups = "select",
    args = {
      launchConfig = {
        type = "execute",
        name = L["Global Config"],
        desc = L["Opens ReAction global configuration settings panel"],
        func = function() ReAction:ShowOptions(); self:Close() end,
        order = 1
      },
      desc = {
        type = "description",
        name = L["Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality."],
        order = 2,
      },
      hdr = {
        type = "header",
        name = L["Select Bar"],
        order = 3,
      },
      _new = {
        type = "group",
        name = L["New Bar..."],
        order = 4,
        args = { 
          desc = {
            type = "description",
            name = L["Choose a name, type, and initial grid for your new action bar:"],
            order = 1,
          },
          name = {
            type = "input",
            name = L["Bar Name"],
            desc = L["Enter a name for your new action bar"],
            get  = function() return self.tmp.barName or "" end,
            set  = function(info, val) self.tmp.barName = val end,
            order = 2,
          },
          type = {
            type = "select",
            name = L["Button Type"],
            get  = function() return self.tmp.barType or ReAction:GetDefaultBarType() or "" end,
            set  = function(info, val) 
                     local c = ReAction:GetDefaultBarConfig(val)
                     self.tmp.barType = val 
                     self.tmp.barSize = c.btnWidth or self.tmp.barSize
                     self.tmp.barRows = c.btnRows or self.tmp.barRows
                     self.tmp.barCols = c.btnColumns or self.tmp.barCols
                     self.tmp.barSpacing = c.spacing or self.tmp.barSpacing
                   end,
            values = "GetBarTypes",
            order = 3,
          },
          go = {
            type = "execute",
            name = L["Create Bar"],
            func = "CreateBar",
            order = 4,
          },
          grid = {
            type = "group",
            name = L["Button Grid"],
            inline = true,
            order = 5,
            args = {
              rows = {
                type = "range",
                name = L["Rows"],
                get  = function() return self.tmp.barRows or 1 end,
                set  = function(info, val) self.tmp.barRows = val end,
                width = "full",
                min = 1,
                max = 32,
                step = 1,
                order = 2,
              },
              cols = {
                type = "range",
                name = L["Columns"],
                get  = function() return self.tmp.barCols or 12 end,
                set  = function(info, val) self.tmp.barCols = val end,
                width = "full",
                min = 1, 
                max = 32,
                step = 1,
                order = 3,
              },
              sz = {
                type = "range",
                name = L["Size"],
                get  = function() return self.tmp.barSize or 36 end,
                set  = function(info, val) self.tmp.barSize = val end,
                width = "full",
                min = 10,
                max = 72,
                step = 1,
                order = 4,
              },
              spacing = {
                type = "range",
                name = L["Spacing"],
                get  = function() return self.tmp.barSpacing or 3 end,
                set  = function(info, val) self.tmp.barSpacing = val end,
                width = "full",
                min = 0,
                max = 24,
                step = 1,
                order = 5,
              }
            }
          }
        }
      }
    }
  }

  self.gui:SetCallback("OnClose", 
    function() 
      ReAction:SetConfigMode(false)
    end )

  AceConfigReg:RegisterOptionsTable(self.configID, self.options)
  AceConfigDialog:SetDefaultSize(self.configID, 700, 540)

  ReAction.RegisterCallback(self,"OnCreateBar")
  ReAction.RegisterCallback(self,"OnDestroyBar")
  ReAction.RegisterCallback(self,"OnRenameBar")

  self:RefreshBarOptions()

  return self
end


function Editor:Open(bar, ...)
  if bar then
    AceConfigDialog:SelectGroup(self.configID, self.barOptMap[bar:GetName()], ...)
  end
  AceConfigDialog:Open(self.configID,self.gui)
  self.gui:SetTitle(self.title)
end

function Editor:Close()
  if self.gui then
    self.gui:ReleaseChildren()
    self.gui:Hide()
  end
end

function Editor:Refresh()
  AceConfigReg:NotifyChange(self.configID)
end

function Editor:UpdateBarOptions(bar)
  local name = bar:GetName()
  local key  = self.barOptMap[name]
  local args = self.options.args

  if not key then
    -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be
    -- unique strings. So generate a unique key (it can be whatever) for the bar
    local i = 1
    repeat
      key = ("bar%s"):format(i)
      i = i+1
    until args[key] == nil
    self.barOptMap[name] = key

    args[key] = { 
      type = "group",
      name = name,
      childGroups = "tab",
      order = i+100,
      args = {
        general = {
          type = "group",
          name = L["General"],
          order = 1,
          args = {
            name = {
              type = "input",
              name = L["Rename Bar"],
              get  = function() return bar:GetName() end,
              set  = function(info, value) return ReAction:RenameBar(bar, value) end,
              order = 1,
            },
            delete = {
              type = "execute",
              name = L["Delete Bar"],
              desc = function() return bar:GetName() end,
              confirm = true,
              func = function() ReAction:EraseBar(bar) end,
              order = 2
            },
            anchor = {
              type = "group",
              name = L["Anchor"],
              inline = true,
              args = {
                frame = {
                  type = "input",
                  name = L["Frame"],
                  desc = L["The frame that the bar is anchored to"],
                  get  = function() local _, f = bar:GetAnchor(); return f end,
                  set  = function(info, val) bar:SetAnchor(nil,val) end,
                  validate = function(info, name) 
                      if name then
                        local f = ReAction:GetBar(name)
                        if f then
                          return true
                        else
                          f = _G[name]
                          if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then
                            local _, explicit = f:IsProtected()
                            return explicit
                          end
                        end
                      end
                      return false
                    end,
                  width = "double",
                  order = 1
                },
                point = {
                  type = "select",
                  name = L["Point"],
                  desc = L["Anchor point on the bar frame"],
                  style = "dropdown",
                  get  = function() return bar:GetAnchor() end,
                  set  = function(info, val) bar:SetAnchor(val) end,
                  values = pointTable,
                  order = 2,
                },
                relativePoint = {
                  type = "select",
                  name = L["Relative Point"],
                  desc = L["Anchor point on the target frame"],
                  style = "dropdown",
                  get  = function() local p,f,r = bar:GetAnchor(); return r end,
                  set  = function(info, val) bar:SetAnchor(nil,nil,val) end,
                  values = pointTable,
                  order = 3,
                },
                x = {
                  type = "input",
                  pattern = "\-?%d+",
                  name = L["X offset"],
                  get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end,
                  set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end,
                  order = 4
                },
                y = {
                  type = "input",
                  pattern = "\-?%d+",
                  name = L["Y offset"],
                  get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end,
                  set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end,
                  order = 5
                },
              },
              order = 3
            },
            alpha = {
              type = "range",
              name = L["Transparency"],
              get  = function() return bar:GetAlpha() end,
              set  = function(info, val) bar:SetAlpha(val) end,
              min = 0, 
              max = 1,
              isPercent = true,
              step = 0.01,
              bigStep = 0.05,
              order = 4,
            },
          },
        },
        buttonOpts = self:CreateButtonOptions(bar)
      },
      plugins = { }
    }
  end

  if ReAction.barOptionGenerators then
    for module, func in pairs(ReAction.barOptionGenerators) do
      local success, r
      if type(func) == "string" then
        success, r = pcall(module[func], module, bar)
      else
        success, r = pcall(func, bar)
      end
      if success then
        if r then
          args[key].plugins[module:GetName()] = { [module:GetName()] = r }
        end
      else
        geterrorhandler()(r)
      end
    end
  end
end

function Editor:CreateButtonOptions(bar)
  local buttonClass = bar:GetButtonClass()
  local classID = buttonClass:GetButtonTypeID()
  local handler = self.buttonHandlers[classID]

  if handler then
    local h = handler:New(bar)
    return h:GetOptions()
  end
end

function Editor:RefreshBarOptions()
  for name, key in pairs(self.barOptMap) do
    if not ReAction:GetBar(name) then
      self.barOptMap[name] = nil
      self.options.args[key] = nil
    end
  end
  for name, bar in ReAction:IterateBars() do
    self:UpdateBarOptions(bar)
  end
  self:Refresh()
end

function Editor:OnCreateBar(evt, bar)
  self:UpdateBarOptions(bar)
  self:Refresh()
end

function Editor:OnDestroyBar(evt, bar, name)
  local key = self.barOptMap[name]
  if key then
    self.barOptMap[name] = nil
    self.options.args[key] = nil
    self:Refresh()
  end
end

function Editor:OnRenameBar(evt, bar, oldname, newname)
  local key = self.barOptMap[oldname]
  if key then
    self.barOptMap[oldname], self.barOptMap[newname] = nil, key
    self.options.args[key].name = newname
    self:Refresh()
  end
end

local _scratch = { }
function Editor:GetBarTypes()
  wipe(_scratch)
  return ReAction:GetBarTypeOptions(_scratch)
end

function Editor:CreateBar()
  if self.tmp.barName and self.tmp.barName ~= "" then
    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)
    if bar then
      AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName])
      self.tmp.barName = nil
    end
  end
end

-------------------------------
---- Action button handler ----
-------------------------------

do
  local ActionHandler = {
    buttonClass = ReAction.Button.Action,
    options = {
      hideEmpty = {
        name = L["Hide Empty Buttons"],
        order = 1,
        type = "toggle",
        width = "double",
        get  = "GetHideEmpty",
        set  = "SetHideEmpty",
      },
      lockButtons = {
        name = L["Lock Buttons"],
        desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
        order = 2,
        type = "toggle",
        get = "GetLockButtons",
        set = "SetLockButtons",
      },
      lockOnlyCombat = {
        name = L["Only in Combat"],
        desc = L["Only lock the buttons when in combat"],
        order = 3,
        type = "toggle",
        disabled = "LockButtonsCombatDisabled",
        get = "GetLockButtonsCombat",
        set = "SetLockButtonsCombat",
      },
      pages = {
        name  = L["# Pages"],
        desc  = L["Use the Dynamic State tab to specify page transitions"],
        order = 4,
        type  = "range",
        min   = 1,
        max   = 10,
        step  = 1,
        get   = "GetNumPages",
        set   = "SetNumPages",
      },
      mindcontrol = {
        name = L["Mind Control Support"],
        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."],
        order = 5,
        type = "toggle",
        width = "double",
        set = "SetMindControl",
        get = "GetMindControl",
      },
      vehicle = {
        name = L["Vehicle Support"],
        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."],
        order = 6,
        type = "toggle",
        width = "double",
        get = "GetVehicle",
        set = "SetVehicle",
      },
      actions = {
        name   = L["Edit Action IDs"],
        order  = 7,
        type   = "group",
        inline = true,
        args   = {
          method = {
            name   = L["Assign"],
            order  = 1,
            type   = "select",
            width  = "double",
            values = { [0] = L["Choose Method..."],
                       [1] = L["Individually"],
                       [2] = L["All at Once"], },
            get    = "GetActionEditMethod",
            set    = "SetActionEditMethod",
          },
          rowSelect = {
            name   = L["Row"],
            desc   = L["Rows are numbered top to bottom"],
            order  = 2,
            type   = "select",
            width  = "half",
            hidden = "IsButtonSelectHidden",
            values = "GetRowList",
            get    = "GetSelectedRow",
            set    = "SetSelectedRow",
          },
          colSelect = {
            name   = L["Col"],
            desc   = L["Columns are numbered left to right"],
            order  = 3,
            type   = "select",
            width  = "half",
            hidden = "IsButtonSelectHidden",
            values = "GetColumnList",
            get    = "GetSelectedColumn",
            set    = "SetSelectedColumn",
          },
          pageSelect = {
            name   = L["Page"],
            order  = 4,
            type   = "select",
            width  = "half",
            hidden = "IsPageSelectHidden",
            values = "GetPageList",
            get    = "GetSelectedPage",
            set    = "SetSelectedPage",
          },
          single = {
            name   = L["Action ID"],
            usage  = L["Specify ID 1-120"],
            order  = 5,
            type   = "input",
            width  = "half",
            hidden = "IsButtonSelectHidden",
            get    = "GetActionID",
            set    = "SetActionID",
            validate = "ValidateActionID",
          },
          multi = {
            name   = L["ID List"],
            usage  = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"],
            order  = 6,
            type   = "input",
            multiline = true,
            width  = "double",
            hidden = "IsMultiIDHidden",
            get    = "GetMultiID",
            set    = "SetMultiID",
            validate = "ValidateMultiID",
          },
        },
      },
    }
  }

  Editor.buttonHandlers[ActionHandler.buttonClass:GetButtonTypeID()] = ActionHandler

  local meta = { __index = ActionHandler }

  function ActionHandler:New( bar )
    return setmetatable(
      {
        bar = bar,
        config = bar:GetConfig(),
      }, 
      meta)
  end

  function ActionHandler:Refresh()
    self.buttonClass:SetupBar(self.bar)
  end

  function ActionHandler:UpdateButtonLock()
    self.buttonClass:SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat)
  end

  function ActionHandler:GetLastButton()
    return self.bar:GetButton(self.bar:GetNumButtons())
  end

    -- options handlers
  function ActionHandler:GetOptions()
    return {
      type = "group",
      name = L["Action Buttons"],
      handler = self,
      order = 2,
      args = self.options
    }
  end

  function ActionHandler:SetHideEmpty(info, value)
    if value ~= self.config.hideEmpty then
      self.config.hideEmpty = value
      for _, b in self.bar:IterateButtons() do
        b:ShowGrid(not value)
      end
    end
  end

  function ActionHandler:GetHideEmpty()
    return self.config.hideEmpty
  end

  function ActionHandler:GetLockButtons()
    return self.config.lockButtons
  end

  function ActionHandler:SetLockButtons(info, value)
    self.config.lockButtons = value
    self:UpdateButtonLock()
  end

  function ActionHandler:GetLockButtonsCombat()
    return self.config.lockButtonsCombat
  end

  function ActionHandler:SetLockButtonsCombat(info, value)
    self.config.lockButtonsCombat = value
    self:UpdateButtonLock()
  end

  function ActionHandler:LockButtonsCombatDisabled()
    return not self.config.lockButtons
  end

  function ActionHandler:GetNumPages()
    return self.config.nPages
  end

  function ActionHandler:SetNumPages(info, value)
    self.config.nPages = value
    self:Refresh()
  end

  function ActionHandler:GetMindControl()
    return self.config.mindcontrol
  end

  function ActionHandler:SetMindControl(info, value)
    self.config.mindcontrol = value
    self:Refresh()
  end

  function ActionHandler:GetVehicle()
    return self.config.vehicle
  end

  function ActionHandler:SetVehicle(info, value)
    self.config.vehicle = value
    self:Refresh()
  end

  function ActionHandler:GetActionEditMethod()
    return self.editMethod or 0
  end

  function ActionHandler:SetActionEditMethod(info, value)
    self.editMethod = value
  end

  function ActionHandler:IsButtonSelectHidden()
    return self.editMethod ~= 1
  end

  function ActionHandler:GetRowList()
    local r,c = self.bar:GetButtonGrid()
    if self.rowList == nil or #self.rowList ~= r then
      local list = { }
      for i = 1, r do
        table.insert(list,i)
      end
      self.rowList = list
    end
    return self.rowList
  end

  function ActionHandler:GetSelectedRow()
    local r, c = self.bar:GetButtonGrid()
    local row = self.selectedRow or 1
    if row > r then
      row = 1
    end
    self.selectedRow = row
    return row
  end

  function ActionHandler:SetSelectedRow(info, value)
    self.selectedRow = value
  end

  function ActionHandler:GetColumnList()
    local r,c = self.bar:GetButtonGrid()
    if self.columnList == nil or #self.columnList ~= c then
      local list = { }
      for i = 1, c do
        table.insert(list,i)
      end
      self.columnList = list
    end
    return self.columnList
  end

  function ActionHandler:GetSelectedColumn()
    local r, c = self.bar:GetButtonGrid()
    local col = self.selectedColumn or 1
    if col > c then
      col = 1
    end
    self.selectedColumn = col
    return col
  end

  function ActionHandler:SetSelectedColumn(info, value)
    self.selectedColumn = value
  end

  function ActionHandler:IsPageSelectHidden()
    return self.editMethod ~= 1 or (self.config.nPages or 1) < 2
  end

  function ActionHandler:GetPageList()
    local n = self.config.nPages or 1
    if self.pageList == nil or #self.pageList ~= n then
      local p = { }
      for i = 1, n do
        table.insert(p,i)
      end
      self.pageList = p
    end
    return self.pageList
  end

  function ActionHandler:GetSelectedPage()
    local p = self.selectedPage or 1
    if p > (self.config.nPages or 1) then
      p = 1
    end
    self.selectedPage = p
    return p
  end

  function ActionHandler:SetSelectedPage(info, value)
    self.selectedPage = value
  end

  function ActionHandler:GetActionID()
    local row = self.selectedRow or 1
    local col = self.selectedColumn or 1
    local r, c = self.bar:GetButtonGrid()
    local n = (row-1) * c + col
    local btn = self.bar:GetButton(n)
    if btn then
      return tostring(btn:GetActionID(self.selectedPage or 1))
    end
  end

  function ActionHandler:SetActionID(info, value)
    local row = self.selectedRow or 1
    local col = self.selectedColumn or 1
    local r, c = self.bar:GetButtonGrid()
    local n = (row-1) * c + col
    local btn = self.bar:GetButton(n)
    if btn then
      btn:SetActionID(tonumber(value), self.selectedPage or 1)
    end
  end

  function ActionHandler:ValidateActionID(info, value)
    value = tonumber(value)
    if value == nil or value < 1 or value > 120 then
      return L["Specify ID 1-120"]
    end
    return true
  end

  function ActionHandler:IsMultiIDHidden()
    return self.editMethod ~= 2
  end

  function ActionHandler:GetMultiID()
    local p = { }
    for i = 1, self.config.nPages or 1 do
      local b = { }
      for _, btn in self.bar:IterateButtons() do
        table.insert(b, btn:GetActionID(i))
      end
      table.insert(p, table.concat(b,","))
    end
    return table.concat(p,";\n")
  end


  local function ParseMultiID(nBtns, nPages, s)
    if s:match("[^%d%s,;]") then
      return nil
    end
    local p = { }
    for list in s:gmatch("[^;]+") do
      local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns))
      local ids = { list:match(pattern) }
      if #ids ~= nBtns then
        return nil
      end
      table.insert(p,ids)
    end
    if #p ~= nPages then
      return nil
    end
    return p
  end

  function ActionHandler:SetMultiID(info, value)
    local p = ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value)
    for page, b in ipairs(p) do
      for button, id in ipairs(b) do
        self.bar:GetButton(button):SetActionID(id, page)
      end
    end
  end

  function ActionHandler:ValidateMultiID(info, value)
    local bad = L["Invalid action ID list string"]
    if value == nil or ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value) == nil then
      return bad
    end
    return true
  end
end


----------------------------------
---- PetAction button handler ----
----------------------------------

do
  local PetHandler = { 
    buttonClass = ReAction.Button.PetAction,
  }

  Editor.buttonHandlers[PetHandler.buttonClass:GetButtonTypeID()] = PetHandler

  local meta = { __index = PetHandler }

  function PetHandler:New(bar)
    return setmetatable(
      {
        bar = bar,
        config = bar.config
      }, meta)
  end

  function PetHandler:GetLockButtons()
    return self.config.lockButtons
  end

  function PetHandler:SetLockButtons(info, value)
    self.config.lockButtons = value
    self.buttonClass:UpdateButtonLock(self.bar)
  end

  function PetHandler:GetLockButtonsCombat()
    return self.config.lockButtonsCombat
  end

  function PetHandler:SetLockButtonsCombat(info, value)
    self.config.lockButtonsCombat = value
    self.buttonClass:UpdateButtonLock(self.bar)
  end

  function PetHandler:LockButtonsCombatDisabled()
    return not self.config.lockButtons
  end

  function PetHandler:GetOptions()
    return {
      type = "group",
      name = L["Pet Buttons"],
      handler = self,
      order = 2,
      args = {
        lockButtons = {
          name = L["Lock Buttons"],
          desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
          order = 2,
          type = "toggle",
          get = "GetLockButtons",
          set = "SetLockButtons",
        },
        lockOnlyCombat = {
          name = L["Only in Combat"],
          desc = L["Only lock the buttons when in combat"],
          order = 3,
          type = "toggle",
          disabled = "LockButtonsCombatDisabled",
          get = "GetLockButtonsCombat",
          set = "SetLockButtonsCombat",
        },
      }
    }
  end
end


-------------------------------------
---- Vehicle Exit button handler ----
-------------------------------------

do
  local VExitHandler = { 
    buttonClass = ReAction.Button.VehicleExit,
  }

  Editor.buttonHandlers[VExitHandler.buttonClass:GetButtonTypeID()] = VExitHandler

  local meta = { __index = VExitHandler }

  function VExitHandler:New(bar)
    return setmetatable(
      {
        bar = bar,
      }, meta)
  end

  function VExitHandler:GetConfig()
    return self.bar:GetConfig()
  end

  function VExitHandler:GetPassengerOnly()
    return not self:GetConfig().withControls
  end

  function VExitHandler:SetPassengerOnly(info, value)
    self:GetConfig().withControls = not value
    self.buttonClass:UpdateRegistration(self.bar)
  end


  function VExitHandler:GetOptions()
    return {
      type = "group",
      name = L["Exit Vehicle"],
      handler = self,
      args = {
        passengerOnly = {
          name = L["Show only when passenger"],
          desc = L["Only show the button when riding as a passenger in a vehicle (no vehicle controls)"],
          order = 2,
          width = "double",
          type = "toggle",
          get = "GetPassengerOnly",
          set = "SetPassengerOnly",
        },
      }
    }
  end
end



---- Export to ReAction ----
function ReAction:ShowEditor(bar, ...)
  if InCombatLockdown() then
    self:UserError(L["ReAction config mode disabled during combat."])
  else
    self.editor = self.editor or Editor:New()
    self.editor:Open(bar, ...)
    self:SetConfigMode(true)
  end
end

function ReAction:CloseEditor()
  if self.editor then
    self.editor:Close()
  end
end

function ReAction:RefreshEditor()
  if self.editor then
    self.editor:RefreshBarOptions()
  end
end

function ReAction:RegisterBarOptionGenerator( module, func )
  if not module or type(module) ~= "table" then -- doesn't need to be a proper module, strictly
    error("ReAction:RegisterBarOptionGenerator() : Invalid module")
  end
  if type(func) == "string" then
    if not module[func] then
      error(("ReAction:RegisterBarOptionGenerator() : Invalid method '%s'"):format(func))
    end
  elseif func and type(func) ~= "function" then
    error("ReAction:RegisterBarOptionGenerator() : Invalid function")
  end
  self.barOptionGenerators = self.barOptionGenerators or { }
  self.barOptionGenerators[module] = func

  if self.editor then
    self.editor:RefreshBarOptions()
  end
end