Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Label] Add support for tab stops. #76129

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/classes/Label.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
<member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]">
Set additional options for BiDi override.
</member>
<member name="tab_stops" type="PackedFloat32Array" setter="set_tab_stops" getter="get_tab_stops" default="PackedFloat32Array()">
Aligns text to the given tab-stops.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could an example be shown using a codeblock? How many values should I add to the array in general?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One value for the const. width stops, or more for different width spacing (list is repeated). Not sure how to best describe it without an image.

Essentially, it's an equivalent of this list in the text editors:
Screenshot 2023-04-16 at 22 56 18

</member>
<member name="text" type="String" setter="set_text" getter="get_text" default="&quot;&quot;">
The text to display on screen.
</member>
Expand Down
43 changes: 34 additions & 9 deletions scene/gui/label.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ void Label::_shape() {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, txt));
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(text_rid, tab_stops);
}
dirty = false;
font_dirty = false;
lines_dirty = true;
Expand Down Expand Up @@ -162,6 +165,9 @@ void Label::_shape() {
PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(line, tab_stops);
}
lines_rid.push_back(line);
}
}
Expand Down Expand Up @@ -205,6 +211,10 @@ void Label::_shape() {

// Fill after min_size calculation.

BitField<TextServer::JustificationFlag> line_jst_flags = jst_flags;
if (!tab_stops.is_empty()) {
line_jst_flags.set_flag(TextServer::JUSTIFICATION_AFTER_LAST_TAB);
}
if (autowrap_mode != TextServer::AUTOWRAP_OFF) {
int visible_lines = get_visible_line_count();
bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
Expand All @@ -213,13 +223,13 @@ void Label::_shape() {
}
if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
int jst_to_line = visible_lines;
if (lines_rid.size() == 1 && jst_flags.has_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE)) {
if (lines_rid.size() == 1 && line_jst_flags.has_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE)) {
jst_to_line = lines_rid.size();
} else {
if (jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE)) {
if (line_jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE)) {
jst_to_line = visible_lines - 1;
}
if (jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS)) {
if (line_jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS)) {
for (int i = visible_lines - 1; i >= 0; i--) {
if (TS->shaped_text_has_visible_chars(lines_rid[i])) {
jst_to_line = i;
Expand All @@ -230,7 +240,7 @@ void Label::_shape() {
}
for (int i = 0; i < lines_rid.size(); i++) {
if (i < jst_to_line) {
TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
}
Expand All @@ -241,13 +251,13 @@ void Label::_shape() {
} else {
// Autowrap disabled.
int jst_to_line = lines_rid.size();
if (lines_rid.size() == 1 && jst_flags.has_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE)) {
if (lines_rid.size() == 1 && line_jst_flags.has_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE)) {
jst_to_line = lines_rid.size();
} else {
if (jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE)) {
if (line_jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE)) {
jst_to_line = lines_rid.size() - 1;
}
if (jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS)) {
if (line_jst_flags.has_flag(TextServer::JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS)) {
for (int i = lines_rid.size() - 1; i >= 0; i--) {
if (TS->shaped_text_has_visible_chars(lines_rid[i])) {
jst_to_line = i;
Expand All @@ -258,10 +268,10 @@ void Label::_shape() {
}
for (int i = 0; i < lines_rid.size(); i++) {
if (i < jst_to_line && horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags);
overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
} else {
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
}
Expand Down Expand Up @@ -853,6 +863,18 @@ bool Label::is_clipping_text() const {
return clip;
}

void Label::set_tab_stops(const PackedFloat32Array &p_tab_stops) {
if (tab_stops != p_tab_stops) {
tab_stops = p_tab_stops;
dirty = true;
queue_redraw();
}
}

PackedFloat32Array Label::get_tab_stops() const {
return tab_stops;
}

void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
if (overrun_behavior == p_behavior) {
return;
Expand Down Expand Up @@ -986,6 +1008,8 @@ void Label::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_justification_flags"), &Label::get_justification_flags);
ClassDB::bind_method(D_METHOD("set_clip_text", "enable"), &Label::set_clip_text);
ClassDB::bind_method(D_METHOD("is_clipping_text"), &Label::is_clipping_text);
ClassDB::bind_method(D_METHOD("set_tab_stops", "tab_stops"), &Label::set_tab_stops);
ClassDB::bind_method(D_METHOD("get_tab_stops"), &Label::get_tab_stops);
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &Label::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &Label::get_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("set_uppercase", "enable"), &Label::set_uppercase);
Expand Down Expand Up @@ -1019,6 +1043,7 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "tab_stops"), "set_tab_stops", "get_tab_stops");

ADD_GROUP("Displayed Text", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
Expand Down
4 changes: 4 additions & 0 deletions scene/gui/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Label : public Control {
float visible_ratio = 1.0;
int lines_skipped = 0;
int max_lines_visible = -1;
PackedFloat32Array tab_stops;

Ref<LabelSettings> settings;

Expand Down Expand Up @@ -142,6 +143,9 @@ class Label : public Control {
void set_clip_text(bool p_clip);
bool is_clipping_text() const;

void set_tab_stops(const PackedFloat32Array &p_tab_stops);
PackedFloat32Array get_tab_stops() const;

void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
TextServer::OverrunBehavior get_text_overrun_behavior() const;

Expand Down