Resizable Label3D (and possibly extending it)

Godot Version

Godot 4.3 Dev 5

Question

Hello, I trying to get my Label3D to resize the text automatically to fit within its width if the text overflows rather than adding new lines.

From what I’ve seen, that functionality doesn’t currently exist, so I began looking into implementing it myself through a class that extends Label3D.

Some issues I’ve run into so far has been trying to override the SetText method and Text property so that I can re-evaluate the size/scale depending on the new text. (What would have been nice is if Label3D fired an event/signal for OnTextChanged)

It looks like the set methods are not virtual and I’ve been unable to extend via C# or GDScript. I had found a plugin that basically created this functionality for the Label control and it looks like they were able to override set_text in GDScript somehow, while I get an error in my class.

I was just looking for some ideas/insight. Is “_set_text” a valid overridable method that will be called by the engine? Some places online seem to hint that methods prefixed with “_” are virtual, though I didn’t see this method in source. (I may have missed it)

Bumping. I would really appreciate any help.

I did a similar thing for Label You may be able to adjust it for Label3D:

@tool
class_name AutoSizeLabel extends Label


@export var max_font_size = 56


func _ready() -> void:
	clip_text = true
	item_rect_changed.connect(_on_item_rect_changed)


func _set(property: StringName, value: Variant) -> bool:
	match property:
		"text":
			# listen for text changes
			update_font_size()

	return false


func update_font_size() -> void:
	var font = get_theme_font("font")
	var font_size = get_theme_font_size("font_size")

	var line = TextLine.new()
	line.direction = text_direction
	line.flags = justification_flags
	line.alignment = horizontal_alignment

	for i in 20:
		line.clear()
		var created = line.add_string(text, font, font_size)
		if created:
			var text_size = line.get_line_width()

			if text_size > floor(size.x):
				font_size -= 1
			elif font_size < max_font_size:
				font_size += 1
			else:
				break
		else:
			push_warning('Could not create a string')
			break

	add_theme_font_size_override("font_size", font_size)


func _on_item_rect_changed() -> void:
	update_font_size()

Thanks mrcdk! I’ll give that a shot.

Sharing the solution that worked for me in case others need it, thanks again mrcdk for the help!

@tool
class_name AutoSizeLabel3D extends Label3D

#region Private Fields

@export 
var maxFontSize = 56

#endregion

#region Public Label3D Methods

func _set( property: StringName, value: Variant ) -> bool:
    # listen for text or width changes
    match property:
        "text":
            _update_font_size( value )
        "width":
            _update_font_size( text )

    return false

#endregion

#region Private Methods

func _update_font_size( textVal: String ) -> void:
    var line = TextLine.new()
    line.direction = text_direction
    line.flags = justification_flags
    line.alignment = horizontal_alignment

    for i in 20:
        line.clear()
        var created = line.add_string( textVal, font, font_size )
        if created:
            var text_size = line.get_line_width()
            if text_size > floor( width ):
                font_size -= 1
            elif font_size < maxFontSize:
                font_size += 1
            else:
                break
        else:
            push_warning( 'Could not create a string' )
            break
    
#endregion