0 votes

I have a very simple scene:

> top_node: Node
>> other_nodes

One of the other nodes should add a very simple toast with a test at the bottom of the screen, centered horizontally:
Goal
I made a control scene to do this:

> toast: MarginContainer
>> PanelContainer
>>> CenterContainer
>>>> Label

I am struggling to correctly set the anchors and margins. As far as I understand, the anchors mean "what proportion of the parent node should my side's margin be relative to?". I set top & bottom to 1 and left/right to 0.5.

However, as the left border takes precedence over the right one, if I set left/right margins to 0, the toast won't be centered, rather its left edge will be at the center. I could set left margin to, say -20 and right one to 20, but I'd like these numbers to depend on the actual size, not to be hardcoded (otherwise it'll create slack if label is smaller than 40 and won't be perfectly centered if it's bigger than 40).

  1. Do I have to recalculate the margins somewhere based on the current size every time I change the text in the label?

After testing the toast scene separately, I tried adding it to the main scene by: get_tree().get_current_scene().add_child(). This put the toast in the top-left corner, as if the scene itself had size 0,0 (and thus anchors didn't have the effect). When I used get_tree().get_root() instead, all worked correctly. I would prefer if the dynamically created nodes were the children of the scene and not the root viewport though.
2. Is there a way to make the top_node fill its viewport? Or maybe it's actually better for the control nodes like this to be children of the viewport?
3. Given that margins set the position of the node, what is the point in having a separate position field for the Control nodes? (When) should I use it at all?

Sorry for the long post, these margins/anchors are hard to wrap one's head around

Godot version v3.1.1-stable
in Engine by (68 points)

1 Answer

+1 vote

You can place a text label (or button, or anything, really) centered horizontally in another container, for example a PanelContainer, by doing the following:

  1. Make sure the label's Container has size flags on "Expand", the left anchor set to 0 and the right anchor set to 1. This assures that the Container that contains the Label will take up all the horizontal space it can.
  2. Now set the label's size flags: Disable horizontal "Fill" and enable horizontal "Expand", and "Shrink Center".

You don't need to touch the label's margins; these will be auto-calculated by it's container.

The thing to realize is that when you place something in a container, you lose much of the control you get via the position, rect size and margin properties (the only thing that stays under your full control is the minimum size, AFAIK). For controls placed in containers, what really matters for layouting is their size flags.

To answer your question 2, I'd add an instanced scene that contains control nodes that I expect to be layouted correctly as a child of a Control container; this way, the layouting of the instanced scene will just work inside the container. If you want the instanced scene to expand to the size of the viewport, you make sure that the container you instance it in has that size (by setting anchors and expand flags).

As to your question 3, I'm not sure. I imagine it's for when you want to place "naked" controls without any containers doing the layouting for you. Possibly "position" and "margin" are just two views into data that's connected at a lower level (kinda like a Rect2 has an "end" property but that depends on the "position" and "size" properties).

by (289 points)
edited by

Re 1: That's why I said "or anything, really" in my first sentence. You can of course replace the Label by another Container, in which you then place the Label. That should work fine, and you can set the inner container's minimum size if you want to control that.

Re 2: That might be a problem. One way to solve this might be to listen to the "resized" signal and set the size manually, then.

Re: 1. if I do this, the PanelContainer will span the whole horizontal area, whereas I'd Iike it to wrap the label, like in the screenshot.
Re: 2: the problem is, the top_node (which is meant to be a parent) is not a Control, so I can't set the anchors there

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.