GUI Objects Should Calculate ZIndex Relative to their Parent

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.

26 Likes

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:

A.ZIndex = 1
	a.ZIndex = 3
	b.ZIndex = 5
B.ZIndex = 2
	c.ZIndex = 4
	d.ZIndex = 6

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.

1 Like

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.

1 Like

Going for modal style windows popups would greatly benefit from this change

2 Likes

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.

1 Like

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.

1 Like

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.

1 Like

I haven’t read this post by @Anaminus in a long time, but it might still be relevant. It’s 4 years old.

3 Likes

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.

1 Like

I had no idea this limitation existed. Does it have to be 1-10 or do you literally mean 10 digits. Like 54245646 is a valid index?

1 Like

I agree with all of this.

2 Likes

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.

1 Like

It’s up to the value of 10. Apparently a technical side effect because of the strategy they use to render multiple UI layers IIRC.

Is there any hard technical reason for 10 or is it just a nice round number?

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

That is ridiculous when combined with no inheritance on Zorder.

I don’t believe that the cost of sorting is a performance bottleneck especially when coherence is so high (sort rarely changes from frame to frame).

It is very easy to have a GUI where more than 10 things overlap - Handle Overlapping Buttons Properly.

2 Likes

Please

3 Likes

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.

1 Like