annotate Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua @ 25:ac501d71c890 tip

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