Your suspicion is correct - before a new message is added check to see if you're scrolled to the bottom, then after adding the new message set the scroll position to maximum.
However there are two problems to deal with.
The first is detecting whether you're scrolled to the bottom. When scrolled all the way down, a scrollbar's value
is not equal to its max_value
. The max_value
is closer to value
plus the scroll container's height, so compare the value
to max_value
minus the scroll container's rect_size.y
. I'm not sure if you'll have issues with margins or custom theme settings, so this might need some tweaking.
The other problem is that the scroll container is not updated on the same frame as when the message is added, so be sure to wait a frame before attempting to set the scrollbar's value. One way to do this is to wait for the SceneTree's idle_frame
signal.
In the following example I have a ScrollContainer named scroll_box
and inside of that a VBoxContainer named msg_container
.
func add_message(message: String) -> void:
var scroll_bar = scroll_box.get_v_scrollbar()
var should_auto_scroll = ((scroll_bar.max_value - scroll_box.rect_size.y) - scroll_bar.value) <= 0
var label = Label.new()
label.text = message
msg_container.add_child(label)
yield(get_tree(), "idle_frame")
if should_auto_scroll:
scroll_bar.value = scroll_bar.max_value