Nesting Groups
This tutorial demonstrates how to nest Odin's Group Attributes. We will learn how group paths work and how to handle special cases like the TabGroup attribute. I'm also going to provide a few examples of varying complexity.
Group Paths
Understanding Odin's group paths are the key to mastering nesting all groups in pretty much every combination imaginable. Odin uses group paths to decide how groups get nested because the order in which attributes are specified in C# is not guaranteed and therefore can't reliably be used to group elements on its own (see Attribute Specification).
Let's begin by creating our first group.
1 2 |
|
"Box"
.
Let's have a look at the BoxGroup constructor and see what this string is used for.
1 2 3 4 5 6 7 |
|
As we can see the BoxGroup attribute takes a few arguments, but we'll just focus on the
string group
parameter for now. We can see that the constructor's body
doesn't do anything with this value and instead passes it to the base constructor.
Let's have a look at that.
1 2 3 4 5 |
|
There we have it! The string we pass is used as the group's identifier and we will use it to refer to this group when we want to nest it with other groups. Let's test this knowledge and nest a FoldoutGroup inside the BoxGroup we created earlier. Groups are nested like folder paths so the only thing we need to do is to
- Add the group attribute
- Write the first folders name/identifier
- Add a
/
- Write the second "folders" name/identifier
1 2 3 |
|
The final folder hierarchy now looks like this:
1 2 |
|
We can see that we have a BoxGroup which has a FoldoutGroup inside of it. This is the main benefit of visualizing it like a folder hierarchy, but it also shows that for a group to be nested inside another one, it must first be separately created. Imagine that we didn't declare the BoxGroup our code would look like this:
1 2 |
|
1 2 |
|
You do not have to write the BoxGroup attribute before the FoldoutGroup. It just needs to exist inside the file. Since as we've discussed in the beginning, order doesn't matter for attributes. So this still works:
1 2 3 |
|
These principles apply to all groups and can theoretically be nested as much as you want. We add another group attribute and pass it the full path of identifiers as if it were a folder path. The only group that behaves slightly differently is the TabGroup, which we will look at next.
TabGroups are (not) special
How to nest TabGroups is probably the most asked question when it comes to nesting groups. We will soon see that it's easier than you might think. Let's start with an example of how most people instinctively try to nest a TabGroup and see why that doesn't work.
1 2 3 |
|
Based on our knowledge about group paths, this should work, so what is going on here? Let's investigate a bit and look at the TabGroups constructors to get a better understanding.
1 2 3 |
|
1 2 3 |
|
The first thing that we've found out is that the TabGroup has two
constructors. We're using the first one in our example since it's the only one
that has only one non-optional parameter string tab
. Judging by the names we can see that
we're passing the tab name and not the group identifier. This explains why it's not working,
but how does Odin identify the group if we don't specify one ourselves? The answer is simple,
Odin calls the second constructor and assigns "_DefaultTabGroup"
as the group identifier.
Now you're maybe thinking "I just have to change my identifier to "_DefaultTabGroup"
and I'm good to go".
Unfortunately, this is still not the solution. The TabGroups identifier consists of the group identifier
and the tab name and if we think about it, it makes sense. How else could Odin know in what tab you want to
put your nested groups? We can now build our group path successfully by
- Writing
"_DefaultTabGroup"
- Adding a
\
- Writin the tab name
1 2 3 4 5 |
|
We now have a working TabGroup nesting example, but it's still not ideal. I know, I know, but we're almost there. Using this method has several drawbacks.
"_DefaultTabGroup"
is hard to read."_DefaultTabGroup"
seems to magically exist without us creating it in the file leading to confusion.- What do we do if we have multiple TabGroups? They would all have the same group identifier leading to undesired and hard to debug behaviour.
What's the solution? It's quite simple. Instead of letting Odin call the second constructor and passing it the
"_DefaultTabGroup"
string, we call it ourselves and pass the group identifier and the tab name at once.
We can then just substitute the "_DefaultTabGroup"
string with our group identifier.
1 2 3 |
|
That's it! You should now be able to nest all of Odin's groups no matter the complexity by simply applying the rules you learned. If you're having problems remembering the correct syntax just keep the folder analogy in mind.
1 2 3 |
|
Examples
BoxGroups in a BoxGroup
1 2 3 4 5 6 7 8 9 |
|
BoxGroup in a ShowIfGroup
1 2 3 4 5 |
|
BoxGroups in a TabGroup
1 2 3 4 5 6 7 |
|
TabGroup in a TabGroup
1 2 3 4 5 6 |
|
BoxGroup in a TabGroup in a ToggleGroup
1 2 3 4 5 6 7 8 9 |
|
What even...?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Gotchas
If you have missing or duplicate elements, make sure to check your group path, this is a sign that you did not nest your group correctly.