I have a TextLabel under an ImageLabel in the Explorer
Both have ZIndex set to the default (1).
If I set the ZIndex of the ImageLabel to be 10, it now draws on top of the TextLabel. I think this is wrong.
Since the TextLabel is a child of the ImageLabel, it should have ZIndex 10 (inherited from parent) + 1 (it’s own default ZIndex).
If I wanted the current behavior (no inheritance of ZIndex), I would make them siblings.
At the moment if I want to create a GUI out of a bunch of elements and then bring it to the front, I need to recursively traverse the datamodel and set these Zs myself. zzzz.
Yeah, I agree with you that sometimes working with Guis is unintuitive. In fact, my favorite time was when the order in which you instantiate Guis was the order in which they render (for siblings with equal ZIndices). While that’s not a great solution for the masses (there is no way in studio to shuffle them around), it was so predictable. Then they changed it up to optimize rendering, and TextLabels and ImageLabels started behaving strangely.
In general, you shouldn’t really want a situation where a child renders on top of its parent. That’s unusual and kind of subverts the whole parent-child relationship, so in that sense, you’re right.
I think a nice, intuitive solution would be that:
Children always render on top of their ancestors.
Elements do not interleave Z-levels with cousins (anything not a descendant of the parent).
ZIndex only specifies relations between siblings.
ScreenGuis have a ZIndex (not really necessary, but it seems to make sense).
So the biggest place where my suggestion differs from yours is bullet 2. If you just used simple ZIndex addition, you could still allow cousins to interleave Z levels, which is (in general) not desired. If someone thinks of a scenario where you want this, let me know. I think it just opens opportunity for two Guis not designed with each other in mind to interfere.
As a clarification, when I talk about Z-level interleaving between cousins, I mean something like this:
The rendering order in this case would be: A --> B --> a --> c --> b --> d. This could render d on top of b, but b on top of c. This is unusual. One would probably expect the entire group of A to render first, in this style: A --> a --> b --> B --> c --> d.
Regardless of whether they take either of our suggestions, I hope they add something to the Trello board to reconsider how to layer gui elements, because right now, it’s painful.
I want to reevaluate the importance of this optimization. I frequently see UI bugs because of this. We used to have a pretty slow UI renderer (in OGRE times); since then it has become much more efficient. Current order is still faster but maybe the difference is not that big any more.
I’ll create a separate thread next week - I’ll need examples of real complicated UI to test the possibility of this change.
I disagree. I don’t necessarily want a child to be shown on top of the parent.
e.g. If I want to give a frame a shadow, logically the shadow should be a child of the frame. What you’re suggesting would force me to either (a parent the frame to the shadow or (b parent both frame and shadow to the same instance, and make sure I move the shadow along with the frame.
The better option would be to give us more than 10 digits for ZIndex.
Or allow negative values for ZIndex in addition to OP’s suggestion. A child being displayed under the parent is niche compared to the regular need to have a child be displayed over the parent. GUI layering should be tailored to displaying descendants over their ancestors for that very reason.
I haven’t looked at the code but if ZIndexes are being calculated using an array this might be really weird to implement. @Sharksie would know when it comes to this.
Quite relevant, and favorable to my cause. He also supports using ZIndex only among siblings.
He actually goes over the “shadow under gui” example, and gives a good reason why you wouldn’t want to make it a child of the frame, and provides a decent alternative.
The crux of the argument is that a shadow shouldn’t be a child of the frame it belongs to. It’s not a member of the frame (like a button, text field, etc.), but related in another way. As such, the frame and its shadow are better represented as siblings within some invisible element.
This is a weird edge case and should not be allowed to influence the design of the GUI API.
The proper way to give a dialog a shadow is to use a slice 9 GUI with shadow and only have one Frame. The problem with this is that Frames currently do not support slice 9 theming - Extend Slicing to all GuiObjects. This is probably an oversight instead of an intentional choice since it makes no sense.
I think they perform an algorithm for each separate level and they just had to pick a relatively small number that would still allow for some customization. I’ll see if I can find a primary source of it being a small limited number for a technical reason.
EDIT: I think it was because they use counting sort to sort the UI elements based on ZIndex
The only problem I have with ZIndex being 1-10, is that the default is 1.
So its impossible to put GUIs under other guis, without going through EVERYTHING and increasing the ZIndex, to ‘create room’ for going down.
The default should be like 5. So you can go both above and below. Would probably be enough to have Enum.ZIndexType.Absolute/Relative as a property. With the usual parenting-order effect for things with same ZIndex.