Merge pull request #98036 from bruvzg/para_btn_spacing

[TextParagraph/Button] Add support for line spacing.
This commit is contained in:
Thaddeus Crews 2024-11-10 12:13:03 -06:00
commit 6bbc1cb6a9
No known key found for this signature in database
GPG Key ID: 62181B86FE9E5D84
12 changed files with 52 additions and 14 deletions

View File

@ -127,6 +127,9 @@
<theme_item name="icon_max_width" data_type="constant" type="int" default="0"> <theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the [Button]'s icon. This limit is applied on top of the default size of the icon, or its expanded size if [member expand_icon] is [code]true[/code]. The height is adjusted according to the icon's ratio. If the button has additional icons (e.g. [CheckBox]), they will also be limited. The maximum allowed width of the [Button]'s icon. This limit is applied on top of the default size of the icon, or its expanded size if [member expand_icon] is [code]true[/code]. The height is adjusted according to the icon's ratio. If the button has additional icons (e.g. [CheckBox]), they will also be limited.
</theme_item> </theme_item>
<theme_item name="line_spacing" data_type="constant" type="int" default="0">
Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0"> <theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline. The size of the text outline.
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.

View File

@ -122,7 +122,7 @@
[Color] of the text's shadow effect. [Color] of the text's shadow effect.
</theme_item> </theme_item>
<theme_item name="line_spacing" data_type="constant" type="int" default="3"> <theme_item name="line_spacing" data_type="constant" type="int" default="3">
Vertical space between lines in multiline [Label]. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</theme_item> </theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0"> <theme_item name="outline_size" data_type="constant" type="int" default="0">
Text outline size. Text outline size.

View File

@ -79,7 +79,7 @@
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member> </member>
<member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0"> <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0">
Vertical space between lines in multiline [Label3D]. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</member> </member>
<member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour">
Text [Color] of the [Label3D]. Text [Color] of the [Label3D].

View File

@ -19,7 +19,7 @@
Size of the text. Size of the text.
</member> </member>
<member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="3.0"> <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="3.0">
Vertical space between lines when the text is multiline. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</member> </member>
<member name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)"> <member name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)">
The color of the outline. The color of the outline.

View File

@ -810,7 +810,7 @@
The default background color for odd rows. The default background color for odd rows.
</theme_item> </theme_item>
<theme_item name="line_separation" data_type="constant" type="int" default="0"> <theme_item name="line_separation" data_type="constant" type="int" default="0">
The vertical space between lines. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</theme_item> </theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0"> <theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline. The size of the text outline.

View File

@ -1624,7 +1624,7 @@
The caret's width in pixels. Greater values can be used to improve accessibility by ensuring the caret is easily visible, or to ensure consistency with a large font size. If set to [code]0[/code] or lower, the caret width is automatically set to 1 pixel and multiplied by the display scaling factor. The caret's width in pixels. Greater values can be used to improve accessibility by ensuring the caret is easily visible, or to ensure consistency with a large font size. If set to [code]0[/code] or lower, the caret width is automatically set to 1 pixel and multiplied by the display scaling factor.
</theme_item> </theme_item>
<theme_item name="line_spacing" data_type="constant" type="int" default="4"> <theme_item name="line_spacing" data_type="constant" type="int" default="4">
Sets the spacing between the lines. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</theme_item> </theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0"> <theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline. The size of the text outline.

View File

@ -37,7 +37,7 @@
Language code used for text shaping algorithms, if left empty current locale is used instead. Language code used for text shaping algorithms, if left empty current locale is used instead.
</member> </member>
<member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0"> <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0">
Vertical space between lines in multiline [TextMesh]. Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</member> </member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
The text drawing offset (in pixels). The text drawing offset (in pixels).

View File

@ -280,6 +280,9 @@
<member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163"> <member name="justification_flags" type="int" setter="set_justification_flags" getter="get_justification_flags" enum="TextServer.JustificationFlag" is_bitfield="true" default="163">
Line fill alignment rules. See [enum TextServer.JustificationFlag] for more information. Line fill alignment rules. See [enum TextServer.JustificationFlag] for more information.
</member> </member>
<member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0">
Additional vertical spacing between lines (in pixels), spacing is added to line descent. This value can be negative.
</member>
<member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1"> <member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1">
Limits the lines of text shown. Limits the lines of text shown.
</member> </member>

View File

@ -561,6 +561,7 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
} }
autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES; autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
p_paragraph->set_break_flags(autowrap_flags); p_paragraph->set_break_flags(autowrap_flags);
p_paragraph->set_line_spacing(theme_cache.line_spacing);
if (text_direction == Control::TEXT_DIRECTION_INHERITED) { if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@ -833,6 +834,7 @@ void Button::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, icon_max_width); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, icon_max_width);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, align_to_largest_stylebox); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, align_to_largest_stylebox);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, line_spacing);
} }
Button::Button(const String &p_text) { Button::Button(const String &p_text) {

View File

@ -100,6 +100,7 @@ private:
int h_separation = 0; int h_separation = 0;
int icon_max_width = 0; int icon_max_width = 0;
int line_spacing = 0;
} theme_cache; } theme_cache;
void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = ""); void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = "");

View File

