[TextParagraph/Button] Add support for line spacing.

This commit is contained in:
bruvzg 2024-10-09 19:41:03 +03:00
parent 4c4e673344
commit 309712551c
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
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">
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 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">
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.

View File

@ -122,7 +122,7 @@
[Color] of the text's shadow effect.
</theme_item>
<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 name="outline_size" data_type="constant" type="int" default="0">
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.
</member>
<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 name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour">
Text [Color] of the [Label3D].

View File

@ -19,7 +19,7 @@
Size of the text.
</member>
<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 name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)">
The color of the outline.

View File

@ -810,7 +810,7 @@
The default background color for odd rows.
</theme_item>
<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 name="outline_size" data_type="constant" type="int" default="0">
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.
</theme_item>
<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 name="outline_size" data_type="constant" type="int" default="0">
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.
</member>
<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 name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
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">
Line fill alignment rules. See [enum TextServer.JustificationFlag] for more information.
</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">
Limits the lines of text shown.
</member>

View File

@ -568,6 +568,7 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
}
autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
p_paragraph->set_break_flags(autowrap_flags);
p_paragraph->set_line_spacing(theme_cache.line_spacing);
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@ -840,6 +841,7 @@ void Button::_bind_methods() {
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, line_spacing);
}
Button::Button(const String &p_text) {

View File

@ -100,6 +100,7 @@ private:
int h_separation = 0;
int icon_max_width = 0;
int line_spacing = 0;
} theme_cache;
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");
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_object_rect", "line", "key"), &TextParagraph::get_line_object_rect);
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) {
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;
h += line_spacing;
if (!tab_stops.is_empty()) {
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.y += lsize.y;
if (i != visible_lines - 1) {
size.y += line_spacing;
}
} else {
if (h_offset > 0 && i <= dropcap_lines) {
lsize.y += h_offset;
}
size.x += lsize.x;
size.y = MAX(size.y, lsize.y);
if (i != visible_lines - 1) {
size.x += line_spacing;
}
}
}
if (h_offset > 0) {
@ -612,6 +624,19 @@ int TextParagraph::get_max_lines_visible() const {
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 {
_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 (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
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 {
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);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
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 {
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);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
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 {
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)) {
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 {
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);
}
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;

View File

@ -51,6 +51,7 @@ private:
bool lines_dirty = true;
float line_spacing = 0.0;
float width = -1.0;
int max_lines_visible = -1;
@ -122,6 +123,9 @@ public:
void set_max_lines_visible(int p_lines);
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_size() const;