godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.69k stars 20.11k forks source link

RichTextLabel: Newly Instanced RichTextLabel's add_text() and append_text() don't add to text #94630

Open Joey-Einerhand opened 1 month ago

Joey-Einerhand commented 1 month ago

Tested versions

System information

Godot v4.2.1.stable - Windows 11- GLES3 (Compatibility)

Issue description

When a RichTextLabel is instanced via code, the methods add_text() and append_text() do not add text to the RichTextLabel. This happends regardless of waiting; see code snippet below. RichTextLabel's Text property stays empty.

When a RichTextLabel is instanced via code, adding text via label.text += "text to add" successfully adds text to the RichTextLabel.

When a RichTextLabel is instanced in the editor, the methods add_text() and append_text() successfully adds text to the RichTextLabel.

I've also attached an Minimal reproduction project to this issue.

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
    create_new_richtextlabel()

func create_new_richtextlabel() -> void:
    var text_to_add: String = "Hello World!"
    var new_richtextlabel: RichTextLabel = RichTextLabel.new()
    add_child(new_richtextlabel)

    # Wait until were sure the new richtextlabel is ready
    while (not new_richtextlabel.is_node_ready()):
        await get_tree().process_frame

    print("Waited, RichTextLabel is now ready")
    print("Text to add is: \'", text_to_add, "\'")
    new_richtextlabel.add_text(text_to_add)
    print("Text after add_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.append_text(text_to_add)
    print("Text after append_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.text += text_to_add
    print("Text after += is \' ", new_richtextlabel.text, "\'")

    print("\n Clearing text.. \n")
    new_richtextlabel.text = ""

    print("Waiting for 5 seconds")
    await get_tree().create_timer(5.0).timeout
    print("Text to add is: \'", text_to_add, "\'")
    new_richtextlabel.add_text(text_to_add)
    print("Text after add_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.append_text(text_to_add)
    print("Text after append_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.text += text_to_add
    print("Text after += is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.push_font_size(25)

Output:

Waited, RichTextLabel is now ready
Text to add is: 'Hello World!'
Text after add_text() is ' '
Text after append_text() is ' '
Text after += is ' Hello World!'

 Clearing text.. 

Waiting for 5 seconds
Text to add is: 'Hello World!'
Text after add_text() is ' '
Text after append_text() is ' '
Text after += is ' Hello World!'

Steps to reproduce

  1. Download the minimal reproduction project
  2. Run the current scene
  3. Look at the output in the console, you will notice new_richtextlabel.text is empty
  4. Look at the new_richtextlabel in the Remote Scene view and you'll notice it's text box is empty

Minimal reproduction project (MRP)

RichTextLabel_AddText_MRP.zip

Giganzo commented 1 month ago

If you set the size of the RichTextLabel to something does the text show up then? Like:

new_richtextlabel.size = Vector2(150,150)

Edit: The text in inspector for remote stays empty and printing .text is empty. However .get_parsed_text() prints the text.

Question, if you switch to the remote tab and try to type in the text box for the RichTextLabel does it jump the caret to the start while you are typing? So if you was to type something like "testing" it becomes "ingtest".

AThousandShips commented 1 month ago

Can you please confirm with 4.2.2, or even better 4.3.beta3 to get an idea where this currently occurs

Please make bug reports with a supported version, 4.2.1 is not supported and a lot of bugs have been fixed since 4.2.1

Giganzo commented 1 month ago

I did my test in 4.3beta3

Not sure how the RichTextLabel works, but is this intended and something that should be more clear in documentation?

Joey-Einerhand commented 1 month ago

Question, if you switch to the remote tab and try to type in the text box for the RichTextLabel does it jump the caret to the start while you are typing? So if you was to type something like "testing" it becomes "ingtest".

4.3.beta3, Godot 4.2.2-stable: This results in the caret jumping to the start, "testing" becomes "ingtest". However I can't seem to find a pattern for when this happends; it's not after a certain amount of time or amount of characters.

4.0-alpha1: Carret does not jump to start; after each letter typed, the text box empties itself after a few milliseconds, before the next letter is typed (even when no letter is typed after it). so "t" becomes "", "testing" becomes ""

Godot 3.6-rc1: Typing in the Bbcode text and text fields in the Remote tab works as expected.

Edit: The text in inspector for remote stays empty and printing .text is empty. However .get_parsed_text() prints the text.

Can confirm for 4.3beta3, Godot 4.2.2-stable, v4.2.1.stable.official, Godot 4.0-alpha1 that .get_parsed_text() prints the correct text, but still does not show text in the Remote inspector's text field, and neither is the text displayed on-screen regardless if bbcode enabled is enabled or size is set with new_richtextlabel.size = Vector2(150,150)

Can you please confirm with 4.2.2, or even better 4.3.beta3 to get an idea where this currently occurs Please make bug reports with a supported version, 4.2.1 is not supported and a lot of bugs have been fixed since 4.2.1

Apologies, I read over the In a given minor release series, only the latest patch release receives support..

Issue exists in: 4.3beta3, Godot 4.2.2-stable, v4.2.1.stable.official, Godot 4.0-alpha1 (earliest available Godot 4 build), results are the same as in original post; Issue does not exist in: Godot 3.6-rc1 (oldest Godot 3 candidate)

hence this issue was introduced in the transition to Godot 4.

In 3.6-rc1, both add_text and append_bbcode() (which is the 3.6 equivelant of append_text()) work correctly; they do add text after initialisation.

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
    create_new_richtextlabel()

func create_new_richtextlabel() -> void:
    var text_to_add: String = "Hello World!"
    var new_richtextlabel: RichTextLabel = RichTextLabel.new()
    add_child(new_richtextlabel)

    # Wait until were sure the new richtextlabel is ready
    while (not new_richtextlabel.is_node_ready()):
        yield(get_tree(), "idle_frame")

    print("Waited, RichTextLabel is now ready")
    print("Text to add is: \'", text_to_add, "\'")
    new_richtextlabel.add_text(text_to_add)
    print("Text after add_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.append_bbcode(text_to_add)
    print("Text after append_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.text += text_to_add
    print("Text after += is \' ", new_richtextlabel.text, "\'")

    print("\n Clearing text.. \n")
    new_richtextlabel.text = ""

    print("Waiting for 5 seconds")
    yield(get_tree().create_timer(5.0), "timeout")
    print("Text to add is: \'", text_to_add, "\'")
    new_richtextlabel.add_text(text_to_add)
    print("Text after add_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.append_bbcode(text_to_add)
    print("Text after append_text() is \' ", new_richtextlabel.text, "\'")
    new_richtextlabel.text += text_to_add
    print("Text after += is \' ", new_richtextlabel.text, "\'")

Results in:

Waited, RichTextLabel is now ready
Text to add is: 'Hello World!'
Text after add_text() is ' Hello World!'
Text after append_text() is ' Hello World!Hello World!'
Text after += is ' Hello World!Hello World!Hello World!'

 Clearing text.. 

Waiting for 5 seconds
Text to add is: 'Hello World!'
Text after add_text() is ' Hello World!'
Text after append_text() is ' Hello World!Hello World!'
Text after += is ' Hello World!Hello World!Hello World!

Which is the expected result.

Edit: Exact versions also edited into OP, but for completeness sake:

bruvzg commented 1 month ago

This is exactly how it supposed to work, in 4.x text property is equivalent to 3.x bbcode_text, and 3.x text property is replaced with get_parsed_text().

Joey-Einerhand commented 1 month ago

If you set the size of the RichTextLabel to something does the text show up then? Like:

Let me correct myself; the text does show up when size is set and font_size is set, apologies

This is exactly how it supposed to work, in 4.x text property is equivalent to 3.x bbcode_text, and 3.x text property is replaced with get_parsed_text().

Understood. However, I believe the caret jumping to the start of the text box in the text property to still be a bug; should I make a seperate issue for this?

richtextlabel_caretjump

In any case I'll aim towards discussion of the current topic. I have a few questions:

  1. Editor: Would it make the workings of RichTextLabel more clear to the user, if they were able to edit or at least see the "parsed_text" in the remote inspector on runtime?
  2. Editor: Would it be wise to mirror the contents of parsed_text to the text property so it can be edited in the remote inspector on runtime?

And a few opinions:

  1. Documentation: In the RichTextLabel.text property section in the docs, there is a note recommending to, instead of using += when bbcode_enabled is enabled to use "Use append_text for adding text instead". This specific wording might make it sound like using append_text() adds text to the RichTextLabel.text field, regardless of the "Is not representative of manual modifications to the internal tag stack." warning at the start of the RichTextLabel.text section. We might want to word this differently and reference to the Tag Stack as described in append_text()
  2. Documentation: We might want to expand a bit upon the "Is not representative of manual modifications to the internal tag stack." warning at the start of the RichTextLabel.text section. It is a clear description if you know about the way RichTextLabel works, but might be unclear to newcommers; Maybe we want to expand upon this a bit?
  3. Documentation: While we're at it, it might be more clear to newcommers if we explain the concept of the Tag Stack in general.
  4. Documentation: In a potential new Tag Stack section in the docs, it would be clearer if we explicitly reiterated that changing the Tag Stack via append_text() and add_text() does not change RichTextLabel.Text directly, but RichTextLabel.Text += does
bruvzg commented 1 month ago

However, I believe the caret jumping to the start of the text box in the text property to still be a bug; should I make a seperate issue for this?

Definitely a bug.

Editor: Would it make the workings of RichTextLabel more clear to the user, if they were able to edit or at least see the "parsed_text" in the remote inspector on runtime? Editor: Would it be wise to mirror the contents of parsed_text to the text property so it can be edited in the remote inspector on runtime?

Editing parsed text makes no sense, it won't contain any tags set by push_* and will reset RTL to plain text only if edited, this is exactly why it was removed and replaced with read only method. Generating BBCode from tags and updating and updating text might be worth implementing.

Internally, RTL use stack of tags, not text property. So when text is set, it will be parsed into a series of add_text, push_*, pop calls to update internal RTL state, but this is one way process. Even if we'll add a method to re-generate BBCode from internal state, it won't be fully identical to the source text, since the same tags can be formatted differently. append_text do the same, but without resetting current internal state.

get_parsed_text() returns only plain text, it is used for copying it to the clipboard.

Joey-Einerhand commented 1 month ago

Definitely a bug.

I'll make a seperate issue, then.

Editing parsed text makes no sense, it won't contain any tags set by push_* and will reset RTL to plain text only if edited, this is exactly why it was removed and replaced with read only method.

I see.

Internally, RTL use stack of tags, not text property. So when text is set, it will be parsed into a series of addtext, push*, pop calls to update internal RTL state, but this is one way process. Even if we'll add a method to re-generate BBCode from internal state, it won't be fully identical to the source text, since the same tags can be formatted differently. append_text do the same, but without resetting current internal state.

I'm not sure I completely understand, but I think displaying any approximation of the current internal state of the stack in remote-only read-only editor field would be incredibly helpful to the users, even if it doesn't exactly match the source text. More in the line of a "How does RTL see the stack". If I have the wrong idea of how this works, please do tell.

What do you think?