@ -112,6 +112,11 @@ void TextParagraph::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible"), "set_max_lines_visible", "get_max_lines_visible"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible"), "set_max_lines_visible", "get_max_lines_visible");
ClassDB::bind_method(D_METHOD("set_line_spacing", "line_spacing"), &TextParagraph::set_line_spacing);
ClassDB::bind_method(D_METHOD("get_line_spacing"), &TextParagraph::get_line_spacing);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing"), "set_line_spacing", "get_line_spacing");
ClassDB::bind_method(D_METHOD("get_line_objects", "line"), &TextParagraph::get_line_objects); ClassDB::bind_method(D_METHOD("get_line_objects", "line"), &TextParagraph::get_line_objects);
ClassDB::bind_method(D_METHOD("get_line_object_rect", "line", "key"), &TextParagraph::get_line_object_rect); ClassDB::bind_method(D_METHOD("get_line_object_rect", "line", "key"), &TextParagraph::get_line_object_rect);
ClassDB::bind_method(D_METHOD("get_line_size", "line"), &TextParagraph::get_line_size); ClassDB::bind_method(D_METHOD("get_line_size", "line"), &TextParagraph::get_line_size);
@ -180,6 +185,7 @@ void TextParagraph::_shape_lines() {
for (int i = 0; i < line_breaks.size(); i = i + 2) { for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]); RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x; float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x;
h += line_spacing;
if (!tab_stops.is_empty()) { if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(line, tab_stops); TS->shaped_text_tab_align(line, tab_stops);
} }
@ -574,12 +580,18 @@ Size2 TextParagraph::get_size() const {
} }
size.x = MAX(size.x, lsize.x); size.x = MAX(size.x, lsize.x);
size.y += lsize.y; size.y += lsize.y;
if (i != visible_lines - 1) {
size.y += line_spacing;
}
} else { } else {
if (h_offset > 0 && i <= dropcap_lines) { if (h_offset > 0 && i <= dropcap_lines) {
lsize.y += h_offset; lsize.y += h_offset;
} }
size.x += lsize.x; size.x += lsize.x;
size.y = MAX(size.y, lsize.y); size.y = MAX(size.y, lsize.y);
if (i != visible_lines - 1) {
size.x += line_spacing;
}
} }
} }
if (h_offset > 0) { if (h_offset > 0) {
@ -612,6 +624,19 @@ int TextParagraph::get_max_lines_visible() const {
return max_lines_visible; return max_lines_visible;
} }
void TextParagraph::set_line_spacing(float p_spacing) {
_THREAD_SAFE_METHOD_
if (line_spacing != p_spacing) {
line_spacing = p_spacing;
lines_dirty = true;
}
}
float TextParagraph::get_line_spacing() const {
return line_spacing;
}
Array TextParagraph::get_line_objects(int p_line) const { Array TextParagraph::get_line_objects(int p_line) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
@ -697,10 +722,10 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
if (i != p_line) { if (i != p_line) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) { if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = 0.f; ofs.x = 0.f;
ofs.y += TS->shaped_text_get_descent(lines_rid[i]); ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else { } else {
ofs.y = 0.f; ofs.y = 0.f;
ofs.x += TS->shaped_text_get_descent(lines_rid[i]); ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} }
} }
} }
@ -872,10 +897,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color); TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) { if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x; ofs.x = p_pos.x;
ofs.y += TS->shaped_text_get_descent(lines_rid[i]); ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else { } else {
ofs.y = p_pos.y; ofs.y = p_pos.y;
ofs.x += TS->shaped_text_get_descent(lines_rid[i]); ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} }
} }
} }
@ -974,10 +999,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color); TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) { if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x; ofs.x = p_pos.x;
ofs.y += TS->shaped_text_get_descent(lines_rid[i]); ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else { } else {
ofs.y = p_pos.y; ofs.y = p_pos.y;
ofs.x += TS->shaped_text_get_descent(lines_rid[i]); ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} }
} }
} }
@ -1001,12 +1026,12 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(line_rid).y)) { if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(line_rid).y)) {
return TS->shaped_text_hit_test_position(line_rid, p_coords.x); return TS->shaped_text_hit_test_position(line_rid, p_coords.x);
} }
ofs.y += TS->shaped_text_get_size(line_rid).y; ofs.y += TS->shaped_text_get_size(line_rid).y + line_spacing;
} else { } else {
if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(line_rid).x)) { if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(line_rid).x)) {
return TS->shaped_text_hit_test_position(line_rid, p_coords.y); return TS->shaped_text_hit_test_position(line_rid, p_coords.y);
} }
ofs.y += TS->shaped_text_get_size(line_rid).x; ofs.y += TS->shaped_text_get_size(line_rid).x + line_spacing;
} }
} }
return TS->shaped_text_get_range(rid).y; return TS->shaped_text_get_range(rid).y;

View File

@ -51,6 +51,7 @@ private:
bool lines_dirty = true; bool lines_dirty = true;
float line_spacing = 0.0;
float width = -1.0; float width = -1.0;
int max_lines_visible = -1; int max_lines_visible = -1;
@ -122,6 +123,9 @@ public:
void set_max_lines_visible(int p_lines); void set_max_lines_visible(int p_lines);
int get_max_lines_visible() const; int get_max_lines_visible() const;
void set_line_spacing(float p_spacing);
float get_line_spacing() const;
Size2 get_non_wrapped_size() const; Size2 get_non_wrapped_size() const;
Size2 get_size() const; Size2 get_size() const;