godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.13k stars 92 forks source link

Add more methods to operate on visible lines in RichTextLabel #2698

Open Xascoria opened 3 years ago

Xascoria commented 3 years ago

Describe the project you are working on

Text-based game.

Describe the problem or limitation you are having in your project

I'm making a text game where new lines are added in like terminal, pretty basic stuffs. However, I wanted to discard the old lines after the screen is full. The problem is that the only method on visible lines in the richtextlabel is get_visible_line_count(), which is useful to know when I should discard the line on top. However, there's no way to do this. All the line-based methods (ie. remove_line) within RichTextLabel operates on \n new line, which potentially discard more than 1 visible line.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add methods like remove_line(int line), scroll_to_line(int line) but for visible lines of the Richtextlabel.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

remove_visible_line(int line),scroll_to_visible_line(int line) etc

If this enhancement will not be used often, can it be worked around with a few lines of script?

Since it's not possible to get font glyph size in godot, there's no way to calculate how much characters a line takes up unless it's monospaced. (Wrong, see @Error7Studios' response) I tried using Labels for each line, but that would mean removing characters 1 by 1 until I know it fits within a line is with get_visible_line_count(). I think I don't have to say how janky that is.

Is there a reason why this should be core and not an add-on in the asset library?

N/A

Calinou commented 3 years ago

I'm making a text game where new lines are added in like terminal, pretty basic stuffs. However, I wanted to discard the old lines after the screen is full.

You could enable the follow scrolling property in RichTextLabel and disallow manually scrolling.

Error7Studios commented 3 years ago

@Xascoria I made an example project that will scroll to any (wrapped) line in a pixel-perfect way. Also included a function to erase all the lines above the top displayed line.

Video:

https://user-images.githubusercontent.com/60025044/117550143-36c26780-b004-11eb-9b66-c3df84e378fa.mp4

Project: Custom RichTextLabel Scrolling - 2.zip

Controls: Up Arrow: Scroll up 3 lines Down Arrow: Scroll down 3 lines Z: Delete all lines above top displayed line Escape: Quit

@Calinou I think functions like get_wrapped_lines() from the example project should be included in the RichTextLabel class. It took me a while to figure out how to get that working.

Xascoria commented 3 years ago

@Calinou Could work, but I would also potential be storing couple hundreds or thousands of lines that I no longer need, it probably won't get to the point where it starts impacting performance. I could probably make the buffer a lot bigger than it needs to be and then just use remove_line(int line) to ensure that 99.9% of the time I wouldn't erase something I want. But again, janky as hell.

@Error7Studios I spent some times to looked at this, this is exactly what I wanted so thank you? (Although I was gonna implement it myself today). And yea I agree, way too much workaround just for something like this.

Error7Studios commented 3 years ago

Bugfix. Newline characters are now preserved. Custom RichTextLabel Scrolling - 2.zip

https://user-images.githubusercontent.com/60025044/117563486-de26b500-b06b-11eb-89e3-f431277349e3.mp4

Tols-Toy commented 3 years ago

This is by no means a knock on your proposal, but is there any reason why you're not creating RTL children for each line inside a VBoxContainer? I've done that in (albeit extreme small) test projects, and it worked a charm for exactly your problem. Also gave me a lot of flexibility that only one RTL node wouldn't have given me.

Xascoria commented 3 years ago

@Tols-Toy No worries dude, it was because I need a line that's too long and wrapped around be considered 2 lines, which is very janky to detect (see above). And really that's all I need anyway, not other features of RTL.