Mercurial > wow > icu
comparison Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua @ 0:98c6f55e6619
First commit
| author | Xiiph |
|---|---|
| date | Sat, 05 Feb 2011 16:45:02 +0100 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:98c6f55e6619 |
|---|---|
| 1 --- AceConfigRegistry-3.0 handles central registration of options tables in use by addons and modules.\\ | |
| 2 -- Options tables can be registered as raw tables, OR as function refs that return a table.\\ | |
| 3 -- Such functions receive three arguments: "uiType", "uiName", "appName". \\ | |
| 4 -- * Valid **uiTypes**: "cmd", "dropdown", "dialog". This is verified by the library at call time. \\ | |
| 5 -- * The **uiName** field is expected to contain the full name of the calling addon, including version, e.g. "FooBar-1.0". This is verified by the library at call time.\\ | |
| 6 -- * The **appName** field is the options table name as given at registration time \\ | |
| 7 -- | |
| 8 -- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName". | |
| 9 -- @class file | |
| 10 -- @name AceConfigRegistry-3.0 | |
| 11 -- @release $Id: AceConfigRegistry-3.0.lua 921 2010-05-09 15:49:14Z nevcairiel $ | |
| 12 local MAJOR, MINOR = "AceConfigRegistry-3.0", 12 | |
| 13 local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR) | |
| 14 | |
| 15 if not AceConfigRegistry then return end | |
| 16 | |
| 17 AceConfigRegistry.tables = AceConfigRegistry.tables or {} | |
| 18 | |
| 19 local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") | |
| 20 | |
| 21 if not AceConfigRegistry.callbacks then | |
| 22 AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry) | |
| 23 end | |
| 24 | |
| 25 -- Lua APIs | |
| 26 local tinsert, tconcat = table.insert, table.concat | |
| 27 local strfind, strmatch = string.find, string.match | |
| 28 local type, tostring, select, pairs = type, tostring, select, pairs | |
| 29 local error, assert = error, assert | |
| 30 | |
| 31 ----------------------------------------------------------------------- | |
| 32 -- Validating options table consistency: | |
| 33 | |
| 34 | |
| 35 AceConfigRegistry.validated = { | |
| 36 -- list of options table names ran through :ValidateOptionsTable automatically. | |
| 37 -- CLEARED ON PURPOSE, since newer versions may have newer validators | |
| 38 cmd = {}, | |
| 39 dropdown = {}, | |
| 40 dialog = {}, | |
| 41 } | |
| 42 | |
| 43 | |
| 44 | |
| 45 local function err(msg, errlvl, ...) | |
| 46 local t = {} | |
| 47 for i=select("#",...),1,-1 do | |
| 48 tinsert(t, (select(i, ...))) | |
| 49 end | |
| 50 error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2) | |
| 51 end | |
| 52 | |
| 53 | |
| 54 local isstring={["string"]=true, _="string"} | |
| 55 local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"} | |
| 56 local istable={["table"]=true, _="table"} | |
| 57 local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"} | |
| 58 local optstring={["nil"]=true,["string"]=true, _="string"} | |
| 59 local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"} | |
| 60 local optnumber={["nil"]=true,["number"]=true, _="number"} | |
| 61 local optmethod={["nil"]=true,["string"]=true,["function"]=true, _="methodname or funcref"} | |
| 62 local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"} | |
| 63 local optmethodnumber={["nil"]=true,["string"]=true,["function"]=true,["number"]=true, _="methodname, funcref or number"} | |
| 64 local optmethodtable={["nil"]=true,["string"]=true,["function"]=true,["table"]=true, _="methodname, funcref or table"} | |
| 65 local optmethodbool={["nil"]=true,["string"]=true,["function"]=true,["boolean"]=true, _="methodname, funcref or boolean"} | |
| 66 local opttable={["nil"]=true,["table"]=true, _="table"} | |
| 67 local optbool={["nil"]=true,["boolean"]=true, _="boolean"} | |
| 68 local optboolnumber={["nil"]=true,["boolean"]=true,["number"]=true, _="boolean or number"} | |
| 69 | |
| 70 local basekeys={ | |
| 71 type=isstring, | |
| 72 name=isstringfunc, | |
| 73 desc=optstringfunc, | |
| 74 descStyle=optstring, | |
| 75 order=optmethodnumber, | |
| 76 validate=optmethodfalse, | |
| 77 confirm=optmethodbool, | |
| 78 confirmText=optstring, | |
| 79 disabled=optmethodbool, | |
| 80 hidden=optmethodbool, | |
| 81 guiHidden=optmethodbool, | |
| 82 dialogHidden=optmethodbool, | |
| 83 dropdownHidden=optmethodbool, | |
| 84 cmdHidden=optmethodbool, | |
| 85 icon=optstringfunc, | |
| 86 iconCoords=optmethodtable, | |
| 87 handler=opttable, | |
| 88 get=optmethodfalse, | |
| 89 set=optmethodfalse, | |
| 90 func=optmethodfalse, | |
| 91 arg={["*"]=true}, | |
| 92 width=optstring, | |
| 93 } | |
| 94 | |
| 95 local typedkeys={ | |
| 96 header={}, | |
| 97 description={ | |
| 98 image=optstringfunc, | |
| 99 imageCoords=optmethodtable, | |
| 100 imageHeight=optnumber, | |
| 101 imageWidth=optnumber, | |
| 102 fontSize=optstringfunc, | |
| 103 }, | |
| 104 group={ | |
| 105 args=istable, | |
| 106 plugins=opttable, | |
| 107 inline=optbool, | |
| 108 cmdInline=optbool, | |
| 109 guiInline=optbool, | |
| 110 dropdownInline=optbool, | |
| 111 dialogInline=optbool, | |
| 112 childGroups=optstring, | |
| 113 }, | |
| 114 execute={ | |
| 115 image=optstringfunc, | |
| 116 imageCoords=optmethodtable, | |
| 117 imageHeight=optnumber, | |
| 118 imageWidth=optnumber, | |
| 119 }, | |
| 120 input={ | |
| 121 pattern=optstring, | |
| 122 usage=optstring, | |
| 123 control=optstring, | |
| 124 dialogControl=optstring, | |
| 125 dropdownControl=optstring, | |
| 126 multiline=optboolnumber, | |
| 127 }, | |
| 128 toggle={ | |
| 129 tristate=optbool, | |
| 130 image=optstringfunc, | |
| 131 imageCoords=optmethodtable, | |
| 132 }, | |
| 133 tristate={ | |
| 134 }, | |
| 135 range={ | |
| 136 min=optnumber, | |
| 137 softMin=optnumber, | |
| 138 max=optnumber, | |
| 139 softMax=optnumber, | |
| 140 step=optnumber, | |
| 141 bigStep=optnumber, | |
| 142 isPercent=optbool, | |
| 143 }, | |
| 144 select={ | |
| 145 values=ismethodtable, | |
| 146 style={ | |
| 147 ["nil"]=true, | |
| 148 ["string"]={dropdown=true,radio=true}, | |
| 149 _="string: 'dropdown' or 'radio'" | |
| 150 }, | |
| 151 control=optstring, | |
| 152 dialogControl=optstring, | |
| 153 dropdownControl=optstring, | |
| 154 }, | |
| 155 multiselect={ | |
| 156 values=ismethodtable, | |
| 157 style=optstring, | |
| 158 tristate=optbool, | |
| 159 control=optstring, | |
| 160 dialogControl=optstring, | |
| 161 dropdownControl=optstring, | |
| 162 }, | |
| 163 color={ | |
| 164 hasAlpha=optbool, | |
| 165 }, | |
| 166 keybinding={ | |
| 167 -- TODO | |
| 168 }, | |
| 169 } | |
| 170 | |
| 171 local function validateKey(k,errlvl,...) | |
| 172 errlvl=(errlvl or 0)+1 | |
| 173 if type(k)~="string" then | |
| 174 err("["..tostring(k).."] - key is not a string", errlvl,...) | |
| 175 end | |
| 176 if strfind(k, "[%c\127]") then | |
| 177 err("["..tostring(k).."] - key name contained control characters", errlvl,...) | |
| 178 end | |
| 179 end | |
| 180 | |
| 181 local function validateVal(v, oktypes, errlvl,...) | |
| 182 errlvl=(errlvl or 0)+1 | |
| 183 local isok=oktypes[type(v)] or oktypes["*"] | |
| 184 | |
| 185 if not isok then | |
| 186 err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,...) | |
| 187 end | |
| 188 if type(isok)=="table" then -- isok was a table containing specific values to be tested for! | |
| 189 if not isok[v] then | |
| 190 err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,...) | |
| 191 end | |
| 192 end | |
| 193 end | |
| 194 | |
| 195 local function validate(options,errlvl,...) | |
| 196 errlvl=(errlvl or 0)+1 | |
| 197 -- basic consistency | |
| 198 if type(options)~="table" then | |
| 199 err(": expected a table, got a "..type(options), errlvl,...) | |
| 200 end | |
| 201 if type(options.type)~="string" then | |
| 202 err(".type: expected a string, got a "..type(options.type), errlvl,...) | |
| 203 end | |
| 204 | |
| 205 -- get type and 'typedkeys' member | |
| 206 local tk = typedkeys[options.type] | |
| 207 if not tk then | |
| 208 err(".type: unknown type '"..options.type.."'", errlvl,...) | |
| 209 end | |
| 210 | |
| 211 -- make sure that all options[] are known parameters | |
| 212 for k,v in pairs(options) do | |
| 213 if not (tk[k] or basekeys[k]) then | |
| 214 err(": unknown parameter", errlvl,tostring(k),...) | |
| 215 end | |
| 216 end | |
| 217 | |
| 218 -- verify that required params are there, and that everything is the right type | |
| 219 for k,oktypes in pairs(basekeys) do | |
| 220 validateVal(options[k], oktypes, errlvl,k,...) | |
| 221 end | |
| 222 for k,oktypes in pairs(tk) do | |
| 223 validateVal(options[k], oktypes, errlvl,k,...) | |
| 224 end | |
| 225 | |
| 226 -- extra logic for groups | |
| 227 if options.type=="group" then | |
| 228 for k,v in pairs(options.args) do | |
| 229 validateKey(k,errlvl,"args",...) | |
| 230 validate(v, errlvl,k,"args",...) | |
| 231 end | |
| 232 if options.plugins then | |
| 233 for plugname,plugin in pairs(options.plugins) do | |
| 234 if type(plugin)~="table" then | |
| 235 err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",...) | |
| 236 end | |
| 237 for k,v in pairs(plugin) do | |
| 238 validateKey(k,errlvl,tostring(plugname),"plugins",...) | |
| 239 validate(v, errlvl,k,tostring(plugname),"plugins",...) | |
| 240 end | |
| 241 end | |
| 242 end | |
| 243 end | |
| 244 end | |
| 245 | |
| 246 | |
| 247 --- Validates basic structure and integrity of an options table \\ | |
| 248 -- Does NOT verify that get/set etc actually exist, since they can be defined at any depth | |
| 249 -- @param options The table to be validated | |
| 250 -- @param name The name of the table to be validated (shown in any error message) | |
| 251 -- @param errlvl (optional number) error level offset, default 0 (=errors point to the function calling :ValidateOptionsTable) | |
| 252 function AceConfigRegistry:ValidateOptionsTable(options,name,errlvl) | |
| 253 errlvl=(errlvl or 0)+1 | |
| 254 name = name or "Optionstable" | |
| 255 if not options.name then | |
| 256 options.name=name -- bit of a hack, the root level doesn't really need a .name :-/ | |
| 257 end | |
| 258 validate(options,errlvl,name) | |
| 259 end | |
| 260 | |
| 261 --- Fires a "ConfigTableChange" callback for those listening in on it, allowing config GUIs to refresh. | |
| 262 -- You should call this function if your options table changed from any outside event, like a game event | |
| 263 -- or a timer. | |
| 264 -- @param appName The application name as given to `:RegisterOptionsTable()` | |
| 265 function AceConfigRegistry:NotifyChange(appName) | |
| 266 if not AceConfigRegistry.tables[appName] then return end | |
| 267 AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName) | |
| 268 end | |
| 269 | |
| 270 -- ------------------------------------------------------------------- | |
| 271 -- Registering and retreiving options tables: | |
| 272 | |
| 273 | |
| 274 -- validateGetterArgs: helper function for :GetOptionsTable (or, rather, the getter functions returned by it) | |
| 275 | |
| 276 local function validateGetterArgs(uiType, uiName, errlvl) | |
| 277 errlvl=(errlvl or 0)+2 | |
| 278 if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then | |
| 279 error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl) | |
| 280 end | |
| 281 if not strmatch(uiName, "[A-Za-z]%-[0-9]") then -- Expecting e.g. "MyLib-1.2" | |
| 282 error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl) | |
| 283 end | |
| 284 end | |
| 285 | |
| 286 --- Register an options table with the config registry. | |
| 287 -- @param appName The application name as given to `:RegisterOptionsTable()` | |
| 288 -- @param options The options table, OR a function reference that generates it on demand. \\ | |
| 289 -- See the top of the page for info on arguments passed to such functions. | |
| 290 function AceConfigRegistry:RegisterOptionsTable(appName, options) | |
| 291 if type(options)=="table" then | |
| 292 if options.type~="group" then -- quick sanity checker | |
| 293 error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - missing type='group' member in root group", 2) | |
| 294 end | |
| 295 AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl) | |
| 296 errlvl=(errlvl or 0)+1 | |
| 297 validateGetterArgs(uiType, uiName, errlvl) | |
| 298 if not AceConfigRegistry.validated[uiType][appName] then | |
| 299 AceConfigRegistry:ValidateOptionsTable(options, appName, errlvl) -- upgradable | |
| 300 AceConfigRegistry.validated[uiType][appName] = true | |
| 301 end | |
| 302 return options | |
| 303 end | |
| 304 elseif type(options)=="function" then | |
| 305 AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl) | |
| 306 errlvl=(errlvl or 0)+1 | |
| 307 validateGetterArgs(uiType, uiName, errlvl) | |
| 308 local tab = assert(options(uiType, uiName, appName)) | |
| 309 if not AceConfigRegistry.validated[uiType][appName] then | |
| 310 AceConfigRegistry:ValidateOptionsTable(tab, appName, errlvl) -- upgradable | |
| 311 AceConfigRegistry.validated[uiType][appName] = true | |
| 312 end | |
| 313 return tab | |
| 314 end | |
| 315 else | |
| 316 error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - expected table or function reference", 2) | |
| 317 end | |
| 318 end | |
| 319 | |
| 320 --- Returns an iterator of ["appName"]=funcref pairs | |
| 321 function AceConfigRegistry:IterateOptionsTables() | |
| 322 return pairs(AceConfigRegistry.tables) | |
| 323 end | |
| 324 | |
| 325 | |
| 326 | |
| 327 | |
| 328 --- Query the registry for a specific options table. | |
| 329 -- If only appName is given, a function is returned which you | |
| 330 -- can call with (uiType,uiName) to get the table.\\ | |
| 331 -- If uiType&uiName are given, the table is returned. | |
| 332 -- @param appName The application name as given to `:RegisterOptionsTable()` | |
| 333 -- @param uiType The type of UI to get the table for, one of "cmd", "dropdown", "dialog" | |
| 334 -- @param uiName The name of the library/addon querying for the table, e.g. "MyLib-1.0" | |
| 335 function AceConfigRegistry:GetOptionsTable(appName, uiType, uiName) | |
| 336 local f = AceConfigRegistry.tables[appName] | |
| 337 if not f then | |
| 338 return nil | |
| 339 end | |
| 340 | |
| 341 if uiType then | |
| 342 return f(uiType,uiName,1) -- get the table for us | |
| 343 else | |
| 344 return f -- return the function | |
| 345 end | |
| 346 end |
