summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/navigation_agent_2d.cpp49
-rw-r--r--scene/2d/navigation_agent_2d.h2
-rw-r--r--scene/2d/navigation_region_2d.cpp1
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.cpp1
-rw-r--r--scene/3d/audio_stream_player_3d.cpp9
-rw-r--r--scene/3d/audio_stream_player_3d.h3
-rw-r--r--scene/3d/fog_volume.cpp2
-rw-r--r--scene/3d/navigation_agent_3d.cpp51
-rw-r--r--scene/3d/navigation_agent_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp11
-rw-r--r--scene/3d/visual_instance_3d.cpp9
-rw-r--r--scene/3d/visual_instance_3d.h1
-rw-r--r--scene/gui/graph_edit.cpp116
-rw-r--r--scene/gui/graph_edit.h10
-rw-r--r--scene/gui/graph_node.cpp34
-rw-r--r--scene/gui/graph_node.h6
-rw-r--r--scene/gui/line_edit.cpp18
-rw-r--r--scene/gui/rich_text_label.cpp90
-rw-r--r--scene/gui/rich_text_label.h6
-rw-r--r--scene/gui/tab_bar.cpp1
-rw-r--r--scene/gui/text_edit.cpp2
-rw-r--r--scene/gui/tree.cpp14
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/viewport.cpp16
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp2
-rw-r--r--scene/multiplayer/multiplayer_synchronizer.cpp2
-rw-r--r--scene/resources/default_theme/default_theme.cpp6
-rw-r--r--scene/resources/style_box.cpp12
-rw-r--r--scene/resources/texture.cpp10
-rw-r--r--scene/resources/tile_set.cpp2
-rw-r--r--scene/resources/visual_shader_nodes.cpp8
-rw-r--r--scene/resources/visual_shader_nodes.h4
33 files changed, 378 insertions, 126 deletions
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 00082b321e..80d60dca17 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -96,16 +96,30 @@ void NavigationAgent2D::_bind_methods() {
void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- agent_parent = Object::cast_to<Node2D>(get_parent());
- if (agent_parent != nullptr) {
- // place agent on navigation map first or else the RVO agent callback creation fails silently later
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
- set_avoidance_enabled(avoidance_enabled);
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
+ // cannot use READY as ready does not get called if Node is readded to SceneTree
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
+ case NOTIFICATION_PARENTED: {
+ if (is_inside_tree() && (get_parent() != agent_parent)) {
+ // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around
+ // PARENTED notification fires also when Node is added in scripts to a parent
+ // this would spam transforms fails and world fails while Node is outside SceneTree
+ // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ // if agent has no parent no point in processing it until reparented
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
+ } break;
+
case NOTIFICATION_PAUSED: {
if (agent_parent && !agent_parent->can_process()) {
map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
@@ -133,7 +147,11 @@ void NavigationAgent2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ if (avoidance_enabled) {
+ // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
+ // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
+ NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ }
_check_distance_to_target();
}
} break;
@@ -167,6 +185,21 @@ bool NavigationAgent2D::get_avoidance_enabled() const {
return avoidance_enabled;
}
+void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
+ // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ agent_parent = Object::cast_to<Node2D>(p_agent_parent);
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
+ // create new avoidance callback if enabled
+ set_avoidance_enabled(avoidance_enabled);
+ } else {
+ agent_parent = nullptr;
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) {
bool layers_changed = navigable_layers != p_layers;
navigable_layers = p_layers;
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 5ab4cdba5d..c9983119d0 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -82,6 +82,8 @@ public:
void set_avoidance_enabled(bool p_enabled);
bool get_avoidance_enabled() const;
+ void set_agent_parent(Node *p_agent_parent);
+
void set_navigable_layers(uint32_t p_layers);
uint32_t get_navigable_layers() const;
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 260faf1d68..41773d81c5 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -331,6 +331,7 @@ void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh);
ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp
index 33dd737416..1971dc1240 100644
--- a/scene/2d/visible_on_screen_notifier_2d.cpp
+++ b/scene/2d/visible_on_screen_notifier_2d.cpp
@@ -66,6 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) {
if (is_inside_tree()) {
RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit));
}
+ update();
}
Rect2 VisibleOnScreenNotifier2D::get_rect() const {
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 735ce0bb07..7c1fb3779f 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -273,7 +273,8 @@ void AudioStreamPlayer3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
// Update anything related to position first, if possible of course.
Vector<AudioFrame> volume_vector;
- if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) {
+ if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) {
+ force_update_panning = false;
volume_vector = _update_panning();
}
@@ -318,6 +319,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
}
}
+// Interacts with PhysicsServer3D, so can only be called during _physics_process
Area3D *AudioStreamPlayer3D::_get_overriding_area() {
//check if any area is diverting sound into a bus
Ref<World3D> world_3d = get_world_3d();
@@ -356,6 +358,7 @@ Area3D *AudioStreamPlayer3D::_get_overriding_area() {
return nullptr;
}
+// Interacts with PhysicsServer3D, so can only be called during _physics_process
StringName AudioStreamPlayer3D::_get_actual_bus() {
Area3D *overriding_area = _get_overriding_area();
if (overriding_area && overriding_area->is_overriding_audio_bus() && !overriding_area->is_using_reverb_bus()) {
@@ -364,6 +367,7 @@ StringName AudioStreamPlayer3D::_get_actual_bus() {
return bus;
}
+// Interacts with PhysicsServer3D, so can only be called during _physics_process
Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
Vector<AudioFrame> output_volume_vector;
output_volume_vector.resize(4);
@@ -537,6 +541,7 @@ float AudioStreamPlayer3D::get_unit_db() const {
void AudioStreamPlayer3D::set_unit_size(float p_volume) {
unit_size = p_volume;
+ update_gizmos();
}
float AudioStreamPlayer3D::get_unit_size() const {
@@ -665,6 +670,7 @@ void AudioStreamPlayer3D::_bus_layout_changed() {
void AudioStreamPlayer3D::set_max_distance(float p_metres) {
ERR_FAIL_COND(p_metres < 0.0);
max_distance = p_metres;
+ update_gizmos();
}
float AudioStreamPlayer3D::get_max_distance() const {
@@ -725,6 +731,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const {
void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) {
ERR_FAIL_INDEX((int)p_model, 4);
attenuation_model = p_model;
+ update_gizmos();
}
AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 53cdd2e630..bc47a8de93 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -82,12 +82,13 @@ private:
int max_polyphony = 1;
uint64_t last_mix_count = -1;
+ bool force_update_panning = false;
static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output);
void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol);
- static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_update_panning(); }
+ static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->force_update_panning = true; }
void _set_playing(bool p_enable);
bool _is_active() const;
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 8d05254a25..8fbadb4b7b 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -41,7 +41,7 @@ void FogVolume::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &FogVolume::get_material);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid,Box,World"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid (Local),Cone (Local),Cylinder (Local),Box (Local),World (Global)"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
}
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 88f676d031..947d6012d5 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -102,18 +102,32 @@ void NavigationAgent3D::_bind_methods() {
void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- agent_parent = Object::cast_to<Node3D>(get_parent());
- if (agent_parent != nullptr) {
- // place agent on navigation map first or else the RVO agent callback creation fails silently later
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
- set_avoidance_enabled(avoidance_enabled);
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
+ // cannot use READY as ready does not get called if Node is readded to SceneTree
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
+ case NOTIFICATION_PARENTED: {
+ if (is_inside_tree() && (get_parent() != agent_parent)) {
+ // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around
+ // PARENTED notification fires also when Node is added in scripts to a parent
+ // this would spam transforms fails and world fails while Node is outside SceneTree
+ // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ // if agent has no parent no point in processing it until reparented
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
+ } break;
+
case NOTIFICATION_EXIT_TREE: {
- agent_parent = nullptr;
+ set_agent_parent(nullptr);
set_physics_process_internal(false);
} break;
@@ -139,7 +153,11 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ if (avoidance_enabled) {
+ // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
+ // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
+ NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ }
_check_distance_to_target();
}
} break;
@@ -174,6 +192,21 @@ bool NavigationAgent3D::get_avoidance_enabled() const {
return avoidance_enabled;
}
+void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
+ // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ agent_parent = Object::cast_to<Node3D>(p_agent_parent);
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ // create new avoidance callback if enabled
+ set_avoidance_enabled(avoidance_enabled);
+ } else {
+ agent_parent = nullptr;
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
void NavigationAgent3D::set_navigable_layers(uint32_t p_layers) {
bool layers_changed = navigable_layers != p_layers;
navigable_layers = p_layers;
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 28bcffd5b4..633bf091d1 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -84,6 +84,8 @@ public:
void set_avoidance_enabled(bool p_enabled);
bool get_avoidance_enabled() const;
+ void set_agent_parent(Node *p_agent_parent);
+
void set_navigable_layers(uint32_t p_layers);
uint32_t get_navigable_layers() const;
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 6404432631..cb8da182ee 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -131,6 +131,17 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
+ if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
+ MeshInstance3D *dm = memnew(MeshInstance3D);
+ dm->set_mesh(navmesh->get_debug_mesh());
+ if (is_enabled()) {
+ dm->set_material_override(get_tree()->get_debug_navigation_material());
+ } else {
+ dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ }
+ add_child(dm);
+ debug_view = dm;
+ }
if (debug_view && navmesh.is_valid()) {
Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
}
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 273e01989a..e40c8bfa2b 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -496,3 +496,12 @@ void GeometryInstance3D::_bind_methods() {
GeometryInstance3D::GeometryInstance3D() {
//RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
}
+
+GeometryInstance3D::~GeometryInstance3D() {
+ if (material_overlay.is_valid()) {
+ set_material_overlay(Ref<Material>());
+ }
+ if (material_override.is_valid()) {
+ set_material_override(Ref<Material>());
+ }
+}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index f8fd4378fe..e5f98bd65e 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -188,6 +188,7 @@ public:
TypedArray<String> get_configuration_warnings() const override;
GeometryInstance3D();
+ virtual ~GeometryInstance3D();
};
VARIANT_ENUM_CAST(GeometryInstance3D::ShadowCastingSetting);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index fdff6a88a9..8ad55fc6ef 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")));
@@ -508,8 +508,9 @@ void GraphEdit::_notification(int p_what) {
void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes) {
Rect2 comment_node_rect = p_node->get_rect();
- Vector<GraphNode *> enclosed_nodes;
+ comment_node_rect.size *= zoom;
+ Vector<GraphNode *> enclosed_nodes;
for (int i = 0; i < get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn || gn->is_selected()) {
@@ -517,6 +518,8 @@ void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<S
}
Rect2 node_rect = gn->get_rect();
+ node_rect.size *= zoom;
+
bool included = comment_node_rect.encloses(node_rect);
if (included) {
enclosed_nodes.push_back(gn);
@@ -544,8 +547,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 +555,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 +578,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 +590,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 +637,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 +694,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 +705,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 +720,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 +770,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 +819,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 +834,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 +860,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 +1697,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();
@@ -2244,6 +2284,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);
@@ -2280,6 +2323,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 5484a2317c..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);
@@ -250,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;
@@ -344,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/line_edit.cpp b/scene/gui/line_edit.cpp
index 73188d6602..fa600d24ef 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;
}
@@ -1686,13 +1686,17 @@ Size2 LineEdit::get_minimum_size() const {
min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM), font->get_height(font_size));
// Take icons into account.
- bool using_placeholder = text.is_empty() && ime_text.is_empty();
- bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
- if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
- min_size.width += r_icon->get_width();
- min_size.height = MAX(min_size.height, r_icon->get_height());
+ int icon_max_width = 0;
+ if (right_icon.is_valid()) {
+ min_size.height = MAX(min_size.height, right_icon->get_height());
+ icon_max_width = right_icon->get_width();
+ }
+ if (clear_button_enabled) {
+ Ref<Texture2D> clear_icon = Control::get_theme_icon(SNAME("clear"));
+ min_size.height = MAX(min_size.height, clear_icon->get_height());
+ icon_max_width = MAX(icon_max_width, clear_icon->get_width());
}
+ min_size.width += icon_max_width;
return style->get_minimum_size() + min_size;
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 94c2a9e64b..cf7bf930a5 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -414,7 +414,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
}
l.offset.y = p_h;
- return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ return _calculate_line_vertical_offset(l);
}
float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset) {
@@ -683,7 +683,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
*r_char_offset = l.char_offset + l.char_count;
l.offset.y = p_h;
- return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ return _calculate_line_vertical_offset(l);
}
int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) {
@@ -1566,7 +1566,7 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const {
while (l < r) {
int m = Math::floor(double(l + r) / 2.0);
MutexLock lock(main->lines[m].text_buf->get_mutex());
- int ofs = main->lines[m].offset.y + main->lines[m].text_buf->get_size().y + main->lines[m].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ int ofs = _calculate_line_vertical_offset(main->lines[m]);
if (ofs < p_vofs) {
l = m + 1;
} else {
@@ -1576,6 +1576,10 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const {
return l;
}
+_FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTextLabel::Line &line) const {
+ return line.get_height(get_theme_constant(SNAME("line_separation")));
+}
+
void RichTextLabel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_MOUSE_EXIT: {
@@ -1609,6 +1613,7 @@ void RichTextLabel::_notification(int p_what) {
update();
} break;
+ case NOTIFICATION_PREDELETE:
case NOTIFICATION_EXIT_TREE: {
_stop_thread();
} break;
@@ -2489,7 +2494,7 @@ bool RichTextLabel::_validate_line_caches() {
// Resize lines without reshaping.
int fi = main->first_resized_line.load();
- float total_height = 0;
+ float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _resize_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
@@ -2551,6 +2556,10 @@ bool RichTextLabel::_validate_line_caches() {
void RichTextLabel::_process_line_caches() {
// Shape invalid lines.
+ if (!is_inside_tree()) {
+ return;
+ }
+
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
@@ -2560,10 +2569,9 @@ void RichTextLabel::_process_line_caches() {
int fi = main->first_invalid_line.load();
int total_chars = (fi == 0) ? 0 : (main->lines[fi].char_offset + main->lines[fi].char_count);
- float total_height = 0;
+ float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
total_height = _shape_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
-
updating_scroll = true;
bool exceeds = total_height > ctrl_height && scroll_active;
if (exceeds != scroll_visible) {
@@ -2577,11 +2585,11 @@ void RichTextLabel::_process_line_caches() {
scroll_w = 0;
vscroll->hide();
}
-
main->first_invalid_line.store(0);
main->first_resized_line.store(0);
main->first_invalid_font_line.store(0);
+ // since scroll was added or removed we need to resize all lines
total_height = 0;
for (int j = 0; j <= i; j++) {
total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
@@ -3369,21 +3377,34 @@ void RichTextLabel::append_text(const String &p_bbcode) {
bool in_bold = false;
bool in_italics = false;
+ bool after_list_open_tag = false;
+ bool after_list_close_tag = false;
set_process_internal(false);
- while (pos < p_bbcode.length()) {
+ while (pos <= p_bbcode.length()) {
int brk_pos = p_bbcode.find("[", pos);
if (brk_pos < 0) {
brk_pos = p_bbcode.length();
}
- if (brk_pos > pos) {
- add_text(p_bbcode.substr(pos, brk_pos - pos));
+ String text = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : "";
+
+ // Trim the first newline character, it may be added later as needed.
+ if (after_list_close_tag || after_list_open_tag) {
+ text = text.trim_prefix("\n");
}
if (brk_pos == p_bbcode.length()) {
+ // For tags that are not properly closed.
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n";
+ }
+
+ if (!text.is_empty()) {
+ add_text(text);
+ }
break; //nothing else to add
}
@@ -3391,7 +3412,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
if (brk_end == -1) {
//no close, add the rest
- add_text(p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos));
+ text += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos);
+ add_text(text);
break;
}
@@ -3437,18 +3459,60 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
if (!tag_ok) {
- add_text("[" + tag);
+ text += "[" + tag;
+ add_text(text);
+ after_list_open_tag = false;
+ after_list_close_tag = false;
pos = brk_end;
continue;
}
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n"; // Make empty list have at least one item.
+ }
+ after_list_open_tag = false;
+
+ if (tag == "/ol" || tag == "/ul") {
+ if (!text.is_empty()) {
+ // Make sure text ends with a newline character, that is, the last item
+ // will wrap at the end of block.
+ if (!text.ends_with("\n")) {
+ text += "\n";
+ }
+ } else if (!after_list_close_tag) {
+ text = "\n"; // Make the innermost list item wrap at the end of lists.
+ }
+ after_list_close_tag = true;
+ } else {
+ after_list_close_tag = false;
+ }
+
+ if (!text.is_empty()) {
+ add_text(text);
+ }
+
tag_stack.pop_front();
pos = brk_end + 1;
if (tag != "/img" && tag != "/dropcap") {
pop();
}
+ continue;
+ }
+
+ if (tag == "ol" || tag.begins_with("ol ") || tag == "ul" || tag.begins_with("ul ")) {
+ if (text.is_empty() && after_list_open_tag) {
+ text = "\n"; // Make each list have at least one item at the beginning.
+ }
+ after_list_open_tag = true;
+ } else {
+ after_list_open_tag = false;
+ }
+ if (!text.is_empty()) {
+ add_text(text);
+ }
+ after_list_close_tag = false;
- } else if (tag == "b") {
+ if (tag == "b") {
//use bold font
in_bold = true;
if (in_italics) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 7fbd5f1745..93e57058b0 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -117,6 +117,10 @@ private:
int char_count = 0;
Line() { text_buf.instantiate(); }
+
+ _FORCE_INLINE_ float get_height(float line_separation) const {
+ return offset.y + text_buf->get_size().y + text_buf->get_line_count() * line_separation;
+ }
};
struct Item {
@@ -504,6 +508,8 @@ private:
void _scroll_changed(double);
int _find_first_line(int p_from, int p_to, int p_vofs) const;
+ _FORCE_INLINE_ float _calculate_line_vertical_offset(const Line &line) const;
+
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual String get_tooltip(const Point2 &p_pos) const override;
Item *_get_next_item(Item *p_item, bool p_free = false) const;
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 0f74c9c357..8e948203f1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3080,7 +3080,7 @@ void TextEdit::set_line(int p_line, const String &p_new_text) {
_remove_text(p_line, 0, p_line, text[p_line].length());
_insert_text(p_line, 0, p_new_text);
if (caret.line == p_line && caret.column > p_new_text.length()) {
- set_caret_column(MIN(caret.column, p_new_text.length()), false);
+ set_caret_column(p_new_text.length(), false);
}
if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) {
selection.to_column = text[p_line].length();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 4d18bc91c4..d3e7540790 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2164,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);
}
@@ -3971,16 +3971,15 @@ TreeItem *Tree::get_last_item() const {
return last;
}
-void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index) {
+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_mouse_index == MouseButton::NONE) {
- emit_signal(SNAME("item_edited"));
- } else {
- emit_signal(SNAME("custom_item_clicked"), p_mouse_index);
+ emit_signal(SNAME("item_edited"));
+ if (p_custom_mouse_index != MouseButton::NONE) {
+ emit_signal(SNAME("custom_item_clicked"), p_custom_mouse_index);
}
}
@@ -4524,6 +4523,7 @@ Point2 Tree::get_scroll() const {
}
void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) {
+ 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.
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index a70f24cb62..0a8dd3204a 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -474,7 +474,7 @@ private:
void _notification(int p_what);
- void item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index = MouseButton::NONE);
+ 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/main/viewport.cpp b/scene/main/viewport.cpp
index 590c73de0b..7c7809fd75 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3458,8 +3458,8 @@ void Viewport::_own_world_3d_changed() {
_update_audio_listener_3d();
}
-void Viewport::set_use_own_world_3d(bool p_world_3d) {
- if (p_world_3d == own_world_3d.is_valid()) {
+void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
+ if (p_use_own_world_3d == own_world_3d.is_valid()) {
return;
}
@@ -3467,18 +3467,18 @@ void Viewport::set_use_own_world_3d(bool p_world_3d) {
_propagate_exit_world_3d(this);
}
- if (!p_world_3d) {
- own_world_3d = Ref<World3D>();
- if (world_3d.is_valid()) {
- world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
- }
- } else {
+ if (p_use_own_world_3d) {
if (world_3d.is_valid()) {
own_world_3d = world_3d->duplicate();
world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
} else {
own_world_3d = Ref<World3D>(memnew(World3D));
}
+ } else {
+ own_world_3d = Ref<World3D>();
+ if (world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
}
if (is_inside_tree()) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 5bca5a2dda..833b302e97 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -676,7 +676,7 @@ public:
Ref<World3D> get_world_3d() const;
Ref<World3D> find_world_3d() const;
void _own_world_3d_changed();
- void set_use_own_world_3d(bool p_world_3d);
+ void set_use_own_world_3d(bool p_use_own_world_3d);
bool is_using_own_world_3d() const;
void _propagate_enter_world_3d(Node *p_node);
void _propagate_exit_world_3d(Node *p_node);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 193f18c075..9b347ed7c8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -681,7 +681,7 @@ void Window::_update_viewport_size() {
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
- final_size = viewport_size;
+ final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
} break;
diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp
index 34d5abf9f6..78cec9ee10 100644
--- a/scene/multiplayer/multiplayer_synchronizer.cpp
+++ b/scene/multiplayer/multiplayer_synchronizer.cpp
@@ -96,7 +96,7 @@ void MultiplayerSynchronizer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config);
ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "congiruation", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config");
}
void MultiplayerSynchronizer::_notification(int p_what) {
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index ba22fdcad3..5fcaf8f2c4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -1004,13 +1004,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3));
theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8));
theme->set_color("activity", "GraphEdit", Color(1, 1, 1));
- theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale);
- theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale);
// Visual Node Ports
- theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale);
- theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale);
+ theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale);
+ theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale);
theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0);
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index f3cb2b9ea7..b54bbc1478 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -122,7 +122,7 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw);
- ADD_GROUP("Content Margin", "content_margin_");
+ ADD_GROUP("Content Margins", "content_margin_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
@@ -315,15 +315,14 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_GROUP("Margin", "margin_");
+ ADD_GROUP("Margins", "margin_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
- ADD_GROUP("Expand Margin", "expand_margin_");
+ ADD_GROUP("Expand Margins", "expand_margin_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
@@ -333,6 +332,9 @@ void StyleBoxTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_GROUP("Sub-Region", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
+
ADD_GROUP("Modulate", "modulate_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
@@ -921,7 +923,7 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
- ADD_GROUP("Expand Margin", "expand_margin_");
+ ADD_GROUP("Expand Margins", "expand_margin_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 9442a58ac1..04b85e3e36 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2161,7 +2161,7 @@ void GradientTexture1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
@@ -2249,7 +2249,7 @@ void GradientTexture1D::_update() {
}
void GradientTexture1D::set_width(int p_width) {
- ERR_FAIL_COND(p_width <= 0);
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2413,6 +2413,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
}
void GradientTexture2D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2422,6 +2423,7 @@ int GradientTexture2D::get_width() const {
}
void GradientTexture2D::set_height(int p_height) {
+ ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
height = p_height;
_queue_update();
}
@@ -2515,8 +2517,8 @@ void GradientTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
ADD_GROUP("Fill", "fill_");
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 1b1107d79e..9d2d4cdb20 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -281,7 +281,7 @@ void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
int in_array_index = 0;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
- ERR_FAIL_COND(in_array_index >= p_terrains.size());
+ ERR_FAIL_INDEX(in_array_index, p_terrains.size());
set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
in_array_index++;
}
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 5c0f36ca92..b8667f07fe 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -2462,7 +2462,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeFloatFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeFloatFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Fract,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -2481,7 +2481,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_FLOOR);
BIND_ENUM_CONSTANT(FUNC_ROUND);
BIND_ENUM_CONSTANT(FUNC_CEIL);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
BIND_ENUM_CONSTANT(FUNC_ACOSH);
@@ -2713,7 +2713,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Fract,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
@@ -2733,7 +2733,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_EXP);
BIND_ENUM_CONSTANT(FUNC_EXP2);
BIND_ENUM_CONSTANT(FUNC_FLOOR);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
BIND_ENUM_CONSTANT(FUNC_LOG);
BIND_ENUM_CONSTANT(FUNC_LOG2);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index b159d25eba..1eb7b7240f 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -934,7 +934,7 @@ public:
FUNC_FLOOR,
FUNC_ROUND,
FUNC_CEIL,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_SATURATE,
FUNC_NEGATE,
FUNC_ACOSH,
@@ -1053,7 +1053,7 @@ public:
FUNC_EXP,
FUNC_EXP2,
FUNC_FLOOR,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_INVERSE_SQRT,
FUNC_LOG,
FUNC_LOG2,