summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/code_edit.h4
-rw-r--r--scene/gui/control.cpp15
-rw-r--r--scene/gui/graph_edit.cpp144
-rw-r--r--scene/gui/graph_edit.h33
-rw-r--r--scene/gui/graph_node.cpp34
-rw-r--r--scene/gui/graph_node.h6
-rw-r--r--scene/gui/grid_container.cpp9
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_label.cpp3
-rw-r--r--scene/gui/tab_bar.cpp1
-rw-r--r--scene/gui/text_edit.cpp6
-rw-r--r--scene/gui/texture_progress_bar.cpp4
-rw-r--r--scene/gui/tree.cpp204
-rw-r--r--scene/gui/tree.h10
-rw-r--r--scene/gui/video_stream_player.cpp2
18 files changed, 314 insertions, 169 deletions
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 0b70d285ee..ba3852ec98 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -143,7 +143,7 @@ VARIANT_ENUM_CAST(BaseButton::ActionMode)
class ButtonGroup : public Resource {
GDCLASS(ButtonGroup, Resource);
friend class BaseButton;
- RBSet<BaseButton *> buttons;
+ HashSet<BaseButton *> buttons;
protected:
static void _bind_methods();
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 0b00735f46..ccf046c612 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -58,7 +58,7 @@ private:
String indent_text = "\t";
bool auto_indent = false;
- RBSet<char32_t> auto_indent_prefixes;
+ HashSet<char32_t> auto_indent_prefixes;
bool indent_using_spaces = false;
int _calculate_spaces_till_next_left_indent(int p_column) const;
@@ -214,7 +214,7 @@ private:
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
- RBSet<char32_t> code_completion_prefixes;
+ HashSet<char32_t> code_completion_prefixes;
List<ScriptLanguage::CodeCompletionOption> code_completion_option_submitted;
List<ScriptLanguage::CodeCompletionOption> code_completion_option_sources;
String code_completion_base;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 5c5b2683a4..db78b4adb6 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -836,6 +836,7 @@ void Control::_notification(int p_notification) {
}
} else {
data.minimum_size_valid = false;
+ _update_minimum_size();
_size_changed();
}
} break;
@@ -3301,19 +3302,19 @@ void Control::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
ADD_SUBGROUP_INDENT("Anchor Offsets", "offset_", 1);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_top", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_right", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_top", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_right", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_bottom", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_BOTTOM);
ADD_SUBGROUP_INDENT("Grow Direction", "grow_", 1);
ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Left,Right,Both"), "set_h_grow_direction", "get_h_grow_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Top,Bottom,Both"), "set_v_grow_direction", "get_v_grow_direction");
ADD_SUBGROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset"), "set_pivot_offset", "get_pivot_offset");
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index ccf7e2828a..446d9e800a 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -426,8 +426,8 @@ void GraphEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal"));
- port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical"));
+ port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent");
+ port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent");
zoom_minus->set_icon(get_theme_icon(SNAME("minus")));
zoom_reset->set_icon(get_theme_icon(SNAME("reset")));
@@ -544,8 +544,7 @@ void GraphEdit::_set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashM
}
bool GraphEdit::_filter_input(const Point2 &p_point) {
- Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
- Vector2i port_size = Vector2i(port->get_width(), port->get_height());
+ Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -553,14 +552,18 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
continue;
}
- for (int j = 0; j < gn->get_connection_output_count(); j++) {
- if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
+ for (int j = 0; j < gn->get_connection_input_count(); j++) {
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+ if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
return true;
}
}
- for (int j = 0; j < gn->get_connection_input_count(); j++) {
- if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
+ for (int j = 0; j < gn->get_connection_output_count(); j++) {
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+ if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
return true;
}
}
@@ -572,8 +575,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
- Vector2i port_size = Vector2i(port->get_width(), port->get_height());
+ Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
connecting_valid = false;
click_pos = mb->get_position() / zoom;
@@ -585,6 +587,9 @@ 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();
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+
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
@@ -629,6 +634,10 @@ 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();
+
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+
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
@@ -682,11 +691,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0;
if (connecting_valid) {
- Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
- Vector2i port_size = Vector2i(port->get_width(), port->get_height());
-
Vector2 mpos = mm->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
+ Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn) {
continue;
@@ -695,6 +702,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (!connecting_out) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+
int type = gn->get_connection_output_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) {
connecting_target = true;
@@ -707,6 +717,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
} else {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
+ Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+ port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+
int type = gn->get_connection_input_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) {
connecting_target = true;
@@ -754,19 +767,24 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
-bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) {
- if (p_control->is_set_as_top_level() || !p_control->is_visible()) {
+bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos, const Vector2 &p_offset) {
+ if (p_control->is_set_as_top_level() || !p_control->is_visible() || !p_control->is_inside_tree()) {
return false;
}
- if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
- //test children
+ Rect2 control_rect = p_control->get_rect();
+ control_rect.size *= zoom;
+ control_rect.position *= zoom;
+ control_rect.position += p_offset;
+
+ if (!control_rect.has_point(mpos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
+ // Test children.
for (int i = 0; i < p_control->get_child_count(); i++) {
- Control *subchild = Object::cast_to<Control>(p_control->get_child(i));
- if (!subchild) {
+ Control *child_rect = Object::cast_to<Control>(p_control->get_child(i));
+ if (!child_rect) {
continue;
}
- if (_check_clickable_control(subchild, pos - subchild->get_position())) {
+ if (_check_clickable_control(child_rect, mpos, control_rect.position)) {
return true;
}
}
@@ -798,7 +816,13 @@ bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index,
}
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)) {
+ Rect2 hotzone = Rect2(
+ pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent),
+ pos.y - p_port_size.height / 2.0,
+ port_hotzone_inner_extent + port_hotzone_outer_extent,
+ p_port_size.height);
+
+ if (!hotzone.has_point(p_mouse_pos)) {
return false;
}
@@ -807,23 +831,17 @@ bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_po
if (!child) {
continue;
}
- Rect2 rect = child->get_rect();
-
- // To prevent intersections with other nodes.
- rect.position *= zoom;
- rect.size *= zoom;
-
- if (rect.has_point(p_mouse_pos)) {
- //check sub-controls
- Vector2 subpos = p_mouse_pos - rect.position;
+ Rect2 child_rect = child->get_rect();
+ child_rect.size *= zoom;
+ if (child_rect.has_point(p_mouse_pos * zoom)) {
for (int j = 0; j < child->get_child_count(); j++) {
Control *subchild = Object::cast_to<Control>(child->get_child(j));
if (!subchild) {
continue;
}
- if (_check_clickable_control(subchild, subpos - subchild->get_position())) {
+ if (_check_clickable_control(subchild, p_mouse_pos * zoom, child_rect.position)) {
return false;
}
}
@@ -839,13 +857,23 @@ PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const V
return ret;
}
+ float x_diff = (p_to.x - p_from.x);
+ float cp_offset = x_diff * lines_curvature;
+ if (x_diff < 0) {
+ cp_offset *= -1;
+ }
+
Curve2D curve;
- Vector<Color> colors;
curve.add_point(p_from);
- curve.set_point_out(0, Vector2(60, 0));
+ curve.set_point_out(0, Vector2(cp_offset, 0));
curve.add_point(p_to);
- curve.set_point_in(1, Vector2(-60, 0));
- return curve.tessellate();
+ curve.set_point_in(1, Vector2(-cp_offset, 0));
+
+ if (lines_curvature > 0) {
+ return curve.tessellate(5, 2.0);
+ } else {
+ return curve.tessellate(1);
+ }
}
void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom) {
@@ -1666,6 +1694,15 @@ void GraphEdit::_minimap_toggled() {
}
}
+void GraphEdit::set_connection_lines_curvature(float p_curvature) {
+ lines_curvature = p_curvature;
+ update();
+}
+
+float GraphEdit::get_connection_lines_curvature() const {
+ return lines_curvature;
+}
+
void GraphEdit::set_connection_lines_thickness(float p_thickness) {
lines_thickness = p_thickness;
update();
@@ -1696,7 +1733,7 @@ void GraphEdit::set_warped_panning(bool p_warped) {
warped_panning = p_warped;
}
-int GraphEdit::_set_operations(SET_OPERATIONS p_operation, RBSet<StringName> &r_u, const RBSet<StringName> &r_v) {
+int GraphEdit::_set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v) {
switch (p_operation) {
case GraphEdit::IS_EQUAL: {
for (const StringName &E : r_u) {
@@ -1718,10 +1755,13 @@ int GraphEdit::_set_operations(SET_OPERATIONS p_operation, RBSet<StringName> &r_
return 1;
} break;
case GraphEdit::DIFFERENCE: {
- for (RBSet<StringName>::Element *E = r_u.front(); E; E = E->next()) {
- if (r_v.has(E->get())) {
- r_u.erase(E->get());
+ for (HashSet<StringName>::Iterator E = r_u.begin(); E;) {
+ HashSet<StringName>::Iterator N = E;
+ ++N;
+ if (r_v.has(*E)) {
+ r_u.remove(E);
}
+ E = N;
}
return r_u.size();
} break;
@@ -1739,17 +1779,17 @@ int GraphEdit::_set_operations(SET_OPERATIONS p_operation, RBSet<StringName> &r_
return -1;
}
-HashMap<int, Vector<StringName>> GraphEdit::_layering(const RBSet<StringName> &r_selected_nodes, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours) {
+HashMap<int, Vector<StringName>> GraphEdit::_layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
HashMap<int, Vector<StringName>> l;
- RBSet<StringName> p = r_selected_nodes, q = r_selected_nodes, u, z;
+ HashSet<StringName> p = r_selected_nodes, q = r_selected_nodes, u, z;
int current_layer = 0;
bool selected = false;
while (!_set_operations(GraphEdit::IS_EQUAL, q, u)) {
_set_operations(GraphEdit::DIFFERENCE, p, u);
for (const StringName &E : p) {
- RBSet<StringName> n = r_upper_neighbours[E];
+ HashSet<StringName> n = r_upper_neighbours[E];
if (_set_operations(GraphEdit::IS_SUBSET, n, z)) {
Vector<StringName> t;
t.push_back(E);
@@ -1759,7 +1799,7 @@ HashMap<int, Vector<StringName>> GraphEdit::_layering(const RBSet<StringName> &r
selected = true;
t.append_array(l[current_layer]);
l.insert(current_layer, t);
- RBSet<StringName> V;
+ HashSet<StringName> V;
V.insert(E);
_set_operations(GraphEdit::UNION, u, V);
}
@@ -1801,7 +1841,7 @@ Vector<StringName> GraphEdit::_split(const Vector<StringName> &r_layer, const Ha
return left;
}
-void GraphEdit::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours, const RBSet<StringName> &r_selected_nodes) {
+void GraphEdit::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes) {
for (const StringName &E : r_selected_nodes) {
r_root[E] = E;
r_align[E] = E;
@@ -1841,7 +1881,7 @@ void GraphEdit::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, c
}
}
-void GraphEdit::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours) {
+void GraphEdit::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
if (r_layers.size() == 1) {
return;
}
@@ -1879,7 +1919,7 @@ void GraphEdit::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layer
}
}
-void GraphEdit::_calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const RBSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info) {
+void GraphEdit::_calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info) {
for (const StringName &E : r_block_heads) {
real_t left = 0;
StringName u = E;
@@ -2052,7 +2092,7 @@ void GraphEdit::arrange_nodes() {
}
Dictionary node_names;
- RBSet<StringName> selected_nodes;
+ HashSet<StringName> selected_nodes;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -2063,7 +2103,7 @@ void GraphEdit::arrange_nodes() {
node_names[gn->get_name()] = gn;
}
- HashMap<StringName, RBSet<StringName>> upper_neighbours;
+ HashMap<StringName, HashSet<StringName>> upper_neighbours;
HashMap<StringName, Pair<int, int>> port_info;
Vector2 origin(FLT_MAX, FLT_MAX);
@@ -2078,7 +2118,7 @@ void GraphEdit::arrange_nodes() {
if (gn->is_selected()) {
selected_nodes.insert(gn->get_name());
- RBSet<StringName> s;
+ HashSet<StringName> s;
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]);
if (E->get().to == gn->get_name() && p_from->is_selected()) {
@@ -2115,7 +2155,7 @@ void GraphEdit::arrange_nodes() {
HashMap<StringName, Vector2> new_positions;
Vector2 default_position(FLT_MAX, FLT_MAX);
Dictionary inner_shift;
- RBSet<StringName> block_heads;
+ HashSet<StringName> block_heads;
for (const StringName &E : selected_nodes) {
inner_shift[E] = 0.0f;
@@ -2241,6 +2281,9 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap);
ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap);
+ ClassDB::bind_method(D_METHOD("set_connection_lines_curvature", "curvature"), &GraphEdit::set_connection_lines_curvature);
+ ClassDB::bind_method(D_METHOD("get_connection_lines_curvature"), &GraphEdit::get_connection_lines_curvature);
+
ClassDB::bind_method(D_METHOD("set_connection_lines_thickness", "pixels"), &GraphEdit::set_connection_lines_thickness);
ClassDB::bind_method(D_METHOD("get_connection_lines_thickness"), &GraphEdit::get_connection_lines_thickness);
@@ -2277,6 +2320,7 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans"), "set_panning_scheme", "get_panning_scheme");
ADD_GROUP("Connection Lines", "connection_lines");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_curvature"), "set_connection_lines_curvature", "get_connection_lines_curvature");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased");
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 9e34d5528f..02e90e4717 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -124,8 +124,8 @@ private:
HScrollBar *h_scroll = nullptr;
VScrollBar *v_scroll = nullptr;
- float port_grab_distance_horizontal = 0.0;
- float port_grab_distance_vertical = 0.0;
+ float port_hotzone_inner_extent = 0.0;
+ float port_hotzone_outer_extent = 0.0;
Ref<ViewPanner> panner;
bool warped_panning = true;
@@ -178,6 +178,7 @@ private:
List<Connection> connections;
float lines_thickness = 2.0f;
+ float lines_curvature = 0.5f;
bool lines_antialiased = true;
PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
@@ -218,8 +219,11 @@ private:
uint64_t key = 0;
};
- bool operator<(const ConnType &p_type) const {
- return key < p_type.key;
+ static uint32_t hash(const ConnType &p_conn) {
+ return hash_one_uint64(p_conn.key);
+ }
+ bool operator==(const ConnType &p_type) const {
+ return key == p_type.key;
}
ConnType(uint32_t a = 0, uint32_t b = 0) {
@@ -228,9 +232,9 @@ private:
}
};
- RBSet<ConnType> valid_connection_types;
- RBSet<int> valid_left_disconnect_types;
- RBSet<int> valid_right_disconnect_types;
+ HashSet<ConnType, ConnType> valid_connection_types;
+ HashSet<int> valid_left_disconnect_types;
+ HashSet<int> valid_right_disconnect_types;
HashMap<StringName, Vector<GraphNode *>> comment_enclosed_nodes;
void _update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes);
@@ -247,7 +251,7 @@ private:
friend class GraphEditMinimap;
void _minimap_toggled();
- bool _check_clickable_control(Control *p_control, const Vector2 &pos);
+ bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset);
bool arranging_graph = false;
@@ -258,12 +262,12 @@ private:
UNION,
};
- int _set_operations(SET_OPERATIONS p_operation, RBSet<StringName> &r_u, const RBSet<StringName> &r_v);
- HashMap<int, Vector<StringName>> _layering(const RBSet<StringName> &r_selected_nodes, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours);
+ int _set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v);
+ HashMap<int, Vector<StringName>> _layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
Vector<StringName> _split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings);
- void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours, const RBSet<StringName> &r_selected_nodes);
- void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, RBSet<StringName>> &r_upper_neighbours);
- void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const RBSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
+ void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes);
+ void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours);
+ void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
float _calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions);
void _place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions);
@@ -341,6 +345,9 @@ public:
int get_snap() const;
void set_snap(int p_snap);
+ void set_connection_lines_curvature(float p_curvature);
+ float get_connection_lines_curvature() const;
+
void set_connection_lines_thickness(float p_thickness);
float get_connection_lines_thickness() const;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 45f036d8fc..5cb28a30e8 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -832,6 +832,7 @@ void GraphNode::_connpos_update() {
cc.pos = Point2i(edgeofs, y + h / 2);
cc.type = slot_info[idx].type_left;
cc.color = slot_info[idx].color_left;
+ cc.height = size.height;
conn_input_cache.push_back(cc);
}
if (slot_info[idx].enable_right) {
@@ -839,6 +840,7 @@ void GraphNode::_connpos_update() {
cc.pos = Point2i(get_size().width - edgeofs, y + h / 2);
cc.type = slot_info[idx].type_right;
cc.color = slot_info[idx].color_right;
+ cc.height = size.height;
conn_output_cache.push_back(cc);
}
}
@@ -859,12 +861,13 @@ int GraphNode::get_connection_input_count() {
return conn_input_cache.size();
}
-int GraphNode::get_connection_output_count() {
+int GraphNode::get_connection_input_height(int p_idx) {
if (connpos_dirty) {
_connpos_update();
}
- return conn_output_cache.size();
+ ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
+ return conn_input_cache[p_idx].height;
}
Vector2 GraphNode::get_connection_input_position(int p_idx) {
@@ -897,6 +900,23 @@ Color GraphNode::get_connection_input_color(int p_idx) {
return conn_input_cache[p_idx].color;
}
+int GraphNode::get_connection_output_count() {
+ if (connpos_dirty) {
+ _connpos_update();
+ }
+
+ return conn_output_cache.size();
+}
+
+int GraphNode::get_connection_output_height(int p_idx) {
+ if (connpos_dirty) {
+ _connpos_update();
+ }
+
+ ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
+ return conn_output_cache[p_idx].height;
+}
+
Vector2 GraphNode::get_connection_output_position(int p_idx) {
if (connpos_dirty) {
_connpos_update();
@@ -1066,15 +1086,17 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
- ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count);
+ ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height);
+ ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position);
+ ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type);
+ ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color);
+ ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
+ ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height);
ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position);
ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type);
ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color);
- ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position);
- ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type);
- ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color);
ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button);
ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible);
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 9481a7452d..f6c943dc89 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -81,6 +81,7 @@ private:
Vector2 pos;
int type = 0;
Color color;
+ int height;
};
Vector<ConnCache> conn_input_cache;
@@ -167,10 +168,13 @@ public:
bool is_close_button_visible() const;
int get_connection_input_count();
- int get_connection_output_count();
+ int get_connection_input_height(int p_idx);
Vector2 get_connection_input_position(int p_idx);
int get_connection_input_type(int p_idx);
Color get_connection_input_color(int p_idx);
+
+ int get_connection_output_count();
+ int get_connection_output_height(int p_idx);
Vector2 get_connection_output_position(int p_idx);
int get_connection_output_type(int p_idx);
Color get_connection_output_color(int p_idx);
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 5d9484806b..6f8518a7b0 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -29,12 +29,13 @@
/*************************************************************************/
#include "grid_container.h"
+#include "core/templates/rb_set.h"
void GridContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- HashMap<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col).
- HashMap<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row).
+ RBMap<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col).
+ RBMap<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row).
RBSet<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
RBSet<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
@@ -261,8 +262,8 @@ void GridContainer::_bind_methods() {
}
Size2 GridContainer::get_minimum_size() const {
- HashMap<int, int> col_minw;
- HashMap<int, int> row_minh;
+ RBMap<int, int> col_minw;
+ RBMap<int, int> row_minh;
int hsep = get_theme_constant(SNAME("h_separation"));
int vsep = get_theme_constant(SNAME("v_separation"));
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 73188d6602..fd9db4ea1b 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -695,7 +695,7 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
return false;
}
Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear"));
- int x_ofs = get_theme_stylebox(SNAME("normal"))->get_offset().x;
+ int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT);
return p_pos.x > get_size().width - icon->get_width() - x_ofs;
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 4b79d79846..a86f2bdbc1 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -320,7 +320,7 @@ int OptionButton::get_selectable_item(bool p_from_last) const {
}
}
} else {
- for (int i = get_item_count() - 1; i >= 0; i++) {
+ for (int i = get_item_count() - 1; i >= 0; i--) {
if (!is_item_disabled(i) && !is_item_separator(i)) {
return i;
}
diff --git a/scene/gui/range.h b/scene/gui/range.h
index a59bfa9677..1274821bd1 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -45,7 +45,7 @@ class Range : public Control {
bool exp_ratio = false;
bool allow_greater = false;
bool allow_lesser = false;
- RBSet<Range *> owners;
+ HashSet<Range *> owners;
void emit_value_changed();
void emit_changed(const char *p_what = "");
};
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 78fd682c35..94c2a9e64b 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1839,8 +1839,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
deselect();
}
}
-
- if (!b->is_double_click() && !scroll_updated) {
+ if (!b->is_double_click() && !scroll_updated && !selection.active) {
Item *c_item = nullptr;
bool outside = true;
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index b96ba0ebf9..fec8d11bef 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -862,6 +862,7 @@ void TabBar::_update_hover() {
void TabBar::_update_cache() {
if (tabs.is_empty()) {
+ buttons_visible = false;
return;
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 050c510a96..0f74c9c357 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2452,17 +2452,17 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
if (p_word) {
int column = caret.column;
// Check for the case "<word><space><caret>" and ignore the space.
- // No need to check for column being 0 since it is cheked above.
+ // No need to check for column being 0 since it is checked above.
if (is_whitespace(text[caret.line][caret.column - 1])) {
column -= 1;
}
// Get a list with the indices of the word bounds of the given text line.
const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
if (words.is_empty() || column <= words[0]) {
- // If "words" is empty, meaning no words are left, we can remove everything until the begining of the line.
+ // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line.
column = 0;
} else {
- // Otherwise search for the first word break that is smaller than the index from we're currentlu deleteing
+ // Otherwise search for the first word break that is smaller than the index from which we're currently deleting.
for (int i = words.size() - 2; i >= 0; i = i - 2) {
if (words[i] < column) {
column = words[i];
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index f79c68671c..081d065efe 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -650,8 +650,8 @@ void TextureProgressBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_progress"), "set_tint_progress", "get_tint_progress");
ADD_GROUP("Radial Fill", "radial_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_radial_initial_angle", "get_radial_initial_angle");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_fill_degrees", "get_fill_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider,degrees"), "set_radial_initial_angle", "get_radial_initial_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider,degrees"), "set_fill_degrees", "get_fill_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "radial_center_offset"), "set_radial_center_offset", "get_radial_center_offset");
BIND_ENUM_CONSTANT(FILL_LEFT_TO_RIGHT);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 0ca9a66e08..d3e7540790 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -544,6 +544,21 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::set_visible(bool p_visible) {
+ if (visible == p_visible) {
+ return;
+ }
+ visible = p_visible;
+ if (tree) {
+ tree->update();
+ _changed_notify();
+ }
+}
+
+bool TreeItem::is_visible() {
+ return visible;
+}
+
void TreeItem::uncollapse_tree() {
TreeItem *t = this;
while (t) {
@@ -646,7 +661,7 @@ TreeItem *TreeItem::get_first_child() const {
return first_child;
}
-TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
+TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
TreeItem *current = this;
TreeItem *prev = current->get_prev();
@@ -682,7 +697,21 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
return current;
}
-TreeItem *TreeItem::get_next_visible(bool p_wrap) {
+TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
+ TreeItem *loop = this;
+ TreeItem *prev = this->_get_prev_visible(p_wrap);
+ while (prev && !prev->is_visible()) {
+ prev = prev->_get_prev_visible(p_wrap);
+ if (prev == loop) {
+ // Check that we haven't looped all the way around to the start.
+ prev = nullptr;
+ break;
+ }
+ }
+ return prev;
+}
+
+TreeItem *TreeItem::_get_next_visible(bool p_wrap) {
TreeItem *current = this;
if (!current->collapsed && current->first_child) {
@@ -709,12 +738,37 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return current;
}
+TreeItem *TreeItem::get_next_visible(bool p_wrap) {
+ TreeItem *loop = this;
+ TreeItem *next = this->_get_next_visible(p_wrap);
+ while (next && !next->is_visible()) {
+ next = next->_get_next_visible(p_wrap);
+ if (next == loop) {
+ // Check that we haven't looped all the way around to the start.
+ next = nullptr;
+ break;
+ }
+ }
+ return next;
+}
+
TreeItem *TreeItem::get_child(int p_idx) {
_create_children_cache();
ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
return children_cache.get(p_idx);
}
+int TreeItem::get_visible_child_count() {
+ _create_children_cache();
+ int visible_count = 0;
+ for (int i = 0; i < children_cache.size(); i++) {
+ if (children_cache[i]->is_visible()) {
+ visible_count += 1;
+ }
+ }
+ return visible_count;
+}
+
int TreeItem::get_child_count() {
_create_children_cache();
return children_cache.size();
@@ -1256,6 +1310,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_visible", "enable"), &TreeItem::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
+
ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
@@ -1340,6 +1397,7 @@ void TreeItem::_bind_methods() {
}
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height");
@@ -1445,7 +1503,7 @@ void Tree::update_cache() {
}
int Tree::compute_item_height(TreeItem *p_item) const {
- if (p_item == root && hide_root) {
+ if ((p_item == root && hide_root) || !p_item->is_visible()) {
return 0;
}
@@ -1506,6 +1564,9 @@ int Tree::compute_item_height(TreeItem *p_item) const {
}
int Tree::get_item_height(TreeItem *p_item) const {
+ if (!p_item->is_visible()) {
+ return 0;
+ }
int height = compute_item_height(p_item);
height += cache.vseparation;
@@ -1686,6 +1747,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
return -1; //draw no more!
}
+ if (!p_item->is_visible()) {
+ return 0;
+ }
+
RID ci = get_canvas_item();
int htotal = 0;
@@ -2056,7 +2121,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if (!p_item->disable_folding && !hide_folding && p_item->first_child) { //has children, draw the guide box
+ if (!p_item->disable_folding && !hide_folding && p_item->first_child && p_item->get_visible_child_count() != 0) { //has visible children, draw the guide box
Ref<Texture2D> arrow;
@@ -2099,12 +2164,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
// Draw relationship lines.
- if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) {
+ if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) {
int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
int parent_ofs = p_pos.x + cache.item_margin;
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
- if (c->get_first_child() != nullptr) {
+ if (c->get_visible_child_count() > 0) {
root_pos -= Point2i(cache.arrow->get_width(), 0);
}
@@ -2382,6 +2447,11 @@ void Tree::_range_click_timeout() {
}
int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, MouseButton p_button, const Ref<InputEventWithModifiers> &p_mod) {
+ if (p_item && !p_item->is_visible()) {
+ // Skip any processing of invisible items.
+ return 0;
+ }
+
int item_h = compute_item_height(p_item) + cache.vseparation;
bool skip = (p_item == root && hide_root);
@@ -2491,7 +2561,6 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
cache.click_column = col;
cache.click_pos = click_pos;
update();
- //emit_signal(SNAME("button_pressed"));
return -1;
}
@@ -2513,9 +2582,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
if (!c.selected || p_button == MouseButton::RIGHT) {
p_item->select(col);
emit_signal(SNAME("multi_selected"), p_item, col, true);
- if (p_button == MouseButton::RIGHT) {
- emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position());
- }
+ emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
//p_item->selected_signal.call(col);
} else {
@@ -2530,9 +2597,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
bool inrange = false;
select_single_item(p_item, root, col, selected_item, &inrange);
- if (p_button == MouseButton::RIGHT) {
- emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position());
- }
+ emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
} else {
int icount = _count_selected_items(root);
@@ -2544,9 +2609,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
select_single_item(p_item, root, col);
}
- if (p_button == MouseButton::RIGHT) {
- emit_signal(SNAME("item_rmb_selected"), get_local_mouse_position());
- }
+ emit_signal(SNAME("item_mouse_selected"), get_local_mouse_position(), p_button);
}
}
@@ -2583,11 +2646,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
if (force_edit_checkbox_only_on_checkbox) {
if (x < cache.checked->get_width()) {
p_item->set_checked(col, !c.checked);
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
}
} else {
p_item->set_checked(col, !c.checked);
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
}
click_handled = true;
//p_item->edited_signal.call(col);
@@ -2629,17 +2692,17 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
p_item->set_range(col, c.val + (up ? 1.0 : -1.0) * c.step);
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
} else if (p_button == MouseButton::RIGHT) {
p_item->set_range(col, (up ? c.max : c.min));
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
} else if (p_button == MouseButton::WHEEL_UP) {
p_item->set_range(col, c.val + c.step);
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
} else if (p_button == MouseButton::WHEEL_DOWN) {
p_item->set_range(col, c.val - c.step);
- item_edited(col, p_item);
+ item_edited(col, p_item, p_button);
}
//p_item->edited_signal.call(col);
@@ -2670,7 +2733,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->cells[col].custom_button || !on_arrow) {
- item_edited(col, p_item, p_button == MouseButton::LEFT);
+ item_edited(col, p_item, p_button);
}
click_handled = true;
return -1;
@@ -2717,8 +2780,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
item_h += child_h;
}
}
- if (p_item == root && p_button == MouseButton::RIGHT) {
- emit_signal(SNAME("empty_rmb"), get_local_mouse_position());
+ if (p_item == root) {
+ emit_signal(SNAME("empty_clicked"), get_local_mouse_position(), p_button);
}
}
@@ -3126,7 +3189,6 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
-
if (mm.is_valid()) {
if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
update_cache();
@@ -3256,18 +3318,17 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
}
- Ref<InputEventMouseButton> b = p_event;
-
- if (b.is_valid()) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
update_cache();
}
bool rtl = is_layout_rtl();
- if (!b->is_pressed()) {
- if (b->get_button_index() == MouseButton::LEFT) {
- Point2 pos = b->get_position();
+ if (!mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ Point2 pos = mb->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
}
@@ -3302,7 +3363,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
warp_mouse(range_drag_capture_pos);
} else {
Rect2 rect = get_selected()->get_meta("__focus_rect");
- Point2 mpos = b->get_position();
+ Point2 mpos = mb->get_position();
int icon_size_x = 0;
Ref<Texture2D> icon = get_selected()->get_icon(selected_col);
if (icon.is_valid()) {
@@ -3330,17 +3391,6 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
pressing_for_editor = false;
}
- if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != nullptr) {
- // make sure in case of wrong reference after reconstructing whole TreeItems
- cache.click_item = get_item_at_position(cache.click_pos);
- emit_signal(SNAME("button_pressed"), cache.click_item, cache.click_column, cache.click_id);
- }
- cache.click_type = Cache::CLICK_NONE;
- cache.click_index = -1;
- cache.click_id = -1;
- cache.click_item = nullptr;
- cache.click_column = 0;
-
if (drag_touching) {
if (drag_speed == 0) {
drag_touching_deaccel = false;
@@ -3350,8 +3400,20 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
drag_touching_deaccel = true;
}
}
- update();
}
+
+ if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != nullptr) {
+ // make sure in case of wrong reference after reconstructing whole TreeItems
+ cache.click_item = get_item_at_position(cache.click_pos);
+ emit_signal("button_clicked", cache.click_item, cache.click_column, cache.click_id, mb->get_button_index());
+ }
+
+ cache.click_type = Cache::CLICK_NONE;
+ cache.click_index = -1;
+ cache.click_id = -1;
+ cache.click_item = nullptr;
+ cache.click_column = 0;
+ update();
return;
}
@@ -3359,12 +3421,12 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- switch (b->get_button_index()) {
+ switch (mb->get_button_index()) {
case MouseButton::RIGHT:
case MouseButton::LEFT: {
Ref<StyleBox> bg = cache.bg;
- Point2 pos = b->get_position();
+ Point2 pos = mb->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
}
@@ -3374,7 +3436,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- if (b->get_button_index() == MouseButton::LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
pos.x += cache.offset.x;
int len = 0;
for (int i = 0; i < columns.size(); i++) {
@@ -3391,10 +3453,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
break;
}
}
+
if (!root || (!root->get_first_child() && hide_root)) {
- if (b->get_button_index() == MouseButton::RIGHT && allow_rmb_select) {
- emit_signal(SNAME("empty_tree_rmb_selected"), get_local_mouse_position());
- }
break;
}
@@ -3409,17 +3469,17 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
cache.rtl = is_layout_rtl();
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, b->is_double_click(), root, b->get_button_index(), b);
+ propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb);
blocked--;
if (pressing_for_editor) {
- pressing_pos = b->get_position();
+ pressing_pos = mb->get_position();
if (rtl) {
pressing_pos.x = get_size().width - pressing_pos.x;
}
}
- if (b->get_button_index() == MouseButton::RIGHT) {
+ if (mb->get_button_index() == MouseButton::RIGHT) {
break;
}
@@ -3442,8 +3502,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
set_physics_process_internal(true);
}
- if (b->get_button_index() == MouseButton::LEFT) {
- if (get_item_at_position(b->get_position()) == nullptr && !b->is_shift_pressed() && !b->is_ctrl_pressed() && !b->is_command_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_pressed()) {
emit_signal(SNAME("nothing_selected"));
}
}
@@ -3457,7 +3517,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
} break;
case MouseButton::WHEEL_UP: {
double prev_value = v_scroll->get_value();
- v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
+ v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * mb->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
accept_event();
}
@@ -3465,7 +3525,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
} break;
case MouseButton::WHEEL_DOWN: {
double prev_value = v_scroll->get_value();
- v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
+ v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * mb->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
accept_event();
}
@@ -3911,16 +3971,15 @@ TreeItem *Tree::get_last_item() const {
return last;
}
-void Tree::item_edited(int p_column, TreeItem *p_item, bool p_lmb) {
+void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index) {
edited_item = p_item;
edited_col = p_column;
if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) {
edited_item->cells.write[p_column].dirty = true;
}
- if (p_lmb) {
- emit_signal(SNAME("item_edited"));
- } else {
- emit_signal(SNAME("item_rmb_edited"));
+ emit_signal(SNAME("item_edited"));
+ if (p_custom_mouse_index != MouseButton::NONE) {
+ emit_signal(SNAME("custom_item_clicked"), p_custom_mouse_index);
}
}
@@ -4147,7 +4206,7 @@ int Tree::get_column_minimum_width(int p_column) const {
depth += 1;
} else {
TreeItem *common_parent = item->get_parent();
- while (common_parent != next->get_parent()) {
+ while (common_parent != next->get_parent() && common_parent) {
common_parent = common_parent->get_parent();
depth -= 1;
}
@@ -4464,7 +4523,8 @@ Point2 Tree::get_scroll() const {
}
void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) {
- if (!is_visible_in_tree()) {
+ ERR_FAIL_NULL(p_item);
+ if (!is_visible_in_tree() || !p_item->is_visible()) {
return; // Hack to work around crash in get_item_rect() if Tree is not in tree.
}
@@ -4588,7 +4648,7 @@ void Tree::_do_incr_search(const String &p_add) {
TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int &section) const {
Point2 pos = p_pos;
- if (root != p_item || !hide_root) {
+ if ((root != p_item || !hide_root) && p_item->is_visible()) {
h = compute_item_height(p_item) + cache.vseparation;
if (pos.y < h) {
if (drop_mode_flags == DROP_MODE_ON_ITEM) {
@@ -4621,7 +4681,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
h = 0;
}
- if (p_item->is_collapsed()) {
+ if (p_item->is_collapsed() || !p_item->is_visible()) {
return nullptr; // do not try children, it's collapsed
}
@@ -4965,17 +5025,15 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_selected"));
ADD_SIGNAL(MethodInfo("cell_selected"));
ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected")));
- ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
- ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position")));
- ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
+ ADD_SIGNAL(MethodInfo("item_mouse_selected", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::INT, "mouse_button_index")));
+ ADD_SIGNAL(MethodInfo("empty_clicked", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("item_edited"));
- ADD_SIGNAL(MethodInfo("item_rmb_edited"));
+ ADD_SIGNAL(MethodInfo("custom_item_clicked", PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("item_custom_button_pressed"));
ADD_SIGNAL(MethodInfo("item_double_clicked"));
ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem")));
ADD_SIGNAL(MethodInfo("check_propagated_to_item", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column")));
- //ADD_SIGNAL( MethodInfo("item_double_clicked" ) );
- ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("button_clicked", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked")));
ADD_SIGNAL(MethodInfo("item_activated"));
ADD_SIGNAL(MethodInfo("column_title_pressed", PropertyInfo(Variant::INT, "column")));
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 8ee2a3c382..0a8dd3204a 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -124,6 +124,7 @@ private:
Vector<Cell> cells;
bool collapsed = false; // won't show children
+ bool visible = true;
bool disable_folding = false;
int custom_min_height = 0;
@@ -209,6 +210,9 @@ private:
void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal);
void _propagate_check_through_parents(int p_column, bool p_emit_signal);
+ TreeItem *_get_prev_visible(bool p_wrap = false);
+ TreeItem *_get_next_visible(bool p_wrap = false);
+
public:
void set_text(int p_column, String p_text);
String get_text(int p_column) const;
@@ -273,6 +277,9 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void set_visible(bool p_visible);
+ bool is_visible();
+
void uncollapse_tree();
void set_custom_minimum_height(int p_height);
@@ -335,6 +342,7 @@ public:
TreeItem *get_next_visible(bool p_wrap = false);
TreeItem *get_child(int p_idx);
+ int get_visible_child_count();
int get_child_count();
Array get_children();
int get_index();
@@ -466,7 +474,7 @@ private:
void _notification(int p_what);
- void item_edited(int p_column, TreeItem *p_item, bool p_lmb = true);
+ void item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index = MouseButton::NONE);
void item_changed(int p_column, TreeItem *p_item);
void item_selected(int p_column, TreeItem *p_item);
void item_deselected(int p_column, TreeItem *p_item);
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index ca2dad71af..20bc9a1028 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -443,7 +443,7 @@ void VideoStreamPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_track", PROPERTY_HINT_RANGE, "0,128,1"), "set_audio_track", "get_audio_track");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "VideoStream"), "set_stream", "get_stream");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume", PROPERTY_HINT_RANGE, "0,15,0.01,exp", PROPERTY_USAGE_NONE), "set_volume", "get_volume");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused");