The get_visible_line_count() and scroll_to_line() methods of RichTextLabel don't make sense

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By nimh

As far as I can tell, the get_visible_line_count() method of RichTextLabel only counts autowraps, not actual newlines in your text. Possibly it’s even weirder than that. get_line_count() only counts newlines but not autowraps (and obviously doesn’t care if the lines are visible or not). scroll_to_line() only counts newlines.

Here’s the thing. You have a RichTextLabel with text in it. That label can only fit so many lines of text and you need to scroll to the lines you can’t see, regardless of whether those lines exist because of newlines in the text string or autowraps. So why does scroll_to_line() ignore autowraps, and why can’t you get the actual number of lines your text takes up in the RichTextLabel or the actual number of lines that are visible (according to the the visible_characters property)? Actually you can get the total number of lines, if you know your font’s height, since get_content_height() does work in a useful manner. However, there is no way to scroll to an arbitrary location, so that doesn’t help.

Here’s what I’m trying to do, but can’t. Maybe I’m doing this wrong, and someone can explain how I should go about it. I want to add rich text textboxes to my game. I don’t want them to automatically scroll if there is more text than can fit in the textbox, and I also don’t want them to have a scroll bar. I want them to work like they do in all sorts of games. I want the text to fill up the textbox, and then stop until the player presses a key. Then the textbox clears and is fill up with the next bit of text.

Say for example, I have 8 lines of text (and this means it would take an 8 line tall RichTextLabel to display it all at once. It shouldn’t matter whether I add the newlines, or let the text get autowrapped, it still takes up the same 8 lines) and a RichTextLabel that is tall enough to show 3 lines at a time. I want lines 1-3 shown. When the user presses a key, lines 4-6 are shown. When the user presses a key again, lines 7 & 8 are shown.

I tried to do this in _physics_process(), increasing visible_characters until get_visible_line_count() is larger than the number of lines my RichTextLabel can show (3 in my example). As long as I only use autowrapped text, this works. Then, when a button is pressed, I try to scroll the RichTextLabel to the next line (4 in my example) with scroll_to_line(). This causes an error, since get_visible_line_count() doesn’t count newlines, and scroll_to_line() only counts newlines, so according to it, there is only one line of text. Why can’t they both just count the actual number of lines your text takes up in the RichTextLabel. Failing that, it there was the ability to scroll to some arbitrary point, instead of a line number, I could do the math to make this work.

Now, I can obviously work around this by never having messages that take up more than 3 lines. Instead I can manually break long blocks of text into separate messages. But especially with rich text, it’s hard to know how much text you can fit in three lines. Also, if I later want to change my text, I have to reformat it into separate messages again.

I feel like I’m working around a bad design here, rather than simply going about this in the wrong way, but if there is a better way to do this, I’d love to hear it.

:bust_in_silhouette: Reply From: Gluon

Why dont you just change the text in the label instead of having it all in there and scrolling down?

func _process(delta):
    if input.is_action_pressed("change text"):
        change_text("your new text here")

func change_text(NewText):
    get_node("path to your richtext lable here").text = NewText

then have a dictionary or something and add the new text each time into your call to the change text function.

I don’t have all the text in there. I have a message queue, and messages get displayed one at a time by updating the RichTextLabel text property, like you suggest. Like I said, I can work around this by splitting all the long bits of dialog into multiple messages (that’s what I’m currently doing) but that gets to be a pain. It’s hard to know how much text can fit in my textbox, especially with BBcode, without resorting to trial and error. So for each bunch of text, I would start with trying to print the whole thing at once, see what is visible in the textbox, spilt that off into its own message, and then repeat for the rest of the text, until I have all my correct sized messages. If I decide to change an early part of the message, or notice I made a spelling or grammar error, I need refactor the text again, starting with the message I made the changes in. If there would be translations, I would need to do the refactoring into separate messages again on all of those. It’s certainly doable, but it’s not as easy as just being able to have my textbox object able to print out the text in chunks that always fit in the RichTextLabel. The reason I’m trying to update my textbox code is because I’m annoyed with having to do this manually.

I just want to understand what the rational is behind how get_visible_line_count() and scroll_to_line() work, because I think that they are not well thought out. Perhaps there is a good reason why they work this way, and the majority of people would be annoyed if they changed to treat all lines, whether they happen because of autowraps or newline characters, the same. Also, I’d like to know if anyone has a good solution for making a textbox that can display all the things that you can with RichTextLabel, that will automatically display only the amount of text that can fill the textbox, and then be able to be updated to skip to the next bit of text, and so forth.

nimh | 2022-01-04 18:30