godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.1k stars 69 forks source link

Add `CanvasItem.draw_string_rect()` for bounded text drawing #5639

Open Lielay9 opened 1 year ago

Lielay9 commented 1 year ago

Describe the project you are working on

A game relying mostly on custom drawing for UI elements. This has popped up multiple times while trying to embed text into various buttons and sliders.

Describe the problem or limitation you are having in your project

There are now at least 4 different ways to draw strings from code: CanvasItem.draw_string(), Font.draw_string(), TextLine and TextParagraph. All the methods are difficult to position due to either only accepting the position of the first letters left bottom/top corner. Also, it's only possible to align the text horizontally by providing the optional width parameter, but not vertically.

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

Add a function in which it is possible to provide a Rect2 to draw the text in. The text will be positioned and aligned horizontally and vertically based on the rect. This would reduce boilerplate code repeating something that is already solved in the core (Label).

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

Example (for CanvasItem):

draw_string_rect(font: Font, rect: Rect2, text: String, h_alignment: HorizontalAlignment = 0, v_alignment: VerticalAlignment = 0, font_size: int = 16, modulate: Color = Color(1, 1, 1, 1), jst_flags: JustificationFlag = 3, direction: Direction = 0, orientation: Orientation = 0)

I'd also like it if there were a boolean property to allow the text to write outside the bounds of the rect without wrapping or having defined the maximum amount of allowed lines. It is often more desirable to show the text even if it exceeds the size of the rect and not clip it. Same with draw_string() and length but that's a proposal of its own.

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

It is possible to calculate the string size and descent and manually position the text, but it is error-prone and requires knowledge of the terminology. It's of course also possible to use Label but that defeats the point of custom drawing.

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

The functionality already exists in the core (Label). It'd be redundant to mimic it through add-ons.

Mickeon commented 1 year ago

Label could also internally make use of this method, instead of doing its own logic. It's a lot of arguments for a single method call, but the same can be said for the normal draw_string() method...

There's also draw_multiline_string() actually. It's a more advanced version of the original. Perhaps it may a good idea fo this method to be a derivate of it, to support new lines and tabulations ~(not sure if tabs work?)~, perhaps?

Lielay9 commented 1 year ago

Label could also internally make use of this method, instead of doing its own logic. It's a lot of arguments for a single method call, but the same can be said for the normal draw_string() method...

AFAIK, internally CanvasItem.draw_string() is just a wrapper for Font.draw_string() which just creates a new TextLine with the provided arguments. I'm not certain if there are some tangible benefits for the separation of TextLine or if it could use TextParagraph internally with max lines set to one. Otherwise, we could, in theory, condense all the logic to TextParagraph.

To me, it looks like the code for Label is structured a little differently but does practically the same things as TextParagraph with the addition of handling themes, displayed text (skipped_lines, visible_characters etc.), vertical alignment and auto translating. I think it'd be worthwhile to see if the vertical alignment could be moved to TextParagraph and have the Label switch to use it internally.

Again, not hundred percent positive this is all there is to it so better wait for someone more knowledgeable to tell me why I'm a dumdum.

EDIT:

There's also draw_multiline_string() actually. It's a more advanced version of the original. Perhaps it may a good idea fo this method to be a derivate of it, to support new lines and tabulations ~(not sure if tabs work?)~, perhaps?

I think TextParagraph already supports new lines, but not tabulations. (?)

bruvzg commented 1 year ago

I guess moving vertical align to the TextParagraph would make sense, but not so sure about adding functions to the Font or CanvasItem.

I think TextParagraph already supports new lines, but not tabulations. (?)

Both TexeParagraph and TextLine already have tab_align method.

For the reference, tab_align is equivalent of adding tab marks in the office apps ruler:

Screenshot 2022-10-24 at 08 00 00