How to force Godot to recalculate control nodes size/position?

Viewed 5140

Building UI in Godot 3.2.1. Of course I use anchors so UI elements are arranged within the screen automatically according to specified layout. I have UI scale system - nothing fancy - simply change font size (DynamicFont.size). If font size is large enough then some UI nodes may be pushed out of the screen. However, nodes don't return to normal sizes/positions with font size decreasing. The way to fix a mess is to resize game window which is not always an option and doesn't seem like a correct way to handle the issue. So how can I force Godot to recalculate control nodes size/position?

enter image description here

3 Answers

Changing the parent control's minimum size to Vector2(0, 0) after changing the font size might do the trick:

$Control.rect_min_size = Vector2(0, 0)

If it's already set to Vector2(0, 0), you may have to change it twice using call_deferred() for it to work.

In your scene tree, find the top level container that contains all of the elements that you want to recalculate. This would be the lowest common ancestor in the scene tree, in computer science terminology. Now, hide the container, by setting it's 'visible' property to false. Then, add a deferred call to change it's 'visible' property back to true.

var your_container = $".".find_node("your-container")
your_container.visible = false
your_container.call_deferred("set_visible", true)

This seems to cause Godot to recalculate the layout of 'your_container'.

It looks like only CanvasItem derived classes have a 'visible' property, so you would not be able to simply set the 'visible' property on a CanvasLayer, for example.

Fortunately, Containers and Controls both derive from CannvasItem, so this methodology should work fine if your lowest common ancestor node is either a Container or a Control or other CanvasItem derived class instance.

I got this working by emitting a signal from a parent element, which appears to force a refresh:

canvas_item.emit_signal("item_rect_changed")

The problem child got refreshed, and unlike the visibility method, focus was retained.

Related