I'm trying to create an AceConfig optionstable which lists guild members on the right, with their select-able ranks on the left, but am having trouble figuring out how to do!
My code so far:
[PHP]guildMembersGroup = {
type = "group",
name = "",
childGroups = "tree",
args = {
function()
for i = 1, GuildControlGetNumRanks() do
local rank = GuildControlGetRankName(i);
{
order = i,
type = "group",
name = rank,
args = {
names = {
name = rank,
type = "multiselect",
width = "full",
values = function()
local names = {}
for ci = 1, GetNumGuildMembers() do
names[ci] = GetGuildRosterInfo(ci);
end
return names
end,
},
},
}
end
end,
}
}[/PHP]
Well for one thing, you declare a function then fail to call it. You need to wrap the top level function in parens and invoke it, ie (function() ... end)()
You also need to add a return value and use that to set args (instead of the embedding it in an array then handing it to args).
args = -- note no array braces
(function()
local result = {}
result[1] = ... -- fill the array
return result
end)() -- call the function
It's also worth noting this function is called very early in startup when you construct the options array (before calling AceConfig). If you want code to run later (when the user opens the options window) you'll need to use one of AceConfig's entries that supports a function type.
I'm not sure why you are embedding a multiselect option with the name "rank" (where that's the actual name of a guild rank) inside a group option with the same name "rank"... if there are no other options in the "rank" group, just make the top-level "rank" option a multiselect instead of a group.
Anyway, I think you're actually trying to do something more like this:
-- First, define your options table, leaving the [i]args[/i] node as an empty table:
guildMembersGroup = {
type = "group",
name = "",
childGroups = "tree",
args = {},
}
-- Then, add a child node to the [i]args[/i] table for each guild rank:
for i = 1, GuildControlGetNumRanks() do
local rank = GuildControlGetRankName(i)
-- Define the individual option:
local option = {
order = i,
name = rank,
type = "multiselect",
width = "full",
values = function()
local names = {}
for j = 1, GetNumGuildMembers() do
names[j] = GetGuildRosterInfo(j)
end
return names
end,
}
-- Add it to the guildMembersGroup arguments:
guildMembersGroup.args[rank] = option
end
In practice, you also need to define get and set functions so that your options actually do something when selected/checked/clicked/typed in/etc. However, since you did not explain what you actually want your GUI to do, and you did not post your actual entire code, I'm not even going to try to suggest what those functions should look like.
You would probably also want to update the options table in response to events that indicate changes in the guild structure (eg. you added, changed, or removed a rank) or roster (eg. someone joined the guild, got promoted or demoted, or left).
I'm doing that to have selectable ranks to the left (the group, with the rankname as name). Once selected, the multiselect containing the players of that rank shows on the right. The reason for that also having rank as name is to show the rank name as a header.
I know i missed the get/set functions, I just hadn't made them at that time :)
I went with your solution Phanx, as the overall structure is neater, and it works as intended - thanks alot!
I noticed this approach generates a lot of garbage if the user clicks the ranks several times. Putting in a collectgarbage() in the creation of the ranks options solves the problem, but slows the game significantly.
It's because it's creating a new table each time you click a rank to populate the option values (see my code above). If you're really concerned about garbage creation in an options menu, you can modify it to reuse the same table over and over for each rank:
-- Then, add a child node to the args table for each guild rank:
for i = 1, GuildControlGetNumRanks() do
local rank = GuildControlGetRankName(i)
[B]-- Define a reusable table:
local names = {}[/B]
-- Define the individual option:
local option = {
order = i,
name = rank,
type = "multiselect",
width = "full",
values = function()
[B]-- Clear the reusable table's previous values:
wipe(names)[/B]
-- Fill the table with current values:
for j = 1, GetNumGuildMembers() do
names[j] = GetGuildRosterInfo(j)
end
return names
end,
}
-- Add it to the guildMembersGroup arguments:
guildMembersGroup.args[rank] = option
end
You also mentioned that you wanted each rank to only show the players who were currently at that rank. To do that, you'd want to modify the code some more:
-- Fill the table with current values:
for j = 1, GetNumGuildMembers() do
-- Check if the player is at this rank:
local name, _, rank = GetGuildRosterInfo(j)
if rank + 1 == i then
-- This player is at this rank, add them:
names[j] = rank
end
end
Brilliant, simple solution, should have thought about that - thanks again!
It created about 100kB every click, so yeah, I was concerned.
I was only in doubt about the creation of the options, got the rest figured out and everything's working as intended now, thanks to everybody for your time :D
Btw, you're forgetting the rankIndex returned by GetGuildRosterInfo() starts at 0 so for your code to work, you have to add 1 to rank before checking if it's equal to i.
I'm trying to create an AceConfig optionstable which lists guild members on the right, with their select-able ranks on the left, but am having trouble figuring out how to do!
My code so far:
[PHP]guildMembersGroup = {
type = "group",
name = "",
childGroups = "tree",
args = {
function()
for i = 1, GuildControlGetNumRanks() do
local rank = GuildControlGetRankName(i);
{
order = i,
type = "group",
name = rank,
args = {
names = {
name = rank,
type = "multiselect",
width = "full",
values = function()
local names = {}
for ci = 1, GetNumGuildMembers() do
names[ci] = GetGuildRosterInfo(ci);
end
return names
end,
},
},
}
end
end,
}
}[/PHP]
Does anyone have any tips on what to do?
You also need to add a return value and use that to set args (instead of the embedding it in an array then handing it to args).
I thought the function would be called, but thanks for pointing it out :)
I'm unsure of what to return, do you mean like returning a table to args containing the tables to sit in there or?
It's also worth noting this function is called very early in startup when you construct the options array (before calling AceConfig). If you want code to run later (when the user opens the options window) you'll need to use one of AceConfig's entries that supports a function type.
I'll try it tomorrow when I got time - thanks alot!
Anyway, I think you're actually trying to do something more like this:
In practice, you also need to define get and set functions so that your options actually do something when selected/checked/clicked/typed in/etc. However, since you did not explain what you actually want your GUI to do, and you did not post your actual entire code, I'm not even going to try to suggest what those functions should look like.
You would probably also want to update the options table in response to events that indicate changes in the guild structure (eg. you added, changed, or removed a rank) or roster (eg. someone joined the guild, got promoted or demoted, or left).
I know i missed the get/set functions, I just hadn't made them at that time :)
I went with your solution Phanx, as the overall structure is neater, and it works as intended - thanks alot!
Any suggestions where I might but it?
You also mentioned that you wanted each rank to only show the players who were currently at that rank. To do that, you'd want to modify the code some more:
It created about 100kB every click, so yeah, I was concerned.
I was only in doubt about the creation of the options, got the rest figured out and everything's working as intended now, thanks to everybody for your time :D
Btw, you're forgetting the rankIndex returned by GetGuildRosterInfo() starts at 0 so for your code to work, you have to add 1 to rank before checking if it's equal to i.