diff Editor.lua @ 185:2e7a322e0195

move ConfigUI module to Editor non-module, make it more self-contained
author Flick <flickerstreak@gmail.com>
date Fri, 22 Oct 2010 23:48:02 +0000
parents modules/ConfigUI.lua@1ee86bbb05a0
children d58055179c16
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Editor.lua	Fri Oct 22 23:48:02 2010 +0000
@@ -0,0 +1,476 @@
+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 = { }
+
+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.options = {
+    type = "group",
+    name = L["Select Bar:"],
+    desc = "foo foo foo",
+    handler = self,
+    childGroups = "select",
+    args = {
+      launchConfig = {
+        type = "execute",
+        name = L["Global Config"],
+        desc = L["Opens ReAction global configuration settings panel"],
+        func = function()
+            if ReAction.db.profile.editorCloseOnLaunch then
+              self:Close()
+            end
+            ReAction:ShowOptions()
+          end,
+        order = 1
+      },
+      closeThis = {
+        type = "toggle",
+        name = L["Close Editor"],
+        desc = L["Close the Bar Editor when opening the ReAction global Interface Options"],
+        get  = function() return ReAction.db.profile.editorCloseOnLaunch end,
+        set  = function(info, val) ReAction.db.profile.editorCloseOnLaunch = val end,
+        order = 2,
+      },
+      hdr = {
+        type = "header",
+        name = "",
+        order = 3,
+      },
+      desc = {
+        type = "description",
+        name = L["Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality."],
+        width = "double",
+        order = 4,
+      },
+      _new = {
+        type = "group",
+        name = L["New Bar..."],
+        order = 5,
+        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:GetBarTypeConfig(val)
+                     self.tmp.barType = val 
+                     self.tmp.barSize = c.defaultButtonSize or self.tmp.barSize
+                     self.tmp.barRows = c.defaultBarRows or self.tmp.barRows
+                     self.tmp.barCols = c.defaultBarCols or self.tmp.barCols
+                     self.tmp.barSpacing = c.defaultBarSpacing 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.title = ("%s - %s"):format(L["ReAction"],L["Bar Editor"])
+  self.gui:SetTitle(self.title)
+
+  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,"OnEraseBar")
+  ReAction.RegisterCallback(self,"OnRenameBar")
+
+  for name, bar in ReAction:IterateBars() do
+    self:CreateBarTree(bar)
+  end
+
+  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
+    print("closing...")
+    self.gui:ReleaseChildren()
+    self.gui:Hide()
+  end
+end
+
+function Editor:Refresh()
+  AceConfigReg:NotifyChange(self.configID)
+end
+
+function Editor:CreateBarTree(bar)
+  local name = bar:GetName()
+  -- 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 args = self.options.args
+  local key
+  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,
+          },
+        },
+      },
+    }
+  }
+  self:RefreshBarOptions()
+end
+
+function Editor:RefreshBarOptions()
+  for name, key in pairs(self.barOptMap) do
+    local bar = ReAction:GetBar(name)
+    if bar and key and self.options.args[key] then
+      self.options.args[key].plugins = self:GenerateBarOptionsTable(bar)
+    end
+  end
+  AceConfigReg:NotifyChange(self.configID)
+end
+
+function Editor:OnCreateBar(evt, bar)
+  if not self.tmp.creating then
+    -- a bit of hack to work around OnCreateBar event handler ordering
+    self:CreateBarTree(bar)
+  end
+end
+
+function Editor:OnDestroyBar(evt, bar, name)
+  local key = self.barOptMap[name]
+  if key then
+    self.options.args[key] = nil
+  end
+  self:Refresh()
+end
+
+function Editor:OnEraseBar(evt, name)
+  local key = self.barOptMap[name]
+  self.barOptMap[name] = nil
+  if key then
+    self.options.args[key] = nil
+    self:Refresh()
+  end
+end
+
+function Editor:OnRenameBar(evt, bar, oldname, newname)
+  local key = self.barOptMap[oldname]
+  self.barOptMap[oldname], self.barOptMap[newname] = nil, key
+  if key then
+    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
+    self.tmp.creating = true
+    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
+      self:CreateBarTree(bar)
+      AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName])
+      self.tmp.barName = nil
+    end
+    self.tmp.creating = false
+  end
+end
+
+function Editor:GenerateBarOptionsTable( bar )
+  local opts = { }
+  if not ReAction.barOptionGenerators then
+    return
+  end
+
+  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
+        opts[module:GetName()] = { [module:GetName()] = r }
+      end
+    else
+      geterrorhandler()(r)
+    end
+  end
+  return opts
+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
+