Container Sides - GimmickNG/AIRDock GitHub Wiki
There are five sides in the ContainerSide enumeration class, which are:
ContainerSide.FILL- Adds a panel to the same containerContainerSide.LEFT- Adds a panel to the left subcontainer of the current containerContainerSide.RIGHT- Adds a panel to the right subcontainer of the current containerContainerSide.TOP- Adds a panel to the top subcontainer of the current containerContainerSide.BOTTOM- Adds a panel to the bottom subcontainer of the current container
If there is no subcontainer, then a new subcontainer is created; this process occurs with two possible conditions:
Adding a subcontainer to an empty container
This happens when there are no panels attached to the container; recall that no IContainer instance can have both subcontainers and panels (without undefined behavior occurring). Suppose a container A is empty, and a container needs to be added to the RIGHT side; the tree view and the physical rendering is shown below:
┌───────────────────┐
│ │
A │ │
| │ A │
* │ │
│ │
└───────────────────┘
Then, a new container is created and added as a subcontainer to A (first as a weak link, and then committed; the intermediate step is left out, but it is worth noting). For the DefaultContainer implementation, another container is created, which is complementary to the current side (LEFT in this case):
┌─────────┬─────────┐
A │ │ │
/ \ │ │ │
B C │ C │ B │
| | │ │ │
* * │ │ │
└─────────┴─────────┘
That's pretty much it. Calling A.getSide(PanelContainerSide.RIGHT) returns B, and calling A.getSide(PanelContainerSide.LEFT) returns C.
Adding a subcontainer to a non-empty container
Since no IContainer can have both panels and subcontainers at the same time without undefined behavior occurring, the default behavior which occurs when a container needs to be added to a non-empty container, is to create a new container which is complementary to the container that is being created as a soft link, merge all the container's contents into this container, add the other container as a soft link, and commit right after.
Suppose a container
Ahas 2 panels,bandc, and a new containerBhas to be added to theRIGHTside:
┌───────────────────┐
│ │
A │ │
| │ A │
[b,c] │ │
╞═══╤═══╤═══════════╡
│ b │ c │ │
└───┴───┴───────────┘
Before adding B to the RIGHT side, a new container C is created as a soft link, and the contents are merged into it:
┌───────────────────┐
│ │
A │ │
: \ │ C │
C B │ │
| │ │
[b,c] ╞═══╤═══╤═══════════╡
│ b │ c │ │
└───┴───┴───────────┘
Which finally results in the following layout:
┌─────────┬─────────┐
│ │ │
A │ │ │
/ \ │ │ │
C B │ C │ B │
| │ │ │
[b,c] ╞═══╤═══╤═╡ │
│ b │ c │ │ │
└───┴───┴─┴─────────┘
Because of the merging that occurs, a few points should be noted:
- No priority is given to any side.
- Because no priority is given to any side, the order in which containers are added matters.
- Serializing containers becomes a little trickier because the exact order in which panels are added affects the final layout.
- Non-complementary (aka anti-complementary) sides always result in new containers being created, and the existing contents merged down into the complementary container for the new side.
For an example of #1, #2, and #4, consider the following case:
A container
Ahas to have two containers,BandC, added toLEFTandTOPrespectively. What is the final layout of the container?
- Add container
Bto theLEFTside. A new containerZis created for theRIGHTside, and ifAhad any contents, they would have been merged intoZ. So far, so good:
┌─────────┬─────────┐
A │ │ │
/ \ │ │ │
B Z │ B │ Z │
| | │ │ │
* * │ │ │
└─────────┴─────────┘
- Add container
CtoA. Here, though, the current "side" ofAisLEFT.Cis being added to theTOPside, butTOPis anti-complementary toLEFT; as a result,A's entire subtree will be merged into a new container,Y, andCwill be added to theTOPside:
┌───────────────────┐
A │ │
/ \ │ C │
C Y │ │
| / \ ├─────────┬─────────┤
* B Z │ │ │
| | │ B │ Z │
* * │ │ │
└─────────┴─────────┘
On the other hand, if C were added first and then B, i.e. TOP followed by LEFT, then the following steps would occur instead:
- Add container
Cto theTOPside. A new containerZis created for theBOTTOMside, and ifAhad any contents, they would have been merged intoZ:
┌───────────────────┐
│ │
A │ C │
/ \ │ │
C Z ├───────────────────┤
| | │ │
* * │ Z │
│ │
└───────────────────┘
- Add container
BtoA. Here, though, the current "side" ofAisTOP.Bis being added to theLEFTside, butLEFTis anti-complementary toTOP; as a result,A's entire subtree will be merged into a new container,Y, andBwill be added to theLEFTside:
┌─────────┬─────────┐
A │ │ │
/ \ │ │ C │
B Y │ │ │
| / \ │ B ├─────────┤
* C Z │ │ │
| | │ │ Z │
* * │ │ │
└─────────┴─────────┘
Remember: Don't mix up the order!
Pros:
- No priority over sides - because of only two sides, or none at all - means that there's no situation like the following occurring here (in this example, there are four sides in a container; which side should be longer?
Ais blocking offB, which is blocking offC;Dis blocked off on both sides byAandC)
┌───┬─────────────────┐
│ │ B │
│ ├─────────────┬───┤
│ │ │ │
│ │ │ │
│ │ │ │
│ A │ │ C │
│ │ │ │
│ │ │ │
│ ├─────────────┤ │
│ │ D │ │
└───┴─────────────┴───┘
- Works seamlessly with parked containers (no merging means that parked containers won't be removed from their
stages)
Cons:
- Order of insertion matters
- Serialization is more tricky because the order of insertion has to be kept track of as well, requiring a linear instead of an associative data structure
- Really unbalanced trees can be produced in extreme cases:
Assume containers
[B, C, D, E, F, G, H ...]are to be added toAin alternatingTOP-LEFTsides (where + indicates a container is on theTOPside and * indicates a container is on theLEFTside):
A:
A+ ┌──────────────────────────────┬───────────────────────────────┐
/ \ │ │ │
H+ T* │ │ │
| / \ │ │ │
* G* U+ │ │ C │
| / \ │ │ │
* F+ V* │ │ │
| / \ │ │ │
* E* W+ │ H ├───────────────┬───────────────┤
| / \ │ │ │ │
* D+ X* │ │ │ E │
| / \ │ │ │ │
* C* Y+ │ │ D ├───────┬───────┤
| / \ │ │ │ │ G │
* B+ Z │ │ │ F ├───┬───┤
| | │ │ │ │ H │...│
* * └──────────────────────────────┴───────────────┴───────┴───┴───┘
(Extra truncated due to size constraints.)
Notes about older versions
The newer version contains breaking changes over the older versions, which used the PanelContainerSide class to refer to the same concept (instead of ContainerSide), and an int datatype instead of a String. This has knock-on effects regarding resolvers - namely, newer versions allow for multiple side codes to be scanned in a single function call, something that is not possible in older versions.