Dynamic Groups: Allow dynamic groups to resize auras
InfusOnWoW opened this issue ยท 3 comments
Currently dynamic groups take over the positioning of auras.
With dragonflight users have been experimenting/requesting functionality that allows for resizing auras.
One very common layout has a resource bar (Or in the case of rogue combo points) in a row, and below that a number of icons and the width of these should be synced by either resizing the resource row or resizing the icons.
Sometimes there are additional rows of icons, sometimes the aspect ratio of the icons should be kept.
Additional things to consider
- How do Luxthos/Afenar(?) layout their class auras dynamically
- There's a very similar request for resizing that comes from attaching e.g. a number of progress bars to an unit frame, where the width of the auras should depend on the unit frame's width. Or sometimes a singular aura is attached to a unit frame, and should resize to the unit frame's size.
- How does resizing interact with size-changing conditons and animations that scale auras
- Currently dynamic groups don't relayout auras if the size is changed via conditions/animations. How does that fit in, if dgs do relayout if they are the ones changing the size.
Potential approaches are:
-
Multiple dynamic groups, e.g. for the progress bar adjusts to icons beneath:
** DG1 contains icons
** DG2 contains progress bar and is attached to DG1. DG2 is set to "adjust width to DG1" -
More powerful grow functions
** [...]
Link to an experimental implementation mrbuds@29c82b5
Idea was to have ability to set a minimum and/or maximum width & height
With choices:
- not change
- user defined size
- parent's size
This approach resize each children, all grow functions needs to be slightly rewritten to handle it.
An other approach i have in mind to simplify implementation is to make it change group scale instead of children's size.
Handling of parent resizing is not handled on this implementation
Atrocity does something different, Instead of changing the size of the aura he has a weak aura that change the position of the player/target frames to reposition depending on size of the dynamic group.
I dont think it is the best solution, but it works.
I guess I should post what I posted on your commit also to this ticket, so that it's all in one place:
think this goes in the right direction.
A few conceptual comments:
Fundamentally dynamic groups use ther children sizes to calculate their own size. If you consider nested dynamic groups, that would work the same way. The parent's dynamic group calculates its size based on the dynamic group one level below. And we should imho always consider nested dynamic groups as something we want eventually add.
Adding a fixed/parent size mode to dynamic groups changes that.
For fixed mode, the DG now applies a size to its children.
And to make the discussions a bit easier to follow let's define a few concepts:
static size => whatever is in data.width/data.height
region size => whatever was last set via setRegionWidth/setRegionHeight
layout size => whatever the dg wants the aura size to be, this is the result of the grow function
effective size => the actual size that the aura is set too.
dg own size => the size of a dg based on its children/fixed/parent mode
Where size is obviously height(width. I frequently talk about e.g. setRegionSize, when I mean both SetRegionWidth and SetRegionHeight
This creates problems in three cases:
Text Auras
Nested DGs
Condition sizes
Animations
Layouting with region size
** Text Auras **
Text Auras are a bit different from the other auras, in that we layout them based on their region size not based on their static size. Now, this results in a circular dependency, where we layout based on the region size, calculate a layout size and then set it on the text as its region size. It's imagine a scenario where this would lead to counter-intuitive results.
=> I see two ways around that problem:
Don't allow seting a fixed/parent mode if the dynamic group contains text auras
Distinguish between layout size, region size and effective size. So that is for grow functions the static size/region size is the input and layout size is the output.
** Layout size overrrides region size, effective size is basically whatever the layout says it is
** Region size overrids layout size, so the for text auras whatever the dg thinks is the right size is ignored.
** Nested DGs **
Obviously we don't have these yet, but imho anything we add needs to be conceptually compatible with them. As I think we'll eventually add them.
So let's consider this (contrived) setup:
GP (grand parent dynamic group)
** C (child dynamic group)
*** A (Auras contained in C)
For dynamic groups, they obviously don't have a static size. So if we don't have any fixed mode settings, I think it's obvious how it should work. The auras A get shown/hidden, C layouts A determines its size. GP is informed that C size change and uses C's dg own size to layout. If C has a fixed size, then that's taken into account in the layout, and its own size should respect the fixed size.
But what if GP has a fixed size set and wants to set a size on C. That obviously can't work, as now the size of C is both controlled by itself via its children and GP.
=>I think the answer is similar to text auras.
If a DG contains a DG (or a group for similar reasons), then it can't be set into fixed mode.
** Data Size Condition Sizes **
You are currently calling SetRegionWidth/SetRegionHeight, which are also set via conditions. Thus there an obvious conflict here.
=> There are a few ways to solve that
Don't allow setting a size via conditions if the aura is in a group with fixed/parent mode.
Again introduce the concept of a effectice size
** Layout size overrrides region size, effective size is basically whatever the layout says it is
** Region size overrides layout size, that is the region is layed out according to what the DG assigned as a size to it. But if a condtion makes the aura bigger, than it's simply made bigger in place without affecting others around it. This is somewhat similar to how conditions and DGs work now.
** Animations **
Animations currently affect something called the "scale". Which can also annoyingly flip auras. How does that fit into it?
=> Potential behaviours
Scale is applied at the end, but does not affect layout. It applied to the "effective" size.
Scale applies to the region size, and is overwritten by layout size.
** Layouting with region size **
This does come up from time to time, and while we don't need to include it here, we should at least think about how this fit into it.
I think this can be worked out for fixed sizes. I'm more sceptical about "parent" size, because it has all the same problems but also issues on its own:
What if the parent is a dynamic group?
If the dynamic group is attached somewhere, we probably should adjust to the size if the target frame changes.
=> I'd leave this out, to be figure out at a later date.
WIth that said conceptually I think my preferred solution looks like this:
Each region has 3 properties:
static size
** this is simply what data.size is
region size
** intially nil
** is set via condtions
** there are changes needed so that deactivating a size changing condition sets it to nil again. I think the width/height properies need renaming
scale
** initially 1
** is set via animation
** layout size
** is intially nil
** set via dynamic group's layout funtion
Setting any of them calls a function updateEffectiveSize(), which based on our logic sets the actual frame size to the effective size. Currently that is directly done in SetRegionSize, that basically inserts an additional indirection in between. The old code in SetRegionSize is moved to updateEffectiveSize, and SetRegionSize now calls updateEffectiveSize.
I think the logic in updateEffectiveSize should be:
If region size is set, then use that,
else if layout size is set, then use that,
else use static size
Multiply it with scale to get the final size
For Dynamic Groups
If a dynamic group contains a text/group/dynamic group, there's no fixed mode setting at all
We don't introduce a parent mode setting. I'm think there are too many edge cases there that I don't want to figure out
The grow functions input is the static size (with the exception for text region type)
The grow functions output is a layout size, which is also used for positioning
The effect of that is, that size changes via conditions, or scaling via animations does not affect dynamic group layouts, essentially behaving like they do now.
But I can see how an optional flag for that behaviour would work. The region would need to inform the DG in its setRegionSize function that it needs to layout. And the dynamic group needs to take that flag into account so that it fetches the region size and not the static size. There's no circular dependency, so it should all work and not even require any changes to updateEffectiveSize
Now to your implementation, it's obvious a first take. I think instead of doing the size adjustments directly in getMinMax size, the size should be an output of the grow. Also some of the calculations are done per aura that never changes.
The function should not directly call the regions setters. That should be the job of the dynamic group, similar to how the grow function merely returns the position. Currently the grow function returns per frame/position an array, {x, y, show}. I think we can in a backwards compatible way adaopt a change that rivers did and name them. So {x = x, y = y, show = true, width = w, height = h }. And on reading simply do x = newPositions[..].x or newPositions[..][1]
As to your implementations, the most complex will certainly be grid. then centered and lastly the simple horizontal/vertical.
For grid, let's talk through a complex example:
Grid in right, then down layout. With a row limit of 3
All icons, but different sizes, e.g. first row has 3 big icons 60x60, next row is 3 small icons 30x30
Keep aspect ratio is enabled
The grid exceeds both the max width 120 and max height 60 setting. It is 180 wide and 90 high
So first question if the grid exceeds the sizes, should everything be scaled by the same ratio?
To make the big icons fit, their width needs to be reduced from 180 total, to 120. Should the small icons be also reduced in size?
If yes, then they are reduced from 30 to 20, the ratio of 2/3 works for both.
If not, then the height will be 70, meaning to high with a 2/3 scaling factor.
My conclusion
=> There's one scaling factor and it's applied to everything.
So layouting works in 2 phases. First phase lays out everything without any regard to max/min widht/height setting, calculating a scaling factor as we lay out. I think for the example above of right, then down, we would need for each row check against min/max size and want to remember the smallest scaling factor. And at the end use the height to check against min/max height and again use the smallest scaling factor.
Then we essentially rerun the layouting algorithm with the scaling factor.