summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp13
-rw-r--r--scene/gui/base_button.h3
-rw-r--r--scene/gui/box_container.cpp1
-rw-r--r--scene/gui/control.cpp84
-rw-r--r--scene/gui/control.h8
-rw-r--r--scene/gui/dialogs.cpp4
-rw-r--r--scene/gui/label.cpp127
-rw-r--r--scene/gui/label.h27
-rw-r--r--scene/gui/tree.cpp62
9 files changed, 238 insertions, 91 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index c1ae0479f5..8414c4dc78 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -226,6 +226,18 @@ void BaseButton::set_pressed(bool p_pressed) {
update();
}
+void BaseButton::set_pressed_no_signal(bool p_pressed) {
+ if (!toggle_mode) {
+ return;
+ }
+ if (status.pressed == p_pressed) {
+ return;
+ }
+ status.pressed = p_pressed;
+
+ update();
+}
+
bool BaseButton::is_pressing() const {
return status.press_attempt;
}
@@ -399,6 +411,7 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &BaseButton::_unhandled_key_input);
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed);
ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed);
+ ClassDB::bind_method(D_METHOD("set_pressed_no_signal", "pressed"), &BaseButton::set_pressed_no_signal);
ClassDB::bind_method(D_METHOD("is_hovered"), &BaseButton::is_hovered);
ClassDB::bind_method(D_METHOD("set_toggle_mode", "enabled"), &BaseButton::set_toggle_mode);
ClassDB::bind_method(D_METHOD("is_toggle_mode"), &BaseButton::is_toggle_mode);
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 6c7a8f3433..d86b35daf0 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -98,7 +98,8 @@ public:
bool is_pressing() const; ///< return whether button is pressed (toggled in)
bool is_hovered() const;
- void set_pressed(bool p_pressed); ///only works in toggle mode
+ void set_pressed(bool p_pressed); // Only works in toggle mode.
+ void set_pressed_no_signal(bool p_pressed);
void set_toggle_mode(bool p_on);
bool is_toggle_mode() const;
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 7407ad5b8f..40a49dbb58 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -349,6 +349,7 @@ void BoxContainer::_bind_methods() {
MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control *p_control, bool p_expand) {
Label *l = memnew(Label);
+ l->set_theme_type_variation("HeaderSmall");
l->set_text(p_label);
add_child(l);
MarginContainer *mc = memnew(MarginContainer);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index d42b505f7b..718e754514 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -339,13 +339,6 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
void Control::_get_property_list(List<PropertyInfo> *p_list) const {
Ref<Theme> theme = Theme::get_default();
- /* Using the default theme since the properties below are meant for editor only
- if (data.theme.is_valid()) {
- theme = data.theme;
- } else {
- theme = Theme::get_default();
-
- }*/
{
List<StringName> names;
@@ -421,6 +414,34 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Control::_validate_property(PropertyInfo &property) const {
+ if (property.name == "theme_type_variation") {
+ List<StringName> names;
+
+ // Only the default theme and the project theme are used for the list of options.
+ // This is an imposed limitation to simplify the logic needed to leverage those options.
+ Theme::get_default()->get_type_variation_list(get_class_name(), &names);
+ if (Theme::get_project_default().is_valid()) {
+ Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ }
+ names.sort_custom<StringName::AlphCompare>();
+
+ Vector<StringName> unique_names;
+ String hint_string;
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ // Skip duplicate values.
+ if (unique_names.has(E->get())) {
+ continue;
+ }
+
+ hint_string += String(E->get()) + ",";
+ unique_names.append(E->get());
+ }
+
+ property.hint_string = hint_string;
+ }
+}
+
Control *Control::get_parent_control() const {
return data.parent;
}
@@ -867,18 +888,19 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
}
void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
- if (data.theme_custom_type != StringName()) {
- p_list->push_back(data.theme_custom_type);
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
+ if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
+ Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
+ } else {
+ Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
}
- Theme::get_type_dependencies(get_class_name(), p_list);
} else {
- Theme::get_type_dependencies(p_theme_type, p_list);
+ Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
if (tex) {
return *tex;
@@ -891,7 +913,7 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
if (style) {
return *style;
@@ -904,7 +926,7 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Font> *font = data.font_override.getptr(p_name);
if (font) {
return *font;
@@ -917,7 +939,7 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const int *font_size = data.font_size_override.getptr(p_name);
if (font_size) {
return *font_size;
@@ -930,7 +952,7 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Color *color = data.color_override.getptr(p_name);
if (color) {
return *color;
@@ -943,7 +965,7 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const int *constant = data.constant_override.getptr(p_name);
if (constant) {
return *constant;
@@ -986,7 +1008,7 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
}
bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_icon_override(p_name)) {
return true;
}
@@ -998,7 +1020,7 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
}
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_stylebox_override(p_name)) {
return true;
}
@@ -1010,7 +1032,7 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
}
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_font_override(p_name)) {
return true;
}
@@ -1022,7 +1044,7 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
}
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_font_size_override(p_name)) {
return true;
}
@@ -1034,7 +1056,7 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
}
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_color_override(p_name)) {
return true;
}
@@ -1046,7 +1068,7 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
}
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_theme_constant_override(p_name)) {
return true;
}
@@ -2031,13 +2053,13 @@ Ref<Theme> Control::get_theme() const {
return data.theme;
}
-void Control::set_theme_custom_type(const StringName &p_theme_type) {
- data.theme_custom_type = p_theme_type;
+void Control::set_theme_type_variation(const StringName &p_theme_type) {
+ data.theme_type_variation = p_theme_type;
_propagate_theme_changed(this, data.theme_owner, data.theme_owner_window);
}
-StringName Control::get_theme_custom_type() const {
- return data.theme_custom_type;
+StringName Control::get_theme_type_variation() const {
+ return data.theme_type_variation;
}
void Control::set_tooltip(const String &p_tooltip) {
@@ -2660,8 +2682,8 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Control::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme);
- ClassDB::bind_method(D_METHOD("set_theme_custom_type", "theme_type"), &Control::set_theme_custom_type);
- ClassDB::bind_method(D_METHOD("get_theme_custom_type"), &Control::get_theme_custom_type);
+ ClassDB::bind_method(D_METHOD("set_theme_type_variation", "theme_type"), &Control::set_theme_type_variation);
+ ClassDB::bind_method(D_METHOD("get_theme_type_variation"), &Control::get_theme_type_variation);
ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_override);
ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Control::add_theme_style_override);
@@ -2810,7 +2832,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,20,0.01,or_greater"), "set_stretch_ratio", "get_stretch_ratio");
ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_custom_type"), "set_theme_custom_type", "get_theme_custom_type");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
ADD_GROUP("", "");
BIND_ENUM_CONSTANT(FOCUS_NONE);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 0642686a9f..fb01295668 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -202,7 +202,7 @@ private:
Ref<Theme> theme;
Control *theme_owner = nullptr;
Window *theme_owner_window = nullptr;
- StringName theme_custom_type;
+ StringName theme_type_variation;
String tooltip;
CursorShape default_cursor = CURSOR_ARROW;
@@ -279,8 +279,8 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_notification);
-
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
//bind helpers
@@ -402,8 +402,8 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
- void set_theme_custom_type(const StringName &p_theme_type);
- StringName get_theme_custom_type() const;
+ void set_theme_type_variation(const StringName &p_theme_type);
+ StringName get_theme_type_variation() const;
void set_h_size_flags(int p_flags);
int get_h_size_flags() const;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index dceab00607..9d0a6a3380 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -148,11 +148,11 @@ bool AcceptDialog::get_hide_on_ok() const {
}
void AcceptDialog::set_autowrap(bool p_autowrap) {
- label->set_autowrap(p_autowrap);
+ label->set_autowrap_mode(p_autowrap ? Label::AUTOWRAP_WORD : Label::AUTOWRAP_OFF);
}
bool AcceptDialog::has_autowrap() {
- return label->has_autowrap();
+ return label->get_autowrap_mode() != Label::AUTOWRAP_OFF;
}
void AcceptDialog::register_text_enter(Control *p_line_edit) {
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 6580d794d1..78b9ad2569 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -36,20 +36,20 @@
#include "servers/text_server.h"
-void Label::set_autowrap(bool p_autowrap) {
- if (autowrap != p_autowrap) {
- autowrap = p_autowrap;
+void Label::set_autowrap_mode(Label::AutowrapMode p_mode) {
+ if (autowrap_mode != p_mode) {
+ autowrap_mode = p_mode;
lines_dirty = true;
}
update();
- if (clip) {
+ if (clip || overrun_behavior != OVERRUN_NO_TRIMMING) {
minimum_size_changed();
}
}
-bool Label::has_autowrap() const {
- return autowrap;
+Label::AutowrapMode Label::get_autowrap_mode() const {
+ return autowrap_mode;
}
void Label::set_uppercase(bool p_uppercase) {
@@ -94,24 +94,76 @@ void Label::_shape() {
dirty = false;
lines_dirty = true;
}
+
+ uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
if (lines_dirty) {
for (int i = 0; i < lines_rid.size(); i++) {
TS->free(lines_rid[i]);
}
lines_rid.clear();
- Vector<Vector2i> lines = TS->shaped_text_get_line_breaks(text_rid, width, 0, (autowrap) ? (TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) : TextServer::BREAK_MANDATORY);
+ uint8_t autowrap_flags = TextServer::BREAK_MANDATORY;
+ switch (autowrap_mode) {
+ case AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ break;
+ case AUTOWRAP_WORD:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case AUTOWRAP_ARBITRARY:
+ autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case AUTOWRAP_OFF:
+ break;
+ }
+ Vector<Vector2i> lines = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+
for (int i = 0; i < lines.size(); i++) {
RID line = TS->shaped_text_substr(text_rid, lines[i].x, lines[i].y - lines[i].x);
+
+ switch (overrun_behavior) {
+ case OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_WORD:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ break;
+ case OVERRUN_TRIM_CHAR:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ break;
+ case OVERRUN_NO_TRIMMING:
+ break;
+ }
+
+ if (autowrap_mode == AUTOWRAP_OFF && align != ALIGN_FILL && overrun_behavior != OVERRUN_NO_TRIMMING) {
+ TS->shaped_text_overrun_trim_to_width(line, width, overrun_flags);
+ }
+
lines_rid.push_back(line);
}
+
+ if (autowrap_mode != AUTOWRAP_OFF && overrun_behavior != OVERRUN_NO_TRIMMING) {
+ int visible_lines = get_visible_line_count();
+
+ if (visible_lines < lines_rid.size() && visible_lines > 0) {
+ overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
+ }
+ }
}
if (xl_text.length() == 0) {
minsize = Size2(1, get_line_height());
return;
}
- if (!autowrap) {
+ if (autowrap_mode == AUTOWRAP_OFF) {
minsize.width = 0.0f;
for (int i = 0; i < lines_rid.size(); i++) {
if (minsize.width < TS->shaped_text_get_size(lines_rid[i]).x) {
@@ -120,10 +172,21 @@ void Label::_shape() {
}
}
- if (lines_dirty) { // Fill after min_size calculation.
+ if (lines_dirty) {
+ // Fill after min_size calculation.
if (align == ALIGN_FILL) {
for (int i = 0; i < lines_rid.size(); i++) {
- TS->shaped_text_fit_to_width(lines_rid.write[i], width);
+ if (overrun_behavior != OVERRUN_NO_TRIMMING && autowrap_mode == AUTOWRAP_OFF) {
+ float line_unaltered_width = TS->shaped_text_get_width(lines_rid[i]);
+ TS->shaped_text_fit_to_width(lines_rid[i], width);
+ float new_line_width = TS->shaped_text_get_width(lines_rid[i]);
+ // Begin trimming when there is no space between words available anymore.
+ if (new_line_width < line_unaltered_width) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ }
+ } else {
+ TS->shaped_text_fit_to_width(lines_rid[i], width);
+ }
}
}
lines_dirty = false;
@@ -131,7 +194,7 @@ void Label::_shape() {
_update_visible();
- if (!autowrap || !clip) {
+ if (autowrap_mode == AUTOWRAP_OFF || !clip || overrun_behavior == OVERRUN_NO_TRIMMING) {
minimum_size_changed();
}
}
@@ -370,13 +433,12 @@ Size2 Label::get_minimum_size() const {
min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size("font_size")) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM));
Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
- if (autowrap) {
- return Size2(1, clip ? 1 : min_size.height) + min_style;
+ if (autowrap_mode != AUTOWRAP_OFF) {
+ return Size2(1, (clip || overrun_behavior != OVERRUN_NO_TRIMMING) ? 1 : min_size.height) + min_style;
} else {
- if (clip) {
+ if (clip || overrun_behavior != OVERRUN_NO_TRIMMING) {
min_size.width = 1;
}
-
return min_size + min_style;
}
}
@@ -536,6 +598,21 @@ bool Label::is_clipping_text() const {
return clip;
}
+void Label::set_text_overrun_behavior(Label::OverrunBehavior p_behavior) {
+ if (overrun_behavior != p_behavior) {
+ overrun_behavior = p_behavior;
+ lines_dirty = true;
+ }
+ update();
+ if (clip || overrun_behavior != OVERRUN_NO_TRIMMING) {
+ minimum_size_changed();
+ }
+}
+
+Label::OverrunBehavior Label::get_text_overrun_behavior() const {
+ return overrun_behavior;
+}
+
String Label::get_text() const {
return text;
}
@@ -663,10 +740,12 @@ void Label::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_opentype_features"), &Label::clear_opentype_features);
ClassDB::bind_method(D_METHOD("set_language", "language"), &Label::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &Label::get_language);
- ClassDB::bind_method(D_METHOD("set_autowrap", "enable"), &Label::set_autowrap);
- ClassDB::bind_method(D_METHOD("has_autowrap"), &Label::has_autowrap);
+ ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &Label::set_autowrap_mode);
+ ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &Label::get_autowrap_mode);
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_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);
ClassDB::bind_method(D_METHOD("is_uppercase"), &Label::is_uppercase);
ClassDB::bind_method(D_METHOD("get_line_height", "line"), &Label::get_line_height, DEFVAL(-1));
@@ -696,13 +775,25 @@ void Label::_bind_methods() {
BIND_ENUM_CONSTANT(VALIGN_BOTTOM);
BIND_ENUM_CONSTANT(VALIGN_FILL);
+ BIND_ENUM_CONSTANT(AUTOWRAP_OFF);
+ BIND_ENUM_CONSTANT(AUTOWRAP_ARBITRARY);
+ BIND_ENUM_CONSTANT(AUTOWRAP_WORD);
+ BIND_ENUM_CONSTANT(AUTOWRAP_WORD_SMART);
+
+ BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
ADD_PROPERTY(PropertyInfo(Variant::INT, "valign", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_valign", "get_valign");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autowrap"), "set_autowrap", "has_autowrap");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
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::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 032b4112e1..8b48eb9670 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -51,13 +51,29 @@ public:
VALIGN_FILL
};
+ enum AutowrapMode {
+ AUTOWRAP_OFF,
+ AUTOWRAP_ARBITRARY,
+ AUTOWRAP_WORD,
+ AUTOWRAP_WORD_SMART
+ };
+
+ enum OverrunBehavior {
+ OVERRUN_NO_TRIMMING,
+ OVERRUN_TRIM_CHAR,
+ OVERRUN_TRIM_WORD,
+ OVERRUN_TRIM_ELLIPSIS,
+ OVERRUN_TRIM_WORD_ELLIPSIS,
+ };
+
private:
Align align = ALIGN_LEFT;
VAlign valign = VALIGN_TOP;
String text;
String xl_text;
- bool autowrap = false;
+ AutowrapMode autowrap_mode = AUTOWRAP_OFF;
bool clip = false;
+ OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
Size2 minsize;
bool uppercase = false;
@@ -118,8 +134,8 @@ public:
void set_structured_text_bidi_override_options(Array p_args);
Array get_structured_text_bidi_override_options() const;
- void set_autowrap(bool p_autowrap);
- bool has_autowrap() const;
+ void set_autowrap_mode(AutowrapMode p_mode);
+ AutowrapMode get_autowrap_mode() const;
void set_uppercase(bool p_uppercase);
bool is_uppercase() const;
@@ -131,6 +147,9 @@ public:
void set_clip_text(bool p_clip);
bool is_clipping_text() const;
+ void set_text_overrun_behavior(OverrunBehavior p_behavior);
+ OverrunBehavior get_text_overrun_behavior() const;
+
void set_percent_visible(float p_percent);
float get_percent_visible() const;
@@ -150,5 +169,7 @@ public:
VARIANT_ENUM_CAST(Label::Align);
VARIANT_ENUM_CAST(Label::VAlign);
+VARIANT_ENUM_CAST(Label::AutowrapMode);
+VARIANT_ENUM_CAST(Label::OverrunBehavior);
#endif
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 98de71d81c..4d2cb81f23 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -99,39 +99,44 @@ void TreeItem::_change_tree(Tree *p_tree) {
c = c->next;
}
- if (tree && tree->root == this) {
- tree->root = nullptr;
- }
+ if (tree) {
+ if (tree->root == this) {
+ tree->root = nullptr;
+ }
- if (tree && tree->popup_edited_item == this) {
- tree->popup_edited_item = nullptr;
- tree->pressing_for_editor = false;
- }
+ if (tree->popup_edited_item == this) {
+ tree->popup_edited_item = nullptr;
+ tree->pressing_for_editor = false;
+ }
- if (tree && tree->cache.hover_item == this) {
- tree->cache.hover_item = nullptr;
- }
+ if (tree->cache.hover_item == this) {
+ tree->cache.hover_item = nullptr;
+ }
- if (tree && tree->selected_item == this) {
- tree->selected_item = nullptr;
- }
+ if (tree->selected_item == this) {
+ tree->selected_item = nullptr;
+ }
- if (tree && tree->drop_mode_over == this) {
- tree->drop_mode_over = nullptr;
- }
+ if (tree->drop_mode_over == this) {
+ tree->drop_mode_over = nullptr;
+ }
- if (tree && tree->single_select_defer == this) {
- tree->single_select_defer = nullptr;
- }
+ if (tree->single_select_defer == this) {
+ tree->single_select_defer = nullptr;
+ }
+
+ if (tree->edited_item == this) {
+ tree->edited_item = nullptr;
+ tree->pressing_for_editor = false;
+ }
- if (tree && tree->edited_item == this) {
- tree->edited_item = nullptr;
- tree->pressing_for_editor = false;
+ tree->update();
}
tree = p_tree;
if (tree) {
+ tree->update();
cells.resize(tree->columns.size());
}
}
@@ -451,6 +456,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
TreeItem *ti = memnew(TreeItem(tree));
if (tree) {
ti->cells.resize(tree->columns.size());
+ tree->update();
}
TreeItem *l_prev = nullptr;
@@ -654,11 +660,7 @@ void TreeItem::move_before(TreeItem *p_item) {
next = p_item;
p_item->prev = this;
- if (old_tree && old_tree != tree) {
- old_tree->update();
- }
-
- if (tree) {
+ if (tree && old_tree == tree) {
tree->update();
}
}
@@ -696,11 +698,7 @@ void TreeItem::move_after(TreeItem *p_item) {
parent->children_cache.append(this);
}
- if (old_tree && old_tree != tree) {
- old_tree->update();
- }
-
- if (tree) {
+ if (tree && old_tree == tree) {
tree->update();
}
}