summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp9
-rw-r--r--scene/gui/code_edit.cpp35
-rw-r--r--scene/gui/color_picker.cpp7
-rw-r--r--scene/gui/container.cpp4
-rw-r--r--scene/gui/container.h2
-rw-r--r--scene/gui/control.cpp16
-rw-r--r--scene/gui/control.h2
-rw-r--r--scene/gui/file_dialog.cpp10
-rw-r--r--scene/gui/graph_edit.cpp4
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/item_list.cpp16
-rw-r--r--scene/gui/menu_bar.cpp2
-rw-r--r--scene/gui/popup_menu.cpp11
-rw-r--r--scene/gui/popup_menu.h2
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_label.cpp224
-rw-r--r--scene/gui/rich_text_label.h12
-rw-r--r--scene/gui/scroll_container.cpp4
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/subviewport_container.h2
-rw-r--r--scene/gui/tab_container.cpp4
-rw-r--r--scene/gui/text_edit.cpp19
-rw-r--r--scene/gui/tree.cpp78
-rw-r--r--scene/gui/tree.h10
-rw-r--r--scene/gui/video_stream_player.cpp4
-rw-r--r--scene/gui/video_stream_player.h4
28 files changed, 361 insertions, 134 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index cf467ceafb..af6a99ca62 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -264,7 +264,7 @@ bool BaseButton::is_hovered() const {
BaseButton::DrawMode BaseButton::get_draw_mode() const {
if (status.disabled) {
return DRAW_DISABLED;
- };
+ }
if (!status.press_attempt && status.hovering) {
if (status.pressed) {
@@ -273,8 +273,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_HOVER;
} else {
- /* determine if pressed or not */
-
+ // Determine if pressed or not.
bool pressing;
if (status.press_attempt) {
pressing = (status.pressing_inside || keep_pressed_outside);
@@ -291,8 +290,6 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_NORMAL;
}
}
-
- return DRAW_NORMAL;
}
void BaseButton::set_toggle_mode(bool p_on) {
@@ -469,7 +466,7 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
BIND_ENUM_CONSTANT(DRAW_PRESSED);
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index f6e0e4216d..8069ab465b 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1216,30 +1216,39 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
}
void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (draw_breakpoints && breakpoint_icon.is_valid()) {
bool hovering = p_region.has_point(get_local_mouse_pos());
bool breakpointed = is_line_breakpointed(p_line);
- if (breakpointed || (hovering && !is_dragging_cursor())) {
+ if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
- // Darken icon when hovering & not yet breakpointed.
- Color use_color = hovering && !breakpointed ? breakpoint_color.darkened(0.4) : breakpoint_color;
+ // Darken icon when hovering, shift not pressed & not yet breakpointed.
+ Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color;
breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
- if (draw_bookmarks && is_line_bookmarked(p_line) && bookmark_icon.is_valid()) {
- int horizontal_padding = p_region.size.x / 2;
- int vertical_padding = p_region.size.y / 4;
+ if (draw_bookmarks && bookmark_icon.is_valid()) {
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool bookmarked = is_line_bookmarked(p_line);
- Rect2 bookmark_region = p_region;
- bookmark_region.position += Point2(horizontal_padding, 0);
- bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
- bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color);
+ if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
+ int horizontal_padding = p_region.size.x / 2;
+ int vertical_padding = p_region.size.y / 4;
+ Rect2 icon_region = p_region;
+ icon_region.position += Point2(horizontal_padding, 0);
+ icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
+
+ // Darken icon when hovering, shift pressed & not yet bookmarked.
+ Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color;
+ bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
+ }
}
if (draw_executing_lines && is_line_executing(p_line) && executing_line_icon.is_valid()) {
@@ -2378,9 +2387,13 @@ int CodeEdit::_get_auto_brace_pair_close_at_pos(int p_line, int p_col) {
/* Gutters */
void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (p_gutter == main_gutter) {
- if (draw_breakpoints) {
+ if (draw_breakpoints && !shift_pressed) {
set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line));
+ } else if (draw_bookmarks && shift_pressed) {
+ set_line_as_bookmarked(p_line, !is_line_bookmarked(p_line));
}
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 4a1f2ab7c6..5751c54877 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -427,12 +427,15 @@ void ColorPicker::_html_submitted(const String &p_html) {
return;
}
- float last_alpha = color.a;
+ Color previous_color = color;
color = Color::html(p_html);
if (!is_editing_alpha()) {
- color.a = last_alpha;
+ color.a = previous_color.a;
}
+ if (color == previous_color) {
+ return;
+ }
if (!is_inside_tree()) {
return;
}
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 5512c0f1fd..3c29c37479 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -192,8 +192,8 @@ void Container::_notification(int p_what) {
}
}
-TypedArray<String> Container::get_configuration_warnings() const {
- TypedArray<String> warnings = Control::get_configuration_warnings();
+PackedStringArray Container::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) {
warnings.push_back(RTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 9ec4ad3200..21bdb95186 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -63,7 +63,7 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const;
virtual Vector<int> get_allowed_size_flags_vertical() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Container();
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 347fe9aa11..dc9294df6d 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -213,8 +213,8 @@ 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();
+PackedStringArray Control::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) {
warnings.push_back(RTR("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\"."));
@@ -2225,7 +2225,19 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
void Control::set_default_cursor_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX);
+ if (data.default_cursor == p_shape) {
+ return;
+ }
data.default_cursor = p_shape;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+ if (!get_global_rect().has_point(get_global_mouse_position())) {
+ return;
+ }
+
+ get_viewport()->get_base_window()->update_mouse_cursor_shape();
}
Control::CursorShape Control::get_default_cursor_shape() const {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 38cafd835a..ee6443c81c 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -387,7 +387,7 @@ public:
// Editor integration.
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
virtual bool is_text_field() const;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 57f27e299f..cf7f439aef 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -172,18 +172,20 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
void FileDialog::set_enable_multiple_selection(bool p_enable) {
tree->set_select_mode(p_enable ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
-};
+}
Vector<String> FileDialog::get_selected_files() const {
Vector<String> list;
TreeItem *item = tree->get_root();
- while ((item = tree->get_next_selected(item))) {
+ item = tree->get_next_selected(item);
+ while (item) {
list.push_back(dir_access->get_current_dir().path_join(item->get_text(0)));
- };
+ item = tree->get_next_selected(item);
+ }
return list;
-};
+}
void FileDialog::update_dir() {
if (root_prefix.is_empty()) {
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 5a0236268b..7295ab9e9d 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -190,8 +190,8 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
}
-TypedArray<String> GraphEdit::get_configuration_warnings() const {
- TypedArray<String> warnings = Control::get_configuration_warnings();
+PackedStringArray GraphEdit::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
warnings.push_back(RTR("Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes."));
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0fe9e7c555..101087bdbd 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -287,7 +287,7 @@ protected:
GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int);
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 008109da65..357f2480bd 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -662,19 +662,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
pos.x = get_size().width - pos.x;
}
- int closest = -1;
-
- for (int i = 0; i < items.size(); i++) {
- Rect2 rc = items[i].rect_cache;
- if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width; //not right but works
- }
-
- if (rc.has_point(pos)) {
- closest = i;
- break;
- }
- }
+ int closest = get_item_at_position(mb->get_position(), true);
if (closest != -1 && (mb->get_button_index() == MouseButton::LEFT || (allow_rmb_select && mb->get_button_index() == MouseButton::RIGHT))) {
int i = closest;
@@ -1467,7 +1455,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
for (int i = 0; i < items.size(); i++) {
Rect2 rc = items[i].rect_cache;
if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column
+ rc.size.width = get_size().width - rc.position.x; // Make sure you can still select the last item when clicking past the column.
}
if (rc.has_point(pos)) {
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index d6bf84ea5a..75592a1b99 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -703,7 +703,7 @@ void MenuBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index d4a4efd578..10e13042a7 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -1762,7 +1762,7 @@ void PopupMenu::clear() {
void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
if (!shortcut_refcount.has(p_sc)) {
shortcut_refcount[p_sc] = 1;
- p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ p_sc->connect("changed", callable_mp(this, &PopupMenu::_shortcut_changed));
} else {
shortcut_refcount[p_sc] += 1;
}
@@ -1772,11 +1772,18 @@ void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) {
ERR_FAIL_COND(!shortcut_refcount.has(p_sc));
shortcut_refcount[p_sc]--;
if (shortcut_refcount[p_sc] == 0) {
- p_sc->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ p_sc->disconnect("changed", callable_mp(this, &PopupMenu::_shortcut_changed));
shortcut_refcount.erase(p_sc);
}
}
+void PopupMenu::_shortcut_changed() {
+ for (int i = 0; i < items.size(); i++) {
+ items.write[i].dirty = true;
+ }
+ control->queue_redraw();
+}
+
// Hide on item selection determines whether or not the popup will close after item selection
void PopupMenu::set_hide_on_item_selection(bool p_enabled) {
hide_on_item_selection = p_enabled;
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index ad7909842e..89d3904456 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -121,6 +121,8 @@ class PopupMenu : public Popup {
void _ref_shortcut(Ref<Shortcut> p_sc);
void _unref_shortcut(Ref<Shortcut> p_sc);
+ void _shortcut_changed();
+
bool allow_search = true;
uint64_t search_time_msec = 0;
String search_string = "";
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 1eb412abaf..2d2b3e413d 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -30,8 +30,8 @@
#include "range.h"
-TypedArray<String> Range::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Range::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
warnings.push_back(RTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
diff --git a/scene/gui/range.h b/scene/gui/range.h
index 87bd0d88af..19452243cf 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -100,7 +100,7 @@ public:
void share(Range *p_range);
void unshare();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
Range();
~Range();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 3a238e9edd..7ea46a0b4f 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -52,7 +52,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) co
} else if (p_item->E->next()) {
return p_item->E->next()->get();
} else {
- //go up until something with a next is found
+ // Go up until something with a next is found.
while (p_item->parent && !p_item->E->next()) {
p_item = p_item->parent;
}
@@ -72,7 +72,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) co
} else if (p_item->E->next()) {
return p_item->E->next()->get();
} else {
- //go up until something with a next is found
+ // Go up until something with a next is found.
while (p_item->type != ITEM_FRAME && !p_item->E->next()) {
p_item = p_item->parent;
}
@@ -84,8 +84,6 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) co
}
}
}
-
- return nullptr;
}
RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) const {
@@ -97,7 +95,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) co
} else if (p_item->E->prev()) {
return p_item->E->prev()->get();
} else {
- //go back until something with a prev is found
+ // Go back until something with a prev is found.
while (p_item->parent && !p_item->E->prev()) {
p_item = p_item->parent;
}
@@ -117,7 +115,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) co
} else if (p_item->E->prev()) {
return p_item->E->prev()->get();
} else {
- //go back until something with a prev is found
+ // Go back until something with a prev is found.
while (p_item->type != ITEM_FRAME && !p_item->E->prev()) {
p_item = p_item->parent;
}
@@ -129,8 +127,6 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) co
}
}
}
-
- return nullptr;
}
Rect2 RichTextLabel::_get_text_rect() {
@@ -965,17 +961,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint32_t gl = glyphs[i].index;
uint16_t gl_fl = glyphs[i].flags;
uint8_t gl_cn = glyphs[i].count;
- bool cprev = false;
+ bool cprev_cluster = false;
+ bool cprev_conn = false;
if (gl_cn == 0) { // Parts of the same cluster, always connected.
- cprev = true;
+ cprev_cluster = true;
}
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
- cprev = true;
+ cprev_conn = true;
}
} else {
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
- cprev = true;
+ cprev_conn = true;
}
}
@@ -994,6 +991,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
+ bool cn = cprev_cluster || (cprev_conn && item_fx->connected);
+
if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
@@ -1024,7 +1023,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- if (!cprev) {
+ if (!cn) {
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
@@ -1038,7 +1037,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_wave->amplitude / 10.0f);
item_wave->prev_off = Point2(0, 1) * value;
}
@@ -1046,7 +1045,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
item_tornado->prev_off = Point2(torn_x, torn_y);
@@ -1181,17 +1180,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint32_t gl = glyphs[i].index;
uint16_t gl_fl = glyphs[i].flags;
uint8_t gl_cn = glyphs[i].count;
- bool cprev = false;
+ bool cprev_cluster = false;
+ bool cprev_conn = false;
if (gl_cn == 0) { // Parts of the same grapheme cluster, always connected.
- cprev = true;
+ cprev_cluster = true;
}
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
- cprev = true;
+ cprev_conn = true;
}
} else {
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
- cprev = true;
+ cprev_conn = true;
}
}
@@ -1209,6 +1209,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
+ bool cn = cprev_cluster || (cprev_conn && item_fx->connected);
+
if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
@@ -1239,7 +1241,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
- if (!cprev) {
+ if (!cn) {
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
@@ -1253,7 +1255,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_WAVE) {
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
item_wave->prev_off = Point2(0, 1) * value;
}
@@ -1261,7 +1263,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (item_fx->type == ITEM_TORNADO) {
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
- if (!cprev) {
+ if (!cn) {
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
item_tornado->prev_off = Point2(torn_x, torn_y);
@@ -2190,24 +2192,69 @@ RichTextLabel::ItemFont *RichTextLabel::_find_font(Item *p_item) {
ItemFont *fi = static_cast<ItemFont *>(fontitem);
switch (fi->def_font) {
case NORMAL_FONT: {
- fi->font = theme_cache.normal_font;
- fi->font_size = theme_cache.normal_font_size;
+ if (fi->variation) {
+ Ref<FontVariation> fc = fi->font;
+ if (fc.is_valid()) {
+ fc->set_base_font(theme_cache.normal_font);
+ }
+ } else {
+ fi->font = theme_cache.normal_font;
+ }
+ if (fi->def_size) {
+ fi->font_size = theme_cache.normal_font_size;
+ }
} break;
case BOLD_FONT: {
- fi->font = theme_cache.bold_font;
- fi->font_size = theme_cache.bold_font_size;
+ if (fi->variation) {
+ Ref<FontVariation> fc = fi->font;
+ if (fc.is_valid()) {
+ fc->set_base_font(theme_cache.bold_font);
+ }
+ } else {
+ fi->font = theme_cache.bold_font;
+ }
+ if (fi->def_size) {
+ fi->font_size = theme_cache.bold_font_size;
+ }
} break;
case ITALICS_FONT: {
- fi->font = theme_cache.italics_font;
- fi->font_size = theme_cache.italics_font_size;
+ if (fi->variation) {
+ Ref<FontVariation> fc = fi->font;
+ if (fc.is_valid()) {
+ fc->set_base_font(theme_cache.italics_font);
+ }
+ } else {
+ fi->font = theme_cache.italics_font;
+ }
+ if (fi->def_size) {
+ fi->font_size = theme_cache.italics_font_size;
+ }
} break;
case BOLD_ITALICS_FONT: {
- fi->font = theme_cache.bold_italics_font;
- fi->font_size = theme_cache.bold_italics_font_size;
+ if (fi->variation) {
+ Ref<FontVariation> fc = fi->font;
+ if (fc.is_valid()) {
+ fc->set_base_font(theme_cache.bold_italics_font);
+ }
+ } else {
+ fi->font = theme_cache.bold_italics_font;
+ }
+ if (fi->def_size) {
+ fi->font_size = theme_cache.bold_italics_font_size;
+ }
} break;
case MONO_FONT: {
- fi->font = theme_cache.mono_font;
- fi->font_size = theme_cache.mono_font_size;
+ if (fi->variation) {
+ Ref<FontVariation> fc = fi->font;
+ if (fc.is_valid()) {
+ fc->set_base_font(theme_cache.mono_font);
+ }
+ } else {
+ fi->font = theme_cache.mono_font;
+ }
+ if (fi->def_size) {
+ fi->font_size = theme_cache.mono_font_size;
+ }
} break;
default: {
} break;
@@ -3028,14 +3075,30 @@ void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font
_add_item(item, false);
}
-void RichTextLabel::_push_def_font(DefaultFont p_font) {
+void RichTextLabel::_push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size) {
+ _stop_thread();
+ MutexLock data_lock(data_mutex);
+
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFont *item = memnew(ItemFont);
+
+ item->def_font = p_def_font;
+ item->variation = true;
+ item->font = p_font;
+ item->font_size = p_size;
+ item->def_size = (p_size <= 0);
+ _add_item(item, true);
+}
+
+void RichTextLabel::_push_def_font(DefaultFont p_def_font) {
_stop_thread();
MutexLock data_lock(data_mutex);
ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemFont *item = memnew(ItemFont);
- item->def_font = p_font;
+ item->def_font = p_def_font;
+ item->def_size = true;
_add_item(item, true);
}
@@ -3236,33 +3299,36 @@ void RichTextLabel::push_fade(int p_start_index, int p_length) {
_add_item(item, true);
}
-void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f) {
+void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemShake *item = memnew(ItemShake);
item->strength = p_strength;
item->rate = p_rate;
+ item->connected = p_connected;
_add_item(item, true);
}
-void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f) {
+void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemWave *item = memnew(ItemWave);
item->frequency = p_frequency;
item->amplitude = p_amplitude;
+ item->connected = p_connected;
_add_item(item, true);
}
-void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f) {
+void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f, bool p_connected = true) {
_stop_thread();
MutexLock data_lock(data_mutex);
ItemTornado *item = memnew(ItemTornado);
item->frequency = p_frequency;
item->radius = p_radius;
+ item->connected = p_connected;
_add_item(item, true);
}
@@ -4113,24 +4179,21 @@ void RichTextLabel::append_text(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("font_size");
- } else if (tag.begins_with("opentype_features=")) {
- String fnt_ftr = tag.substr(18, tag.length());
+ } else if (tag.begins_with("opentype_features=") || tag.begins_with("otf=")) {
+ int value_pos = tag.find("=");
+ String fnt_ftr = tag.substr(value_pos + 1);
Vector<String> subtag = fnt_ftr.split(",");
if (subtag.size() > 0) {
Ref<Font> font = theme_cache.normal_font;
- int font_size = 0;
+ DefaultFont def_font = NORMAL_FONT;
+
ItemFont *font_it = _find_font(current);
if (font_it) {
if (font_it->font.is_valid()) {
font = font_it->font;
- }
- if (font_it->font_size > 0) {
- font_size = font_it->font_size;
+ def_font = font_it->def_font;
}
}
- Ref<FontVariation> fc;
- fc.instantiate();
- fc->set_base_font(font);
Dictionary features;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
@@ -4140,11 +4203,21 @@ void RichTextLabel::append_text(const String &p_bbcode) {
features[TS->name_to_tag(subtag_a[0])] = 1;
}
}
+
+ Ref<FontVariation> fc;
+ fc.instantiate();
+
+ fc->set_base_font(font);
fc->set_opentype_features(features);
- push_font(fc, font_size);
+
+ if (def_font != CUSTOM_FONT) {
+ _push_def_font_var(def_font, fc);
+ } else {
+ push_font(fc);
+ }
}
pos = brk_end + 1;
- tag_stack.push_front("opentype_features");
+ tag_stack.push_front(tag.substr(0, value_pos));
} else if (tag.begins_with("font=")) {
String fnt = tag.substr(5, tag.length());
@@ -4160,9 +4233,21 @@ void RichTextLabel::append_text(const String &p_bbcode) {
} else if (tag.begins_with("font ")) {
Vector<String> subtag = tag.substr(2, tag.length()).split(" ");
+ Ref<Font> font = theme_cache.normal_font;
+ DefaultFont def_font = NORMAL_FONT;
+
+ ItemFont *font_it = _find_font(current);
+ if (font_it) {
+ if (font_it->font.is_valid()) {
+ font = font_it->font;
+ def_font = font_it->def_font;
+ }
+ }
+
Ref<FontVariation> fc;
fc.instantiate();
- int fnt_size = 0;
+
+ int fnt_size = -1;
for (int i = 1; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=", true, 2);
if (subtag_a.size() == 2) {
@@ -4170,7 +4255,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
String fnt = subtag_a[1];
Ref<Font> font_data = ResourceLoader::load(fnt, "Font");
if (font_data.is_valid()) {
- fc->set_base_font(font_data);
+ font = font_data;
+ def_font = CUSTOM_FONT;
}
} else if (subtag_a[0] == "size" || subtag_a[0] == "s") {
fnt_size = subtag_a[1].to_int();
@@ -4224,7 +4310,14 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
}
}
- push_font(fc, fnt_size);
+ fc->set_base_font(font);
+
+ if (def_font != CUSTOM_FONT) {
+ _push_def_font_var(def_font, fc, fnt_size);
+ } else {
+ push_font(fc, fnt_size);
+ }
+
pos = brk_end + 1;
tag_stack.push_front("font");
@@ -4265,7 +4358,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
rate = rate_option->value.to_float();
}
- push_shake(strength, rate);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_shake(strength, rate, connected);
pos = brk_end + 1;
tag_stack.push_front("shake");
set_process_internal(true);
@@ -4282,7 +4381,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
period = period_option->value.to_float();
}
- push_wave(period, amplitude);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_wave(period, amplitude, connected);
pos = brk_end + 1;
tag_stack.push_front("wave");
set_process_internal(true);
@@ -4299,7 +4404,13 @@ void RichTextLabel::append_text(const String &p_bbcode) {
frequency = frequency_option->value.to_float();
}
- push_tornado(frequency, radius);
+ bool connected = true;
+ OptionMap::Iterator connected_option = bbcode_options.find("connected");
+ if (connected_option) {
+ connected = connected_option->value.to_int();
+ }
+
+ push_tornado(frequency, radius, connected);
pos = brk_end + 1;
tag_stack.push_front("tornado");
set_process_internal(true);
@@ -4676,7 +4787,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
queue_redraw();
return true;
}
- p_search_previous ? current_line-- : current_line++;
+
+ if (current_line != ending_line) {
+ p_search_previous ? current_line-- : current_line++;
+ }
}
if (p_from_selection && selection.active) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 2a5ec4b5d5..71123602ad 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -189,6 +189,8 @@ private:
struct ItemFont : public Item {
DefaultFont def_font = CUSTOM_FONT;
Ref<Font> font;
+ bool variation = false;
+ bool def_size = false;
int font_size = 0;
ItemFont() { type = ITEM_FONT; }
};
@@ -282,6 +284,7 @@ private:
struct ItemFX : public Item {
double elapsed_time = 0.f;
+ bool connected = true;
};
struct ItemShake : public ItemFX {
@@ -570,7 +573,8 @@ public:
void add_newline();
bool remove_line(const int p_line);
void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
- void _push_def_font(DefaultFont p_font);
+ void _push_def_font(DefaultFont p_def_font);
+ void _push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size = -1);
void push_font(const Ref<Font> &p_font, int p_size = 0);
void push_font_size(int p_font_size);
void push_outline_size(int p_font_size);
@@ -590,9 +594,9 @@ public:
void push_hint(const String &p_string);
void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP);
void push_fade(int p_start_index, int p_length);
- void push_shake(int p_strength, float p_rate);
- void push_wave(float p_frequency, float p_amplitude);
- void push_tornado(float p_frequency, float p_radius);
+ void push_shake(int p_strength, float p_rate, bool p_connected);
+ void push_wave(float p_frequency, float p_amplitude, bool p_connected);
+ void push_tornado(float p_frequency, float p_radius, bool p_connected);
void push_rainbow(float p_saturation, float p_value, float p_frequency);
void push_bgcolor(const Color &p_color);
void push_fgcolor(const Color &p_color);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index c12ac115b7..761072c5bc 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -501,8 +501,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
follow_focus = p_follow;
}
-TypedArray<String> ScrollContainer::get_configuration_warnings() const {
- TypedArray<String> warnings = Container::get_configuration_warnings();
+PackedStringArray ScrollContainer::get_configuration_warnings() const {
+ PackedStringArray warnings = Container::get_configuration_warnings();
int found = 0;
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index f4899846f4..0079358ef7 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -114,7 +114,7 @@ public:
VScrollBar *get_v_scroll_bar();
void ensure_control_visible(Control *p_control);
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
ScrollContainer();
};
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 88e68ec763..3ad84cbc6d 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -227,8 +227,8 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
}
}
-TypedArray<String> SubViewportContainer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray SubViewportContainer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
bool has_viewport = false;
for (int i = 0; i < get_child_count(); i++) {
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 5b488fb79e..63a58b5f07 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -58,7 +58,7 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
virtual Vector<int> get_allowed_size_flags_vertical() const override;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
SubViewportContainer();
};
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 1df698a108..ab4808d312 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -519,12 +519,12 @@ void TabContainer::_refresh_tab_names() {
}
void TabContainer::add_child_notify(Node *p_child) {
+ Container::add_child_notify(p_child);
+
if (p_child == tab_bar) {
return;
}
- Container::add_child_notify(p_child);
-
Control *c = Object::cast_to<Control>(p_child);
if (!c || c->is_set_as_top_level()) {
return;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 318447ecd8..38302136d6 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1201,13 +1201,14 @@ void TextEdit::_notification(int p_what) {
current_color.a = font_readonly_color.a;
}
}
+ Color gl_color = current_color;
if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column;
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
- current_color = font_selected_color;
+ gl_color = font_selected_color;
}
}
@@ -1217,29 +1218,29 @@ void TextEdit::_notification(int p_what) {
if ((brace_open_match_line == line && brace_open_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start && caret.line == line && caret_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) {
if (brace_open_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
if ((brace_close_match_line == line && brace_close_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start + 1 && caret.line == line && caret_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) {
if (brace_close_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
}
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
- tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), current_color);
+ tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), gl_color);
} else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
int yofs = (text_height - space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - space_icon->get_width()) / 2;
- space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), current_color);
+ space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color);
}
}
@@ -1247,10 +1248,10 @@ void TextEdit::_notification(int p_what) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
}
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 237c78407b..f82a853e56 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -563,6 +563,57 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::set_collapsed_recursive(bool p_collapsed) {
+ if (!tree) {
+ return;
+ }
+
+ set_collapsed(p_collapsed);
+
+ TreeItem *child = get_first_child();
+ while (child) {
+ child->set_collapsed_recursive(p_collapsed);
+ child = child->get_next();
+ }
+}
+
+bool TreeItem::_is_any_collapsed(bool p_only_visible) {
+ TreeItem *child = get_first_child();
+
+ // Check on children directly first (avoid recursing if possible).
+ while (child) {
+ if (child->get_first_child() && child->is_collapsed() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count()))) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ child = get_first_child();
+
+ // Otherwise recurse on children.
+ while (child) {
+ if (child->get_first_child() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count())) && child->_is_any_collapsed(p_only_visible)) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ return false;
+}
+
+bool TreeItem::is_any_collapsed(bool p_only_visible) {
+ if (p_only_visible && !is_visible()) {
+ return false;
+ }
+
+ // Collapsed if this is collapsed and it has children (only considers visible if only visible is set).
+ if (is_collapsed() && get_first_child() && (!p_only_visible || get_visible_child_count())) {
+ return true;
+ }
+
+ return _is_any_collapsed(p_only_visible);
+}
+
void TreeItem::set_visible(bool p_visible) {
if (visible == p_visible) {
return;
@@ -1406,6 +1457,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
+ ClassDB::bind_method(D_METHOD("set_collapsed_recursive", "enable"), &TreeItem::set_collapsed_recursive);
+ ClassDB::bind_method(D_METHOD("is_any_collapsed", "only_visible"), &TreeItem::is_any_collapsed, DEFVAL(false));
+
ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
@@ -2572,7 +2626,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1;
}
@@ -2623,7 +2681,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1; //collapse/uncollapse because nothing can be done with item
}
@@ -5026,6 +5088,14 @@ bool Tree::is_folding_hidden() const {
return hide_folding;
}
+void Tree::set_enable_recursive_folding(bool p_enable) {
+ enable_recursive_folding = p_enable;
+}
+
+bool Tree::is_recursive_folding_enabled() const {
+ return enable_recursive_folding;
+}
+
void Tree::set_drop_mode_flags(int p_flags) {
if (drop_mode_flags == p_flags) {
return;
@@ -5129,6 +5199,9 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding);
ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden);
+ ClassDB::bind_method(D_METHOD("set_enable_recursive_folding", "enable"), &Tree::set_enable_recursive_folding);
+ ClassDB::bind_method(D_METHOD("is_recursive_folding_enabled"), &Tree::is_recursive_folding_enabled);
+
ClassDB::bind_method(D_METHOD("set_drop_mode_flags", "flags"), &Tree::set_drop_mode_flags);
ClassDB::bind_method(D_METHOD("get_drop_mode_flags"), &Tree::get_drop_mode_flags);
@@ -5143,6 +5216,7 @@ void Tree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_recursive_folding"), "set_enable_recursive_folding", "is_recursive_folding_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 450943c048..f994a5cec1 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -173,6 +173,8 @@ private:
}
}
+ bool _is_any_collapsed(bool p_only_visible);
+
protected:
static void _bind_methods();
@@ -272,6 +274,9 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void set_collapsed_recursive(bool p_collapsed);
+ bool is_any_collapsed(bool p_only_visible = false);
+
void set_visible(bool p_visible);
bool is_visible();
@@ -613,6 +618,8 @@ private:
bool hide_folding = false;
+ bool enable_recursive_folding = true;
+
int _count_selected_items(TreeItem *p_from) const;
bool _is_branch_selected(TreeItem *p_from) const;
bool _is_sibling_branch_selected(TreeItem *p_from) const;
@@ -712,6 +719,9 @@ public:
void set_hide_folding(bool p_hide);
bool is_folding_hidden() const;
+ void set_enable_recursive_folding(bool p_enable);
+ bool is_recursive_folding_enabled() const;
+
void set_drop_mode_flags(int p_flags);
int get_drop_mode_flags() const;
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index 1e03ed6e76..0ea49b1645 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -381,14 +381,14 @@ String VideoStreamPlayer::get_stream_name() const {
return stream->get_name();
}
-float VideoStreamPlayer::get_stream_position() const {
+double VideoStreamPlayer::get_stream_position() const {
if (playback.is_null()) {
return 0;
}
return playback->get_playback_position();
}
-void VideoStreamPlayer::set_stream_position(float p_position) {
+void VideoStreamPlayer::set_stream_position(double p_position) {
if (playback.is_valid()) {
playback->seek(p_position);
}
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 9974eb8488..b1ba8a65d7 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -105,8 +105,8 @@ public:
float get_volume_db() const;
String get_stream_name() const;
- float get_stream_position() const;
- void set_stream_position(float p_position);
+ double get_stream_position() const;
+ void set_stream_position(double p_position);
void set_autoplay(bool p_enable);
bool has_autoplay() const;