annotate Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua @ 0:169f5211fc7f

First public revision. At this point ItemAuditor watches mail for auctions sold or purchased, watches for buy/sell (money and 1 item type change) and conversions/tradeskills. Milling isn't working yet because there is too much time between the first event and the last event.
author Asa Ayers <Asa.Ayers@Gmail.com>
date Thu, 20 May 2010 19:22:19 -0700
parents
children
rev   line source
Asa@0 1 --- AceConfigDialog-3.0 generates AceGUI-3.0 based windows based on option tables.
Asa@0 2 -- @class file
Asa@0 3 -- @name AceConfigDialog-3.0
Asa@0 4 -- @release $Id: AceConfigDialog-3.0.lua 902 2009-12-12 14:56:14Z nevcairiel $
Asa@0 5
Asa@0 6 local LibStub = LibStub
Asa@0 7 local MAJOR, MINOR = "AceConfigDialog-3.0", 43
Asa@0 8 local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
Asa@0 9
Asa@0 10 if not AceConfigDialog then return end
Asa@0 11
Asa@0 12 AceConfigDialog.OpenFrames = AceConfigDialog.OpenFrames or {}
Asa@0 13 AceConfigDialog.Status = AceConfigDialog.Status or {}
Asa@0 14 AceConfigDialog.frame = AceConfigDialog.frame or CreateFrame("Frame")
Asa@0 15
Asa@0 16 AceConfigDialog.frame.apps = AceConfigDialog.frame.apps or {}
Asa@0 17 AceConfigDialog.frame.closing = AceConfigDialog.frame.closing or {}
Asa@0 18
Asa@0 19 local gui = LibStub("AceGUI-3.0")
Asa@0 20 local reg = LibStub("AceConfigRegistry-3.0")
Asa@0 21
Asa@0 22 -- Lua APIs
Asa@0 23 local tconcat, tinsert, tsort, tremove = table.concat, table.insert, table.sort, table.remove
Asa@0 24 local strmatch, format = string.match, string.format
Asa@0 25 local assert, loadstring, error = assert, loadstring, error
Asa@0 26 local pairs, next, select, type, unpack = pairs, next, select, type, unpack
Asa@0 27 local rawset, tostring = rawset, tostring
Asa@0 28 local math_min, math_max, math_floor = math.min, math.max, math.floor
Asa@0 29
Asa@0 30 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
Asa@0 31 -- List them here for Mikk's FindGlobals script
Asa@0 32 -- GLOBALS: NORMAL_FONT_COLOR, GameTooltip, StaticPopupDialogs, ACCEPT, CANCEL, StaticPopup_Show
Asa@0 33 -- GLOBALS: PlaySound, GameFontHighlight, GameFontHighlightSmall, GameFontHighlightLarge
Asa@0 34 -- GLOBALS: CloseSpecialWindows, InterfaceOptions_AddCategory, geterrorhandler
Asa@0 35
Asa@0 36 local emptyTbl = {}
Asa@0 37
Asa@0 38 --[[
Asa@0 39 xpcall safecall implementation
Asa@0 40 ]]
Asa@0 41 local xpcall = xpcall
Asa@0 42
Asa@0 43 local function errorhandler(err)
Asa@0 44 return geterrorhandler()(err)
Asa@0 45 end
Asa@0 46
Asa@0 47 local function CreateDispatcher(argCount)
Asa@0 48 local code = [[
Asa@0 49 local xpcall, eh = ...
Asa@0 50 local method, ARGS
Asa@0 51 local function call() return method(ARGS) end
Asa@0 52
Asa@0 53 local function dispatch(func, ...)
Asa@0 54 method = func
Asa@0 55 if not method then return end
Asa@0 56 ARGS = ...
Asa@0 57 return xpcall(call, eh)
Asa@0 58 end
Asa@0 59
Asa@0 60 return dispatch
Asa@0 61 ]]
Asa@0 62
Asa@0 63 local ARGS = {}
Asa@0 64 for i = 1, argCount do ARGS[i] = "arg"..i end
Asa@0 65 code = code:gsub("ARGS", tconcat(ARGS, ", "))
Asa@0 66 return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
Asa@0 67 end
Asa@0 68
Asa@0 69 local Dispatchers = setmetatable({}, {__index=function(self, argCount)
Asa@0 70 local dispatcher = CreateDispatcher(argCount)
Asa@0 71 rawset(self, argCount, dispatcher)
Asa@0 72 return dispatcher
Asa@0 73 end})
Asa@0 74 Dispatchers[0] = function(func)
Asa@0 75 return xpcall(func, errorhandler)
Asa@0 76 end
Asa@0 77
Asa@0 78 local function safecall(func, ...)
Asa@0 79 return Dispatchers[select('#', ...)](func, ...)
Asa@0 80 end
Asa@0 81
Asa@0 82 local width_multiplier = 170
Asa@0 83
Asa@0 84 --[[
Asa@0 85 Group Types
Asa@0 86 Tree - All Descendant Groups will all become nodes on the tree, direct child options will appear above the tree
Asa@0 87 - Descendant Groups with inline=true and thier children will not become nodes
Asa@0 88
Asa@0 89 Tab - Direct Child Groups will become tabs, direct child options will appear above the tab control
Asa@0 90 - Grandchild groups will default to inline unless specified otherwise
Asa@0 91
Asa@0 92 Select- Same as Tab but with entries in a dropdown rather than tabs
Asa@0 93
Asa@0 94
Asa@0 95 Inline Groups
Asa@0 96 - Will not become nodes of a select group, they will be effectivly part of thier parent group seperated by a border
Asa@0 97 - If declared on a direct child of a root node of a select group, they will appear above the group container control
Asa@0 98 - When a group is displayed inline, all descendants will also be inline members of the group
Asa@0 99
Asa@0 100 ]]
Asa@0 101
Asa@0 102 -- Recycling functions
Asa@0 103 local new, del, copy
Asa@0 104 --newcount, delcount,createdcount,cached = 0,0,0
Asa@0 105 do
Asa@0 106 local pool = setmetatable({},{__mode='k'})
Asa@0 107 function new()
Asa@0 108 --newcount = newcount + 1
Asa@0 109 local t = next(pool)
Asa@0 110 if t then
Asa@0 111 pool[t] = nil
Asa@0 112 return t
Asa@0 113 else
Asa@0 114 --createdcount = createdcount + 1
Asa@0 115 return {}
Asa@0 116 end
Asa@0 117 end
Asa@0 118 function copy(t)
Asa@0 119 local c = new()
Asa@0 120 for k, v in pairs(t) do
Asa@0 121 c[k] = v
Asa@0 122 end
Asa@0 123 return c
Asa@0 124 end
Asa@0 125 function del(t)
Asa@0 126 --delcount = delcount + 1
Asa@0 127 for k in pairs(t) do
Asa@0 128 t[k] = nil
Asa@0 129 end
Asa@0 130 pool[t] = true
Asa@0 131 end
Asa@0 132 -- function cached()
Asa@0 133 -- local n = 0
Asa@0 134 -- for k in pairs(pool) do
Asa@0 135 -- n = n + 1
Asa@0 136 -- end
Asa@0 137 -- return n
Asa@0 138 -- end
Asa@0 139 end
Asa@0 140
Asa@0 141 -- picks the first non-nil value and returns it
Asa@0 142 local function pickfirstset(...)
Asa@0 143 for i=1,select("#",...) do
Asa@0 144 if select(i,...)~=nil then
Asa@0 145 return select(i,...)
Asa@0 146 end
Asa@0 147 end
Asa@0 148 end
Asa@0 149
Asa@0 150 --gets an option from a given group, checking plugins
Asa@0 151 local function GetSubOption(group, key)
Asa@0 152 if group.plugins then
Asa@0 153 for plugin, t in pairs(group.plugins) do
Asa@0 154 if t[key] then
Asa@0 155 return t[key]
Asa@0 156 end
Asa@0 157 end
Asa@0 158 end
Asa@0 159
Asa@0 160 return group.args[key]
Asa@0 161 end
Asa@0 162
Asa@0 163 --Option member type definitions, used to decide how to access it
Asa@0 164
Asa@0 165 --Is the member Inherited from parent options
Asa@0 166 local isInherited = {
Asa@0 167 set = true,
Asa@0 168 get = true,
Asa@0 169 func = true,
Asa@0 170 confirm = true,
Asa@0 171 validate = true,
Asa@0 172 disabled = true,
Asa@0 173 hidden = true
Asa@0 174 }
Asa@0 175
Asa@0 176 --Does a string type mean a literal value, instead of the default of a method of the handler
Asa@0 177 local stringIsLiteral = {
Asa@0 178 name = true,
Asa@0 179 desc = true,
Asa@0 180 icon = true,
Asa@0 181 usage = true,
Asa@0 182 width = true,
Asa@0 183 image = true,
Asa@0 184 fontSize = true,
Asa@0 185 }
Asa@0 186
Asa@0 187 --Is Never a function or method
Asa@0 188 local allIsLiteral = {
Asa@0 189 type = true,
Asa@0 190 descStyle = true,
Asa@0 191 imageWidth = true,
Asa@0 192 imageHeight = true,
Asa@0 193 }
Asa@0 194
Asa@0 195 --gets the value for a member that could be a function
Asa@0 196 --function refs are called with an info arg
Asa@0 197 --every other type is returned
Asa@0 198 local function GetOptionsMemberValue(membername, option, options, path, appName, ...)
Asa@0 199 --get definition for the member
Asa@0 200 local inherits = isInherited[membername]
Asa@0 201
Asa@0 202
Asa@0 203 --get the member of the option, traversing the tree if it can be inherited
Asa@0 204 local member
Asa@0 205
Asa@0 206 if inherits then
Asa@0 207 local group = options
Asa@0 208 if group[membername] ~= nil then
Asa@0 209 member = group[membername]
Asa@0 210 end
Asa@0 211 for i = 1, #path do
Asa@0 212 group = GetSubOption(group, path[i])
Asa@0 213 if group[membername] ~= nil then
Asa@0 214 member = group[membername]
Asa@0 215 end
Asa@0 216 end
Asa@0 217 else
Asa@0 218 member = option[membername]
Asa@0 219 end
Asa@0 220
Asa@0 221 --check if we need to call a functon, or if we have a literal value
Asa@0 222 if ( not allIsLiteral[membername] ) and ( type(member) == "function" or ((not stringIsLiteral[membername]) and type(member) == "string") ) then
Asa@0 223 --We have a function to call
Asa@0 224 local info = new()
Asa@0 225 --traverse the options table, picking up the handler and filling the info with the path
Asa@0 226 local handler
Asa@0 227 local group = options
Asa@0 228 handler = group.handler or handler
Asa@0 229
Asa@0 230 for i = 1, #path do
Asa@0 231 group = GetSubOption(group, path[i])
Asa@0 232 info[i] = path[i]
Asa@0 233 handler = group.handler or handler
Asa@0 234 end
Asa@0 235
Asa@0 236 info.options = options
Asa@0 237 info.appName = appName
Asa@0 238 info[0] = appName
Asa@0 239 info.arg = option.arg
Asa@0 240 info.handler = handler
Asa@0 241 info.option = option
Asa@0 242 info.type = option.type
Asa@0 243 info.uiType = 'dialog'
Asa@0 244 info.uiName = MAJOR
Asa@0 245
Asa@0 246 local a, b, c ,d
Asa@0 247 --using 4 returns for the get of a color type, increase if a type needs more
Asa@0 248 if type(member) == "function" then
Asa@0 249 --Call the function
Asa@0 250 a,b,c,d = member(info, ...)
Asa@0 251 else
Asa@0 252 --Call the method
Asa@0 253 if handler and handler[member] then
Asa@0 254 a,b,c,d = handler[member](handler, info, ...)
Asa@0 255 else
Asa@0 256 error(format("Method %s doesn't exist in handler for type %s", member, membername))
Asa@0 257 end
Asa@0 258 end
Asa@0 259 del(info)
Asa@0 260 return a,b,c,d
Asa@0 261 else
Asa@0 262 --The value isnt a function to call, return it
Asa@0 263 return member
Asa@0 264 end
Asa@0 265 end
Asa@0 266
Asa@0 267 --[[calls an options function that could be inherited, method name or function ref
Asa@0 268 local function CallOptionsFunction(funcname ,option, options, path, appName, ...)
Asa@0 269 local info = new()
Asa@0 270
Asa@0 271 local func
Asa@0 272 local group = options
Asa@0 273 local handler
Asa@0 274
Asa@0 275 --build the info table containing the path
Asa@0 276 -- pick up functions while traversing the tree
Asa@0 277 if group[funcname] ~= nil then
Asa@0 278 func = group[funcname]
Asa@0 279 end
Asa@0 280 handler = group.handler or handler
Asa@0 281
Asa@0 282 for i, v in ipairs(path) do
Asa@0 283 group = GetSubOption(group, v)
Asa@0 284 info[i] = v
Asa@0 285 if group[funcname] ~= nil then
Asa@0 286 func = group[funcname]
Asa@0 287 end
Asa@0 288 handler = group.handler or handler
Asa@0 289 end
Asa@0 290
Asa@0 291 info.options = options
Asa@0 292 info[0] = appName
Asa@0 293 info.arg = option.arg
Asa@0 294
Asa@0 295 local a, b, c ,d
Asa@0 296 if type(func) == "string" then
Asa@0 297 if handler and handler[func] then
Asa@0 298 a,b,c,d = handler[func](handler, info, ...)
Asa@0 299 else
Asa@0 300 error(string.format("Method %s doesn't exist in handler for type func", func))
Asa@0 301 end
Asa@0 302 elseif type(func) == "function" then
Asa@0 303 a,b,c,d = func(info, ...)
Asa@0 304 end
Asa@0 305 del(info)
Asa@0 306 return a,b,c,d
Asa@0 307 end
Asa@0 308 --]]
Asa@0 309
Asa@0 310 --tables to hold orders and names for options being sorted, will be created with new()
Asa@0 311 --prevents needing to call functions repeatedly while sorting
Asa@0 312 local tempOrders
Asa@0 313 local tempNames
Asa@0 314
Asa@0 315 local function compareOptions(a,b)
Asa@0 316 if not a then
Asa@0 317 return true
Asa@0 318 end
Asa@0 319 if not b then
Asa@0 320 return false
Asa@0 321 end
Asa@0 322 local OrderA, OrderB = tempOrders[a] or 100, tempOrders[b] or 100
Asa@0 323 if OrderA == OrderB then
Asa@0 324 local NameA = (type(tempNames[a] == "string") and tempNames[a]) or ""
Asa@0 325 local NameB = (type(tempNames[b] == "string") and tempNames[b]) or ""
Asa@0 326 return NameA:upper() < NameB:upper()
Asa@0 327 end
Asa@0 328 if OrderA < 0 then
Asa@0 329 if OrderB > 0 then
Asa@0 330 return false
Asa@0 331 end
Asa@0 332 else
Asa@0 333 if OrderB < 0 then
Asa@0 334 return true
Asa@0 335 end
Asa@0 336 end
Asa@0 337 return OrderA < OrderB
Asa@0 338 end
Asa@0 339
Asa@0 340
Asa@0 341
Asa@0 342 --builds 2 tables out of an options group
Asa@0 343 -- keySort, sorted keys
Asa@0 344 -- opts, combined options from .plugins and args
Asa@0 345 local function BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 346 tempOrders = new()
Asa@0 347 tempNames = new()
Asa@0 348
Asa@0 349 if group.plugins then
Asa@0 350 for plugin, t in pairs(group.plugins) do
Asa@0 351 for k, v in pairs(t) do
Asa@0 352 if not opts[k] then
Asa@0 353 tinsert(keySort, k)
Asa@0 354 opts[k] = v
Asa@0 355
Asa@0 356 path[#path+1] = k
Asa@0 357 tempOrders[k] = GetOptionsMemberValue("order", v, options, path, appName)
Asa@0 358 tempNames[k] = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 359 path[#path] = nil
Asa@0 360 end
Asa@0 361 end
Asa@0 362 end
Asa@0 363 end
Asa@0 364
Asa@0 365 for k, v in pairs(group.args) do
Asa@0 366 if not opts[k] then
Asa@0 367 tinsert(keySort, k)
Asa@0 368 opts[k] = v
Asa@0 369
Asa@0 370 path[#path+1] = k
Asa@0 371 tempOrders[k] = GetOptionsMemberValue("order", v, options, path, appName)
Asa@0 372 tempNames[k] = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 373 path[#path] = nil
Asa@0 374 end
Asa@0 375 end
Asa@0 376
Asa@0 377 tsort(keySort, compareOptions)
Asa@0 378
Asa@0 379 del(tempOrders)
Asa@0 380 del(tempNames)
Asa@0 381 end
Asa@0 382
Asa@0 383 local function DelTree(tree)
Asa@0 384 if tree.children then
Asa@0 385 local childs = tree.children
Asa@0 386 for i = 1, #childs do
Asa@0 387 DelTree(childs[i])
Asa@0 388 del(childs[i])
Asa@0 389 end
Asa@0 390 del(childs)
Asa@0 391 end
Asa@0 392 end
Asa@0 393
Asa@0 394 local function CleanUserData(widget, event)
Asa@0 395
Asa@0 396 local user = widget:GetUserDataTable()
Asa@0 397
Asa@0 398 if user.path then
Asa@0 399 del(user.path)
Asa@0 400 end
Asa@0 401
Asa@0 402 if widget.type == "TreeGroup" then
Asa@0 403 local tree = user.tree
Asa@0 404 widget:SetTree(nil)
Asa@0 405 if tree then
Asa@0 406 for i = 1, #tree do
Asa@0 407 DelTree(tree[i])
Asa@0 408 del(tree[i])
Asa@0 409 end
Asa@0 410 del(tree)
Asa@0 411 end
Asa@0 412 end
Asa@0 413
Asa@0 414 if widget.type == "TabGroup" then
Asa@0 415 widget:SetTabs(nil)
Asa@0 416 if user.tablist then
Asa@0 417 del(user.tablist)
Asa@0 418 end
Asa@0 419 end
Asa@0 420
Asa@0 421 if widget.type == "DropdownGroup" then
Asa@0 422 widget:SetGroupList(nil)
Asa@0 423 if user.grouplist then
Asa@0 424 del(user.grouplist)
Asa@0 425 end
Asa@0 426 end
Asa@0 427 end
Asa@0 428
Asa@0 429 -- - Gets a status table for the given appname and options path.
Asa@0 430 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 431 -- @param path The path to the options (a table with all group keys)
Asa@0 432 -- @return
Asa@0 433 function AceConfigDialog:GetStatusTable(appName, path)
Asa@0 434 local status = self.Status
Asa@0 435
Asa@0 436 if not status[appName] then
Asa@0 437 status[appName] = {}
Asa@0 438 status[appName].status = {}
Asa@0 439 status[appName].children = {}
Asa@0 440 end
Asa@0 441
Asa@0 442 status = status[appName]
Asa@0 443
Asa@0 444 if path then
Asa@0 445 for i = 1, #path do
Asa@0 446 local v = path[i]
Asa@0 447 if not status.children[v] then
Asa@0 448 status.children[v] = {}
Asa@0 449 status.children[v].status = {}
Asa@0 450 status.children[v].children = {}
Asa@0 451 end
Asa@0 452 status = status.children[v]
Asa@0 453 end
Asa@0 454 end
Asa@0 455
Asa@0 456 return status.status
Asa@0 457 end
Asa@0 458
Asa@0 459 --- Selects the specified path in the options window.
Asa@0 460 -- The path specified has to match the keys of the groups in the table.
Asa@0 461 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 462 -- @param ... The path to the key that should be selected
Asa@0 463 function AceConfigDialog:SelectGroup(appName, ...)
Asa@0 464 local path = new()
Asa@0 465
Asa@0 466
Asa@0 467 local app = reg:GetOptionsTable(appName)
Asa@0 468 if not app then
Asa@0 469 error(("%s isn't registed with AceConfigRegistry, unable to open config"):format(appName), 2)
Asa@0 470 end
Asa@0 471 local options = app("dialog", MAJOR)
Asa@0 472 local group = options
Asa@0 473 local status = self:GetStatusTable(appName, path)
Asa@0 474 if not status.groups then
Asa@0 475 status.groups = {}
Asa@0 476 end
Asa@0 477 status = status.groups
Asa@0 478 local treevalue
Asa@0 479 local treestatus
Asa@0 480
Asa@0 481 for n = 1, select('#',...) do
Asa@0 482 local key = select(n, ...)
Asa@0 483
Asa@0 484 if group.childGroups == "tab" or group.childGroups == "select" then
Asa@0 485 --if this is a tab or select group, select the group
Asa@0 486 status.selected = key
Asa@0 487 --children of this group are no longer extra levels of a tree
Asa@0 488 treevalue = nil
Asa@0 489 else
Asa@0 490 --tree group by default
Asa@0 491 if treevalue then
Asa@0 492 --this is an extra level of a tree group, build a uniquevalue for it
Asa@0 493 treevalue = treevalue.."\001"..key
Asa@0 494 else
Asa@0 495 --this is the top level of a tree group, the uniquevalue is the same as the key
Asa@0 496 treevalue = key
Asa@0 497 if not status.groups then
Asa@0 498 status.groups = {}
Asa@0 499 end
Asa@0 500 --save this trees status table for any extra levels or groups
Asa@0 501 treestatus = status
Asa@0 502 end
Asa@0 503 --make sure that the tree entry is open, and select it.
Asa@0 504 --the selected group will be overwritten if a child is the final target but still needs to be open
Asa@0 505 treestatus.selected = treevalue
Asa@0 506 treestatus.groups[treevalue] = true
Asa@0 507
Asa@0 508 end
Asa@0 509
Asa@0 510 --move to the next group in the path
Asa@0 511 group = GetSubOption(group, key)
Asa@0 512 if not group then
Asa@0 513 break
Asa@0 514 end
Asa@0 515 tinsert(path, key)
Asa@0 516 status = self:GetStatusTable(appName, path)
Asa@0 517 if not status.groups then
Asa@0 518 status.groups = {}
Asa@0 519 end
Asa@0 520 status = status.groups
Asa@0 521 end
Asa@0 522
Asa@0 523 del(path)
Asa@0 524 reg:NotifyChange(appName)
Asa@0 525 end
Asa@0 526
Asa@0 527 local function OptionOnMouseOver(widget, event)
Asa@0 528 --show a tooltip/set the status bar to the desc text
Asa@0 529 local user = widget:GetUserDataTable()
Asa@0 530 local opt = user.option
Asa@0 531 local options = user.options
Asa@0 532 local path = user.path
Asa@0 533 local appName = user.appName
Asa@0 534
Asa@0 535 GameTooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
Asa@0 536 local name = GetOptionsMemberValue("name", opt, options, path, appName)
Asa@0 537 local desc = GetOptionsMemberValue("desc", opt, options, path, appName)
Asa@0 538 local usage = GetOptionsMemberValue("usage", opt, options, path, appName)
Asa@0 539 local descStyle = opt.descStyle
Asa@0 540
Asa@0 541 if descStyle and descStyle ~= "tooltip" then return end
Asa@0 542
Asa@0 543 GameTooltip:SetText(name, 1, .82, 0, 1)
Asa@0 544
Asa@0 545 if opt.type == 'multiselect' then
Asa@0 546 GameTooltip:AddLine(user.text,0.5, 0.5, 0.8, 1)
Asa@0 547 end
Asa@0 548 if type(desc) == "string" then
Asa@0 549 GameTooltip:AddLine(desc, 1, 1, 1, 1)
Asa@0 550 end
Asa@0 551 if type(usage) == "string" then
Asa@0 552 GameTooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
Asa@0 553 end
Asa@0 554
Asa@0 555 GameTooltip:Show()
Asa@0 556 end
Asa@0 557
Asa@0 558 local function OptionOnMouseLeave(widget, event)
Asa@0 559 GameTooltip:Hide()
Asa@0 560 end
Asa@0 561
Asa@0 562 local function GetFuncName(option)
Asa@0 563 local type = option.type
Asa@0 564 if type == 'execute' then
Asa@0 565 return 'func'
Asa@0 566 else
Asa@0 567 return 'set'
Asa@0 568 end
Asa@0 569 end
Asa@0 570 local function confirmPopup(appName, rootframe, basepath, info, message, func, ...)
Asa@0 571 if not StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] then
Asa@0 572 StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] = {}
Asa@0 573 end
Asa@0 574 local t = StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"]
Asa@0 575 for k in pairs(t) do
Asa@0 576 t[k] = nil
Asa@0 577 end
Asa@0 578 t.text = message
Asa@0 579 t.button1 = ACCEPT
Asa@0 580 t.button2 = CANCEL
Asa@0 581 local dialog, oldstrata
Asa@0 582 t.OnAccept = function()
Asa@0 583 safecall(func, unpack(t))
Asa@0 584 if dialog and oldstrata then
Asa@0 585 dialog:SetFrameStrata(oldstrata)
Asa@0 586 end
Asa@0 587 AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
Asa@0 588 del(info)
Asa@0 589 end
Asa@0 590 t.OnCancel = function()
Asa@0 591 if dialog and oldstrata then
Asa@0 592 dialog:SetFrameStrata(oldstrata)
Asa@0 593 end
Asa@0 594 AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
Asa@0 595 del(info)
Asa@0 596 end
Asa@0 597 for i = 1, select('#', ...) do
Asa@0 598 t[i] = select(i, ...) or false
Asa@0 599 end
Asa@0 600 t.timeout = 0
Asa@0 601 t.whileDead = 1
Asa@0 602 t.hideOnEscape = 1
Asa@0 603
Asa@0 604 dialog = StaticPopup_Show("ACECONFIGDIALOG30_CONFIRM_DIALOG")
Asa@0 605 if dialog then
Asa@0 606 oldstrata = dialog:GetFrameStrata()
Asa@0 607 dialog:SetFrameStrata("TOOLTIP")
Asa@0 608 end
Asa@0 609 end
Asa@0 610
Asa@0 611 local function ActivateControl(widget, event, ...)
Asa@0 612 --This function will call the set / execute handler for the widget
Asa@0 613 --widget:GetUserDataTable() contains the needed info
Asa@0 614 local user = widget:GetUserDataTable()
Asa@0 615 local option = user.option
Asa@0 616 local options = user.options
Asa@0 617 local path = user.path
Asa@0 618 local info = new()
Asa@0 619
Asa@0 620 local func
Asa@0 621 local group = options
Asa@0 622 local funcname = GetFuncName(option)
Asa@0 623 local handler
Asa@0 624 local confirm
Asa@0 625 local validate
Asa@0 626 --build the info table containing the path
Asa@0 627 -- pick up functions while traversing the tree
Asa@0 628 if group[funcname] ~= nil then
Asa@0 629 func = group[funcname]
Asa@0 630 end
Asa@0 631 handler = group.handler or handler
Asa@0 632 confirm = group.confirm
Asa@0 633 validate = group.validate
Asa@0 634 for i = 1, #path do
Asa@0 635 local v = path[i]
Asa@0 636 group = GetSubOption(group, v)
Asa@0 637 info[i] = v
Asa@0 638 if group[funcname] ~= nil then
Asa@0 639 func = group[funcname]
Asa@0 640 end
Asa@0 641 handler = group.handler or handler
Asa@0 642 if group.confirm ~= nil then
Asa@0 643 confirm = group.confirm
Asa@0 644 end
Asa@0 645 if group.validate ~= nil then
Asa@0 646 validate = group.validate
Asa@0 647 end
Asa@0 648 end
Asa@0 649
Asa@0 650 info.options = options
Asa@0 651 info.appName = user.appName
Asa@0 652 info.arg = option.arg
Asa@0 653 info.handler = handler
Asa@0 654 info.option = option
Asa@0 655 info.type = option.type
Asa@0 656 info.uiType = 'dialog'
Asa@0 657 info.uiName = MAJOR
Asa@0 658
Asa@0 659 local name
Asa@0 660 if type(option.name) == "function" then
Asa@0 661 name = option.name(info)
Asa@0 662 elseif type(option.name) == "string" then
Asa@0 663 name = option.name
Asa@0 664 else
Asa@0 665 name = ""
Asa@0 666 end
Asa@0 667 local usage = option.usage
Asa@0 668 local pattern = option.pattern
Asa@0 669
Asa@0 670 local validated = true
Asa@0 671
Asa@0 672 if option.type == "input" then
Asa@0 673 if type(pattern)=="string" then
Asa@0 674 if not strmatch(..., pattern) then
Asa@0 675 validated = false
Asa@0 676 end
Asa@0 677 end
Asa@0 678 end
Asa@0 679
Asa@0 680 local success
Asa@0 681 if validated and option.type ~= "execute" then
Asa@0 682 if type(validate) == "string" then
Asa@0 683 if handler and handler[validate] then
Asa@0 684 success, validated = safecall(handler[validate], handler, info, ...)
Asa@0 685 if not success then validated = false end
Asa@0 686 else
Asa@0 687 error(format("Method %s doesn't exist in handler for type execute", validate))
Asa@0 688 end
Asa@0 689 elseif type(validate) == "function" then
Asa@0 690 success, validated = safecall(validate, info, ...)
Asa@0 691 if not success then validated = false end
Asa@0 692 end
Asa@0 693 end
Asa@0 694
Asa@0 695 local rootframe = user.rootframe
Asa@0 696 if type(validated) == "string" then
Asa@0 697 --validate function returned a message to display
Asa@0 698 if rootframe.SetStatusText then
Asa@0 699 rootframe:SetStatusText(validated)
Asa@0 700 else
Asa@0 701 -- TODO: do something else.
Asa@0 702 end
Asa@0 703 PlaySound("igPlayerInviteDecline")
Asa@0 704 del(info)
Asa@0 705 return true
Asa@0 706 elseif not validated then
Asa@0 707 --validate returned false
Asa@0 708 if rootframe.SetStatusText then
Asa@0 709 if usage then
Asa@0 710 rootframe:SetStatusText(name..": "..usage)
Asa@0 711 else
Asa@0 712 if pattern then
Asa@0 713 rootframe:SetStatusText(name..": Expected "..pattern)
Asa@0 714 else
Asa@0 715 rootframe:SetStatusText(name..": Invalid Value")
Asa@0 716 end
Asa@0 717 end
Asa@0 718 else
Asa@0 719 -- TODO: do something else
Asa@0 720 end
Asa@0 721 PlaySound("igPlayerInviteDecline")
Asa@0 722 del(info)
Asa@0 723 return true
Asa@0 724 else
Asa@0 725
Asa@0 726 local confirmText = option.confirmText
Asa@0 727 --call confirm func/method
Asa@0 728 if type(confirm) == "string" then
Asa@0 729 if handler and handler[confirm] then
Asa@0 730 success, confirm = safecall(handler[confirm], handler, info, ...)
Asa@0 731 if success and type(confirm) == "string" then
Asa@0 732 confirmText = confirm
Asa@0 733 confirm = true
Asa@0 734 elseif not success then
Asa@0 735 confirm = false
Asa@0 736 end
Asa@0 737 else
Asa@0 738 error(format("Method %s doesn't exist in handler for type confirm", confirm))
Asa@0 739 end
Asa@0 740 elseif type(confirm) == "function" then
Asa@0 741 success, confirm = safecall(confirm, info, ...)
Asa@0 742 if success and type(confirm) == "string" then
Asa@0 743 confirmText = confirm
Asa@0 744 confirm = true
Asa@0 745 elseif not success then
Asa@0 746 confirm = false
Asa@0 747 end
Asa@0 748 end
Asa@0 749
Asa@0 750 --confirm if needed
Asa@0 751 if type(confirm) == "boolean" then
Asa@0 752 if confirm then
Asa@0 753 if not confirmText then
Asa@0 754 local name, desc = option.name, option.desc
Asa@0 755 if type(name) == "function" then
Asa@0 756 name = name(info)
Asa@0 757 end
Asa@0 758 if type(desc) == "function" then
Asa@0 759 desc = desc(info)
Asa@0 760 end
Asa@0 761 confirmText = name
Asa@0 762 if desc then
Asa@0 763 confirmText = confirmText.." - "..desc
Asa@0 764 end
Asa@0 765 end
Asa@0 766
Asa@0 767 local iscustom = user.rootframe:GetUserData('iscustom')
Asa@0 768 local rootframe
Asa@0 769
Asa@0 770 if iscustom then
Asa@0 771 rootframe = user.rootframe
Asa@0 772 end
Asa@0 773 local basepath = user.rootframe:GetUserData('basepath')
Asa@0 774 if type(func) == "string" then
Asa@0 775 if handler and handler[func] then
Asa@0 776 confirmPopup(user.appName, rootframe, basepath, info, confirmText, handler[func], handler, info, ...)
Asa@0 777 else
Asa@0 778 error(format("Method %s doesn't exist in handler for type func", func))
Asa@0 779 end
Asa@0 780 elseif type(func) == "function" then
Asa@0 781 confirmPopup(user.appName, rootframe, basepath, info, confirmText, func, info, ...)
Asa@0 782 end
Asa@0 783 --func will be called and info deleted when the confirm dialog is responded to
Asa@0 784 return
Asa@0 785 end
Asa@0 786 end
Asa@0 787
Asa@0 788 --call the function
Asa@0 789 if type(func) == "string" then
Asa@0 790 if handler and handler[func] then
Asa@0 791 safecall(handler[func],handler, info, ...)
Asa@0 792 else
Asa@0 793 error(format("Method %s doesn't exist in handler for type func", func))
Asa@0 794 end
Asa@0 795 elseif type(func) == "function" then
Asa@0 796 safecall(func,info, ...)
Asa@0 797 end
Asa@0 798
Asa@0 799
Asa@0 800
Asa@0 801 local iscustom = user.rootframe:GetUserData('iscustom')
Asa@0 802 local basepath = user.rootframe:GetUserData('basepath') or emptyTbl
Asa@0 803 --full refresh of the frame, some controls dont cause this on all events
Asa@0 804 if option.type == "color" then
Asa@0 805 if event == "OnValueConfirmed" then
Asa@0 806
Asa@0 807 if iscustom then
Asa@0 808 AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
Asa@0 809 else
Asa@0 810 AceConfigDialog:Open(user.appName, unpack(basepath))
Asa@0 811 end
Asa@0 812 end
Asa@0 813 elseif option.type == "range" then
Asa@0 814 if event == "OnMouseUp" then
Asa@0 815 if iscustom then
Asa@0 816 AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
Asa@0 817 else
Asa@0 818 AceConfigDialog:Open(user.appName, unpack(basepath))
Asa@0 819 end
Asa@0 820 end
Asa@0 821 --multiselects don't cause a refresh on 'OnValueChanged' only 'OnClosed'
Asa@0 822 elseif option.type == "multiselect" then
Asa@0 823 user.valuechanged = true
Asa@0 824 else
Asa@0 825 if iscustom then
Asa@0 826 AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
Asa@0 827 else
Asa@0 828 AceConfigDialog:Open(user.appName, unpack(basepath))
Asa@0 829 end
Asa@0 830 end
Asa@0 831
Asa@0 832 end
Asa@0 833 del(info)
Asa@0 834 end
Asa@0 835
Asa@0 836 local function ActivateSlider(widget, event, value)
Asa@0 837 local option = widget:GetUserData('option')
Asa@0 838 local min, max, step = option.min or 0, option.max or 100, option.step
Asa@0 839 if step then
Asa@0 840 value = math_floor((value - min) / step + 0.5) * step + min
Asa@0 841 else
Asa@0 842 value = math_max(math_min(value,max),min)
Asa@0 843 end
Asa@0 844 ActivateControl(widget,event,value)
Asa@0 845 end
Asa@0 846
Asa@0 847 --called from a checkbox that is part of an internally created multiselect group
Asa@0 848 --this type is safe to refresh on activation of one control
Asa@0 849 local function ActivateMultiControl(widget, event, ...)
Asa@0 850 ActivateControl(widget, event, widget:GetUserData('value'), ...)
Asa@0 851 local user = widget:GetUserDataTable()
Asa@0 852 local iscustom = user.rootframe:GetUserData('iscustom')
Asa@0 853 local basepath = user.rootframe:GetUserData('basepath') or emptyTbl
Asa@0 854 if iscustom then
Asa@0 855 AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
Asa@0 856 else
Asa@0 857 AceConfigDialog:Open(user.appName, unpack(basepath))
Asa@0 858 end
Asa@0 859 end
Asa@0 860
Asa@0 861 local function MultiControlOnClosed(widget, event, ...)
Asa@0 862 local user = widget:GetUserDataTable()
Asa@0 863 if user.valuechanged then
Asa@0 864 local iscustom = user.rootframe:GetUserData('iscustom')
Asa@0 865 local basepath = user.rootframe:GetUserData('basepath') or emptyTbl
Asa@0 866 if iscustom then
Asa@0 867 AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
Asa@0 868 else
Asa@0 869 AceConfigDialog:Open(user.appName, unpack(basepath))
Asa@0 870 end
Asa@0 871 end
Asa@0 872 end
Asa@0 873
Asa@0 874 local function FrameOnClose(widget, event)
Asa@0 875 local appName = widget:GetUserData('appName')
Asa@0 876 AceConfigDialog.OpenFrames[appName] = nil
Asa@0 877 gui:Release(widget)
Asa@0 878 end
Asa@0 879
Asa@0 880 local function CheckOptionHidden(option, options, path, appName)
Asa@0 881 --check for a specific boolean option
Asa@0 882 local hidden = pickfirstset(option.dialogHidden,option.guiHidden)
Asa@0 883 if hidden ~= nil then
Asa@0 884 return hidden
Asa@0 885 end
Asa@0 886
Asa@0 887 return GetOptionsMemberValue("hidden", option, options, path, appName)
Asa@0 888 end
Asa@0 889
Asa@0 890 local function CheckOptionDisabled(option, options, path, appName)
Asa@0 891 --check for a specific boolean option
Asa@0 892 local disabled = pickfirstset(option.dialogDisabled,option.guiDisabled)
Asa@0 893 if disabled ~= nil then
Asa@0 894 return disabled
Asa@0 895 end
Asa@0 896
Asa@0 897 return GetOptionsMemberValue("disabled", option, options, path, appName)
Asa@0 898 end
Asa@0 899 --[[
Asa@0 900 local function BuildTabs(group, options, path, appName)
Asa@0 901 local tabs = new()
Asa@0 902 local text = new()
Asa@0 903 local keySort = new()
Asa@0 904 local opts = new()
Asa@0 905
Asa@0 906 BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 907
Asa@0 908 for i = 1, #keySort do
Asa@0 909 local k = keySort[i]
Asa@0 910 local v = opts[k]
Asa@0 911 if v.type == "group" then
Asa@0 912 path[#path+1] = k
Asa@0 913 local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
Asa@0 914 local hidden = CheckOptionHidden(v, options, path, appName)
Asa@0 915 if not inline and not hidden then
Asa@0 916 tinsert(tabs, k)
Asa@0 917 text[k] = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 918 end
Asa@0 919 path[#path] = nil
Asa@0 920 end
Asa@0 921 end
Asa@0 922
Asa@0 923 del(keySort)
Asa@0 924 del(opts)
Asa@0 925
Asa@0 926 return tabs, text
Asa@0 927 end
Asa@0 928 ]]
Asa@0 929 local function BuildSelect(group, options, path, appName)
Asa@0 930 local groups = new()
Asa@0 931 local keySort = new()
Asa@0 932 local opts = new()
Asa@0 933
Asa@0 934 BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 935
Asa@0 936 for i = 1, #keySort do
Asa@0 937 local k = keySort[i]
Asa@0 938 local v = opts[k]
Asa@0 939 if v.type == "group" then
Asa@0 940 path[#path+1] = k
Asa@0 941 local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
Asa@0 942 local hidden = CheckOptionHidden(v, options, path, appName)
Asa@0 943 if not inline and not hidden then
Asa@0 944 groups[k] = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 945 end
Asa@0 946 path[#path] = nil
Asa@0 947 end
Asa@0 948 end
Asa@0 949
Asa@0 950 del(keySort)
Asa@0 951 del(opts)
Asa@0 952
Asa@0 953 return groups
Asa@0 954 end
Asa@0 955
Asa@0 956 local function BuildSubGroups(group, tree, options, path, appName)
Asa@0 957 local keySort = new()
Asa@0 958 local opts = new()
Asa@0 959
Asa@0 960 BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 961
Asa@0 962 for i = 1, #keySort do
Asa@0 963 local k = keySort[i]
Asa@0 964 local v = opts[k]
Asa@0 965 if v.type == "group" then
Asa@0 966 path[#path+1] = k
Asa@0 967 local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
Asa@0 968 local hidden = CheckOptionHidden(v, options, path, appName)
Asa@0 969 if not inline and not hidden then
Asa@0 970 local entry = new()
Asa@0 971 entry.value = k
Asa@0 972 entry.text = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 973 entry.icon = GetOptionsMemberValue("icon", v, options, path, appName)
Asa@0 974 entry.disabled = CheckOptionDisabled(v, options, path, appName)
Asa@0 975 if not tree.children then tree.children = new() end
Asa@0 976 tinsert(tree.children,entry)
Asa@0 977 if (v.childGroups or "tree") == "tree" then
Asa@0 978 BuildSubGroups(v,entry, options, path, appName)
Asa@0 979 end
Asa@0 980 end
Asa@0 981 path[#path] = nil
Asa@0 982 end
Asa@0 983 end
Asa@0 984
Asa@0 985 del(keySort)
Asa@0 986 del(opts)
Asa@0 987 end
Asa@0 988
Asa@0 989 local function BuildGroups(group, options, path, appName, recurse)
Asa@0 990 local tree = new()
Asa@0 991 local keySort = new()
Asa@0 992 local opts = new()
Asa@0 993
Asa@0 994 BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 995
Asa@0 996 for i = 1, #keySort do
Asa@0 997 local k = keySort[i]
Asa@0 998 local v = opts[k]
Asa@0 999 if v.type == "group" then
Asa@0 1000 path[#path+1] = k
Asa@0 1001 local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
Asa@0 1002 local hidden = CheckOptionHidden(v, options, path, appName)
Asa@0 1003 if not inline and not hidden then
Asa@0 1004 local entry = new()
Asa@0 1005 entry.value = k
Asa@0 1006 entry.text = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 1007 entry.icon = GetOptionsMemberValue("icon", v, options, path, appName)
Asa@0 1008 entry.disabled = CheckOptionDisabled(v, options, path, appName)
Asa@0 1009 tinsert(tree,entry)
Asa@0 1010 if recurse and (v.childGroups or "tree") == "tree" then
Asa@0 1011 BuildSubGroups(v,entry, options, path, appName)
Asa@0 1012 end
Asa@0 1013 end
Asa@0 1014 path[#path] = nil
Asa@0 1015 end
Asa@0 1016 end
Asa@0 1017 del(keySort)
Asa@0 1018 del(opts)
Asa@0 1019 return tree
Asa@0 1020 end
Asa@0 1021
Asa@0 1022 local function InjectInfo(control, options, option, path, rootframe, appName)
Asa@0 1023 local user = control:GetUserDataTable()
Asa@0 1024 for i = 1, #path do
Asa@0 1025 user[i] = path[i]
Asa@0 1026 end
Asa@0 1027 user.rootframe = rootframe
Asa@0 1028 user.option = option
Asa@0 1029 user.options = options
Asa@0 1030 user.path = copy(path)
Asa@0 1031 user.appName = appName
Asa@0 1032 control:SetCallback("OnRelease", CleanUserData)
Asa@0 1033 control:SetCallback("OnLeave", OptionOnMouseLeave)
Asa@0 1034 control:SetCallback("OnEnter", OptionOnMouseOver)
Asa@0 1035 end
Asa@0 1036
Asa@0 1037
Asa@0 1038 --[[
Asa@0 1039 options - root of the options table being fed
Asa@0 1040 container - widget that controls will be placed in
Asa@0 1041 rootframe - Frame object the options are in
Asa@0 1042 path - table with the keys to get to the group being fed
Asa@0 1043 --]]
Asa@0 1044
Asa@0 1045 local function FeedOptions(appName, options,container,rootframe,path,group,inline)
Asa@0 1046 local keySort = new()
Asa@0 1047 local opts = new()
Asa@0 1048
Asa@0 1049 BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
Asa@0 1050
Asa@0 1051 for i = 1, #keySort do
Asa@0 1052 local k = keySort[i]
Asa@0 1053 local v = opts[k]
Asa@0 1054 tinsert(path, k)
Asa@0 1055 local hidden = CheckOptionHidden(v, options, path, appName)
Asa@0 1056 local name = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 1057 if not hidden then
Asa@0 1058 if v.type == "group" then
Asa@0 1059 if inline or pickfirstset(v.dialogInline,v.guiInline,v.inline, false) then
Asa@0 1060 --Inline group
Asa@0 1061 local GroupContainer
Asa@0 1062 if name and name ~= "" then
Asa@0 1063 GroupContainer = gui:Create("InlineGroup")
Asa@0 1064 GroupContainer:SetTitle(name or "")
Asa@0 1065 else
Asa@0 1066 GroupContainer = gui:Create("SimpleGroup")
Asa@0 1067 end
Asa@0 1068
Asa@0 1069 GroupContainer.width = "fill"
Asa@0 1070 GroupContainer:SetLayout("flow")
Asa@0 1071 container:AddChild(GroupContainer)
Asa@0 1072 FeedOptions(appName,options,GroupContainer,rootframe,path,v,true)
Asa@0 1073 end
Asa@0 1074 else
Asa@0 1075 --Control to feed
Asa@0 1076 local control
Asa@0 1077
Asa@0 1078 local name = GetOptionsMemberValue("name", v, options, path, appName)
Asa@0 1079
Asa@0 1080 if v.type == "execute" then
Asa@0 1081
Asa@0 1082 local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
Asa@0 1083 local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
Asa@0 1084
Asa@0 1085 if type(image) == 'string' then
Asa@0 1086 control = gui:Create("Icon")
Asa@0 1087 if not width then
Asa@0 1088 width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
Asa@0 1089 end
Asa@0 1090 if not height then
Asa@0 1091 height = GetOptionsMemberValue("imageHeight",v, options, path, appName)
Asa@0 1092 end
Asa@0 1093 if type(imageCoords) == 'table' then
Asa@0 1094 control:SetImage(image, unpack(imageCoords))
Asa@0 1095 else
Asa@0 1096 control:SetImage(image)
Asa@0 1097 end
Asa@0 1098 if type(width) ~= "number" then
Asa@0 1099 width = 32
Asa@0 1100 end
Asa@0 1101 if type(height) ~= "number" then
Asa@0 1102 height = 32
Asa@0 1103 end
Asa@0 1104 control:SetImageSize(width, height)
Asa@0 1105 control:SetLabel(name)
Asa@0 1106 else
Asa@0 1107 control = gui:Create("Button")
Asa@0 1108 control:SetText(name)
Asa@0 1109 end
Asa@0 1110 control:SetCallback("OnClick",ActivateControl)
Asa@0 1111
Asa@0 1112 elseif v.type == "input" then
Asa@0 1113 local controlType = v.dialogControl or v.control or (v.multiline and "MultiLineEditBox") or "EditBox"
Asa@0 1114 control = gui:Create(controlType)
Asa@0 1115 if not control then
Asa@0 1116 geterrorhandler()(("Invalid Custom Control Type - %s"):format(tostring(controlType)))
Asa@0 1117 control = gui:Create(v.multiline and "MultiLineEditBox" or "EditBox")
Asa@0 1118 end
Asa@0 1119
Asa@0 1120 if v.multiline then
Asa@0 1121 local lines = 4
Asa@0 1122 if type(v.multiline) == "number" then
Asa@0 1123 lines = v.multiline
Asa@0 1124 end
Asa@0 1125 control:SetHeight(60 + (14*lines))
Asa@0 1126 end
Asa@0 1127 control:SetLabel(name)
Asa@0 1128 control:SetCallback("OnEnterPressed",ActivateControl)
Asa@0 1129 local text = GetOptionsMemberValue("get",v, options, path, appName)
Asa@0 1130 if type(text) ~= "string" then
Asa@0 1131 text = ""
Asa@0 1132 end
Asa@0 1133 control:SetText(text)
Asa@0 1134
Asa@0 1135 elseif v.type == "toggle" then
Asa@0 1136 control = gui:Create("CheckBox")
Asa@0 1137 control:SetLabel(name)
Asa@0 1138 control:SetTriState(v.tristate)
Asa@0 1139 local value = GetOptionsMemberValue("get",v, options, path, appName)
Asa@0 1140 control:SetValue(value)
Asa@0 1141 control:SetCallback("OnValueChanged",ActivateControl)
Asa@0 1142
Asa@0 1143 if v.descStyle == "inline" then
Asa@0 1144 local desc = GetOptionsMemberValue("desc", v, options, path, appName)
Asa@0 1145 control:SetDescription(desc)
Asa@0 1146 end
Asa@0 1147
Asa@0 1148 local image = GetOptionsMemberValue("image", v, options, path, appName)
Asa@0 1149 local imageCoords = GetOptionsMemberValue("imageCoords", v, options, path, appName)
Asa@0 1150
Asa@0 1151 if type(image) == 'string' then
Asa@0 1152 if type(imageCoords) == 'table' then
Asa@0 1153 control:SetImage(image, unpack(imageCoords))
Asa@0 1154 else
Asa@0 1155 control:SetImage(image)
Asa@0 1156 end
Asa@0 1157 end
Asa@0 1158 elseif v.type == "range" then
Asa@0 1159 control = gui:Create("Slider")
Asa@0 1160 control:SetLabel(name)
Asa@0 1161 control:SetSliderValues(v.min or 0,v.max or 100, v.bigStep or v.step or 0)
Asa@0 1162 control:SetIsPercent(v.isPercent)
Asa@0 1163 local value = GetOptionsMemberValue("get",v, options, path, appName)
Asa@0 1164 if type(value) ~= "number" then
Asa@0 1165 value = 0
Asa@0 1166 end
Asa@0 1167 control:SetValue(value)
Asa@0 1168 control:SetCallback("OnValueChanged",ActivateSlider)
Asa@0 1169 control:SetCallback("OnMouseUp",ActivateSlider)
Asa@0 1170
Asa@0 1171 elseif v.type == "select" then
Asa@0 1172 local values = GetOptionsMemberValue("values", v, options, path, appName)
Asa@0 1173 local controlType = v.dialogControl or v.control or "Dropdown"
Asa@0 1174 control = gui:Create(controlType)
Asa@0 1175 if not control then
Asa@0 1176 geterrorhandler()(("Invalid Custom Control Type - %s"):format(tostring(controlType)))
Asa@0 1177 control = gui:Create("Dropdown")
Asa@0 1178 end
Asa@0 1179 control:SetLabel(name)
Asa@0 1180 control:SetList(values)
Asa@0 1181 local value = GetOptionsMemberValue("get",v, options, path, appName)
Asa@0 1182 if not values[value] then
Asa@0 1183 value = nil
Asa@0 1184 end
Asa@0 1185 control:SetValue(value)
Asa@0 1186 control:SetCallback("OnValueChanged",ActivateControl)
Asa@0 1187
Asa@0 1188 elseif v.type == "multiselect" then
Asa@0 1189 local values = GetOptionsMemberValue("values", v, options, path, appName)
Asa@0 1190 local disabled = CheckOptionDisabled(v, options, path, appName)
Asa@0 1191
Asa@0 1192 local controlType = v.dialogControl or v.control
Asa@0 1193
Asa@0 1194 local valuesort = new()
Asa@0 1195 if values then
Asa@0 1196 for value, text in pairs(values) do
Asa@0 1197 tinsert(valuesort, value)
Asa@0 1198 end
Asa@0 1199 end
Asa@0 1200 tsort(valuesort)
Asa@0 1201
Asa@0 1202 if controlType then
Asa@0 1203 control = gui:Create(controlType)
Asa@0 1204 if not control then
Asa@0 1205 geterrorhandler()(("Invalid Custom Control Type - %s"):format(tostring(controlType)))
Asa@0 1206 end
Asa@0 1207 end
Asa@0 1208 if control then
Asa@0 1209 control:SetMultiselect(true)
Asa@0 1210 control:SetLabel(name)
Asa@0 1211 control:SetList(values)
Asa@0 1212 control:SetDisabled(disabled)
Asa@0 1213 control:SetCallback("OnValueChanged",ActivateControl)
Asa@0 1214 control:SetCallback("OnClosed", MultiControlOnClosed)
Asa@0 1215 local width = GetOptionsMemberValue("width",v,options,path,appName)
Asa@0 1216 if width == "double" then
Asa@0 1217 control:SetWidth(width_multiplier * 2)
Asa@0 1218 elseif width == "half" then
Asa@0 1219 control:SetWidth(width_multiplier / 2)
Asa@0 1220 elseif width == "full" then
Asa@0 1221 control.width = "fill"
Asa@0 1222 else
Asa@0 1223 control:SetWidth(width_multiplier)
Asa@0 1224 end
Asa@0 1225 --check:SetTriState(v.tristate)
Asa@0 1226 for i = 1, #valuesort do
Asa@0 1227 local key = valuesort[i]
Asa@0 1228 local value = GetOptionsMemberValue("get",v, options, path, appName, key)
Asa@0 1229 control:SetItemValue(key,value)
Asa@0 1230 end
Asa@0 1231 else
Asa@0 1232 control = gui:Create("InlineGroup")
Asa@0 1233 control:SetLayout("Flow")
Asa@0 1234 control:SetTitle(name)
Asa@0 1235 control.width = "fill"
Asa@0 1236
Asa@0 1237 control:PauseLayout()
Asa@0 1238 local width = GetOptionsMemberValue("width",v,options,path,appName)
Asa@0 1239 for i = 1, #valuesort do
Asa@0 1240 local value = valuesort[i]
Asa@0 1241 local text = values[value]
Asa@0 1242 local check = gui:Create("CheckBox")
Asa@0 1243 check:SetLabel(text)
Asa@0 1244 check:SetUserData('value', value)
Asa@0 1245 check:SetUserData('text', text)
Asa@0 1246 check:SetDisabled(disabled)
Asa@0 1247 check:SetTriState(v.tristate)
Asa@0 1248 check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, value))
Asa@0 1249 check:SetCallback("OnValueChanged",ActivateMultiControl)
Asa@0 1250 InjectInfo(check, options, v, path, rootframe, appName)
Asa@0 1251 control:AddChild(check)
Asa@0 1252 if width == "double" then
Asa@0 1253 check:SetWidth(width_multiplier * 2)
Asa@0 1254 elseif width == "half" then
Asa@0 1255 check:SetWidth(width_multiplier / 2)
Asa@0 1256 elseif width == "full" then
Asa@0 1257 check.width = "fill"
Asa@0 1258 else
Asa@0 1259 check:SetWidth(width_multiplier)
Asa@0 1260 end
Asa@0 1261 end
Asa@0 1262 control:ResumeLayout()
Asa@0 1263 control:DoLayout()
Asa@0 1264
Asa@0 1265
Asa@0 1266 end
Asa@0 1267
Asa@0 1268 del(valuesort)
Asa@0 1269
Asa@0 1270 elseif v.type == "color" then
Asa@0 1271 control = gui:Create("ColorPicker")
Asa@0 1272 control:SetLabel(name)
Asa@0 1273 control:SetHasAlpha(v.hasAlpha)
Asa@0 1274 control:SetColor(GetOptionsMemberValue("get",v, options, path, appName))
Asa@0 1275 control:SetCallback("OnValueChanged",ActivateControl)
Asa@0 1276 control:SetCallback("OnValueConfirmed",ActivateControl)
Asa@0 1277
Asa@0 1278 elseif v.type == "keybinding" then
Asa@0 1279 control = gui:Create("Keybinding")
Asa@0 1280 control:SetLabel(name)
Asa@0 1281 control:SetKey(GetOptionsMemberValue("get",v, options, path, appName))
Asa@0 1282 control:SetCallback("OnKeyChanged",ActivateControl)
Asa@0 1283
Asa@0 1284 elseif v.type == "header" then
Asa@0 1285 control = gui:Create("Heading")
Asa@0 1286 control:SetText(name)
Asa@0 1287 control.width = "fill"
Asa@0 1288
Asa@0 1289 elseif v.type == "description" then
Asa@0 1290 control = gui:Create("Label")
Asa@0 1291 control:SetText(name)
Asa@0 1292
Asa@0 1293 local fontSize = GetOptionsMemberValue("fontSize",v, options, path, appName)
Asa@0 1294 if fontSize == "medium" then
Asa@0 1295 control:SetFontObject(GameFontHighlight)
Asa@0 1296 elseif fontSize == "large" then
Asa@0 1297 control:SetFontObject(GameFontHighlightLarge)
Asa@0 1298 else -- small or invalid
Asa@0 1299 control:SetFontObject(GameFontHighlightSmall)
Asa@0 1300 end
Asa@0 1301
Asa@0 1302 local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
Asa@0 1303 local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
Asa@0 1304
Asa@0 1305 if type(image) == 'string' then
Asa@0 1306 if not width then
Asa@0 1307 width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
Asa@0 1308 end
Asa@0 1309 if not height then
Asa@0 1310 height = GetOptionsMemberValue("imageHeight",v, options, path, appName)
Asa@0 1311 end
Asa@0 1312 if type(imageCoords) == 'table' then
Asa@0 1313 control:SetImage(image, unpack(imageCoords))
Asa@0 1314 else
Asa@0 1315 control:SetImage(image)
Asa@0 1316 end
Asa@0 1317 if type(width) ~= "number" then
Asa@0 1318 width = 32
Asa@0 1319 end
Asa@0 1320 if type(height) ~= "number" then
Asa@0 1321 height = 32
Asa@0 1322 end
Asa@0 1323 control:SetImageSize(width, height)
Asa@0 1324 end
Asa@0 1325 local width = GetOptionsMemberValue("width",v,options,path,appName)
Asa@0 1326 control.width = not width and "fill"
Asa@0 1327 end
Asa@0 1328
Asa@0 1329 --Common Init
Asa@0 1330 if control then
Asa@0 1331 if control.width ~= "fill" then
Asa@0 1332 local width = GetOptionsMemberValue("width",v,options,path,appName)
Asa@0 1333 if width == "double" then
Asa@0 1334 control:SetWidth(width_multiplier * 2)
Asa@0 1335 elseif width == "half" then
Asa@0 1336 control:SetWidth(width_multiplier / 2)
Asa@0 1337 elseif width == "full" then
Asa@0 1338 control.width = "fill"
Asa@0 1339 else
Asa@0 1340 control:SetWidth(width_multiplier)
Asa@0 1341 end
Asa@0 1342 end
Asa@0 1343 if control.SetDisabled then
Asa@0 1344 local disabled = CheckOptionDisabled(v, options, path, appName)
Asa@0 1345 control:SetDisabled(disabled)
Asa@0 1346 end
Asa@0 1347
Asa@0 1348 InjectInfo(control, options, v, path, rootframe, appName)
Asa@0 1349 container:AddChild(control)
Asa@0 1350 end
Asa@0 1351
Asa@0 1352 end
Asa@0 1353 end
Asa@0 1354 tremove(path)
Asa@0 1355 end
Asa@0 1356 container:ResumeLayout()
Asa@0 1357 container:DoLayout()
Asa@0 1358 del(keySort)
Asa@0 1359 del(opts)
Asa@0 1360 end
Asa@0 1361
Asa@0 1362 local function BuildPath(path, ...)
Asa@0 1363 for i = 1, select('#',...) do
Asa@0 1364 tinsert(path, (select(i,...)))
Asa@0 1365 end
Asa@0 1366 end
Asa@0 1367
Asa@0 1368
Asa@0 1369 local function TreeOnButtonEnter(widget, event, uniquevalue, button)
Asa@0 1370 local user = widget:GetUserDataTable()
Asa@0 1371 if not user then return end
Asa@0 1372 local options = user.options
Asa@0 1373 local option = user.option
Asa@0 1374 local path = user.path
Asa@0 1375 local appName = user.appName
Asa@0 1376
Asa@0 1377 local feedpath = new()
Asa@0 1378 for i = 1, #path do
Asa@0 1379 feedpath[i] = path[i]
Asa@0 1380 end
Asa@0 1381
Asa@0 1382 BuildPath(feedpath, ("\001"):split(uniquevalue))
Asa@0 1383 local group = options
Asa@0 1384 for i = 1, #feedpath do
Asa@0 1385 if not group then return end
Asa@0 1386 group = GetSubOption(group, feedpath[i])
Asa@0 1387 end
Asa@0 1388
Asa@0 1389 local name = GetOptionsMemberValue("name", group, options, feedpath, appName)
Asa@0 1390 local desc = GetOptionsMemberValue("desc", group, options, feedpath, appName)
Asa@0 1391
Asa@0 1392 GameTooltip:SetOwner(button, "ANCHOR_NONE")
Asa@0 1393 if widget.type == "TabGroup" then
Asa@0 1394 GameTooltip:SetPoint("BOTTOM",button,"TOP")
Asa@0 1395 else
Asa@0 1396 GameTooltip:SetPoint("LEFT",button,"RIGHT")
Asa@0 1397 end
Asa@0 1398
Asa@0 1399 GameTooltip:SetText(name, 1, .82, 0, 1)
Asa@0 1400
Asa@0 1401 if type(desc) == "string" then
Asa@0 1402 GameTooltip:AddLine(desc, 1, 1, 1, 1)
Asa@0 1403 end
Asa@0 1404
Asa@0 1405 GameTooltip:Show()
Asa@0 1406 end
Asa@0 1407
Asa@0 1408 local function TreeOnButtonLeave(widget, event, value, button)
Asa@0 1409 GameTooltip:Hide()
Asa@0 1410 end
Asa@0 1411
Asa@0 1412
Asa@0 1413 local function GroupExists(appName, options, path, uniquevalue)
Asa@0 1414 if not uniquevalue then return false end
Asa@0 1415
Asa@0 1416 local feedpath = new()
Asa@0 1417 local temppath = new()
Asa@0 1418 for i = 1, #path do
Asa@0 1419 feedpath[i] = path[i]
Asa@0 1420 end
Asa@0 1421
Asa@0 1422 BuildPath(feedpath, ("\001"):split(uniquevalue))
Asa@0 1423
Asa@0 1424 local group = options
Asa@0 1425 for i = 1, #feedpath do
Asa@0 1426 local v = feedpath[i]
Asa@0 1427 temppath[i] = v
Asa@0 1428 group = GetSubOption(group, v)
Asa@0 1429
Asa@0 1430 if not group or group.type ~= "group" or CheckOptionHidden(group, options, temppath, appName) then
Asa@0 1431 del(feedpath)
Asa@0 1432 del(temppath)
Asa@0 1433 return false
Asa@0 1434 end
Asa@0 1435 end
Asa@0 1436 del(feedpath)
Asa@0 1437 del(temppath)
Asa@0 1438 return true
Asa@0 1439 end
Asa@0 1440
Asa@0 1441 local function GroupSelected(widget, event, uniquevalue)
Asa@0 1442
Asa@0 1443 local user = widget:GetUserDataTable()
Asa@0 1444
Asa@0 1445 local options = user.options
Asa@0 1446 local option = user.option
Asa@0 1447 local path = user.path
Asa@0 1448 local rootframe = user.rootframe
Asa@0 1449
Asa@0 1450 local feedpath = new()
Asa@0 1451 for i = 1, #path do
Asa@0 1452 feedpath[i] = path[i]
Asa@0 1453 end
Asa@0 1454
Asa@0 1455 BuildPath(feedpath, ("\001"):split(uniquevalue))
Asa@0 1456 local group = options
Asa@0 1457 for i = 1, #feedpath do
Asa@0 1458 group = GetSubOption(group, feedpath[i])
Asa@0 1459 end
Asa@0 1460 widget:ReleaseChildren()
Asa@0 1461 AceConfigDialog:FeedGroup(user.appName,options,widget,rootframe,feedpath)
Asa@0 1462
Asa@0 1463 del(feedpath)
Asa@0 1464 end
Asa@0 1465
Asa@0 1466
Asa@0 1467
Asa@0 1468 --[[
Asa@0 1469 -- INTERNAL --
Asa@0 1470 This function will feed one group, and any inline child groups into the given container
Asa@0 1471 Select Groups will only have the selection control (tree, tabs, dropdown) fed in
Asa@0 1472 and have a group selected, this event will trigger the feeding of child groups
Asa@0 1473
Asa@0 1474 Rules:
Asa@0 1475 If the group is Inline, FeedOptions
Asa@0 1476 If the group has no child groups, FeedOptions
Asa@0 1477
Asa@0 1478 If the group is a tab or select group, FeedOptions then add the Group Control
Asa@0 1479 If the group is a tree group FeedOptions then
Asa@0 1480 its parent isnt a tree group: then add the tree control containing this and all child tree groups
Asa@0 1481 if its parent is a tree group, its already a node on a tree
Asa@0 1482 --]]
Asa@0 1483
Asa@0 1484 function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isRoot)
Asa@0 1485 local group = options
Asa@0 1486 --follow the path to get to the curent group
Asa@0 1487 local inline
Asa@0 1488 local grouptype, parenttype = options.childGroups, "none"
Asa@0 1489
Asa@0 1490
Asa@0 1491 --temp path table to pass to callbacks as we traverse the tree
Asa@0 1492 local temppath = new()
Asa@0 1493 for i = 1, #path do
Asa@0 1494 local v = path[i]
Asa@0 1495 temppath[i] = v
Asa@0 1496 group = GetSubOption(group, v)
Asa@0 1497 inline = inline or pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
Asa@0 1498 parenttype = grouptype
Asa@0 1499 grouptype = group.childGroups
Asa@0 1500 end
Asa@0 1501 del(temppath)
Asa@0 1502
Asa@0 1503 if not parenttype then
Asa@0 1504 parenttype = "tree"
Asa@0 1505 end
Asa@0 1506
Asa@0 1507 --check if the group has child groups
Asa@0 1508 local hasChildGroups
Asa@0 1509 for k, v in pairs(group.args) do
Asa@0 1510 if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
Asa@0 1511 hasChildGroups = true
Asa@0 1512 end
Asa@0 1513 end
Asa@0 1514 if group.plugins then
Asa@0 1515 for plugin, t in pairs(group.plugins) do
Asa@0 1516 for k, v in pairs(t) do
Asa@0 1517 if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
Asa@0 1518 hasChildGroups = true
Asa@0 1519 end
Asa@0 1520 end
Asa@0 1521 end
Asa@0 1522 end
Asa@0 1523
Asa@0 1524 container:SetLayout("flow")
Asa@0 1525 local scroll
Asa@0 1526
Asa@0 1527 --Add a scrollframe if we are not going to add a group control, this is the inverse of the conditions for that later on
Asa@0 1528 if (not (hasChildGroups and not inline)) or (grouptype ~= "tab" and grouptype ~= "select" and (parenttype == "tree" and not isRoot)) then
Asa@0 1529 if container.type ~= "InlineGroup" and container.type ~= "SimpleGroup" then
Asa@0 1530 scroll = gui:Create("ScrollFrame")
Asa@0 1531 scroll:SetLayout("flow")
Asa@0 1532 scroll.width = "fill"
Asa@0 1533 scroll.height = "fill"
Asa@0 1534 container:SetLayout("fill")
Asa@0 1535 container:AddChild(scroll)
Asa@0 1536 container = scroll
Asa@0 1537 end
Asa@0 1538 end
Asa@0 1539
Asa@0 1540 FeedOptions(appName,options,container,rootframe,path,group,nil)
Asa@0 1541
Asa@0 1542 if scroll then
Asa@0 1543 container:PerformLayout()
Asa@0 1544 local status = self:GetStatusTable(appName, path)
Asa@0 1545 if not status.scroll then
Asa@0 1546 status.scroll = {}
Asa@0 1547 end
Asa@0 1548 scroll:SetStatusTable(status.scroll)
Asa@0 1549 end
Asa@0 1550
Asa@0 1551 if hasChildGroups and not inline then
Asa@0 1552 local name = GetOptionsMemberValue("name", group, options, path, appName)
Asa@0 1553 if grouptype == "tab" then
Asa@0 1554
Asa@0 1555 local tab = gui:Create("TabGroup")
Asa@0 1556 InjectInfo(tab, options, group, path, rootframe, appName)
Asa@0 1557 tab:SetCallback("OnGroupSelected", GroupSelected)
Asa@0 1558 tab:SetCallback("OnTabEnter", TreeOnButtonEnter)
Asa@0 1559 tab:SetCallback("OnTabLeave", TreeOnButtonLeave)
Asa@0 1560
Asa@0 1561 local status = AceConfigDialog:GetStatusTable(appName, path)
Asa@0 1562 if not status.groups then
Asa@0 1563 status.groups = {}
Asa@0 1564 end
Asa@0 1565 tab:SetStatusTable(status.groups)
Asa@0 1566 tab.width = "fill"
Asa@0 1567 tab.height = "fill"
Asa@0 1568
Asa@0 1569 local tabs = BuildGroups(group, options, path, appName)
Asa@0 1570 tab:SetTabs(tabs)
Asa@0 1571 tab:SetUserData("tablist", tabs)
Asa@0 1572
Asa@0 1573 for i = 1, #tabs do
Asa@0 1574 local entry = tabs[i]
Asa@0 1575 if not entry.disabled then
Asa@0 1576 tab:SelectTab((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
Asa@0 1577 break
Asa@0 1578 end
Asa@0 1579 end
Asa@0 1580
Asa@0 1581 container:AddChild(tab)
Asa@0 1582
Asa@0 1583 elseif grouptype == "select" then
Asa@0 1584
Asa@0 1585 local select = gui:Create("DropdownGroup")
Asa@0 1586 select:SetTitle(name)
Asa@0 1587 InjectInfo(select, options, group, path, rootframe, appName)
Asa@0 1588 select:SetCallback("OnGroupSelected", GroupSelected)
Asa@0 1589 local status = AceConfigDialog:GetStatusTable(appName, path)
Asa@0 1590 if not status.groups then
Asa@0 1591 status.groups = {}
Asa@0 1592 end
Asa@0 1593 select:SetStatusTable(status.groups)
Asa@0 1594 local grouplist = BuildSelect(group, options, path, appName)
Asa@0 1595 select:SetGroupList(grouplist)
Asa@0 1596 select:SetUserData("grouplist", grouplist)
Asa@0 1597 local firstgroup
Asa@0 1598 for k, v in pairs(grouplist) do
Asa@0 1599 if not firstgroup or k < firstgroup then
Asa@0 1600 firstgroup = k
Asa@0 1601 end
Asa@0 1602 end
Asa@0 1603
Asa@0 1604 if firstgroup then
Asa@0 1605 select:SetGroup((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or firstgroup)
Asa@0 1606 end
Asa@0 1607
Asa@0 1608 select.width = "fill"
Asa@0 1609 select.height = "fill"
Asa@0 1610
Asa@0 1611 container:AddChild(select)
Asa@0 1612
Asa@0 1613 --assume tree group by default
Asa@0 1614 --if parenttype is tree then this group is already a node on that tree
Asa@0 1615 elseif (parenttype ~= "tree") or isRoot then
Asa@0 1616 local tree = gui:Create("TreeGroup")
Asa@0 1617 InjectInfo(tree, options, group, path, rootframe, appName)
Asa@0 1618 tree:EnableButtonTooltips(false)
Asa@0 1619
Asa@0 1620 tree.width = "fill"
Asa@0 1621 tree.height = "fill"
Asa@0 1622
Asa@0 1623 tree:SetCallback("OnGroupSelected", GroupSelected)
Asa@0 1624 tree:SetCallback("OnButtonEnter", TreeOnButtonEnter)
Asa@0 1625 tree:SetCallback("OnButtonLeave", TreeOnButtonLeave)
Asa@0 1626
Asa@0 1627 local status = AceConfigDialog:GetStatusTable(appName, path)
Asa@0 1628 if not status.groups then
Asa@0 1629 status.groups = {}
Asa@0 1630 end
Asa@0 1631 local treedefinition = BuildGroups(group, options, path, appName, true)
Asa@0 1632 tree:SetStatusTable(status.groups)
Asa@0 1633
Asa@0 1634 tree:SetTree(treedefinition)
Asa@0 1635 tree:SetUserData("tree",treedefinition)
Asa@0 1636
Asa@0 1637 for i = 1, #treedefinition do
Asa@0 1638 local entry = treedefinition[i]
Asa@0 1639 if not entry.disabled then
Asa@0 1640 tree:SelectByValue((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
Asa@0 1641 break
Asa@0 1642 end
Asa@0 1643 end
Asa@0 1644
Asa@0 1645 container:AddChild(tree)
Asa@0 1646 end
Asa@0 1647 end
Asa@0 1648 end
Asa@0 1649
Asa@0 1650 local old_CloseSpecialWindows
Asa@0 1651
Asa@0 1652
Asa@0 1653 local function RefreshOnUpdate(this)
Asa@0 1654 for appName in pairs(this.closing) do
Asa@0 1655 if AceConfigDialog.OpenFrames[appName] then
Asa@0 1656 AceConfigDialog.OpenFrames[appName]:Hide()
Asa@0 1657 end
Asa@0 1658 if AceConfigDialog.BlizOptions and AceConfigDialog.BlizOptions[appName] then
Asa@0 1659 for key, widget in pairs(AceConfigDialog.BlizOptions[appName]) do
Asa@0 1660 if not widget:IsVisible() then
Asa@0 1661 widget:ReleaseChildren()
Asa@0 1662 end
Asa@0 1663 end
Asa@0 1664 end
Asa@0 1665 this.closing[appName] = nil
Asa@0 1666 end
Asa@0 1667
Asa@0 1668 if this.closeAll then
Asa@0 1669 for k, v in pairs(AceConfigDialog.OpenFrames) do
Asa@0 1670 v:Hide()
Asa@0 1671 end
Asa@0 1672 this.closeAll = nil
Asa@0 1673 end
Asa@0 1674
Asa@0 1675 for appName in pairs(this.apps) do
Asa@0 1676 if AceConfigDialog.OpenFrames[appName] then
Asa@0 1677 local user = AceConfigDialog.OpenFrames[appName]:GetUserDataTable()
Asa@0 1678 AceConfigDialog:Open(appName, unpack(user.basepath or emptyTbl))
Asa@0 1679 end
Asa@0 1680 if AceConfigDialog.BlizOptions and AceConfigDialog.BlizOptions[appName] then
Asa@0 1681 for key, widget in pairs(AceConfigDialog.BlizOptions[appName]) do
Asa@0 1682 local user = widget:GetUserDataTable()
Asa@0 1683 if widget:IsVisible() then
Asa@0 1684 AceConfigDialog:Open(widget:GetUserData('appName'), widget, unpack(user.basepath or emptyTbl))
Asa@0 1685 end
Asa@0 1686 end
Asa@0 1687 end
Asa@0 1688 this.apps[appName] = nil
Asa@0 1689 end
Asa@0 1690 this:SetScript("OnUpdate", nil)
Asa@0 1691 end
Asa@0 1692
Asa@0 1693 -- Upgrade the OnUpdate script as well, if needed.
Asa@0 1694 if AceConfigDialog.frame:GetScript("OnUpdate") then
Asa@0 1695 AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
Asa@0 1696 end
Asa@0 1697
Asa@0 1698 --- Close all open options windows
Asa@0 1699 function AceConfigDialog:CloseAll()
Asa@0 1700 AceConfigDialog.frame.closeAll = true
Asa@0 1701 AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
Asa@0 1702 if next(self.OpenFrames) then
Asa@0 1703 return true
Asa@0 1704 end
Asa@0 1705 end
Asa@0 1706
Asa@0 1707 --- Close a specific options window.
Asa@0 1708 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 1709 function AceConfigDialog:Close(appName)
Asa@0 1710 if self.OpenFrames[appName] then
Asa@0 1711 AceConfigDialog.frame.closing[appName] = true
Asa@0 1712 AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
Asa@0 1713 return true
Asa@0 1714 end
Asa@0 1715 end
Asa@0 1716
Asa@0 1717 -- Internal -- Called by AceConfigRegistry
Asa@0 1718 function AceConfigDialog:ConfigTableChanged(event, appName)
Asa@0 1719 AceConfigDialog.frame.apps[appName] = true
Asa@0 1720 AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
Asa@0 1721 end
Asa@0 1722
Asa@0 1723 reg.RegisterCallback(AceConfigDialog, "ConfigTableChange", "ConfigTableChanged")
Asa@0 1724
Asa@0 1725 --- Sets the default size of the options window for a specific application.
Asa@0 1726 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 1727 -- @param width The default width
Asa@0 1728 -- @param height The default height
Asa@0 1729 function AceConfigDialog:SetDefaultSize(appName, width, height)
Asa@0 1730 local status = AceConfigDialog:GetStatusTable(appName)
Asa@0 1731 if type(width) == "number" and type(height) == "number" then
Asa@0 1732 status.width = width
Asa@0 1733 status.height = height
Asa@0 1734 end
Asa@0 1735 end
Asa@0 1736
Asa@0 1737 --- Open an option window at the specified path (if any).
Asa@0 1738 -- This function can optionally feed the group into a pre-created container
Asa@0 1739 -- instead of creating a new container frame.
Asa@0 1740 -- @paramsig appName [, container][, ...]
Asa@0 1741 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 1742 -- @param container An optional container frame to feed the options into
Asa@0 1743 -- @param ... The path to open after creating the options window (see `:SelectGroup` for details)
Asa@0 1744 function AceConfigDialog:Open(appName, container, ...)
Asa@0 1745 if not old_CloseSpecialWindows then
Asa@0 1746 old_CloseSpecialWindows = CloseSpecialWindows
Asa@0 1747 CloseSpecialWindows = function()
Asa@0 1748 local found = old_CloseSpecialWindows()
Asa@0 1749 return self:CloseAll() or found
Asa@0 1750 end
Asa@0 1751 end
Asa@0 1752 local app = reg:GetOptionsTable(appName)
Asa@0 1753 if not app then
Asa@0 1754 error(("%s isn't registed with AceConfigRegistry, unable to open config"):format(appName), 2)
Asa@0 1755 end
Asa@0 1756 local options = app("dialog", MAJOR)
Asa@0 1757
Asa@0 1758 local f
Asa@0 1759
Asa@0 1760 local path = new()
Asa@0 1761 local name = GetOptionsMemberValue("name", options, options, path, appName)
Asa@0 1762
Asa@0 1763 --If an optional path is specified add it to the path table before feeding the options
Asa@0 1764 --as container is optional as well it may contain the first element of the path
Asa@0 1765 if type(container) == "string" then
Asa@0 1766 tinsert(path, container)
Asa@0 1767 container = nil
Asa@0 1768 end
Asa@0 1769 for n = 1, select('#',...) do
Asa@0 1770 tinsert(path, (select(n, ...)))
Asa@0 1771 end
Asa@0 1772
Asa@0 1773 --if a container is given feed into that
Asa@0 1774 if container then
Asa@0 1775 f = container
Asa@0 1776 f:ReleaseChildren()
Asa@0 1777 f:SetUserData('appName', appName)
Asa@0 1778 f:SetUserData('iscustom', true)
Asa@0 1779 if #path > 0 then
Asa@0 1780 f:SetUserData('basepath', copy(path))
Asa@0 1781 end
Asa@0 1782 local status = AceConfigDialog:GetStatusTable(appName)
Asa@0 1783 if not status.width then
Asa@0 1784 status.width = 700
Asa@0 1785 end
Asa@0 1786 if not status.height then
Asa@0 1787 status.height = 500
Asa@0 1788 end
Asa@0 1789 if f.SetStatusTable then
Asa@0 1790 f:SetStatusTable(status)
Asa@0 1791 end
Asa@0 1792 if f.SetTitle then
Asa@0 1793 f:SetTitle(name or "")
Asa@0 1794 end
Asa@0 1795 else
Asa@0 1796 if not self.OpenFrames[appName] then
Asa@0 1797 f = gui:Create("Frame")
Asa@0 1798 self.OpenFrames[appName] = f
Asa@0 1799 else
Asa@0 1800 f = self.OpenFrames[appName]
Asa@0 1801 end
Asa@0 1802 f:ReleaseChildren()
Asa@0 1803 f:SetCallback("OnClose", FrameOnClose)
Asa@0 1804 f:SetUserData('appName', appName)
Asa@0 1805 if #path > 0 then
Asa@0 1806 f:SetUserData('basepath', copy(path))
Asa@0 1807 end
Asa@0 1808 f:SetTitle(name or "")
Asa@0 1809 local status = AceConfigDialog:GetStatusTable(appName)
Asa@0 1810 f:SetStatusTable(status)
Asa@0 1811 end
Asa@0 1812
Asa@0 1813 self:FeedGroup(appName,options,f,f,path,true)
Asa@0 1814 if f.Show then
Asa@0 1815 f:Show()
Asa@0 1816 end
Asa@0 1817 del(path)
Asa@0 1818 end
Asa@0 1819
Asa@0 1820 -- convert pre-39 BlizOptions structure to the new format
Asa@0 1821 if oldminor and oldminor < 39 and AceConfigDialog.BlizOptions then
Asa@0 1822 local old = AceConfigDialog.BlizOptions
Asa@0 1823 local new = {}
Asa@0 1824 for key, widget in pairs(old) do
Asa@0 1825 local appName = widget:GetUserData('appName')
Asa@0 1826 if not new[appName] then new[appName] = {} end
Asa@0 1827 new[appName][key] = widget
Asa@0 1828 end
Asa@0 1829 AceConfigDialog.BlizOptions = new
Asa@0 1830 else
Asa@0 1831 AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {}
Asa@0 1832 end
Asa@0 1833
Asa@0 1834 local function FeedToBlizPanel(widget, event)
Asa@0 1835 local path = widget:GetUserData('path')
Asa@0 1836 AceConfigDialog:Open(widget:GetUserData('appName'), widget, unpack(path or emptyTbl))
Asa@0 1837 end
Asa@0 1838
Asa@0 1839 local function ClearBlizPanel(widget, event)
Asa@0 1840 local appName = widget:GetUserData('appName')
Asa@0 1841 AceConfigDialog.frame.closing[appName] = true
Asa@0 1842 AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
Asa@0 1843 end
Asa@0 1844
Asa@0 1845 --- Add an option table into the Blizzard Interface Options panel.
Asa@0 1846 -- You can optionally supply a descriptive name to use and a parent frame to use,
Asa@0 1847 -- as well as a path in the options table.\\
Asa@0 1848 -- If no name is specified, the appName will be used instead.
Asa@0 1849 --
Asa@0 1850 -- If you specify a proper `parent` (by name), the interface options will generate a
Asa@0 1851 -- tree layout. Note that only one level of children is supported, so the parent always
Asa@0 1852 -- has to be a head-level note.
Asa@0 1853 --
Asa@0 1854 -- This function returns a reference to the container frame registered with the Interface
Asa@0 1855 -- Options. You can use this reference to open the options with the API function
Asa@0 1856 -- `InterfaceOptionsFrame_OpenToCategory`.
Asa@0 1857 -- @param appName The application name as given to `:RegisterOptionsTable()`
Asa@0 1858 -- @param name A descriptive name to display in the options tree (defaults to appName)
Asa@0 1859 -- @param parent The parent to use in the interface options tree.
Asa@0 1860 -- @param ... The path in the options table to feed into the interface options panel.
Asa@0 1861 -- @return The reference to the frame registered into the Interface Options.
Asa@0 1862 function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
Asa@0 1863 local BlizOptions = AceConfigDialog.BlizOptions
Asa@0 1864
Asa@0 1865 local key = appName
Asa@0 1866 for n = 1, select('#', ...) do
Asa@0 1867 key = key..'\001'..select(n, ...)
Asa@0 1868 end
Asa@0 1869
Asa@0 1870 if not BlizOptions[appName] then
Asa@0 1871 BlizOptions[appName] = {}
Asa@0 1872 end
Asa@0 1873
Asa@0 1874 if not BlizOptions[appName][key] then
Asa@0 1875 local group = gui:Create("BlizOptionsGroup")
Asa@0 1876 BlizOptions[appName][key] = group
Asa@0 1877 group:SetName(name or appName, parent)
Asa@0 1878
Asa@0 1879 group:SetTitle(name or appName)
Asa@0 1880 group:SetUserData('appName', appName)
Asa@0 1881 if select('#', ...) > 0 then
Asa@0 1882 local path = {}
Asa@0 1883 for n = 1, select('#',...) do
Asa@0 1884 tinsert(path, (select(n, ...)))
Asa@0 1885 end
Asa@0 1886 group:SetUserData('path', path)
Asa@0 1887 end
Asa@0 1888 group:SetCallback("OnShow", FeedToBlizPanel)
Asa@0 1889 group:SetCallback("OnHide", ClearBlizPanel)
Asa@0 1890 InterfaceOptions_AddCategory(group.frame)
Asa@0 1891 return group.frame
Asa@0 1892 else
Asa@0 1893 error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2)
Asa@0 1894 end
Asa@0 1895 end