summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp4
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/button.cpp4
-rw-r--r--scene/gui/code_edit.cpp10
-rw-r--r--scene/gui/control.cpp4
-rw-r--r--scene/gui/control.h2
-rw-r--r--scene/gui/dialogs.cpp4
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/gradient_edit.h1
-rw-r--r--scene/gui/graph_edit.cpp54
-rw-r--r--scene/gui/graph_edit.h4
-rw-r--r--scene/gui/graph_node.cpp2
-rw-r--r--scene/gui/item_list.cpp16
-rw-r--r--scene/gui/label.cpp2
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/link_button.cpp2
-rw-r--r--scene/gui/option_button.cpp105
-rw-r--r--scene/gui/option_button.h7
-rw-r--r--scene/gui/popup_menu.cpp30
-rw-r--r--scene/gui/rich_text_label.cpp10
-rw-r--r--scene/gui/spin_box.cpp4
-rw-r--r--scene/gui/tab_bar.cpp8
-rw-r--r--scene/gui/tab_container.cpp6
-rw-r--r--scene/gui/text_edit.cpp151
-rw-r--r--scene/gui/text_edit.h5
-rw-r--r--scene/gui/tree.cpp20
26 files changed, 276 insertions, 191 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 9f712ed478..5f740ecaa0 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -355,8 +355,8 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const {
String tooltip = Control::get_tooltip(p_pos);
if (shortcut_in_tooltip && shortcut.is_valid() && shortcut->has_valid_event()) {
String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")";
- if (tooltip != String() && shortcut->get_name().nocasecmp_to(tooltip) != 0) {
- text += "\n" + tooltip;
+ if (!tooltip.is_empty() && shortcut->get_name().nocasecmp_to(tooltip) != 0) {
+ text += "\n" + atr(tooltip);
}
tooltip = text;
}
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index fc05d51937..6aaa8433ec 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -351,11 +351,11 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control
Label *l = memnew(Label);
l->set_theme_type_variation("HeaderSmall");
l->set_text(p_label);
- add_child(l, false, INTERNAL_MODE_FRONT);
+ add_child(l);
MarginContainer *mc = memnew(MarginContainer);
mc->add_theme_constant_override("margin_left", 0);
mc->add_child(p_control, true);
- add_child(mc, false, INTERNAL_MODE_FRONT);
+ add_child(mc);
if (p_expand) {
mc->set_v_size_flags(SIZE_EXPAND_FILL);
}
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 655fc783d7..8bb41e7abf 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -52,7 +52,7 @@ Size2 Button::get_minimum_size() const {
if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
minsize.width += _icon->get_width();
- if (xl_text != "") {
+ if (!xl_text.is_empty()) {
minsize.width += get_theme_constant(SNAME("hseparation"));
}
} else {
@@ -359,7 +359,7 @@ void Button::_shape() {
} else {
text_buf->set_direction((TextServer::Direction)text_direction);
}
- text_buf->add_string(xl_text, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ text_buf->add_string(xl_text, font, font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
}
void Button::set_text(const String &p_text) {
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 23ac36c5eb..ba37d51e24 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -189,7 +189,7 @@ void CodeEdit::_notification(int p_what) {
}
/* Code hint */
- if (caret_visible && code_hint != "" && (!code_completion_active || (code_completion_below != code_hint_draw_below))) {
+ if (caret_visible && !code_hint.is_empty() && (!code_completion_active || (code_completion_below != code_hint_draw_below))) {
const int font_height = font->get_height(font_size);
Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"));
Color font_color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
@@ -315,7 +315,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
} else {
if (mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_command_pressed() && symbol_lookup_word != String()) {
+ if (mb->is_command_pressed() && !symbol_lookup_word.is_empty()) {
Vector2i mpos = mb->get_position();
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
@@ -530,7 +530,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
/* General overrides */
Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
- if (symbol_lookup_word != String()) {
+ if (!symbol_lookup_word.is_empty()) {
return CURSOR_POINTING_HAND;
}
@@ -2597,7 +2597,7 @@ void CodeEdit::_add_delimiter(const String &p_start_key, const String &p_end_key
delimiter.type = p_type;
delimiter.start_key = p_start_key;
delimiter.end_key = p_end_key;
- delimiter.line_only = p_line_only || p_end_key == "";
+ delimiter.line_only = p_line_only || p_end_key.is_empty();
delimiters.insert(at, delimiter);
if (!setting_delimiters) {
delimiter_cache.clear();
@@ -2647,7 +2647,7 @@ void CodeEdit::_set_delimiters(const TypedArray<String> &p_delimiters, Delimiter
const String start_key = key.get_slice(" ", 0);
const String end_key = key.get_slice_count(" ") > 1 ? key.get_slice(" ", 1) : String();
- _add_delimiter(start_key, end_key, end_key == "", p_type);
+ _add_delimiter(start_key, end_key, end_key.is_empty(), p_type);
}
setting_delimiters = false;
_update_delimiter_cache();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 3a926b3fb5..1fdc30eb6d 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2597,7 +2597,7 @@ bool Control::is_text_field() const {
return false;
}
-Array Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const {
+Array Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String &p_text) const {
Array ret;
switch (p_theme_type) {
case STRUCTURED_TEXT_URI: {
@@ -2791,7 +2791,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
TypedArray<String> Control::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
- if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") {
+ if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
warnings.push_back(TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
}
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 4cc949d0a8..ae9ca1489a 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -279,7 +279,7 @@ protected:
//virtual void _window_gui_input(InputEvent p_event);
- virtual Array structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const;
+ virtual Array structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String &p_text) const;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index f66d3f6835..f1725e57ea 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -242,7 +242,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
hbc->add_spacer(true);
}
- if (p_action != "") {
+ if (!p_action.is_empty()) {
button->connect("pressed", callable_mp(this, &AcceptDialog::_custom_action), varray(p_action));
}
@@ -251,7 +251,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
- if (p_cancel == "") {
+ if (p_cancel.is_empty()) {
c = TTRC("Cancel");
}
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 1210be15ce..b887499ad4 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -432,6 +432,10 @@ Gradient::InterpolationMode GradientEdit::get_interpolation_mode() {
return interpolation_mode;
}
+ColorPicker *GradientEdit::get_picker() {
+ return picker;
+}
+
void GradientEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("ramp_changed"));
}
diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h
index 66b60d87c7..1e2059c4e3 100644
--- a/scene/gui/gradient_edit.h
+++ b/scene/gui/gradient_edit.h
@@ -75,6 +75,7 @@ public:
Vector<Gradient::Point> &get_points();
void set_interpolation_mode(Gradient::InterpolationMode p_interp_mode);
Gradient::InterpolationMode get_interpolation_mode();
+ ColorPicker *get_picker();
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 32c62b7226..a008ed7180 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -549,15 +549,13 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
}
for (int j = 0; j < gn->get_connection_output_count(); j++) {
- Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (is_in_hot_zone(pos / zoom, p_point / zoom, port_size, false)) {
+ if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
return true;
}
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
- Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (is_in_hot_zone(pos / zoom, p_point / zoom, port_size, true)) {
+ if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
return true;
}
}
@@ -582,7 +580,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (is_in_hot_zone(pos / zoom, click_pos, port_size, false)) {
+ if (is_in_output_hotzone(gn, j, click_pos, port_size)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
for (const Connection &E : connections) {
@@ -624,7 +622,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (is_in_hot_zone(pos / zoom, click_pos, port_size, true)) {
+ if (is_in_input_hotzone(gn, j, click_pos, port_size)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
for (const Connection &E : connections) {
@@ -690,7 +688,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos, port_size, false)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_output_hotzone(gn, j, mpos, port_size)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -702,7 +700,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos, port_size, true)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_input_hotzone(gn, j, mpos, port_size)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -773,25 +771,27 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos)
}
}
-bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) {
- if (p_left) {
- if (!Rect2(
- pos.x - p_port_size.x / 2 - port_grab_distance_horizontal,
- pos.y - p_port_size.y / 2 - port_grab_distance_vertical / 2,
- p_port_size.x + port_grab_distance_horizontal,
- p_port_size.y + port_grab_distance_vertical)
- .has_point(p_mouse_pos)) {
- return false;
- }
+bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
+ if (get_script_instance() && get_script_instance()->has_method("_is_in_input_hotzone")) {
+ return get_script_instance()->call("_is_in_input_hotzone", p_graph_node, p_slot_index, p_mouse_pos);
} else {
- if (!Rect2(
- pos.x - p_port_size.x / 2,
- pos.y - p_port_size.y / 2 - port_grab_distance_vertical / 2,
- p_port_size.x + port_grab_distance_horizontal,
- p_port_size.y + port_grab_distance_vertical)
- .has_point(p_mouse_pos)) {
- return false;
- }
+ Vector2 pos = p_graph_node->get_connection_input_position(p_slot_index) + p_graph_node->get_position();
+ return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, true);
+ }
+}
+
+bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
+ if (get_script_instance() && get_script_instance()->has_method("_is_in_output_hotzone")) {
+ return get_script_instance()->call("_is_in_output_hotzone", p_graph_node, p_slot_index, p_mouse_pos);
+ } else {
+ Vector2 pos = p_graph_node->get_connection_output_position(p_slot_index) + p_graph_node->get_position();
+ return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, false);
+ }
+}
+
+bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) {
+ if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) {
+ return false;
}
for (int i = 0; i < get_child_count(); i++) {
@@ -2216,6 +2216,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset);
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "_is_in_input_hotzone", PropertyInfo(Variant::OBJECT, "graph_node"), PropertyInfo(Variant::INT, "slot_index"), PropertyInfo(Variant::VECTOR2, "mouse_position")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "_is_in_output_hotzone", PropertyInfo(Variant::OBJECT, "graph_node"), PropertyInfo(Variant::INT, "slot_index"), PropertyInfo(Variant::VECTOR2, "mouse_position")));
ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 6c11f9df6a..e064c237d0 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -183,7 +183,9 @@ private:
GraphEditMinimap *minimap;
void _top_layer_input(const Ref<InputEvent> &p_ev);
- bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
+ bool is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
void _top_layer_draw();
void _connections_layer_draw();
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 3177911a70..7a7b35585e 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -458,7 +458,7 @@ void GraphNode::_shape() {
} else {
title_buf->set_direction((TextServer::Direction)text_direction);
}
- title_buf->add_string(title, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ title_buf->add_string(title, font, font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
}
#ifdef TOOLS_ENABLED
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index a3235dd382..6deb39b9e2 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -43,7 +43,7 @@ void ItemList::_shape(int p_idx) {
} else {
item.text_buf->set_direction((TextServer::Direction)item.text_direction);
}
- item.text_buf->add_string(item.text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), item.opentype_features, (item.language != "") ? item.language : TranslationServer::get_singleton()->get_tool_locale());
+ item.text_buf->add_string(item.text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), item.opentype_features, (!item.language.is_empty()) ? item.language : TranslationServer::get_singleton()->get_tool_locale());
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
item.text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND);
} else {
@@ -653,7 +653,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed() && items.size() > 0) {
if (p_event->is_action("ui_up")) {
- if (search_string != "") {
+ if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
@@ -683,7 +683,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
accept_event();
}
} else if (p_event->is_action("ui_down")) {
- if (search_string != "") {
+ if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
@@ -920,7 +920,7 @@ void ItemList::_notification(int p_what) {
minsize = items[i].get_icon_size() * icon_scale;
}
- if (items[i].text != "") {
+ if (!items[i].text.is_empty()) {
if (icon_mode == ICON_MODE_TOP) {
minsize.y += icon_margin;
} else {
@@ -929,7 +929,7 @@ void ItemList::_notification(int p_what) {
}
}
- if (items[i].text != "") {
+ if (!items[i].text.is_empty()) {
int max_width = -1;
if (fixed_column_width) {
max_width = fixed_column_width;
@@ -1188,7 +1188,7 @@ void ItemList::_notification(int p_what) {
draw_texture(items[i].tag_icon, draw_pos + base_ofs);
}
- if (items[i].text != "") {
+ if (!items[i].text.is_empty()) {
int max_len = -1;
Vector2 size2 = items[i].text_buf->get_size();
@@ -1360,10 +1360,10 @@ String ItemList::get_tooltip(const Point2 &p_pos) const {
if (!items[closest].tooltip_enabled) {
return "";
}
- if (items[closest].tooltip != "") {
+ if (!items[closest].tooltip.is_empty()) {
return items[closest].tooltip;
}
- if (items[closest].text != "") {
+ if (!items[closest].text.is_empty()) {
return items[closest].text;
}
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index bd3a2c2e53..0a09d87509 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -96,7 +96,7 @@ void Label::_shape() {
if (visible_chars >= 0) {
text = text.substr(0, visible_chars);
}
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
dirty = false;
lines_dirty = true;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 9df2f7309c..810781995e 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1017,7 +1017,7 @@ void LineEdit::paste_text() {
// Strip escape characters like \n and \t as they can't be displayed on LineEdit.
String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes();
- if (paste_buffer != "") {
+ if (!paste_buffer.is_empty()) {
int prev_len = text.length();
if (selection.enabled) {
selection_delete();
@@ -2078,7 +2078,7 @@ void LineEdit::_shape() {
const Ref<Font> &font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
ERR_FAIL_COND(font.is_null());
- TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t));
full_width = TS->shaped_text_get_size(text_rid).x;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 9856247b7c..b59f4fb7d4 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -42,7 +42,7 @@ void LinkButton::_shape() {
text_buf->set_direction((TextServer::Direction)text_direction);
}
TS->shaped_text_set_bidi_override(text_buf->get_rid(), structured_text_parser(st_parser, st_args, xl_text));
- text_buf->add_string(xl_text, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ text_buf->add_string(xl_text, font, font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
}
void LinkButton::set_text(const String &p_text) {
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index cbbda09261..61c72fa580 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -110,6 +110,63 @@ void OptionButton::_notification(int p_what) {
}
}
+bool OptionButton::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0] == "popup") {
+ bool valid;
+ popup->set(String(p_name).trim_prefix("popup/"), p_value, &valid);
+
+ int idx = components[1].get_slice("_", 1).to_int();
+ if (idx == current) {
+ // Force refreshing currently displayed item.
+ current = -1;
+ _select(idx, false);
+ }
+
+ return valid;
+ }
+ return false;
+}
+
+bool OptionButton::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0] == "popup") {
+ bool valid;
+ r_ret = popup->get(String(p_name).trim_prefix("popup/"), &valid);
+ return valid;
+ }
+ return false;
+}
+
+void OptionButton::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < popup->get_item_count(); i++) {
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("popup/item_%d/text", i)));
+
+ PropertyInfo pi = PropertyInfo(Variant::OBJECT, vformat("popup/item_%d/icon", i), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D");
+ pi.usage &= ~(popup->get_item_icon(i).is_null() ? PROPERTY_USAGE_STORAGE : 0);
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("popup/item_%d/checkable", i), PROPERTY_HINT_ENUM, "No,As checkbox,As radio button");
+ pi.usage &= ~(!popup->is_item_checkable(i) ? PROPERTY_USAGE_STORAGE : 0);
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::BOOL, vformat("popup/item_%d/checked", i));
+ pi.usage &= ~(!popup->is_item_checked(i) ? PROPERTY_USAGE_STORAGE : 0);
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("popup/item_%d/id", i), PROPERTY_HINT_RANGE, "1,10,1,or_greater");
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::BOOL, vformat("popup/item_%d/disabled", i));
+ pi.usage &= ~(!popup->is_item_disabled(i) ? PROPERTY_USAGE_STORAGE : 0);
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::BOOL, vformat("popup/item_%d/separator", i));
+ pi.usage &= ~(!popup->is_item_separator(i) ? PROPERTY_USAGE_STORAGE : 0);
+ p_list->push_back(pi);
+ }
+}
+
void OptionButton::_focused(int p_which) {
emit_signal(SNAME("item_focused"), p_which);
}
@@ -191,6 +248,12 @@ bool OptionButton::is_item_disabled(int p_idx) const {
return popup->is_item_disabled(p_idx);
}
+void OptionButton::set_item_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ popup->set_item_count(p_count);
+ notify_property_list_changed();
+}
+
int OptionButton::get_item_count() const {
return popup->get_item_count();
}
@@ -267,38 +330,6 @@ PopupMenu *OptionButton::get_popup() const {
return popup;
}
-Array OptionButton::_get_items() const {
- Array items;
- for (int i = 0; i < get_item_count(); i++) {
- items.push_back(get_item_text(i));
- items.push_back(get_item_icon(i));
- items.push_back(is_item_disabled(i));
- items.push_back(get_item_id(i));
- items.push_back(get_item_metadata(i));
- }
-
- return items;
-}
-
-void OptionButton::_set_items(const Array &p_items) {
- ERR_FAIL_COND(p_items.size() % 5);
- clear();
-
- for (int i = 0; i < p_items.size(); i += 5) {
- String text = p_items[i + 0];
- Ref<Texture2D> icon = p_items[i + 1];
- bool disabled = p_items[i + 2];
- int id = p_items[i + 3];
- Variant meta = p_items[i + 4];
-
- int idx = get_item_count();
- add_item(text, id);
- set_item_icon(idx, icon);
- set_item_disabled(idx, disabled);
- set_item_metadata(idx, meta);
- }
-}
-
void OptionButton::get_translatable_strings(List<String> *p_strings) const {
popup->get_translatable_strings(p_strings);
}
@@ -317,7 +348,6 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_index", "id"), &OptionButton::get_item_index);
ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &OptionButton::get_item_metadata);
ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &OptionButton::is_item_disabled);
- ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count);
ClassDB::bind_method(D_METHOD("add_separator"), &OptionButton::add_separator);
ClassDB::bind_method(D_METHOD("clear"), &OptionButton::clear);
ClassDB::bind_method(D_METHOD("select", "idx"), &OptionButton::select);
@@ -329,11 +359,10 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup);
- ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items);
- ClassDB::bind_method(D_METHOD("_get_items"), &OptionButton::_get_items);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
- // "selected" property must come after "items", otherwise GH-10213 occurs.
+ ClassDB::bind_method(D_METHOD("set_item_count"), &OptionButton::set_item_count);
+ ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count);
+ // "selected" property must come after "item_count", otherwise GH-10213 occurs.
+ ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "popup/item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 953337ecce..7430100ad7 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -45,14 +45,14 @@ class OptionButton : public Button {
void _select(int p_which, bool p_emit = false);
void _select_int(int p_which);
- Array _get_items() const;
- void _set_items(const Array &p_items);
-
virtual void pressed() override;
protected:
Size2 get_minimum_size() const override;
void _notification(int p_what);
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
@@ -76,6 +76,7 @@ public:
Variant get_item_metadata(int p_idx) const;
bool is_item_disabled(int p_idx) const;
+ void set_item_count(int p_count);
int get_item_count() const;
void add_separator();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 4e16111f99..a61d77e95c 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -80,7 +80,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
accel_max_w = MAX(accel_w, accel_max_w);
}
- if (items[i].submenu != "") {
+ if (!items[i].submenu.is_empty()) {
size.width += get_theme_icon(SNAME("submenu"))->get_width();
}
@@ -326,13 +326,13 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
set_input_as_handled();
}
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !!items[mouse_over].separator && items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over);
set_input_as_handled();
}
} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
- if (items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+ if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over);
} else {
activate_item(mouse_over);
@@ -371,7 +371,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
// Disable clicks under a time threshold to avoid selection right when opening the popup.
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - popup_time_msec;
- if (diff < 100) {
+ if (diff < 150) {
return;
}
@@ -387,7 +387,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (items[over].submenu != "") {
+ if (!items[over].submenu.is_empty()) {
_activate_submenu(over);
return;
}
@@ -419,7 +419,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (items[over].submenu != "" && submenu_over != over) {
+ if (!items[over].submenu.is_empty() && submenu_over != over) {
submenu_over = over;
submenu_timer->start();
}
@@ -558,7 +558,7 @@ void PopupMenu::_draw_items() {
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
- if (text != String()) {
+ if (!text.is_empty()) {
int text_size = items[i].text_buf->get_size().width;
int text_center = display_width / 2;
int text_left = text_center - text_size / 2;
@@ -599,7 +599,7 @@ void PopupMenu::_draw_items() {
}
// Submenu arrow on right hand side
- if (items[i].submenu != "") {
+ if (!items[i].submenu.is_empty()) {
if (rtl) {
submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
@@ -611,7 +611,7 @@ void PopupMenu::_draw_items() {
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
if (items[i].separator) {
- if (text != String()) {
+ if (!text.is_empty()) {
int center = (display_width - items[i].text_buf->get_size().width) / 2;
Vector2 text_pos = Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (outline_size > 0 && font_outline_color.a > 0) {
@@ -701,7 +701,7 @@ void PopupMenu::_shape_item(int p_item) {
} else {
items.write[p_item].text_buf->set_direction((TextServer::Direction)items[p_item].text_direction);
}
- items.write[p_item].text_buf->add_string(items.write[p_item].xl_text, font, font_size, items[p_item].opentype_features, (items[p_item].language != "") ? items[p_item].language : TranslationServer::get_singleton()->get_tool_locale());
+ items.write[p_item].text_buf->add_string(items.write[p_item].xl_text, font, font_size, items[p_item].opentype_features, !items[p_item].language.is_empty() ? items[p_item].language : TranslationServer::get_singleton()->get_tool_locale());
items.write[p_item].accel_text_buf->clear();
items.write[p_item].accel_text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@@ -736,7 +736,7 @@ void PopupMenu::_notification(int p_what) {
grab_focus();
} break;
case NOTIFICATION_WM_MOUSE_EXIT: {
- if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) {
+ if (mouse_over >= 0 && (items[mouse_over].submenu.is_empty() || submenu_over != -1)) {
mouse_over = -1;
control->update();
}
@@ -769,7 +769,7 @@ void PopupMenu::_notification(int p_what) {
}
for (int i = 0; i < items.size(); i++) {
- if (items[i].submenu == "") {
+ if (items[i].submenu.is_empty()) {
continue;
}
@@ -1323,7 +1323,7 @@ bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_fo
return true;
}
- if (items[i].submenu != "") {
+ if (!items[i].submenu.is_empty()) {
Node *n = get_node(items[i].submenu);
if (!n) {
continue;
@@ -1412,7 +1412,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
Item sep;
sep.separator = true;
sep.id = p_id;
- if (p_text != String()) {
+ if (!p_text.is_empty()) {
sep.text = p_text;
sep.xl_text = atr(p_text);
}
@@ -1510,7 +1510,7 @@ void PopupMenu::set_parent_rect(const Rect2 &p_rect) {
void PopupMenu::get_translatable_strings(List<String> *p_strings) const {
for (int i = 0; i < items.size(); i++) {
- if (items[i].xl_text != "") {
+ if (!items[i].xl_text.is_empty()) {
p_strings->push_back(items[i].xl_text);
}
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c69565c2f7..7ed8056826 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -670,7 +670,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
prefix = segment + prefix;
}
}
- if (prefix != "") {
+ if (!prefix.is_empty()) {
Ref<Font> font = _find_font(l.from);
if (font.is_null()) {
font = get_theme_font(SNAME("normal_font"));
@@ -1423,7 +1423,7 @@ void RichTextLabel::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
- if (text != "") {
+ if (!text.is_empty()) {
set_text(text);
}
@@ -3853,7 +3853,7 @@ String RichTextLabel::get_selected_text() const {
void RichTextLabel::selection_copy() {
String text = get_selected_text();
- if (text != "") {
+ if (!text.is_empty()) {
DisplayServer::get_singleton()->clipboard_set(text);
}
}
@@ -4005,7 +4005,7 @@ float RichTextLabel::get_percent_visible() const {
void RichTextLabel::set_effects(Array p_effects) {
custom_effects = p_effects;
- if ((text != "") && use_bbcode) {
+ if ((!text.is_empty()) && use_bbcode) {
parse_bbcode(text);
}
}
@@ -4020,7 +4020,7 @@ void RichTextLabel::install_effect(const Variant effect) {
if (rteffect.is_valid()) {
custom_effects.push_back(effect);
- if ((text != "") && use_bbcode) {
+ if ((!text.is_empty()) && use_bbcode) {
parse_bbcode(text);
}
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index c4a1d8e5a6..8d6315d085 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -41,10 +41,10 @@ Size2 SpinBox::get_minimum_size() const {
void SpinBox::_value_changed(double) {
String value = TS->format_number(String::num(get_value(), Math::range_step_decimals(get_step())));
- if (prefix != "") {
+ if (!prefix.is_empty()) {
value = prefix + " " + value;
}
- if (suffix != "") {
+ if (!suffix.is_empty()) {
value += " " + suffix;
}
line_edit->set_text(value);
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index dd410e2472..3d88c117e7 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -50,7 +50,7 @@ Size2 TabBar::get_minimum_size() const {
Ref<Texture2D> tex = tabs[i].icon;
if (tex.is_valid()) {
ms.height = MAX(ms.height, tex->get_size().height);
- if (tabs[i].text != "") {
+ if (!tabs[i].text.is_empty()) {
ms.width += get_theme_constant(SNAME("hseparation"));
}
}
@@ -270,7 +270,7 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction);
}
- tabs.write[p_tab].text_buf->add_string(tabs.write[p_tab].xl_text, font, font_size, tabs[p_tab].opentype_features, (tabs[p_tab].language != "") ? tabs[p_tab].language : TranslationServer::get_singleton()->get_tool_locale());
+ tabs.write[p_tab].text_buf->add_string(tabs.write[p_tab].xl_text, font, font_size, tabs[p_tab].opentype_features, !tabs[p_tab].language.is_empty() ? tabs[p_tab].language : TranslationServer::get_singleton()->get_tool_locale());
}
void TabBar::_notification(int p_what) {
@@ -385,7 +385,7 @@ void TabBar::_notification(int p_what) {
} else {
icon->draw(ci, Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2));
}
- if (tabs[i].text != "") {
+ if (!tabs[i].text.is_empty()) {
w += icon->get_width() + get_theme_constant(SNAME("hseparation"));
}
}
@@ -980,7 +980,7 @@ int TabBar::get_tab_width(int p_idx) const {
Ref<Texture2D> tex = tabs[p_idx].icon;
if (tex.is_valid()) {
x += tex->get_width();
- if (tabs[p_idx].text != "") {
+ if (!tabs[p_idx].text.is_empty()) {
x += get_theme_constant(SNAME("hseparation"));
}
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 23e8f2bce8..fd5df5c93b 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -561,7 +561,7 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in
if (icon.is_valid()) {
int y = y_center - (icon->get_height() / 2);
icon->draw(canvas, Point2i(x_content, y));
- if (text != "") {
+ if (!text.is_empty()) {
x_content += icon->get_width() + icon_text_distance;
}
}
@@ -656,7 +656,7 @@ int TabContainer::_get_tab_width(int p_index) const {
Ref<Texture2D> icon = control->get_meta("_tab_icon");
if (icon.is_valid()) {
width += icon->get_width();
- if (text != "") {
+ if (!text.is_empty()) {
width += get_theme_constant(SNAME("icon_separation"));
}
}
@@ -1108,7 +1108,7 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const {
String name = c->get_meta("_tab_name");
- if (name != "") {
+ if (!name.is_empty()) {
p_strings->push_back(name);
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index c54b4dda00..63e3740a97 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -155,30 +155,30 @@ _FORCE_INLINE_ const String &TextEdit::Text::operator[](int p_line) const {
void TextEdit::Text::_calculate_line_height() {
int height = 0;
- for (int i = 0; i < text.size(); i++) {
+ for (const Line &l : text) {
// Found another line with the same height...nothing to update.
- if (text[i].height == line_height) {
+ if (l.height == line_height) {
height = line_height;
break;
}
- height = MAX(height, text[i].height);
+ height = MAX(height, l.height);
}
line_height = height;
}
void TextEdit::Text::_calculate_max_line_width() {
int width = 0;
- for (int i = 0; i < text.size(); i++) {
- if (is_hidden(i)) {
+ for (const Line &l : text) {
+ if (l.hidden) {
continue;
}
// Found another line with the same width...nothing to update.
- if (text[i].width == max_width) {
+ if (l.width == max_width) {
width = max_width;
break;
}
- width = MAX(width, text[i].width);
+ width = MAX(width, l.width);
}
max_width = width;
}
@@ -216,7 +216,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
// Update height.
const int old_height = text.write[p_line].height;
const int wrap_amount = get_line_wrap_amount(p_line);
- int height = font->get_height(font_size);
+ int height = font_height;
for (int i = 0; i <= wrap_amount; i++) {
height = MAX(height, text[p_line].data_buf->get_line_size(i).y);
}
@@ -267,6 +267,13 @@ void TextEdit::Text::invalidate_all() {
return;
}
+ max_width = -1;
+ line_height = -1;
+
+ if (!font.is_null() && font_size > 0) {
+ font_height = font->get_height(font_size);
+ }
+
for (int i = 0; i < text.size(); i++) {
invalidate_cache(i);
}
@@ -275,7 +282,15 @@ void TextEdit::Text::invalidate_all() {
void TextEdit::Text::clear() {
text.clear();
- insert(0, "", Array());
+
+ max_width = -1;
+ line_height = -1;
+
+ Line line;
+ line.gutters.resize(gutter_count);
+ line.data = "";
+ text.insert(0, line);
+ invalidate_cache(0);
}
int TextEdit::Text::get_max_width() const {
@@ -290,30 +305,64 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_o
invalidate_cache(p_line);
}
-void TextEdit::Text::insert(int p_at, const String &p_text, const Array &p_bidi_override) {
- Line line;
- line.gutters.resize(gutter_count);
- line.hidden = false;
- line.data = p_text;
- line.bidi_override = p_bidi_override;
- text.insert(p_at, line);
+void TextEdit::Text::insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override) {
+ int new_line_count = p_text.size() - 1;
+ if (new_line_count > 0) {
+ text.resize(text.size() + new_line_count);
+ for (int i = (text.size() - 1); i > p_at; i--) {
+ if ((i - new_line_count) <= 0) {
+ break;
+ }
+ text.write[i] = text[i - new_line_count];
+ }
+ }
- invalidate_cache(p_at);
+ for (int i = 0; i < p_text.size(); i++) {
+ if (i == 0) {
+ set(p_at + i, p_text[i], p_bidi_override[i]);
+ continue;
+ }
+ Line line;
+ line.gutters.resize(gutter_count);
+ line.data = p_text[i];
+ line.bidi_override = p_bidi_override[i];
+ text.write[p_at + i] = line;
+ invalidate_cache(p_at + i);
+ }
}
-void TextEdit::Text::remove_at(int p_index) {
- int height = text[p_index].height;
- int width = text[p_index].width;
+void TextEdit::Text::remove_range(int p_from_line, int p_to_line) {
+ if (p_from_line == p_to_line) {
+ return;
+ }
+
+ bool dirty_height = false;
+ bool dirty_width = false;
+ for (int i = p_from_line; i < p_to_line; i++) {
+ if (!dirty_height && text[i].height == line_height) {
+ dirty_height = true;
+ }
- text.remove_at(p_index);
+ if (!dirty_width && text[i].width == max_width) {
+ dirty_width = true;
+ }
- // If this is the tallest line, we need to get the next tallest.
- if (height == line_height) {
+ if (dirty_height && dirty_width) {
+ break;
+ }
+ }
+
+ int diff = (p_to_line - p_from_line);
+ for (int i = p_to_line; i < text.size() - 1; i++) {
+ text.write[(i - diff) + 1] = text[i + 1];
+ }
+ text.resize(text.size() - diff);
+
+ if (dirty_height) {
_calculate_line_height();
}
- // If this is the longest line, we need to get the next longest.
- if (width == max_width) {
+ if (dirty_width) {
_calculate_max_line_width();
}
}
@@ -601,7 +650,7 @@ void TextEdit::_notification(int p_what) {
String highlighted_text = get_selected_text();
// Check if highlighted words contain only whitespaces (tabs or spaces).
- bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
+ bool only_whitespaces_highlighted = highlighted_text.strip_edges().is_empty();
const int caret_wrap_index = get_caret_wrap_index();
@@ -916,7 +965,7 @@ void TextEdit::_notification(int p_what) {
switch (gutter.type) {
case GUTTER_TYPE_STRING: {
const String &text = get_line_gutter_text(line, g);
- if (text == "") {
+ if (text.is_empty()) {
break;
}
@@ -2428,7 +2477,7 @@ void TextEdit::_update_caches() {
} else {
dir = (TextServer::Direction)text_direction;
}
- text.set_direction_and_language(dir, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
text.set_font_features(opentype_features);
text.set_draw_control_chars(draw_control_chars);
text.set_font(font);
@@ -2611,7 +2660,7 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) {
} else {
dir = (TextServer::Direction)text_direction;
}
- text.set_direction_and_language(dir, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
text.invalidate_all();
if (menu_dir) {
@@ -2662,7 +2711,7 @@ void TextEdit::set_language(const String &p_language) {
} else {
dir = (TextServer::Direction)text_direction;
}
- text.set_direction_and_language(dir, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+ text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
text.invalidate_all();
update();
}
@@ -4226,7 +4275,10 @@ double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
return p_line;
}
- double new_line_scroll_pos = get_visible_line_count_in_range(0, CLAMP(p_line, 0, text.size() - 1));
+ double new_line_scroll_pos = 0.0;
+ if (p_line > 0) {
+ new_line_scroll_pos = get_visible_line_count_in_range(0, MIN(p_line - 1, text.size() - 1));
+ }
new_line_scroll_pos += p_wrap_index;
return new_line_scroll_pos;
}
@@ -4290,7 +4342,7 @@ int TextEdit::get_visible_line_count_in_range(int p_from_line, int p_to_line) co
/* Returns the total number of (lines + wrapped - hidden). */
if (!_is_hiding_enabled() && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
- return p_to_line - p_from_line;
+ return (p_to_line - p_from_line) + 1;
}
int total_rows = 0;
@@ -6289,11 +6341,11 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
ERR_FAIL_COND(p_char < 0);
/* STEP 1: Remove \r from source text and separate in substrings. */
-
- Vector<String> substrings = p_text.replace("\r", "").split("\n");
+ const String text_to_insert = p_text.replace("\r", "");
+ Vector<String> substrings = text_to_insert.split("\n");
// Is this just a new empty line?
- bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n";
+ bool shift_first_line = p_char == 0 && substrings.size() == 2 && text_to_insert == "\n";
/* STEP 2: Add spaces if the char is greater than the end of the line. */
while (p_char > text[p_line].length()) {
@@ -6301,24 +6353,19 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
}
/* STEP 3: Separate dest string in pre and post text. */
-
- String preinsert_text = text[p_line].substr(0, p_char);
String postinsert_text = text[p_line].substr(p_char, text[p_line].size());
- for (int j = 0; j < substrings.size(); j++) {
- // Insert the substrings.
-
- if (j == 0) {
- text.set(p_line, preinsert_text + substrings[j], structured_text_parser(st_parser, st_args, preinsert_text + substrings[j]));
- } else {
- text.insert(p_line + j, substrings[j], structured_text_parser(st_parser, st_args, substrings[j]));
- }
+ substrings.write[0] = text[p_line].substr(0, p_char) + substrings[0];
+ substrings.write[substrings.size() - 1] += postinsert_text;
- if (j == substrings.size() - 1) {
- text.set(p_line + j, text[p_line + j] + postinsert_text, structured_text_parser(st_parser, st_args, text[p_line + j] + postinsert_text));
- }
+ Vector<Array> bidi_override;
+ bidi_override.resize(substrings.size());
+ for (int i = 0; i < substrings.size(); i++) {
+ bidi_override.write[i] = structured_text_parser(st_parser, st_args, substrings[i]);
}
+ text.insert(p_line, substrings, bidi_override);
+
if (shift_first_line) {
text.move_gutters(p_line, p_line + 1);
text.set_hidden(p_line + 1, text.is_hidden(p_line));
@@ -6351,7 +6398,7 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin
ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // 'from > to'.
ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // 'from > to'.
- String ret;
+ StringBuilder ret;
for (int i = p_from_line; i <= p_to_line; i++) {
int begin = (i == p_from_line) ? p_from_column : 0;
@@ -6363,7 +6410,7 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin
ret += text[i].substr(begin, end - begin);
}
- return ret;
+ return ret.as_string();
}
void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
@@ -6377,9 +6424,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
String pre_text = text[p_from_line].substr(0, p_from_column);
String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length());
- for (int i = p_from_line; i < p_to_line; i++) {
- text.remove_at(p_from_line + 1);
- }
+ text.remove_range(p_from_line, p_to_line);
text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text));
if (!text_changed_dirty && !setting_text) {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a1b2ed59f5..df3edca943 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -159,6 +159,7 @@ private:
mutable Vector<Line> text;
Ref<Font> font;
int font_size = -1;
+ int font_height = 0;
Dictionary opentype_features;
String language;
@@ -204,8 +205,8 @@ private:
}
}
bool is_hidden(int p_line) const { return text[p_line].hidden; }
- void insert(int p_at, const String &p_text, const Array &p_bidi_override);
- void remove_at(int p_index);
+ void insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override);
+ void remove_range(int p_from_line, int p_to_line);
int size() const { return text.size(); }
void clear();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index d2d4167a25..5a6ac7c0d2 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1536,7 +1536,7 @@ void Tree::update_column(int p_col) {
columns.write[p_col].text_buf->set_direction((TextServer::Direction)columns[p_col].text_direction);
}
- columns.write[p_col].text_buf->add_string(columns[p_col].title, cache.font, cache.font_size, columns[p_col].opentype_features, (columns[p_col].language != "") ? columns[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
+ columns.write[p_col].text_buf->add_string(columns[p_col].title, cache.font, cache.font_size, columns[p_col].opentype_features, !columns[p_col].language.is_empty() ? columns[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
}
void Tree::update_item_cell(TreeItem *p_item, int p_col) {
@@ -1544,7 +1544,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) {
p_item->cells.write[p_col].text_buf->clear();
if (p_item->cells[p_col].mode == TreeItem::CELL_MODE_RANGE) {
- if (p_item->cells[p_col].text != "") {
+ if (!p_item->cells[p_col].text.is_empty()) {
if (!p_item->cells[p_col].editable) {
return;
}
@@ -1571,7 +1571,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) {
valtext = p_item->cells[p_col].text;
}
- if (p_item->cells[p_col].suffix != String()) {
+ if (!p_item->cells[p_col].suffix.is_empty()) {
valtext += " " + p_item->cells[p_col].suffix;
}
@@ -1594,7 +1594,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) {
} else {
font_size = cache.font_size;
}
- p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].opentype_features, (p_item->cells[p_col].language != "") ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
+ p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].opentype_features, !p_item->cells[p_col].language.is_empty() ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext));
p_item->cells.write[p_col].dirty = false;
}
@@ -1660,7 +1660,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].expand_right) {
int plus = 1;
- while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) {
+ while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text.is_empty() && p_item->cells[i + plus].icon.is_null()) {
w += get_column_width(i + plus);
plus++;
skip2++;
@@ -1857,7 +1857,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
} break;
case TreeItem::CELL_MODE_RANGE: {
- if (p_item->cells[i].text != "") {
+ if (!p_item->cells[i].text.is_empty()) {
if (!p_item->cells[i].editable) {
break;
}
@@ -2337,7 +2337,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
if (p_item->cells[i].expand_right) {
int plus = 1;
- while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) {
+ while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text.is_empty() && p_item->cells[i + plus].icon.is_null()) {
col_width += cache.hseparation;
col_width += get_column_width(i + plus);
plus++;
@@ -2520,7 +2520,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
} break;
case TreeItem::CELL_MODE_RANGE: {
- if (c.text != "") {
+ if (!c.text.is_empty()) {
//if (x >= (get_column_width(col)-item_h/2)) {
popup_menu->clear();
for (int i = 0; i < c.text.get_slice_count(","); i++) {
@@ -3430,7 +3430,7 @@ bool Tree::edit_selected() {
item_edited(col, s);
return true;
- } else if (c.mode == TreeItem::CELL_MODE_RANGE && c.text != "") {
+ } else if (c.mode == TreeItem::CELL_MODE_RANGE && !c.text.is_empty()) {
popup_menu->clear();
for (int i = 0; i < c.text.get_slice_count(","); i++) {
String s2 = c.text.get_slicec(',', i);
@@ -4679,7 +4679,7 @@ String Tree::get_tooltip(const Point2 &p_pos) const {
Size2 size = b->get_size() + cache.button_pressed->get_minimum_size();
if (pos.x > col_width - size.width) {
String tooltip = c.buttons[j].tooltip;
- if (tooltip != "") {
+ if (!tooltip.is_empty()) {
return tooltip;
}
}