57a5cdabdf
Imported from /srv/add01/wow-ascension/Interface/AddOns/Bartender4 — the build Ascension's WotLK 3.3.5 client ships. Single vendored drop: Ascension's build process bundles their custom patches with the standard CurseForge packager output (embedded libs), and the individual patches aren't published separately. Net delta vs Nevcairiel 4.4.2, excluding bundled libs and CRLF normalization: 21 files, 2213+/52- — the Ascension-specific adaptations for WotLK 3.3.5 hero classes / custom action systems. License: All rights reserved (per .toc).
788 lines
24 KiB
Lua
788 lines
24 KiB
Lua
--- AceConfigCmd-3.0 handles access to an options table through the "command line" interface via the ChatFrames.
|
|
-- @class file
|
|
-- @name AceConfigCmd-3.0
|
|
-- @release $Id: AceConfigCmd-3.0.lua 904 2009-12-13 11:56:37Z nevcairiel $
|
|
|
|
--[[
|
|
AceConfigCmd-3.0
|
|
|
|
Handles commandline optionstable access
|
|
|
|
REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
|
|
|
|
]]
|
|
|
|
-- TODO: plugin args
|
|
|
|
|
|
local MAJOR, MINOR = "AceConfigCmd-3.0", 12
|
|
local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
|
|
|
|
if not AceConfigCmd then return end
|
|
|
|
AceConfigCmd.commands = AceConfigCmd.commands or {}
|
|
local commands = AceConfigCmd.commands
|
|
|
|
local cfgreg = LibStub("AceConfigRegistry-3.0")
|
|
local AceConsole -- LoD
|
|
local AceConsoleName = "AceConsole-3.0"
|
|
|
|
-- Lua APIs
|
|
local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
|
|
local format, tonumber, tostring = string.format, tonumber, tostring
|
|
local tsort, tinsert = table.sort, table.insert
|
|
local select, pairs, next, type = select, pairs, next, type
|
|
local error, assert = error, assert
|
|
|
|
-- WoW APIs
|
|
local _G = _G
|
|
|
|
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
|
-- List them here for Mikk's FindGlobals script
|
|
-- GLOBALS: LibStub, SELECTED_CHAT_FRAME, DEFAULT_CHAT_FRAME
|
|
|
|
|
|
local L = setmetatable({}, { -- TODO: replace with proper locale
|
|
__index = function(self,k) return k end
|
|
})
|
|
|
|
|
|
|
|
local function print(msg)
|
|
(SELECTED_CHAT_FRAME or DEFAULT_CHAT_FRAME):AddMessage(msg)
|
|
end
|
|
|
|
-- constants used by getparam() calls below
|
|
|
|
local handlertypes = {["table"]=true}
|
|
local handlermsg = "expected a table"
|
|
|
|
local functypes = {["function"]=true, ["string"]=true}
|
|
local funcmsg = "expected function or member name"
|
|
|
|
|
|
-- pickfirstset() - picks the first non-nil value and returns it
|
|
|
|
local function pickfirstset(...)
|
|
for i=1,select("#",...) do
|
|
if select(i,...)~=nil then
|
|
return select(i,...)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- err() - produce real error() regarding malformed options tables etc
|
|
|
|
local function err(info,inputpos,msg )
|
|
local cmdstr=" "..strsub(info.input, 1, inputpos-1)
|
|
error(MAJOR..": /" ..info[0] ..cmdstr ..": "..(msg or "malformed options table"), 2)
|
|
end
|
|
|
|
|
|
-- usererr() - produce chatframe message regarding bad slash syntax etc
|
|
|
|
local function usererr(info,inputpos,msg )
|
|
local cmdstr=strsub(info.input, 1, inputpos-1);
|
|
print("/" ..info[0] .. " "..cmdstr ..": "..(msg or "malformed options table"))
|
|
end
|
|
|
|
|
|
-- callmethod() - call a given named method (e.g. "get", "set") with given arguments
|
|
|
|
local function callmethod(info, inputpos, tab, methodtype, ...)
|
|
local method = info[methodtype]
|
|
if not method then
|
|
err(info, inputpos, "'"..methodtype.."': not set")
|
|
end
|
|
|
|
info.arg = tab.arg
|
|
info.option = tab
|
|
info.type = tab.type
|
|
|
|
if type(method)=="function" then
|
|
return method(info, ...)
|
|
elseif type(method)=="string" then
|
|
if type(info.handler[method])~="function" then
|
|
err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
|
|
end
|
|
return info.handler[method](info.handler, info, ...)
|
|
else
|
|
assert(false) -- type should have already been checked on read
|
|
end
|
|
end
|
|
|
|
-- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
|
|
|
|
local function callfunction(info, tab, methodtype, ...)
|
|
local method = tab[methodtype]
|
|
|
|
info.arg = tab.arg
|
|
info.option = tab
|
|
info.type = tab.type
|
|
|
|
if type(method)=="function" then
|
|
return method(info, ...)
|
|
else
|
|
assert(false) -- type should have already been checked on read
|
|
end
|
|
end
|
|
|
|
-- do_final() - do the final step (set/execute) along with validation and confirmation
|
|
|
|
local function do_final(info, inputpos, tab, methodtype, ...)
|
|
if info.validate then
|
|
local res = callmethod(info,inputpos,tab,"validate",...)
|
|
if type(res)=="string" then
|
|
usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
|
|
return
|
|
end
|
|
end
|
|
-- console ignores .confirm
|
|
|
|
callmethod(info,inputpos,tab,methodtype, ...)
|
|
end
|
|
|
|
|
|
-- getparam() - used by handle() to retreive and store "handler", "get", "set", etc
|
|
|
|
local function getparam(info, inputpos, tab, depth, paramname, types, errormsg)
|
|
local old,oldat = info[paramname], info[paramname.."_at"]
|
|
local val=tab[paramname]
|
|
if val~=nil then
|
|
if val==false then
|
|
val=nil
|
|
elseif not types[type(val)] then
|
|
err(info, inputpos, "'" .. paramname.. "' - "..errormsg)
|
|
end
|
|
info[paramname] = val
|
|
info[paramname.."_at"] = depth
|
|
end
|
|
return old,oldat
|
|
end
|
|
|
|
|
|
-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
|
|
local dummytable={}
|
|
|
|
local function iterateargs(tab)
|
|
if not tab.plugins then
|
|
return pairs(tab.args)
|
|
end
|
|
|
|
local argtabkey,argtab=next(tab.plugins)
|
|
local v
|
|
|
|
return function(_, k)
|
|
while argtab do
|
|
k,v = next(argtab, k)
|
|
if k then return k,v end
|
|
if argtab==tab.args then
|
|
argtab=nil
|
|
else
|
|
argtabkey,argtab = next(tab.plugins, argtabkey)
|
|
if not argtabkey then
|
|
argtab=tab.args
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function checkhidden(info, inputpos, tab)
|
|
if tab.cmdHidden~=nil then
|
|
return tab.cmdHidden
|
|
end
|
|
local hidden = tab.hidden
|
|
if type(hidden) == "function" or type(hidden) == "string" then
|
|
info.hidden = hidden
|
|
hidden = callmethod(info, inputpos, tab, 'hidden')
|
|
info.hidden = nil
|
|
end
|
|
return hidden
|
|
end
|
|
|
|
local function showhelp(info, inputpos, tab, depth, noHead)
|
|
if not noHead then
|
|
print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
|
|
end
|
|
|
|
local sortTbl = {} -- [1..n]=name
|
|
local refTbl = {} -- [name]=tableref
|
|
|
|
for k,v in iterateargs(tab) do
|
|
if not refTbl[k] then -- a plugin overriding something in .args
|
|
tinsert(sortTbl, k)
|
|
refTbl[k] = v
|
|
end
|
|
end
|
|
|
|
tsort(sortTbl, function(one, two)
|
|
local o1 = refTbl[one].order or 100
|
|
local o2 = refTbl[two].order or 100
|
|
if type(o1) == "function" or type(o1) == "string" then
|
|
info.order = o1
|
|
info[#info+1] = one
|
|
o1 = callmethod(info, inputpos, refTbl[one], "order")
|
|
info[#info] = nil
|
|
info.order = nil
|
|
end
|
|
if type(o2) == "function" or type(o1) == "string" then
|
|
info.order = o2
|
|
info[#info+1] = two
|
|
o2 = callmethod(info, inputpos, refTbl[two], "order")
|
|
info[#info] = nil
|
|
info.order = nil
|
|
end
|
|
if o1<0 and o2<0 then return o1<o2 end
|
|
if o2<0 then return true end
|
|
if o1<0 then return false end
|
|
if o1==o2 then return tostring(one)<tostring(two) end -- compare names
|
|
return o1<o2
|
|
end)
|
|
|
|
for i = 1, #sortTbl do
|
|
local k = sortTbl[i]
|
|
local v = refTbl[k]
|
|
if not checkhidden(info, inputpos, v) then
|
|
if v.type ~= "description" and v.type ~= "header" then
|
|
-- recursively show all inline groups
|
|
local name, desc = v.name, v.desc
|
|
if type(name) == "function" then
|
|
name = callfunction(info, v, 'name')
|
|
end
|
|
if type(desc) == "function" then
|
|
desc = callfunction(info, v, 'desc')
|
|
end
|
|
if v.type == "group" and pickfirstset(v.cmdInline, v.inline, false) then
|
|
print(" "..(desc or name)..":")
|
|
local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
|
|
showhelp(info, inputpos, v, depth, true)
|
|
info.handler,info.handler_at = oldhandler,oldhandler_at
|
|
else
|
|
local key = k:gsub(" ", "_")
|
|
print(" |cffffff78"..key.."|r - "..(desc or name or ""))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function keybindingValidateFunc(text)
|
|
if text == nil or text == "NONE" then
|
|
return nil
|
|
end
|
|
text = text:upper()
|
|
local shift, ctrl, alt
|
|
local modifier
|
|
while true do
|
|
if text == "-" then
|
|
break
|
|
end
|
|
modifier, text = strsplit('-', text, 2)
|
|
if text then
|
|
if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
|
|
return false
|
|
end
|
|
if modifier == "SHIFT" then
|
|
if shift then
|
|
return false
|
|
end
|
|
shift = true
|
|
end
|
|
if modifier == "CTRL" then
|
|
if ctrl then
|
|
return false
|
|
end
|
|
ctrl = true
|
|
end
|
|
if modifier == "ALT" then
|
|
if alt then
|
|
return false
|
|
end
|
|
alt = true
|
|
end
|
|
else
|
|
text = modifier
|
|
break
|
|
end
|
|
end
|
|
if text == "" then
|
|
return false
|
|
end
|
|
if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then
|
|
return false
|
|
end
|
|
local s = text
|
|
if shift then
|
|
s = "SHIFT-" .. s
|
|
end
|
|
if ctrl then
|
|
s = "CTRL-" .. s
|
|
end
|
|
if alt then
|
|
s = "ALT-" .. s
|
|
end
|
|
return s
|
|
end
|
|
|
|
-- handle() - selfrecursing function that processes input->optiontable
|
|
-- - depth - starts at 0
|
|
-- - retfalse - return false rather than produce error if a match is not found (used by inlined groups)
|
|
|
|
local function handle(info, inputpos, tab, depth, retfalse)
|
|
|
|
if not(type(tab)=="table" and type(tab.type)=="string") then err(info,inputpos) end
|
|
|
|
-------------------------------------------------------------------
|
|
-- Grab hold of handler,set,get,func,etc if set (and remember old ones)
|
|
-- Note that we do NOT validate if method names are correct at this stage,
|
|
-- the handler may change before they're actually used!
|
|
|
|
local oldhandler,oldhandler_at = getparam(info,inputpos,tab,depth,"handler",handlertypes,handlermsg)
|
|
local oldset,oldset_at = getparam(info,inputpos,tab,depth,"set",functypes,funcmsg)
|
|
local oldget,oldget_at = getparam(info,inputpos,tab,depth,"get",functypes,funcmsg)
|
|
local oldfunc,oldfunc_at = getparam(info,inputpos,tab,depth,"func",functypes,funcmsg)
|
|
local oldvalidate,oldvalidate_at = getparam(info,inputpos,tab,depth,"validate",functypes,funcmsg)
|
|
--local oldconfirm,oldconfirm_at = getparam(info,inputpos,tab,depth,"confirm",functypes,funcmsg)
|
|
|
|
-------------------------------------------------------------------
|
|
-- Act according to .type of this table
|
|
|
|
if tab.type=="group" then
|
|
------------ group --------------------------------------------
|
|
|
|
if type(tab.args)~="table" then err(info, inputpos) end
|
|
if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
|
|
|
|
-- grab next arg from input
|
|
local _,nextpos,arg = (info.input):find(" *([^ ]+) *", inputpos)
|
|
if not arg then
|
|
showhelp(info, inputpos, tab, depth)
|
|
return
|
|
end
|
|
nextpos=nextpos+1
|
|
|
|
-- loop .args and try to find a key with a matching name
|
|
for k,v in iterateargs(tab) do
|
|
if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
|
|
|
|
-- is this child an inline group? if so, traverse into it
|
|
if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then
|
|
info[depth+1] = k
|
|
if handle(info, inputpos, v, depth+1, true)==false then
|
|
info[depth+1] = nil
|
|
-- wasn't found in there, but that's ok, we just keep looking down here
|
|
else
|
|
return -- done, name was found in inline group
|
|
end
|
|
-- matching name and not a inline group
|
|
elseif strlower(arg)==strlower(k:gsub(" ", "_")) then
|
|
info[depth+1] = k
|
|
return handle(info,nextpos,v,depth+1)
|
|
end
|
|
end
|
|
|
|
-- no match
|
|
if retfalse then
|
|
-- restore old infotable members and return false to indicate failure
|
|
info.handler,info.handler_at = oldhandler,oldhandler_at
|
|
info.set,info.set_at = oldset,oldset_at
|
|
info.get,info.get_at = oldget,oldget_at
|
|
info.func,info.func_at = oldfunc,oldfunc_at
|
|
info.validate,info.validate_at = oldvalidate,oldvalidate_at
|
|
--info.confirm,info.confirm_at = oldconfirm,oldconfirm_at
|
|
return false
|
|
end
|
|
|
|
-- couldn't find the command, display error
|
|
usererr(info, inputpos, "'"..arg.."' - " .. L["unknown argument"])
|
|
return
|
|
end
|
|
|
|
local str = strsub(info.input,inputpos);
|
|
|
|
if tab.type=="execute" then
|
|
------------ execute --------------------------------------------
|
|
do_final(info, inputpos, tab, "func")
|
|
|
|
|
|
|
|
elseif tab.type=="input" then
|
|
------------ input --------------------------------------------
|
|
|
|
local res = true
|
|
if tab.pattern then
|
|
if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
|
|
if not strmatch(str, tab.pattern) then
|
|
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
|
|
return
|
|
end
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", str)
|
|
|
|
|
|
|
|
elseif tab.type=="toggle" then
|
|
------------ toggle --------------------------------------------
|
|
local b
|
|
local str = strtrim(strlower(str))
|
|
if str=="" then
|
|
b = callmethod(info, inputpos, tab, "get")
|
|
|
|
if tab.tristate then
|
|
--cycle in true, nil, false order
|
|
if b then
|
|
b = nil
|
|
elseif b == nil then
|
|
b = false
|
|
else
|
|
b = true
|
|
end
|
|
else
|
|
b = not b
|
|
end
|
|
|
|
elseif str==L["on"] then
|
|
b = true
|
|
elseif str==L["off"] then
|
|
b = false
|
|
elseif tab.tristate and str==L["default"] then
|
|
b = nil
|
|
else
|
|
if tab.tristate then
|
|
usererr(info, inputpos, format(L["'%s' - expected 'on', 'off' or 'default', or no argument to toggle."], str))
|
|
else
|
|
usererr(info, inputpos, format(L["'%s' - expected 'on' or 'off', or no argument to toggle."], str))
|
|
end
|
|
return
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", b)
|
|
|
|
|
|
elseif tab.type=="range" then
|
|
------------ range --------------------------------------------
|
|
local val = tonumber(str)
|
|
if not val then
|
|
usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
|
|
return
|
|
end
|
|
if type(info.step)=="number" then
|
|
val = val- (val % info.step)
|
|
end
|
|
if type(info.min)=="number" and val<info.min then
|
|
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.min)) )
|
|
return
|
|
end
|
|
if type(info.max)=="number" and val>info.max then
|
|
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
|
|
return
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", val)
|
|
|
|
|
|
elseif tab.type=="select" then
|
|
------------ select ------------------------------------
|
|
local str = strtrim(strlower(str))
|
|
|
|
local values = tab.values
|
|
if type(values) == "function" or type(values) == "string" then
|
|
info.values = values
|
|
values = callmethod(info, inputpos, tab, "values")
|
|
info.values = nil
|
|
end
|
|
|
|
if str == "" then
|
|
local b = callmethod(info, inputpos, tab, "get")
|
|
local fmt = "|cffffff78- [%s]|r %s"
|
|
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
|
|
print(L["Options for |cffffff78"..info[#info].."|r:"])
|
|
for k, v in pairs(values) do
|
|
if b == k then
|
|
print(fmt_sel:format(k, v))
|
|
else
|
|
print(fmt:format(k, v))
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
local ok
|
|
for k,v in pairs(values) do
|
|
if strlower(k)==str then
|
|
str = k -- overwrite with key (in case of case mismatches)
|
|
ok = true
|
|
break
|
|
end
|
|
end
|
|
if not ok then
|
|
usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
|
|
return
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", str)
|
|
|
|
elseif tab.type=="multiselect" then
|
|
------------ multiselect -------------------------------------------
|
|
local str = strtrim(strlower(str))
|
|
|
|
local values = tab.values
|
|
if type(values) == "function" or type(values) == "string" then
|
|
info.values = values
|
|
values = callmethod(info, inputpos, tab, "values")
|
|
info.values = nil
|
|
end
|
|
|
|
if str == "" then
|
|
local fmt = "|cffffff78- [%s]|r %s"
|
|
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
|
|
print(L["Options for |cffffff78"..info[#info].."|r (multiple possible):"])
|
|
for k, v in pairs(values) do
|
|
if callmethod(info, inputpos, tab, "get", k) then
|
|
print(fmt_sel:format(k, v))
|
|
else
|
|
print(fmt:format(k, v))
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
--build a table of the selections, checking that they exist
|
|
--parse for =on =off =default in the process
|
|
--table will be key = true for options that should toggle, key = [on|off|default] for options to be set
|
|
local sels = {}
|
|
for v in str:gmatch("[^ ]+") do
|
|
--parse option=on etc
|
|
local opt, val = v:match('(.+)=(.+)')
|
|
--get option if toggling
|
|
if not opt then
|
|
opt = v
|
|
end
|
|
|
|
--check that the opt is valid
|
|
local ok
|
|
for k,v in pairs(values) do
|
|
if strlower(k)==opt then
|
|
opt = k -- overwrite with key (in case of case mismatches)
|
|
ok = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if not ok then
|
|
usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
|
|
return
|
|
end
|
|
|
|
--check that if val was supplied it is valid
|
|
if val then
|
|
if val == L["on"] or val == L["off"] or (tab.tristate and val == L["default"]) then
|
|
--val is valid insert it
|
|
sels[opt] = val
|
|
else
|
|
if tab.tristate then
|
|
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on', 'off' or 'default', or no argument to toggle."], v, val))
|
|
else
|
|
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
|
|
end
|
|
return
|
|
end
|
|
else
|
|
-- no val supplied, toggle
|
|
sels[opt] = true
|
|
end
|
|
end
|
|
|
|
for opt, val in pairs(sels) do
|
|
local newval
|
|
|
|
if (val == true) then
|
|
--toggle the option
|
|
local b = callmethod(info, inputpos, tab, "get", opt)
|
|
|
|
if tab.tristate then
|
|
--cycle in true, nil, false order
|
|
if b then
|
|
b = nil
|
|
elseif b == nil then
|
|
b = false
|
|
else
|
|
b = true
|
|
end
|
|
else
|
|
b = not b
|
|
end
|
|
newval = b
|
|
else
|
|
--set the option as specified
|
|
if val==L["on"] then
|
|
newval = true
|
|
elseif val==L["off"] then
|
|
newval = false
|
|
elseif val==L["default"] then
|
|
newval = nil
|
|
end
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", opt, newval)
|
|
end
|
|
|
|
|
|
elseif tab.type=="color" then
|
|
------------ color --------------------------------------------
|
|
local str = strtrim(strlower(str))
|
|
if str == "" then
|
|
--TODO: Show current value
|
|
return
|
|
end
|
|
|
|
local r, g, b, a
|
|
|
|
if tab.hasAlpha then
|
|
if str:len() == 8 and str:find("^%x*$") then
|
|
--parse a hex string
|
|
r,g,b,a = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255, tonumber(str:sub(7, 8), 16) / 255
|
|
else
|
|
--parse seperate values
|
|
r,g,b,a = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
|
|
r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
|
|
end
|
|
if not (r and g and b and a) then
|
|
usererr(info, inputpos, format(L["'%s' - expected 'RRGGBBAA' or 'r g b a'."], str))
|
|
return
|
|
end
|
|
|
|
if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 and a >= 0.0 and a <= 1.0 then
|
|
--values are valid
|
|
elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 and a >= 0 and a <= 255 then
|
|
--values are valid 0..255, convert to 0..1
|
|
r = r / 255
|
|
g = g / 255
|
|
b = b / 255
|
|
a = a / 255
|
|
else
|
|
--values are invalid
|
|
usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0..1 or 0..255."], str))
|
|
end
|
|
else
|
|
a = 1.0
|
|
if str:len() == 6 and str:find("^%x*$") then
|
|
--parse a hex string
|
|
r,g,b = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255
|
|
else
|
|
--parse seperate values
|
|
r,g,b = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
|
|
r,g,b = tonumber(r), tonumber(g), tonumber(b)
|
|
end
|
|
if not (r and g and b) then
|
|
usererr(info, inputpos, format(L["'%s' - expected 'RRGGBB' or 'r g b'."], str))
|
|
return
|
|
end
|
|
if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 then
|
|
--values are valid
|
|
elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 then
|
|
--values are valid 0..255, convert to 0..1
|
|
r = r / 255
|
|
g = g / 255
|
|
b = b / 255
|
|
else
|
|
--values are invalid
|
|
usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0-1 or 0-255."], str))
|
|
end
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", r,g,b,a)
|
|
|
|
elseif tab.type=="keybinding" then
|
|
------------ keybinding --------------------------------------------
|
|
local str = strtrim(strlower(str))
|
|
if str == "" then
|
|
--TODO: Show current value
|
|
return
|
|
end
|
|
local value = keybindingValidateFunc(str:upper())
|
|
if value == false then
|
|
usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str))
|
|
return
|
|
end
|
|
|
|
do_final(info, inputpos, tab, "set", value)
|
|
|
|
elseif tab.type=="description" then
|
|
------------ description --------------------
|
|
-- ignore description, GUI config only
|
|
else
|
|
err(info, inputpos, "unknown options table item type '"..tostring(tab.type).."'")
|
|
end
|
|
end
|
|
|
|
--- Handle the chat command.
|
|
-- This is usually called from a chat command handler to parse the command input as operations on an aceoptions table.\\
|
|
-- AceConfigCmd uses this function internally when a slash command is registered with `:CreateChatCommand`
|
|
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
|
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
|
-- @param input The commandline input (as given by the WoW handler, i.e. without the command itself)
|
|
-- @usage
|
|
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceConsole-3.0")
|
|
-- -- Use AceConsole-3.0 to register a Chat Command
|
|
-- MyAddon:RegisterChatCommand("mychat", "ChatCommand")
|
|
--
|
|
-- -- Show the GUI if no input is supplied, otherwise handle the chat input.
|
|
-- function MyAddon:ChatCommand(input)
|
|
-- -- Assuming "MyOptions" is the appName of a valid options table
|
|
-- if not input or input:trim() == "" then
|
|
-- LibStub("AceConfigDialog-3.0"):Open("MyOptions")
|
|
-- else
|
|
-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
|
|
-- end
|
|
-- end
|
|
function AceConfigCmd:HandleCommand(slashcmd, appName, input)
|
|
|
|
local optgetter = cfgreg:GetOptionsTable(appName)
|
|
if not optgetter then
|
|
error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'appName' - no options table "]]..tostring(appName)..[[" has been registered]], 2)
|
|
end
|
|
local options = assert( optgetter("cmd", MAJOR) )
|
|
|
|
local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
|
|
[0] = slashcmd,
|
|
appName = appName,
|
|
options = options,
|
|
input = input,
|
|
self = self,
|
|
handler = self,
|
|
uiType = "cmd",
|
|
uiName = MAJOR,
|
|
}
|
|
|
|
handle(info, 1, options, 0) -- (info, inputpos, table, depth)
|
|
end
|
|
|
|
--- Utility function to create a slash command handler.
|
|
-- Also registers tab completion with AceTab
|
|
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
|
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
|
function AceConfigCmd:CreateChatCommand(slashcmd, appName)
|
|
if not AceConsole then
|
|
AceConsole = LibStub(AceConsoleName)
|
|
end
|
|
if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
|
|
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
|
|
end,
|
|
true) then -- succesfully registered so lets get the command -> app table in
|
|
commands[slashcmd] = appName
|
|
end
|
|
end
|
|
|
|
--- Utility function that returns the options table that belongs to a slashcommand.
|
|
-- Designed to be used for the AceTab interface.
|
|
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
|
-- @return The options table associated with the slash command (or nil if the slash command was not registered)
|
|
function AceConfigCmd:GetChatCommandOptions(slashcmd)
|
|
return commands[slashcmd]
|
|
end
|