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 |