summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite_2d.cpp66
-rw-r--r--scene/2d/area_2d.cpp2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp7
-rw-r--r--scene/2d/camera_2d.cpp4
-rw-r--r--scene/2d/cpu_particles_2d.cpp28
-rw-r--r--scene/2d/navigation_link_2d.cpp4
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp52
-rw-r--r--scene/2d/navigation_obstacle_2d.h7
-rw-r--r--scene/2d/node_2d.cpp4
-rw-r--r--scene/2d/path_2d.cpp6
-rw-r--r--scene/2d/physics_body_2d.cpp2
-rw-r--r--scene/2d/polygon_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp99
-rw-r--r--scene/2d/tile_map.h14
-rw-r--r--scene/3d/area_3d.cpp2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp7
-rw-r--r--scene/3d/cpu_particles_3d.cpp28
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/joint_3d.cpp2
-rw-r--r--scene/3d/lightmap_gi.cpp1
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp52
-rw-r--r--scene/3d/navigation_obstacle_3d.h7
-rw-r--r--scene/3d/navigation_region_3d.cpp1
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/path_3d.cpp6
-rw-r--r--scene/3d/physics_body_3d.cpp6
-rw-r--r--scene/3d/shape_cast_3d.cpp6
-rw-r--r--scene/3d/sprite_3d.cpp188
-rw-r--r--scene/3d/sprite_3d.h11
-rw-r--r--scene/animation/animation_blend_tree.cpp2
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp5
-rw-r--r--scene/gui/check_box.cpp4
-rw-r--r--scene/gui/check_box.h2
-rw-r--r--scene/gui/check_button.cpp20
-rw-r--r--scene/gui/check_button.h2
-rw-r--r--scene/gui/code_edit.cpp6
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/control.cpp445
-rw-r--r--scene/gui/control.h31
-rw-r--r--scene/gui/dialogs.cpp195
-rw-r--r--scene/gui/dialogs.h17
-rw-r--r--scene/gui/file_dialog.cpp20
-rw-r--r--scene/gui/file_dialog.h6
-rw-r--r--scene/gui/graph_edit.cpp152
-rw-r--r--scene/gui/graph_edit.h6
-rw-r--r--scene/gui/graph_node.cpp154
-rw-r--r--scene/gui/graph_node.h30
-rw-r--r--scene/gui/item_list.cpp42
-rw-r--r--scene/gui/item_list.h8
-rw-r--r--scene/gui/line_edit.cpp26
-rw-r--r--scene/gui/line_edit.h6
-rw-r--r--scene/gui/menu_bar.cpp2
-rw-r--r--scene/gui/menu_button.cpp4
-rw-r--r--scene/gui/option_button.cpp4
-rw-r--r--scene/gui/popup_menu.cpp10
-rw-r--r--scene/gui/popup_menu.h4
-rw-r--r--scene/gui/progress_bar.cpp46
-rw-r--r--scene/gui/progress_bar.h10
-rw-r--r--scene/gui/rich_text_label.cpp22
-rw-r--r--scene/gui/scroll_bar.cpp4
-rw-r--r--scene/gui/scroll_container.cpp12
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/split_container.cpp325
-rw-r--r--scene/gui/split_container.h32
-rw-r--r--scene/gui/tab_bar.cpp4
-rw-r--r--scene/gui/text_edit.cpp26
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/gui/texture_button.cpp2
-rw-r--r--scene/gui/texture_rect.cpp8
-rw-r--r--scene/gui/tree.cpp74
-rw-r--r--scene/gui/tree.h6
-rw-r--r--scene/main/canvas_item.cpp8
-rw-r--r--scene/main/canvas_item.h1
-rw-r--r--scene/main/canvas_layer.cpp4
-rw-r--r--scene/main/http_request.cpp26
-rw-r--r--scene/main/http_request.h10
-rw-r--r--scene/main/node.cpp75
-rw-r--r--scene/main/node.h10
-rw-r--r--scene/main/scene_tree.cpp146
-rw-r--r--scene/main/scene_tree.h19
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/main/window.cpp118
-rw-r--r--scene/main/window.h11
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/default_theme/default_theme.cpp86
-rw-r--r--scene/resources/environment.cpp6
-rw-r--r--scene/resources/fog_material.cpp2
-rw-r--r--scene/resources/navigation_mesh.cpp98
-rw-r--r--scene/resources/navigation_mesh.h8
-rw-r--r--scene/resources/particle_process_material.cpp36
-rw-r--r--scene/resources/primitive_meshes.cpp14
-rw-r--r--scene/resources/style_box.cpp36
-rw-r--r--scene/resources/style_box.h5
-rw-r--r--scene/resources/texture.cpp68
-rw-r--r--scene/resources/texture.h18
-rw-r--r--scene/resources/visual_shader.cpp11
-rw-r--r--scene/resources/visual_shader.h4
-rw-r--r--scene/resources/visual_shader_nodes.cpp21
-rw-r--r--scene/resources/visual_shader_nodes.h4
-rw-r--r--scene/theme/theme_owner.cpp410
-rw-r--r--scene/theme/theme_owner.h75
102 files changed, 2042 insertions, 1695 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index b1b1cb23ed..7fe464d2f4 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -108,6 +108,7 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
+
if (p_property.name == "animation") {
p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
@@ -137,9 +138,15 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
+ return;
}
if (p_property.name == "frame") {
+ if (playing) {
+ p_property.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY;
+ return;
+ }
+
p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
@@ -175,33 +182,38 @@ void AnimatedSprite2D::_notification(int p_what) {
if (timeout <= 0) {
timeout = _get_frame_duration();
- int fc = frames->get_frame_count(animation);
- if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) {
- if (frames->get_animation_loop(animation)) {
- if (backwards) {
- frame = fc - 1;
- } else {
- frame = 0;
- }
-
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
- } else {
- if (backwards) {
+ int last_frame = frames->get_frame_count(animation) - 1;
+ if (!backwards) {
+ // Forward.
+ if (frame >= last_frame) {
+ if (frames->get_animation_loop(animation)) {
frame = 0;
- } else {
- frame = fc - 1;
- }
-
- if (!is_over) {
- is_over = true;
emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = last_frame;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
}
+ } else {
+ frame++;
}
} else {
- if (backwards) {
- frame--;
+ // Reversed.
+ if (frame <= 0) {
+ if (frames->get_animation_loop(animation)) {
+ frame = last_frame;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = 0;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
} else {
- frame++;
+ frame--;
}
}
@@ -259,14 +271,15 @@ void AnimatedSprite2D::_notification(int p_what) {
void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
+
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
frame = 0;
} else {
set_frame(frame);
@@ -283,7 +296,7 @@ Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
}
void AnimatedSprite2D::set_frame(int p_frame) {
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
return;
}
@@ -318,7 +331,7 @@ void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
speed_scale = MAX(p_speed_scale, 0.0f);
- // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
timeout -= elapsed;
}
@@ -378,6 +391,7 @@ void AnimatedSprite2D::set_playing(bool p_playing) {
playing = p_playing;
_reset_timeout();
set_process_internal(playing);
+ notify_property_list_changed();
}
bool AnimatedSprite2D::is_playing() const {
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index f168d0c139..3def41eaa5 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -607,7 +607,7 @@ void Area2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_lesser,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_less,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity");
ADD_GROUP("Linear Damp", "linear_damp_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index fc019b6cf9..85ec745aee 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -43,13 +43,18 @@ void AudioStreamPlayer2D::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_EXIT_TREE: {
- stop();
+ set_stream_paused(true);
AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
} break;
+ case NOTIFICATION_PREDELETE: {
+ stop();
+ } break;
+
case NOTIFICATION_PAUSED: {
if (!can_process()) {
// Node can't process so we start fading out to silence.
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index ce77c6ba8d..a11b2b66bf 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -701,8 +701,8 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_margin", "margin", "drag_margin"), &Camera2D::set_drag_margin);
ClassDB::bind_method(D_METHOD("get_drag_margin", "margin"), &Camera2D::get_drag_margin);
- ClassDB::bind_method(D_METHOD("get_camera_position"), &Camera2D::get_camera_position);
- ClassDB::bind_method(D_METHOD("get_camera_screen_center"), &Camera2D::get_camera_screen_center);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &Camera2D::get_camera_position);
+ ClassDB::bind_method(D_METHOD("get_screen_center_position"), &Camera2D::get_camera_screen_center);
ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &Camera2D::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &Camera2D::get_zoom);
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 58e357ab5f..4523e5dfe9 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -1383,32 +1383,32 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1428,8 +1428,8 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 38a03aaf97..8ba51482ee 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -113,6 +113,10 @@ void NavigationLink2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
Rect2 NavigationLink2D::_edit_get_rect() const {
+ if (!is_inside_tree()) {
+ return Rect2();
+ }
+
real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
Rect2 rect(get_start_location(), Size2());
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index a592d20cba..1850e00ecd 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -38,6 +38,9 @@
void NavigationObstacle2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid);
+ ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle2D::set_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle2D::get_navigation_map);
+
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius);
@@ -57,28 +60,26 @@ void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const {
void NavigationObstacle2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- parent_node2d = Object::cast_to<Node2D>(get_parent());
- reevaluate_agent_radius();
- if (parent_node2d != 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(), parent_node2d->get_world_2d()->get_navigation_map());
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- parent_node2d = nullptr;
+ set_agent_parent(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_PARENTED: {
- parent_node2d = Object::cast_to<Node2D>(get_parent());
- reevaluate_agent_radius();
+ if (is_inside_tree() && (get_parent() != parent_node2d)) {
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
} break;
case NOTIFICATION_UNPARENTED: {
- parent_node2d = nullptr;
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
} break;
case NOTIFICATION_PAUSED: {
@@ -182,6 +183,35 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
return 1.0; // Never a 0 radius
}
+void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
+ if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
+ parent_node2d = Object::cast_to<Node2D>(p_agent_parent);
+ if (map_override.is_valid()) {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_override);
+ } else {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map());
+ }
+ reevaluate_agent_radius();
+ } else {
+ parent_node2d = nullptr;
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
+void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
+ map_override = p_navigation_map;
+ NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
+}
+
+RID NavigationObstacle2D::get_navigation_map() const {
+ if (map_override.is_valid()) {
+ return map_override;
+ } else if (parent_node2d != nullptr) {
+ return parent_node2d->get_world_2d()->get_navigation_map();
+ }
+ return RID();
+}
+
void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) {
estimate_radius = p_estimate_radius;
notify_property_list_changed();
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 5795c6c94f..6eff95adec 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -38,8 +38,10 @@ class NavigationObstacle2D : public Node {
GDCLASS(NavigationObstacle2D, Node);
Node2D *parent_node2d = nullptr;
+
RID agent;
RID map_before_pause;
+ RID map_override;
bool estimate_radius = true;
real_t radius = 1.0;
@@ -57,6 +59,11 @@ public:
return agent;
}
+ void set_agent_parent(Node *p_agent_parent);
+
+ void set_navigation_map(RID p_navigation_map);
+ RID get_navigation_map() const;
+
void set_estimate_radius(bool p_estimate_radius);
bool is_radius_estimated() const {
return estimate_radius;
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 4599785ce4..7765533016 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -437,8 +437,8 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_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, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,no_slider,suffix:px"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform");
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index be17299f07..90b2e3d460 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -252,7 +252,7 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
max = path->get_curve()->get_baked_length();
}
- p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater";
}
}
@@ -293,8 +293,8 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_progress", "get_progress");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:px"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating");
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 61fe00669a..714d196779 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1024,7 +1024,7 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass");
ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 111a0df89a..5e77902977 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -640,7 +640,7 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale", PROPERTY_HINT_LINK), "set_texture_scale", "get_texture_scale");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_texture_rotation", "get_texture_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_texture_rotation", "get_texture_rotation");
ADD_GROUP("Skeleton", "");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 129cce93fa..5de6d547d7 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -34,6 +34,10 @@
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
+#ifdef DEBUG_ENABLED
+#include "servers/navigation_server_3d.h"
+#endif // DEBUG_ENABLED
+
HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
HashMap<Vector2i, TileSet::CellNeighbor> output;
@@ -828,13 +832,13 @@ void TileMap::_update_dirty_quadrants() {
// Update the coords cache.
for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- q->self()->map_to_world.clear();
- q->self()->world_to_map.clear();
+ q->self()->map_to_local.clear();
+ q->self()->local_to_map.clear();
for (const Vector2i &E : q->self()->cells) {
Vector2i pk = E;
- Vector2i pk_world_coords = map_to_world(pk);
- q->self()->map_to_world[pk] = pk_world_coords;
- q->self()->world_to_map[pk_world_coords] = pk;
+ Vector2i pk_local_coords = map_to_local(pk);
+ q->self()->map_to_local[pk] = pk_local_coords;
+ q->self()->local_to_map[pk_local_coords] = pk;
}
}
@@ -852,7 +856,7 @@ void TileMap::_update_dirty_quadrants() {
for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
rs->canvas_item_clear(q->self()->debug_canvas_item);
Transform2D xform;
- xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size(layer)));
+ xform.set_origin(map_to_local(q->self()->coords * get_effective_quadrant_size(layer)));
rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
_rendering_draw_quadrant_debug(q->self());
@@ -978,10 +982,10 @@ void TileMap::_recompute_rect_cache() {
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
Rect2 r;
- r.position = map_to_world(E.key * get_effective_quadrant_size(layer));
- r.expand_to(map_to_world((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
+ r.position = map_to_local(E.key * get_effective_quadrant_size(layer));
+ r.expand_to(map_to_local((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_local((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_local((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
if (first) {
r_total = r;
first = false;
@@ -1010,7 +1014,7 @@ void TileMap::_rendering_notification(int p_what) {
TileMapQuadrant &q = E_quadrant.value;
// Update occluders transform.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
Transform2D xform;
xform.set_origin(E_cell.key);
for (const RID &occluder : q.occluders) {
@@ -1030,7 +1034,7 @@ void TileMap::_rendering_notification(int p_what) {
TileMapQuadrant &q = E_quadrant.value;
// Update occluders transform.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
Transform2D xform;
xform.set_origin(E_cell.key);
for (const RID &occluder : q.occluders) {
@@ -1126,7 +1130,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
// Iterate over the cells of the quadrant.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
TileSetSource *source;
@@ -1151,7 +1155,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int z_index = tile_data->get_z_index();
// Quandrant pos.
- Vector2 position = map_to_world(q.coords * get_effective_quadrant_size(q.layer));
+ Vector2 position = map_to_local(q.coords * get_effective_quadrant_size(q.layer));
if (is_y_sort_enabled() && layers[q.layer].y_sort_enabled) {
// When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin();
@@ -1223,14 +1227,14 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int index = -(int64_t)0x80000000; //always must be drawn below children.
for (int layer = 0; layer < (int)layers.size(); layer++) {
- // Sort the quadrants coords per world coordinates
- RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
+ // Sort the quadrants coords per local coordinates.
+ RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map;
for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- world_to_map[map_to_world(E.key)] = E.key;
+ local_to_map[map_to_local(E.key)] = E.key;
}
- // Sort the quadrants
- for (const KeyValue<Vector2i, Vector2i> &E : world_to_map) {
+ // Sort the quadrants.
+ for (const KeyValue<Vector2i, Vector2i> &E : local_to_map) {
TileMapQuadrant &q = layers[layer].quadrant_map[E.value];
for (const RID &ci : q.canvas_items) {
RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
@@ -1270,7 +1274,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1302,7 +1306,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -1423,7 +1427,7 @@ void TileMap::_physics_notification(int p_what) {
for (RID body : q.bodies) {
Transform2D xform;
- xform.set_origin(map_to_world(bodies_coords[body]));
+ xform.set_origin(map_to_local(bodies_coords[body]));
xform = global_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
@@ -1446,7 +1450,7 @@ void TileMap::_physics_notification(int p_what) {
for (RID body : q.bodies) {
Transform2D xform;
- xform.set_origin(map_to_world(bodies_coords[body]));
+ xform.set_origin(map_to_local(bodies_coords[body]));
xform = new_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
@@ -1516,7 +1520,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
ps->body_set_space(body, space);
Transform2D xform;
- xform.set_origin(map_to_world(E_cell));
+ xform.set_origin(map_to_local(E_cell));
xform = global_transform * xform;
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
@@ -1602,7 +1606,7 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
Vector<Color> color;
color.push_back(debug_collision_color);
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
Transform2D qudrant_xform;
qudrant_xform.set_origin(quadrant_pos);
Transform2D global_transform_inv = (get_global_transform() * qudrant_xform).affine_inverse();
@@ -1641,7 +1645,7 @@ void TileMap::_navigation_notification(int p_what) {
continue;
}
Transform2D tile_transform;
- tile_transform.set_origin(map_to_world(E_region.key));
+ tile_transform.set_origin(map_to_local(E_region.key));
NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
}
}
@@ -1656,14 +1660,6 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!tile_set.is_valid());
- // Get colors for debug.
- SceneTree *st = SceneTree::get_singleton();
- Color debug_navigation_color;
- bool debug_navigation = st && st->is_debugging_navigation_hint();
- if (debug_navigation) {
- debug_navigation_color = st->get_debug_navigation_color();
- }
-
Transform2D tilemap_xform = get_global_transform();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
@@ -1709,7 +1705,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (navpoly.is_valid()) {
Transform2D tile_transform;
- tile_transform.set_origin(map_to_world(E_cell));
+ tile_transform.set_origin(map_to_local(E_cell));
RID region = NavigationServer2D::get_singleton()->region_create();
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
@@ -1766,10 +1762,13 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
RenderingServer *rs = RenderingServer::get_singleton();
- Color color = get_tree()->get_debug_navigation_color();
+ Color color = Color(0.5, 1.0, 1.0, 1.0);
+#ifdef DEBUG_ENABLED
+ color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+#endif // DEBUG_ENABLED
RandomPCG rand;
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
TileMapCell c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1792,7 +1791,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
@@ -1866,10 +1865,10 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
Control *scene_as_control = Object::cast_to<Control>(scene);
Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
if (scene_as_control) {
- scene_as_control->set_position(map_to_world(E_cell) + scene_as_control->get_position());
+ scene_as_control->set_position(map_to_local(E_cell) + scene_as_control->get_position());
} else if (scene_as_node2d) {
Transform2D xform;
- xform.set_origin(map_to_world(E_cell));
+ xform.set_origin(map_to_local(E_cell));
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
}
q.scenes[E_cell] = scene->get_name();
@@ -1903,7 +1902,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1933,7 +1932,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -2822,7 +2821,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
// Iterate over the cells of the quadrant.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
TileSetSource *source;
@@ -2981,7 +2980,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
+Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
// SHOULD RETURN THE CENTER OF THE CELL
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
@@ -3058,10 +3057,10 @@ Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size();
}
-Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
+Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i());
- Vector2 ret = p_pos;
+ Vector2 ret = p_local_position;
ret /= tile_set->get_tile_size();
TileSet::TileShape tile_shape = tile_set->get_tile_shape();
@@ -3086,7 +3085,7 @@ Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
ret.x /= overlapping_ratio;
}
- // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the world position accordingly.
+ // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly.
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
// square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
@@ -3771,7 +3770,7 @@ void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Co
TileSet::TileShape shape = tile_set->get_tile_shape();
for (const Vector2i &E : p_cells) {
- Vector2 center = map_to_world(E);
+ Vector2 center = map_to_local(E);
#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
if (!p_cells.has(get_neighbor_cell(E, side))) { \
@@ -3901,8 +3900,8 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
- ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &TileMap::map_to_world);
- ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map);
+ ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local);
+ ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &TileMap::local_to_map);
ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index ecc6ee1d59..a819eeab71 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -40,7 +40,7 @@ class TileSetAtlasSource;
struct TileMapQuadrant {
struct CoordsWorldComparator {
_ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const {
- // We sort the cells by their world coords, as it is needed by rendering.
+ // We sort the cells by their local coords, as it is needed by rendering.
if (p_a.y == p_b.y) {
return p_a.x > p_b.x;
} else {
@@ -49,7 +49,7 @@ struct TileMapQuadrant {
}
};
- // Dirty list element
+ // Dirty list element.
SelfList<TileMapQuadrant> dirty_list_element;
// Quadrant layer and coords.
@@ -58,10 +58,10 @@ struct TileMapQuadrant {
// TileMapCells
RBSet<Vector2i> cells;
- // We need those two maps to sort by world position for rendering
+ // We need those two maps to sort by local position for rendering
// This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead.
- RBMap<Vector2i, Vector2i> map_to_world;
- RBMap<Vector2i, Vector2i, CoordsWorldComparator> world_to_map;
+ RBMap<Vector2i, Vector2i> map_to_local;
+ RBMap<Vector2i, Vector2i, CoordsWorldComparator> local_to_map;
// Debug.
RID debug_canvas_item;
@@ -368,8 +368,8 @@ public:
virtual void set_y_sort_enabled(bool p_enable) override;
- Vector2 map_to_world(const Vector2i &p_pos) const;
- Vector2i world_to_map(const Vector2 &p_pos) const;
+ Vector2 map_to_local(const Vector2i &p_pos) const;
+ Vector2i local_to_map(const Vector2 &p_pos) const;
bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const;
Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 92e6d53139..f118080009 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -727,7 +727,7 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_lesser,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
ADD_GROUP("Linear Damp", "linear_damp_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 0e7b71f74a..21cf3bdb3b 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -247,13 +247,18 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_EXIT_TREE: {
- stop();
+ set_stream_paused(true);
AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
} break;
+ case NOTIFICATION_PREDELETE: {
+ stop();
+ } break;
+
case NOTIFICATION_PAUSED: {
if (!can_process()) {
// Node can't process so we start fading out to silence.
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index e14bb1aa94..d7bf76a6f6 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -1568,32 +1568,32 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1613,8 +1613,8 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 1cfd889272..24bfa7b6de 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -807,7 +807,7 @@ void GPUParticlesAttractor3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality);
ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_lesser"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_less"), "set_strength", "get_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index d5cab6728a..7dc094062b 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -309,7 +309,7 @@ void HingeJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_less,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
BIND_ENUM_CONSTANT(PARAM_BIAS);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 32c112d21f..b0bccc4571 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -105,6 +105,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) {
Vector<Ref<Image>> images;
for (int i = 0; i < p_data.size(); i++) {
Ref<TextureLayered> texture = p_data[i];
+ ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i));
for (int j = 0; j < texture->get_layers(); j++) {
images.push_back(texture->get_layer_data(j));
}
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 953e52e591..9b49238333 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -37,6 +37,9 @@
void NavigationObstacle3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle3D::get_rid);
+ ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle3D::set_navigation_map);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle3D::get_navigation_map);
+
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle3D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle3D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle3D::set_radius);
@@ -56,28 +59,26 @@ void NavigationObstacle3D::_validate_property(PropertyInfo &p_property) const {
void NavigationObstacle3D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- parent_node3d = Object::cast_to<Node3D>(get_parent());
- reevaluate_agent_radius();
- if (parent_node3d != 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(), parent_node3d->get_world_3d()->get_navigation_map());
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- parent_node3d = nullptr;
+ set_agent_parent(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_PARENTED: {
- parent_node3d = Object::cast_to<Node3D>(get_parent());
- reevaluate_agent_radius();
+ if (is_inside_tree() && (get_parent() != parent_node3d)) {
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
} break;
case NOTIFICATION_UNPARENTED: {
- parent_node3d = nullptr;
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
} break;
case NOTIFICATION_PAUSED: {
@@ -189,6 +190,35 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
return 1.0; // Never a 0 radius
}
+void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
+ if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
+ parent_node3d = Object::cast_to<Node3D>(p_agent_parent);
+ if (map_override.is_valid()) {
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), map_override);
+ } else {
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map());
+ }
+ reevaluate_agent_radius();
+ } else {
+ parent_node3d = nullptr;
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
+void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) {
+ map_override = p_navigation_map;
+ NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
+}
+
+RID NavigationObstacle3D::get_navigation_map() const {
+ if (map_override.is_valid()) {
+ return map_override;
+ } else if (parent_node3d != nullptr) {
+ return parent_node3d->get_world_3d()->get_navigation_map();
+ }
+ return RID();
+}
+
void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) {
estimate_radius = p_estimate_radius;
notify_property_list_changed();
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 7f6af668b6..24caf50680 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -37,8 +37,10 @@ class NavigationObstacle3D : public Node {
GDCLASS(NavigationObstacle3D, Node);
Node3D *parent_node3d = nullptr;
+
RID agent;
RID map_before_pause;
+ RID map_override;
bool estimate_radius = true;
real_t radius = 1.0;
@@ -56,6 +58,11 @@ public:
return agent;
}
+ void set_agent_parent(Node *p_agent_parent);
+
+ void set_navigation_map(RID p_navigation_map);
+ RID get_navigation_map() const;
+
void set_estimate_radius(bool p_estimate_radius);
bool is_radius_estimated() const {
return estimate_radius;
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 29ad1ba93d..049ca4c8a0 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -539,6 +539,7 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() {
}
Vector<Vector3> vertex_array;
+ vertex_array.resize(connections_count * 6);
for (int i = 0; i < connections_count; i++) {
Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i);
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 095aeef560..59ec036558 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -1052,8 +1052,8 @@ void Node3D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 3d23206e6b..2d1f4a579b 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -337,7 +337,7 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
max = path->get_curve()->get_baked_length();
}
- p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater";
}
}
@@ -380,8 +380,8 @@ void PathFollow3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_progress", "get_progress");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:m"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode");
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 86dbcc2306..8888aa183a 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1088,7 +1088,7 @@ void RigidBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5m\u00B2"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass");
ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -2346,7 +2346,7 @@ void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_lis
JointData::_get_property_list(p_list);
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/swing_span"), PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_less,or_greater"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/relaxation"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
@@ -2997,7 +2997,7 @@ void PhysicalBone3D::_bind_methods() {
ADD_GROUP("Joint", "joint_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_joint_offset", "get_joint_offset");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_less,or_greater,radians"), "set_joint_rotation", "get_joint_rotation");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_body_offset", "get_body_offset");
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index d324e09df5..a2fecf9c31 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -205,7 +205,7 @@ bool ShapeCast3D::is_enabled() const {
void ShapeCast3D::set_target_position(const Vector3 &p_point) {
target_position = p_point;
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -306,7 +306,7 @@ real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const {
}
void ShapeCast3D::resource_changed(Ref<Resource> p_res) {
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -327,7 +327,7 @@ void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) {
shape_rid = shape->get_rid();
}
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 4515277dc3..7a89bf81bb 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -30,7 +30,6 @@
#include "sprite_3d.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
Color SpriteBase3D::_get_color_accum() {
@@ -58,7 +57,7 @@ void SpriteBase3D::_propagate_color_changed() {
}
color_dirty = true;
- _queue_update();
+ _queue_redraw();
for (SpriteBase3D *&E : children) {
E->_propagate_color_changed();
@@ -90,7 +89,7 @@ void SpriteBase3D::_notification(int p_what) {
void SpriteBase3D::set_centered(bool p_center) {
centered = p_center;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_centered() const {
@@ -99,7 +98,7 @@ bool SpriteBase3D::is_centered() const {
void SpriteBase3D::set_offset(const Point2 &p_offset) {
offset = p_offset;
- _queue_update();
+ _queue_redraw();
}
Point2 SpriteBase3D::get_offset() const {
@@ -108,7 +107,7 @@ Point2 SpriteBase3D::get_offset() const {
void SpriteBase3D::set_flip_h(bool p_flip) {
hflip = p_flip;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_flipped_h() const {
@@ -117,7 +116,7 @@ bool SpriteBase3D::is_flipped_h() const {
void SpriteBase3D::set_flip_v(bool p_flip) {
vflip = p_flip;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_flipped_v() const {
@@ -127,7 +126,7 @@ bool SpriteBase3D::is_flipped_v() const {
void SpriteBase3D::set_modulate(const Color &p_color) {
modulate = p_color;
_propagate_color_changed();
- _queue_update();
+ _queue_redraw();
}
Color SpriteBase3D::get_modulate() const {
@@ -137,7 +136,7 @@ Color SpriteBase3D::get_modulate() const {
void SpriteBase3D::set_render_priority(int p_priority) {
ERR_FAIL_COND(p_priority < RS::MATERIAL_RENDER_PRIORITY_MIN || p_priority > RS::MATERIAL_RENDER_PRIORITY_MAX);
render_priority = p_priority;
- _queue_update();
+ _queue_redraw();
}
int SpriteBase3D::get_render_priority() const {
@@ -146,7 +145,7 @@ int SpriteBase3D::get_render_priority() const {
void SpriteBase3D::set_pixel_size(real_t p_amount) {
pixel_size = p_amount;
- _queue_update();
+ _queue_redraw();
}
real_t SpriteBase3D::get_pixel_size() const {
@@ -156,7 +155,7 @@ real_t SpriteBase3D::get_pixel_size() const {
void SpriteBase3D::set_axis(Vector3::Axis p_axis) {
ERR_FAIL_INDEX(p_axis, 3);
axis = p_axis;
- _queue_update();
+ _queue_redraw();
}
Vector3::Axis SpriteBase3D::get_axis() const {
@@ -171,7 +170,8 @@ void SpriteBase3D::_im_update() {
//texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
}
-void SpriteBase3D::_queue_update() {
+void SpriteBase3D::_queue_redraw() {
+ // The 3D equivalent of CanvasItem.queue_redraw().
if (pending_update) {
return;
}
@@ -250,7 +250,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags[p_flag] = p_enable;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
@@ -261,7 +261,7 @@ bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
ERR_FAIL_INDEX(p_mode, 3);
alpha_cut = p_mode;
- _queue_update();
+ _queue_redraw();
}
SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
@@ -269,9 +269,9 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
}
void SpriteBase3D::set_billboard_mode(StandardMaterial3D::BillboardMode p_mode) {
- ERR_FAIL_INDEX(p_mode, 3);
+ ERR_FAIL_INDEX(p_mode, 3); // Cannot use BILLBOARD_PARTICLES.
billboard_mode = p_mode;
- _queue_update();
+ _queue_redraw();
}
StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const {
@@ -281,7 +281,7 @@ StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const {
void SpriteBase3D::set_texture_filter(StandardMaterial3D::TextureFilter p_filter) {
if (texture_filter != p_filter) {
texture_filter = p_filter;
- _queue_update();
+ _queue_redraw();
}
}
@@ -329,7 +329,6 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
- ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
@@ -368,7 +367,7 @@ SpriteBase3D::SpriteBase3D() {
}
material = RenderingServer::get_singleton()->material_create();
- // Set defaults for material, names need to match up those in StandardMaterial3D
+ // Set defaults for material, names need to match up those in StandardMaterial3D.
RS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1));
RS::get_singleton()->material_set_param(material, "specular", 0.5);
RS::get_singleton()->material_set_param(material, "metallic", 0.0);
@@ -394,7 +393,7 @@ SpriteBase3D::SpriteBase3D() {
mesh_colors.resize(4);
mesh_uvs.resize(4);
- // create basic mesh and store format information
+ // Create basic mesh and store format information.
for (int i = 0; i < 4; i++) {
mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0);
mesh_tangents.write[i * 4 + 0] = 0.0;
@@ -554,7 +553,7 @@ void Sprite3D::_draw() {
AABB aabb;
- // Everything except position and UV is compressed
+ // Everything except position and UV is compressed.
uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
@@ -637,13 +636,14 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
return;
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
+ texture->disconnect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
+ texture->connect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw));
}
- _queue_update();
+
+ _queue_redraw();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
@@ -657,7 +657,7 @@ void Sprite3D::set_region_enabled(bool p_region) {
}
region = p_region;
- _queue_update();
+ _queue_redraw();
}
bool Sprite3D::is_region_enabled() const {
@@ -668,7 +668,7 @@ void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
bool changed = region_rect != p_region_rect;
region_rect = p_region_rect;
if (region && changed) {
- _queue_update();
+ _queue_redraw();
}
}
@@ -681,7 +681,7 @@ void Sprite3D::set_frame(int p_frame) {
frame = p_frame;
- _queue_update();
+ _queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -704,7 +704,7 @@ Vector2i Sprite3D::get_frame_coords() const {
void Sprite3D::set_vframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
vframes = p_amount;
- _queue_update();
+ _queue_redraw();
notify_property_list_changed();
}
@@ -715,7 +715,7 @@ int Sprite3D::get_vframes() const {
void Sprite3D::set_hframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
hframes = p_amount;
- _queue_update();
+ _queue_redraw();
notify_property_list_changed();
}
@@ -820,9 +820,9 @@ void AnimatedSprite3D::_draw() {
}
Ref<Texture2D> texture = frames->get_frame(animation, frame);
- if (!texture.is_valid()) {
+ if (texture.is_null()) {
set_base(RID());
- return; //no texuture no life
+ return;
}
Size2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0) {
@@ -917,7 +917,7 @@ void AnimatedSprite3D::_draw() {
AABB aabb;
- // Everything except position and UV is compressed
+ // Everything except position and UV is compressed.
uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
@@ -997,6 +997,7 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
+
if (p_property.name == "animation") {
p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
@@ -1026,9 +1027,15 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
+ return;
}
if (p_property.name == "frame") {
+ if (playing) {
+ p_property.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY;
+ return;
+ }
+
p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
@@ -1056,27 +1063,51 @@ void AnimatedSprite3D::_notification(int p_what) {
double remaining = get_process_delta_time();
while (remaining) {
- double speed = frames->get_animation_speed(animation);
+ double speed = frames->get_animation_speed(animation) * speed_scale;
if (speed == 0) {
return; // Do nothing.
}
if (timeout <= 0) {
- timeout = 1.0 / speed;
-
- int fc = frames->get_frame_count(animation);
- if (frame >= fc - 1) {
- if (frames->get_animation_loop(animation)) {
- frame = 0;
+ timeout = _get_frame_duration();
+
+ int last_frame = frames->get_frame_count(animation) - 1;
+ if (!backwards) {
+ // Forward.
+ if (frame >= last_frame) {
+ if (frames->get_animation_loop(animation)) {
+ frame = 0;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = last_frame;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
} else {
- frame = fc - 1;
+ frame++;
}
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
} else {
- frame++;
+ // Reversed.
+ if (frame <= 0) {
+ if (frames->get_animation_loop(animation)) {
+ frame = last_frame;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = 0;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
+ } else {
+ frame--;
+ }
}
- _queue_update();
+ _queue_redraw();
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -1090,14 +1121,15 @@ void AnimatedSprite3D::_notification(int p_what) {
void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", Callable(this, "_res_changed"));
+ frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed));
}
+
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", Callable(this, "_res_changed"));
+ frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed));
}
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
frame = 0;
} else {
set_frame(frame);
@@ -1105,7 +1137,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
- _queue_update();
+ _queue_redraw();
update_configuration_warnings();
}
@@ -1114,7 +1146,7 @@ Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
}
void AnimatedSprite3D::set_frame(int p_frame) {
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
return;
}
@@ -1135,7 +1167,8 @@ void AnimatedSprite3D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
- _queue_update();
+ _queue_redraw();
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -1143,6 +1176,20 @@ int AnimatedSprite3D::get_frame() const {
return frame;
}
+void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
+ double elapsed = _get_frame_duration() - timeout;
+
+ speed_scale = MAX(p_speed_scale, 0.0f);
+
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
+ _reset_timeout();
+ timeout -= elapsed;
+}
+
+double AnimatedSprite3D::get_speed_scale() const {
+ return speed_scale;
+}
+
Rect2 AnimatedSprite3D::get_item_rect() const {
if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2(0, 0, 1, 1);
@@ -1171,7 +1218,8 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
void AnimatedSprite3D::_res_changed() {
set_frame(frame);
- _queue_update();
+
+ _queue_redraw();
}
void AnimatedSprite3D::set_playing(bool p_playing) {
@@ -1181,16 +1229,24 @@ void AnimatedSprite3D::set_playing(bool p_playing) {
playing = p_playing;
_reset_timeout();
set_process_internal(playing);
+ notify_property_list_changed();
}
bool AnimatedSprite3D::is_playing() const {
return playing;
}
-void AnimatedSprite3D::play(const StringName &p_animation) {
+void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) {
+ backwards = p_backwards;
+
if (p_animation) {
set_animation(p_animation);
+ if (frames.is_valid() && backwards && get_frame() == 0) {
+ set_frame(frames->get_frame_count(p_animation) - 1);
+ }
}
+
+ is_over = false;
set_playing(true);
}
@@ -1198,24 +1254,28 @@ void AnimatedSprite3D::stop() {
set_playing(false);
}
+double AnimatedSprite3D::_get_frame_duration() {
+ if (frames.is_valid() && frames->has_animation(animation)) {
+ double speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed > 0) {
+ return 1.0 / speed;
+ }
+ }
+ return 0.0;
+}
+
void AnimatedSprite3D::_reset_timeout() {
if (!playing) {
return;
}
- if (frames.is_valid() && frames->has_animation(animation)) {
- float speed = frames->get_animation_speed(animation);
- if (speed > 0) {
- timeout = 1.0 / speed;
- } else {
- timeout = 0;
- }
- } else {
- timeout = 0;
- }
+ timeout = _get_frame_duration();
+ is_over = false;
}
void AnimatedSprite3D::set_animation(const StringName &p_animation) {
+ ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation));
+ ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation));
if (animation == p_animation) {
return;
}
@@ -1224,7 +1284,7 @@ void AnimatedSprite3D::set_animation(const StringName &p_animation) {
_reset_timeout();
set_frame(0);
notify_property_list_changed();
- _queue_update();
+ _queue_redraw();
}
StringName AnimatedSprite3D::get_animation() const {
@@ -1261,12 +1321,15 @@ void AnimatedSprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite3D::set_playing);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
- ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName()));
+ ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite3D::play, DEFVAL(StringName()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop);
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite3D::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite3D::get_speed_scale);
+
ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed);
ADD_SIGNAL(MethodInfo("frame_changed"));
@@ -1275,6 +1338,7 @@ void AnimatedSprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "set_playing", "is_playing");
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 84244a2476..e6a546a76d 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -106,7 +106,7 @@ protected:
uint32_t skin_stride = 0;
uint32_t mesh_surface_format = 0;
- void _queue_update();
+ void _queue_redraw();
public:
void set_centered(bool p_center);
@@ -209,15 +209,19 @@ class AnimatedSprite3D : public SpriteBase3D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool backwards = false;
StringName animation = "default";
int frame = 0;
+ float speed_scale = 1.0f;
bool centered = false;
+ bool is_over = false;
double timeout = 0.0;
void _res_changed();
+ double _get_frame_duration();
void _reset_timeout();
RID last_shader;
@@ -233,7 +237,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName());
+ void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
@@ -245,6 +249,9 @@ public:
void set_frame(int p_frame);
int get_frame() const;
+ void set_speed_scale(double p_speed_scale);
+ double get_speed_scale() const;
+
virtual Rect2 get_item_rect() const override;
virtual TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 3d81b6b9e8..99f17a1eef 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -542,7 +542,7 @@ AnimationNodeBlend3::AnimationNodeBlend3() {
/////////////////////////////////
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
- r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_lesser,or_greater"));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater"));
}
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 073f61bfdd..096f4edee2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -323,7 +323,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
#endif // _3D_DISABLED
if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
- child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
+ child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONE_SHOT);
}
TrackNodeCacheKey key;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 04feb0dc6f..03115e765f 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -40,6 +40,7 @@ void AudioStreamPlayer::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -64,6 +65,10 @@ void AudioStreamPlayer::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
+ set_stream_paused(true);
+ } break;
+
+ case NOTIFICATION_PREDELETE: {
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
AudioServer::get_singleton()->stop_playback_stream(playback);
}
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 37db7d53f0..f5eb0b957f 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -77,7 +77,7 @@ void CheckBox::_update_theme_item_cache() {
Button::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
+ theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset"));
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
theme_cache.checked = get_theme_icon(SNAME("checked"));
@@ -134,7 +134,7 @@ void CheckBox::_notification(int p_what) {
} else {
ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT);
}
- ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_adjust;
+ ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_offset;
if (is_pressed()) {
on_tex->draw(ci, ofs);
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
index beafece3dc..8438d0e589 100644
--- a/scene/gui/check_box.h
+++ b/scene/gui/check_box.h
@@ -38,7 +38,7 @@ class CheckBox : public Button {
struct ThemeCache {
int h_separation = 0;
- int check_v_adjust = 0;
+ int check_v_offset = 0;
Ref<StyleBox> normal_style;
Ref<Texture2D> checked;
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index b01081e31b..9466512699 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -82,17 +82,17 @@ void CheckButton::_update_theme_item_cache() {
Button::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
+ theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset"));
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
- theme_cache.checked = get_theme_icon(SNAME("on"));
- theme_cache.unchecked = get_theme_icon(SNAME("off"));
- theme_cache.checked_disabled = get_theme_icon(SNAME("on_disabled"));
- theme_cache.unchecked_disabled = get_theme_icon(SNAME("off_disabled"));
- theme_cache.checked_mirrored = get_theme_icon(SNAME("on_mirrored"));
- theme_cache.unchecked_mirrored = get_theme_icon(SNAME("off_mirrored"));
- theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("on_disabled_mirrored"));
- theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("off_disabled_mirrored"));
+ theme_cache.checked = get_theme_icon(SNAME("checked"));
+ theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
+ theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
+ theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
+ theme_cache.checked_mirrored = get_theme_icon(SNAME("checked_mirrored"));
+ theme_cache.unchecked_mirrored = get_theme_icon(SNAME("unchecked_mirrored"));
+ theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("checked_disabled_mirrored"));
+ theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("unchecked_disabled_mirrored"));
}
void CheckButton::_notification(int p_what) {
@@ -142,7 +142,7 @@ void CheckButton::_notification(int p_what) {
} else {
ofs.x = get_size().width - (tex_size.width + theme_cache.normal_style->get_margin(SIDE_RIGHT));
}
- ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_adjust;
+ ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_offset;
if (is_pressed()) {
on_tex->draw(ci, ofs);
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index e71472c870..3878c9628a 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -38,7 +38,7 @@ class CheckButton : public Button {
struct ThemeCache {
int h_separation = 0;
- int check_v_adjust = 0;
+ int check_v_offset = 0;
Ref<StyleBox> normal_style;
Ref<Texture2D> checked;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 1ef1801457..f6e0e4216d 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -344,7 +344,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
} else {
if (mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_command_pressed() && !symbol_lookup_word.is_empty()) {
+ if (mb->is_command_or_control_pressed() && !symbol_lookup_word.is_empty()) {
Vector2i mpos = mb->get_position();
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
@@ -371,7 +371,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (symbol_lookup_on_click_enabled) {
- if (mm->is_command_pressed() && mm->get_button_mask() == MouseButton::NONE && !is_dragging_cursor()) {
+ if (mm->is_command_or_control_pressed() && mm->get_button_mask() == MouseButton::NONE && !is_dragging_cursor()) {
symbol_lookup_new_word = get_word_at_pos(mpos);
if (symbol_lookup_new_word != symbol_lookup_word) {
emit_signal(SNAME("symbol_validate"), symbol_lookup_new_word);
@@ -432,7 +432,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
/* Allow unicode handling if: */
/* No Modifiers are pressed (except shift) */
- bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
/* AUTO-COMPLETE */
if (code_completion_enabled && k->is_action("ui_text_completion_query", true)) {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 41ed1d16c4..4a1f2ab7c6 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -1086,7 +1086,7 @@ void ColorPicker::_screen_pick_pressed() {
} else {
screen->show();
}
- screen->raise();
+ screen->move_to_front();
#ifndef _MSC_VER
#warning show modal no longer works, needs to be converted to a popup
#endif
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 06819283fa..347fe9aa11 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -44,6 +44,7 @@
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#include "scene/theme/theme_db.h"
+#include "scene/theme/theme_owner.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -1563,7 +1564,7 @@ Size2 Control::get_minimum_size() const {
return Vector2();
}
-void Control::set_custom_minimum_size(const Size2 &p_custom) {
+void Control::set_custom_minimum_size(const Size2i &p_custom) {
if (p_custom == data.custom_minimum_size) {
return;
}
@@ -1571,7 +1572,7 @@ void Control::set_custom_minimum_size(const Size2 &p_custom) {
update_minimum_size();
}
-Size2 Control::get_custom_minimum_size() const {
+Size2i Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
@@ -2261,57 +2262,9 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) {
- Control *c = Object::cast_to<Control>(p_at);
- Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
-
- if (!c && !w) {
- // Theme inheritance chains are broken by nodes that aren't Control or Window.
- return;
- }
-
- bool assign = p_assign;
- if (c) {
- if (c != p_owner && c->data.theme.is_valid()) {
- // Has a theme, so we don't want to change the theme owner,
- // but we still want to propagate in case this child has theme items
- // it inherits from the theme this node uses.
- // See https://github.com/godotengine/godot/issues/62844.
- assign = false;
- }
-
- if (assign) {
- c->data.theme_owner = p_owner;
- c->data.theme_owner_window = p_owner_window;
- }
-
- if (p_notify) {
- c->notification(Control::NOTIFICATION_THEME_CHANGED);
- }
- } else if (w) {
- if (w != p_owner_window && w->theme.is_valid()) {
- // Same as above.
- assign = false;
- }
-
- if (assign) {
- w->theme_owner = p_owner;
- w->theme_owner_window = p_owner_window;
- }
-
- if (p_notify) {
- w->notification(Window::NOTIFICATION_THEME_CHANGED);
- }
- }
-
- for (int i = 0; i < p_at->get_child_count(); i++) {
- _propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign);
- }
-}
-
void Control::_theme_changed() {
if (is_inside_tree()) {
- _propagate_theme_changed(this, this, nullptr, true, false);
+ data.theme_owner->propagate_theme_changed(this, this, true, false);
}
}
@@ -2333,6 +2286,18 @@ void Control::_invalidate_theme_cache() {
void Control::_update_theme_item_cache() {
}
+void Control::set_theme_owner_node(Node *p_node) {
+ data.theme_owner->set_owner_node(p_node);
+}
+
+Node *Control::get_theme_owner_node() const {
+ return data.theme_owner->get_owner_node();
+}
+
+bool Control::has_theme_owner_node() const {
+ return data.theme_owner->has_owner_node();
+}
+
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@@ -2344,24 +2309,24 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
data.theme = p_theme;
if (data.theme.is_valid()) {
- _propagate_theme_changed(this, this, nullptr, is_inside_tree(), true);
+ data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
return;
}
Control *parent_c = Object::cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- _propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
return;
}
Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- _propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
return;
}
- _propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
+ data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2384,130 +2349,6 @@ StringName Control::get_theme_type_variation() const {
/// Theme property lookup.
-template <class T>
-T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E);
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
- return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E);
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
- return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E);
- }
- }
- // If they don't exist, use any type to return the default/empty value.
- return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
-}
-
-bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- return false;
-}
-
-void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
- if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(data.theme_type_variation) != StringName()) {
- ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- } else {
- ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- }
- } else {
- ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
- }
-}
-
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
@@ -2521,8 +2362,8 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
data.theme_icon_cache[p_theme_type][p_name] = icon;
return icon;
}
@@ -2540,8 +2381,8 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
data.theme_style_cache[p_theme_type][p_name] = style;
return style;
}
@@ -2559,8 +2400,8 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
data.theme_font_cache[p_theme_type][p_name] = font;
return font;
}
@@ -2578,8 +2419,8 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
data.theme_font_size_cache[p_theme_type][p_name] = font_size;
return font_size;
}
@@ -2597,8 +2438,8 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
data.theme_color_cache[p_theme_type][p_name] = color;
return color;
}
@@ -2616,8 +2457,8 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
data.theme_constant_cache[p_theme_type][p_name] = constant;
return constant;
}
@@ -2630,8 +2471,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2642,8 +2483,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2654,8 +2495,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2666,8 +2507,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2678,8 +2519,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2690,8 +2531,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
/// Local property overrides.
@@ -2821,157 +2662,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
/// Default theme properties.
-float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_base_scale()) {
- return theme_owner->data.theme->get_default_base_scale();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) {
- return theme_owner_window->theme->get_default_base_scale();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
- if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) {
- return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
- return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
- }
- return ThemeDB::get_singleton()->get_fallback_base_scale();
-}
-
float Control::get_theme_default_base_scale() const {
- return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
-}
-
-Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font()) {
- return theme_owner->data.theme->get_default_font();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font()) {
- return theme_owner_window->theme->get_default_font();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
- if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) {
- return ThemeDB::get_singleton()->get_project_theme()->get_default_font();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
- return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
- }
- return ThemeDB::get_singleton()->get_fallback_font();
+ return data.theme_owner->get_theme_default_base_scale();
}
Ref<Font> Control::get_theme_default_font() const {
- return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
-}
-
-int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font_size()) {
- return theme_owner->data.theme->get_default_font_size();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) {
- return theme_owner_window->theme->get_default_font_size();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
- if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) {
- return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
- return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
- }
- return ThemeDB::get_singleton()->get_fallback_font_size();
+ return data.theme_owner->get_theme_default_font();
}
int Control::get_theme_default_font_size() const {
- return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+ return data.theme_owner->get_theme_default_font_size();
}
/// Bulk actions.
@@ -3089,21 +2789,6 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
// Base object overrides.
-void Control::add_child_notify(Node *p_child) {
- // We propagate when this node uses a custom theme, so it can pass it on to its children.
- if (data.theme_owner || data.theme_owner_window) {
- // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
- _propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true);
- }
-}
-
-void Control::remove_child_notify(Node *p_child) {
- // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
- if (data.theme_owner || data.theme_owner_window) {
- _propagate_theme_changed(p_child, nullptr, nullptr, false, true);
- }
-}
-
void Control::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_POSTINITIALIZE: {
@@ -3111,10 +2796,16 @@ void Control::_notification(int p_notification) {
_update_theme_item_cache();
} break;
+ case NOTIFICATION_PARENTED: {
+ data.theme_owner->assign_theme_on_parented(this);
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ data.theme_owner->clear_theme_on_unparented(this);
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
- // Need to defer here, because theme owner information might be set in
- // add_child_notify, which doesn't get called until right after this.
- call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ notification(NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_POST_ENTER_TREE: {
@@ -3130,7 +2821,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_READY: {
#ifdef DEBUG_ENABLED
- connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONESHOT);
+ connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT);
#endif
} break;
@@ -3441,7 +3132,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
@@ -3455,10 +3146,10 @@ void Control::_bind_methods() {
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
- 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_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,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,suffix:px"), "set_offset", "get_offset", SIDE_LEFT);
@@ -3474,7 +3165,7 @@ void Control::_bind_methods() {
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::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset");
@@ -3611,7 +3302,13 @@ void Control::_bind_methods() {
GDVIRTUAL_BIND(_gui_input, "event");
}
+Control::Control() {
+ data.theme_owner = memnew(ThemeOwner);
+}
+
Control::~Control() {
+ memdelete(data.theme_owner);
+
// Resources need to be disconnected.
for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index ac5d481f3a..38cafd835a 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -41,6 +41,7 @@
class Viewport;
class Label;
class Panel;
+class ThemeOwner;
class Control : public CanvasItem {
GDCLASS(Control, CanvasItem);
@@ -199,7 +200,7 @@ private:
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
real_t expand = 1.0;
- Point2 custom_minimum_size;
+ Point2i custom_minimum_size;
// Input events and rendering.
@@ -219,9 +220,8 @@ private:
// Theming.
+ ThemeOwner *theme_owner = nullptr;
Ref<Theme> theme;
- Control *theme_owner = nullptr;
- Window *theme_owner_window = nullptr;
StringName theme_type_variation;
bool bulk_theme_override = false;
@@ -261,7 +261,6 @@ private:
// Global relations.
friend class Viewport;
- friend class Window;
// Positioning and sizing.
@@ -303,13 +302,6 @@ private:
void _notify_theme_override_changed();
void _invalidate_theme_cache();
- static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign);
-
- template <class T>
- static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
- static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
- _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
-
// Extra properties.
String get_tooltip_text() const;
@@ -335,9 +327,6 @@ protected:
// Base object overrides.
- virtual void add_child_notify(Node *p_child) override;
- virtual void remove_child_notify(Node *p_child) override;
-
void _notification(int p_notification);
static void _bind_methods();
@@ -471,8 +460,8 @@ public:
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
- void set_custom_minimum_size(const Size2 &p_custom);
- Size2 get_custom_minimum_size() const;
+ void set_custom_minimum_size(const Size2i &p_custom);
+ Size2i get_custom_minimum_size() const;
// Container sizing.
@@ -542,6 +531,10 @@ public:
// Theming.
+ void set_theme_owner_node(Node *p_node);
+ Node *get_theme_owner_node() const;
+ bool has_theme_owner_node() const;
+
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
@@ -586,10 +579,6 @@ public:
bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
- static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window);
- static Ref<Font> fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window);
- static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window);
-
float get_theme_default_base_scale() const;
Ref<Font> get_theme_default_font() const;
int get_theme_default_font_size() const;
@@ -612,7 +601,7 @@ public:
virtual String get_tooltip(const Point2 &p_pos) const;
virtual Control *make_custom_tooltip(const String &p_text) const;
- Control() {}
+ Control();
~Control();
};
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 0a1aeeda71..f5edaf02d8 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -54,16 +54,23 @@ void AcceptDialog::_update_theme_item_cache() {
Window::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.margin = get_theme_constant(SNAME("margin"));
- theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
+ theme_cache.buttons_separation = get_theme_constant(SNAME("buttons_separation"));
}
void AcceptDialog::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_VISIBILITY_CHANGED: {
+ case NOTIFICATION_POST_ENTER_TREE: {
if (is_visible()) {
get_ok_button()->grab_focus();
+ }
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+ if (get_ok_button()->is_inside_tree()) {
+ get_ok_button()->grab_focus();
+ }
_update_child_rects();
+
parent_visible = get_parent_visible_window();
if (parent_visible) {
parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
@@ -77,10 +84,12 @@ void AcceptDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- bg->add_theme_style_override("panel", theme_cache.panel_style);
+ bg_panel->add_theme_style_override("panel", theme_cache.panel_style);
- label->set_begin(Point2(theme_cache.margin, theme_cache.margin));
- label->set_end(Point2(-theme_cache.margin, -theme_cache.button_margin - 10));
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -137,14 +146,16 @@ void AcceptDialog::_cancel_pressed() {
}
String AcceptDialog::get_text() const {
- return label->get_text();
+ return message_label->get_text();
}
void AcceptDialog::set_text(String p_text) {
- if (label->get_text() == p_text) {
+ if (message_label->get_text() == p_text) {
return;
}
- label->set_text(p_text);
+
+ message_label->set_text(p_text);
+
child_controls_changed();
if (is_visible()) {
_update_child_rects();
@@ -168,19 +179,24 @@ bool AcceptDialog::get_close_on_escape() const {
}
void AcceptDialog::set_autowrap(bool p_autowrap) {
- label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF);
+ message_label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF);
}
bool AcceptDialog::has_autowrap() {
- return label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF;
+ return message_label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF;
}
void AcceptDialog::set_ok_button_text(String p_ok_button_text) {
- ok->set_text(p_ok_button_text);
+ ok_button->set_text(p_ok_button_text);
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
}
String AcceptDialog::get_ok_button_text() const {
- return ok->get_text();
+ return ok_button->get_text();
}
void AcceptDialog::register_text_enter(Control *p_line_edit) {
@@ -192,68 +208,79 @@ void AcceptDialog::register_text_enter(Control *p_line_edit) {
}
void AcceptDialog::_update_child_rects() {
- Size2 label_size = label->get_minimum_size();
- if (label->get_text().is_empty()) {
- label_size.height = 0;
- }
-
Size2 size = get_size();
- Size2 hminsize = hbc->get_combined_minimum_size();
+ float h_margins = theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT);
+ float v_margins = theme_cache.panel_style->get_margin(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_BOTTOM);
- Vector2 cpos(theme_cache.margin, theme_cache.margin + label_size.height);
- Vector2 csize(size.x - theme_cache.margin * 2, size.y - theme_cache.margin * 3 - hminsize.y - label_size.height);
+ // Fill the entire size of the window with the background.
+ bg_panel->set_position(Point2());
+ bg_panel->set_size(size);
+
+ // Place the buttons from the bottom edge to their minimum required size.
+ Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size();
+ Size2 buttons_size = Size2(size.x - h_margins, buttons_minsize.y);
+ Point2 buttons_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), size.y - theme_cache.panel_style->get_margin(SIDE_BOTTOM) - buttons_size.y);
+ buttons_hbox->set_position(buttons_position);
+ buttons_hbox->set_size(buttons_size);
+
+ // Place the content from the top to fill the rest of the space (minus the separation).
+ Point2 content_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), theme_cache.panel_style->get_margin(SIDE_TOP));
+ Size2 content_size = Size2(size.x - h_margins, size.y - v_margins - buttons_size.y - theme_cache.buttons_separation);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c) {
continue;
}
-
- if (c == hbc || c == label || c == bg || c->is_set_as_top_level()) {
+ if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) {
continue;
}
- c->set_position(cpos);
- c->set_size(csize);
+ c->set_position(content_position);
+ c->set_size(content_size);
}
-
- cpos.y += csize.y + theme_cache.margin;
- csize.y = hminsize.y;
-
- hbc->set_position(cpos);
- hbc->set_size(csize);
-
- bg->set_position(Point2());
- bg->set_size(size);
}
Size2 AcceptDialog::_get_contents_minimum_size() const {
- Size2 minsize = label->get_combined_minimum_size();
-
+ // First, we then iterate over the label and any other custom controls
+ // to try and find the size that encompasses all content.
+ Size2 content_minsize;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c) {
continue;
}
- if (c == hbc || c == label || c->is_set_as_top_level()) {
+ // Buttons will be included afterwards.
+ // The panel only displays the stylebox and doesn't contribute to the size.
+ if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) {
continue;
}
- Size2 cminsize = c->get_combined_minimum_size();
- minsize.x = MAX(cminsize.x, minsize.x);
- minsize.y = MAX(cminsize.y, minsize.y);
+ Size2 child_minsize = c->get_combined_minimum_size();
+ content_minsize.x = MAX(child_minsize.x, content_minsize.x);
+ content_minsize.y = MAX(child_minsize.y, content_minsize.y);
+ }
+
+ // Then we take the background panel as it provides the offsets,
+ // which are always added to the minimum size.
+ if (theme_cache.panel_style.is_valid()) {
+ content_minsize += theme_cache.panel_style->get_minimum_size();
}
- Size2 hminsize = hbc->get_combined_minimum_size();
- minsize.x = MAX(hminsize.x, minsize.x);
- minsize.y += hminsize.y;
- minsize.x += theme_cache.margin * 2;
- minsize.y += theme_cache.margin * 3; //one as separation between hbc and child
+ // Then we add buttons. Horizontally we're interested in whichever
+ // value is the biggest. Vertically buttons add to the overall size.
+ Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size();
+ content_minsize.x = MAX(buttons_minsize.x, content_minsize.x);
+ content_minsize.y += buttons_minsize.y;
+ // Plus there is a separation size added on top.
+ content_minsize.y += theme_cache.buttons_separation;
- Size2 wmsize = get_min_size();
- minsize.x = MAX(wmsize.x, minsize.x);
- return minsize;
+ // Last, we make sure that we aren't below the minimum window size.
+ Size2 window_minsize = get_min_size();
+ content_minsize.x = MAX(window_minsize.x, content_minsize.x);
+ content_minsize.y = MAX(window_minsize.y, content_minsize.y);
+ return content_minsize;
}
void AcceptDialog::_custom_action(const String &p_action) {
@@ -264,13 +291,19 @@ void AcceptDialog::_custom_action(const String &p_action) {
Button *AcceptDialog::add_button(const String &p_text, bool p_right, const String &p_action) {
Button *button = memnew(Button);
button->set_text(p_text);
+
if (p_right) {
- hbc->add_child(button);
- hbc->add_spacer();
+ buttons_hbox->add_child(button);
+ buttons_hbox->add_spacer();
} else {
- hbc->add_child(button);
- hbc->move_child(button, 0);
- hbc->add_spacer(true);
+ buttons_hbox->add_child(button);
+ buttons_hbox->move_child(button, 0);
+ buttons_hbox->add_spacer(true);
+ }
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
}
if (!p_action.is_empty()) {
@@ -285,24 +318,19 @@ Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
if (p_cancel.is_empty()) {
c = "Cancel";
}
+
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
+
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
+
return b;
}
void AcceptDialog::remove_button(Control *p_button) {
Button *button = Object::cast_to<Button>(p_button);
ERR_FAIL_NULL(button);
- ERR_FAIL_COND_MSG(button->get_parent() != hbc, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name()));
- ERR_FAIL_COND_MSG(button == ok, "Cannot remove dialog's OK button.");
-
- Node *right_spacer = hbc->get_child(button->get_index() + 1);
- // Should always be valid but let's avoid crashing
- if (right_spacer) {
- hbc->remove_child(right_spacer);
- memdelete(right_spacer);
- }
- hbc->remove_child(button);
+ ERR_FAIL_COND_MSG(button->get_parent() != buttons_hbox, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name()));
+ ERR_FAIL_COND_MSG(button == ok_button, "Cannot remove dialog's OK button.");
if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action));
@@ -310,6 +338,19 @@ void AcceptDialog::remove_button(Control *p_button) {
if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed))) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
}
+
+ Node *right_spacer = buttons_hbox->get_child(button->get_index() + 1);
+ // Should always be valid but let's avoid crashing.
+ if (right_spacer) {
+ buttons_hbox->remove_child(right_spacer);
+ memdelete(right_spacer);
+ }
+ buttons_hbox->remove_child(button);
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
}
void AcceptDialog::_bind_methods() {
@@ -355,25 +396,25 @@ AcceptDialog::AcceptDialog() {
set_exclusive(true);
set_clamp_to_embedder(true);
- bg = memnew(Panel);
- add_child(bg, false, INTERNAL_MODE_FRONT);
+ bg_panel = memnew(Panel);
+ add_child(bg_panel, false, INTERNAL_MODE_FRONT);
- hbc = memnew(HBoxContainer);
+ buttons_hbox = memnew(HBoxContainer);
- label = memnew(Label);
- label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
- label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
- add_child(label, false, INTERNAL_MODE_FRONT);
+ message_label = memnew(Label);
+ message_label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
+ message_label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
+ add_child(message_label, false, INTERNAL_MODE_FRONT);
- add_child(hbc, false, INTERNAL_MODE_FRONT);
+ add_child(buttons_hbox, false, INTERNAL_MODE_FRONT);
- hbc->add_spacer();
- ok = memnew(Button);
- ok->set_text("OK");
- hbc->add_child(ok);
- hbc->add_spacer();
+ buttons_hbox->add_spacer();
+ ok_button = memnew(Button);
+ ok_button->set_text("OK");
+ buttons_hbox->add_child(ok_button);
+ buttons_hbox->add_spacer();
- ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
+ ok_button->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
set_title(TTRC("Alert!"));
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 8ba9c93861..81e82d851e 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -45,17 +45,18 @@ class AcceptDialog : public Window {
GDCLASS(AcceptDialog, Window);
Window *parent_visible = nullptr;
- Panel *bg = nullptr;
- HBoxContainer *hbc = nullptr;
- Label *label = nullptr;
- Button *ok = nullptr;
+
+ Panel *bg_panel = nullptr;
+ Label *message_label = nullptr;
+ HBoxContainer *buttons_hbox = nullptr;
+ Button *ok_button = nullptr;
+
bool hide_on_ok = true;
bool close_on_escape = true;
struct ThemeCache {
Ref<StyleBox> panel_style;
- int margin = 0;
- int button_margin = 0;
+ int buttons_separation = 0;
} theme_cache;
void _custom_action(const String &p_action);
@@ -82,12 +83,12 @@ protected:
void _cancel_pressed();
public:
- Label *get_label() { return label; }
+ Label *get_label() { return message_label; }
static void set_swap_cancel_ok(bool p_swap);
void register_text_enter(Control *p_line_edit);
- Button *get_ok_button() { return ok; }
+ Button *get_ok_button() { return ok_button; }
Button *add_button(const String &p_text, bool p_right = false, const String &p_action = "");
Button *add_cancel_button(const String &p_cancel = "");
void remove_button(Control *p_button);
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index a0cf5f5970..57f27e299f 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -70,9 +70,9 @@ void FileDialog::_update_theme_item_cache() {
theme_cache.folder = get_theme_icon(SNAME("folder"));
theme_cache.file = get_theme_icon(SNAME("file"));
- theme_cache.folder_icon_modulate = get_theme_color(SNAME("folder_icon_modulate"));
- theme_cache.file_icon_modulate = get_theme_color(SNAME("file_icon_modulate"));
- theme_cache.files_disabled = get_theme_color(SNAME("files_disabled"));
+ theme_cache.folder_icon_color = get_theme_color(SNAME("folder_icon_color"));
+ theme_cache.file_icon_color = get_theme_color(SNAME("file_icon_color"));
+ theme_cache.file_disabled_color = get_theme_color(SNAME("file_disabled_color"));
// TODO: Define own colors?
theme_cache.icon_normal_color = get_theme_color(SNAME("font_color"), SNAME("Button"));
@@ -87,6 +87,8 @@ void FileDialog::_notification(int p_what) {
if (!is_visible()) {
set_process_shortcut_input(false);
}
+
+ invalidate(); // Put it here to preview in the editor.
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -143,7 +145,7 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
switch (k->get_keycode()) {
case Key::H: {
- if (k->is_command_pressed()) {
+ if (k->is_command_or_control_pressed()) {
set_show_hidden_files(!show_hidden_files);
} else {
handled = false;
@@ -223,10 +225,6 @@ void FileDialog::_save_confirm_pressed() {
void FileDialog::_post_popup() {
ConfirmationDialog::_post_popup();
- if (invalidated) {
- update_file_list();
- invalidated = false;
- }
if (mode == FILE_MODE_SAVE_FILE) {
file->grab_focus();
} else {
@@ -552,7 +550,7 @@ void FileDialog::update_file_list() {
TreeItem *ti = tree->create_item(root);
ti->set_text(0, dir_name);
ti->set_icon(0, theme_cache.folder);
- ti->set_icon_modulate(0, theme_cache.folder_icon_modulate);
+ ti->set_icon_modulate(0, theme_cache.folder_icon_color);
Dictionary d;
d["name"] = dir_name;
@@ -613,10 +611,10 @@ void FileDialog::update_file_list() {
} else {
ti->set_icon(0, theme_cache.file);
}
- ti->set_icon_modulate(0, theme_cache.file_icon_modulate);
+ ti->set_icon_modulate(0, theme_cache.file_icon_color);
if (mode == FILE_MODE_OPEN_DIR) {
- ti->set_custom_color(0, theme_cache.files_disabled);
+ ti->set_custom_color(0, theme_cache.file_disabled_color);
ti->set_selectable(0, false);
}
Dictionary d;
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 5c892288b5..1add0a9cf5 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -118,9 +118,9 @@ private:
Ref<Texture2D> folder;
Ref<Texture2D> file;
- Color folder_icon_modulate;
- Color file_icon_modulate;
- Color files_disabled;
+ Color folder_icon_color;
+ Color file_icon_color;
+ Color file_disabled_color;
Color icon_normal_color;
Color icon_hover_color;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 8c16f8ca26..69512903b4 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -351,9 +351,22 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
if (gn->is_comment()) {
move_child(gn, 0);
} else {
- gn->raise();
+ gn->move_to_front();
}
- emit_signal(SNAME("node_selected"), p_gn);
+}
+
+void GraphEdit::_graph_node_selected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_selected"), gn);
+}
+
+void GraphEdit::_graph_node_deselected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_deselected"), gn);
}
void GraphEdit::_graph_node_moved(Node *p_gn) {
@@ -383,6 +396,8 @@ void GraphEdit::add_child_notify(Node *p_child) {
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn));
+ gn->connect("selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(gn));
+ gn->connect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).bind(gn));
gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised).bind(gn));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
@@ -409,6 +424,8 @@ void GraphEdit::remove_child_notify(Node *p_child) {
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
+ gn->disconnect("selected", callable_mp(this, &GraphEdit::_graph_node_selected));
+ gn->disconnect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected));
gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
@@ -756,25 +773,25 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (connecting_valid) {
if (connecting && connecting_target) {
String from = connecting_from;
- int from_slot = connecting_index;
+ int from_port = connecting_index;
String to = connecting_target_to;
- int to_slot = connecting_target_index;
+ int to_port = connecting_target_index;
if (!connecting_out) {
SWAP(from, to);
- SWAP(from_slot, to_slot);
+ SWAP(from_port, to_port);
}
- emit_signal(SNAME("connection_request"), from, from_slot, to, to_slot);
+ emit_signal(SNAME("connection_request"), from, from_port, to, to_port);
} else if (!just_disconnected) {
String from = connecting_from;
- int from_slot = connecting_index;
+ int from_port = connecting_index;
Vector2 ofs = mb->get_position();
if (!connecting_out) {
- emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs);
+ emit_signal(SNAME("connection_from_empty"), from, from_port, ofs);
} else {
- emit_signal(SNAME("connection_to_empty"), from, from_slot, ofs);
+ emit_signal(SNAME("connection_to_empty"), from, from_port, ofs);
}
}
}
@@ -813,22 +830,22 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos
}
}
-bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
+bool GraphEdit::is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool success;
- if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) {
+ if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_node, p_port, p_mouse_pos, success)) {
return success;
} else {
- Vector2 pos = p_graph_node->get_connection_input_position(p_slot_index) + p_graph_node->get_position();
+ Vector2 pos = p_node->get_connection_input_position(p_port) + p_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, true);
}
}
-bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
+bool GraphEdit::is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool success;
- if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) {
+ if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_node, p_port, p_mouse_pos, success)) {
return success;
} else {
- Vector2 pos = p_graph_node->get_connection_output_position(p_slot_index) + p_graph_node->get_position();
+ Vector2 pos = p_node->get_connection_output_position(p_port) + p_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, false);
}
}
@@ -1083,11 +1100,11 @@ void GraphEdit::_minimap_draw() {
continue;
}
- Vector2 from_slot_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port);
- Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset;
+ Vector2 from_port_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port);
+ Vector2 from_position = minimap->_convert_from_graph_position(from_port_position - graph_offset) + minimap_offset;
Color from_color = gfrom->get_connection_output_color(E.from_port);
- Vector2 to_slot_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port);
- Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset;
+ Vector2 to_port_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port);
+ Vector2 to_position = minimap->_convert_from_graph_position(to_port_position - graph_offset) + minimap_offset;
Color to_color = gto->get_connection_input_color(E.to_port);
if (E.activity > 0) {
@@ -1170,24 +1187,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
bool in_box = r.intersects(box_selecting_rect);
if (in_box) {
- if (!gn->is_selected() && box_selection_mode_additive) {
- emit_signal(SNAME("node_selected"), gn);
- } else if (gn->is_selected() && !box_selection_mode_additive) {
- emit_signal(SNAME("node_deselected"), gn);
- }
- if (gn->is_selectable()) {
- gn->set_selected(box_selection_mode_additive);
- }
+ gn->set_selected(box_selection_mode_additive);
} else {
- bool select = (previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- if (gn->is_selectable()) {
- gn->set_selected(select);
- }
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
}
@@ -1206,13 +1208,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- gn->set_selected(select);
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
top_layer->queue_redraw();
minimap->queue_redraw();
@@ -1235,7 +1231,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
Rect2 r = gn->get_rect();
r.size *= zoom;
if (r.has_point(b->get_position())) {
- emit_signal(SNAME("node_deselected"), gn);
gn->set_selected(false);
}
}
@@ -1270,18 +1265,21 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
GraphNode *gn = nullptr;
+ // Find node which was clicked on.
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn_selected = Object::cast_to<GraphNode>(get_child(i));
- if (gn_selected) {
- if (gn_selected->is_resizing()) {
- continue;
- }
+ if (!gn_selected) {
+ continue;
+ }
- if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
- gn = gn_selected;
- break;
- }
+ if (gn_selected->is_resizing()) {
+ continue;
+ }
+
+ if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
+ gn = gn_selected;
+ break;
}
}
@@ -1290,26 +1288,22 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on a node, select it.
dragging = true;
drag_accum = Vector2();
just_selected = !gn->is_selected();
if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
- if (o_gn) {
- if (o_gn == gn) {
- o_gn->set_selected(o_gn->is_selectable());
- } else {
- if (o_gn->is_selected()) {
- emit_signal(SNAME("node_deselected"), o_gn);
- }
- o_gn->set_selected(false);
- }
+ if (!o_gn) {
+ continue;
}
+
+ o_gn->set_selected(o_gn == gn);
}
}
- gn->set_selected(gn->is_selectable());
+ gn->set_selected(true);
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1332,6 +1326,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on empty space, start box select.
box_selecting = true;
box_selecting_from = b->get_position();
if (b->is_ctrl_pressed()) {
@@ -1364,9 +1359,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (!gn2) {
continue;
}
- if (gn2->is_selected()) {
- emit_signal(SNAME("node_deselected"), gn2);
- }
+
gn2->set_selected(false);
}
}
@@ -1374,6 +1367,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (b->get_button_index() == MouseButton::LEFT && !b->is_pressed() && box_selecting) {
+ // Box selection ended. Nodes were selected during mouse movement.
box_selecting = false;
box_selecting_rect = Rect2();
previous_selected.clear();
@@ -2309,10 +2303,10 @@ void GraphEdit::arrange_nodes() {
}
void GraphEdit::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_node", "from", "from_port", "to", "to_port"), &GraphEdit::connect_node);
- ClassDB::bind_method(D_METHOD("is_node_connected", "from", "from_port", "to", "to_port"), &GraphEdit::is_node_connected);
- ClassDB::bind_method(D_METHOD("disconnect_node", "from", "from_port", "to", "to_port"), &GraphEdit::disconnect_node);
- ClassDB::bind_method(D_METHOD("set_connection_activity", "from", "from_port", "to", "to_port", "amount"), &GraphEdit::set_connection_activity);
+ ClassDB::bind_method(D_METHOD("connect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::connect_node);
+ ClassDB::bind_method(D_METHOD("is_node_connected", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::is_node_connected);
+ ClassDB::bind_method(D_METHOD("disconnect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::disconnect_node);
+ ClassDB::bind_method(D_METHOD("set_connection_activity", "from_node", "from_port", "to_node", "to_port", "amount"), &GraphEdit::set_connection_activity);
ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list);
ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections);
ClassDB::bind_method(D_METHOD("force_connection_drag_end"), &GraphEdit::force_connection_drag_end);
@@ -2326,7 +2320,7 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type);
ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type);
ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type);
- ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line);
+ ClassDB::bind_method(D_METHOD("get_connection_line", "from_node", "to_node"), &GraphEdit::get_connection_line);
ClassDB::bind_method(D_METHOD("set_panning_scheme", "scheme"), &GraphEdit::set_panning_scheme);
ClassDB::bind_method(D_METHOD("get_panning_scheme"), &GraphEdit::get_panning_scheme);
@@ -2376,8 +2370,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset);
- GDVIRTUAL_BIND(_is_in_input_hotzone, "graph_node", "slot_index", "mouse_position");
- GDVIRTUAL_BIND(_is_in_output_hotzone, "graph_node", "slot_index", "mouse_position");
+ GDVIRTUAL_BIND(_is_in_input_hotzone, "in_node", "in_port", "mouse_position");
+ GDVIRTUAL_BIND(_is_in_output_hotzone, "in_node", "in_port", "mouse_position");
ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox);
@@ -2385,8 +2379,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected);
- GDVIRTUAL_BIND(_get_connection_line, "from", "to")
- GDVIRTUAL_BIND(_is_node_hover_valid, "from", "from_slot", "to", "to_slot");
+ GDVIRTUAL_BIND(_get_connection_line, "from_position", "to_position")
+ GDVIRTUAL_BIND(_is_node_hover_valid, "from_node", "from_port", "to_node", "to_port");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_ofs", "get_scroll_ofs");
@@ -2414,21 +2408,21 @@ void GraphEdit::_bind_methods() {
ADD_GROUP("UI", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arrange_nodes_button_hidden"), "set_arrange_nodes_button_hidden", "is_arrange_nodes_button_hidden");
- ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
- ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
+ ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port")));
+ ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port")));
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
ADD_SIGNAL(MethodInfo("copy_nodes_request"));
ADD_SIGNAL(MethodInfo("paste_nodes_request"));
ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_deselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
- ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
- ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
+ ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::VECTOR2, "release_position")));
+ ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName")));
ADD_SIGNAL(MethodInfo("begin_node_move"));
ADD_SIGNAL(MethodInfo("end_node_move"));
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset")));
- ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
+ ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0a0676699f..9371ed3df4 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -186,6 +186,8 @@ private:
PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
void _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);
+ void _graph_node_selected(Node *p_gn);
+ void _graph_node_deselected(Node *p_gn);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
void _graph_node_slot_updated(int p_index, Node *p_gn);
@@ -199,8 +201,8 @@ private:
GraphEditMinimap *minimap = nullptr;
void _top_layer_input(const Ref<InputEvent> &p_ev);
- bool is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
- bool is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
+ bool is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
bool is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
void _top_layer_draw();
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 5976d9fc37..21c0b5a842 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -736,11 +736,12 @@ Vector2 GraphNode::get_position_offset() const {
}
void GraphNode::set_selected(bool p_selected) {
- if (selected == p_selected) {
+ if (!is_selectable() || selected == p_selected) {
return;
}
selected = p_selected;
+ emit_signal(p_selected ? SNAME("selected") : SNAME("deselected"));
queue_redraw();
}
@@ -778,8 +779,8 @@ void GraphNode::_connpos_update() {
int sep = get_theme_constant(SNAME("separation"));
Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
- conn_input_cache.clear();
- conn_output_cache.clear();
+ left_port_cache.clear();
+ right_port_cache.clear();
int vofs = 0;
int idx = 0;
@@ -800,20 +801,26 @@ void GraphNode::_connpos_update() {
if (slot_info.has(idx)) {
if (slot_info[idx].enable_left) {
- ConnCache cc;
- cc.pos = Point2i(edgeofs, y + h / 2);
+ PortCache cc;
+ cc.position = Point2i(edgeofs, y + h / 2);
+ cc.height = size.height;
+
+ cc.slot_idx = idx;
cc.type = slot_info[idx].type_left;
cc.color = slot_info[idx].color_left;
- cc.height = size.height;
- conn_input_cache.push_back(cc);
+
+ left_port_cache.push_back(cc);
}
if (slot_info[idx].enable_right) {
- ConnCache cc;
- cc.pos = Point2i(get_size().width - edgeofs, y + h / 2);
+ PortCache cc;
+ cc.position = Point2i(get_size().width - edgeofs, y + h / 2);
+ cc.height = size.height;
+
+ cc.slot_idx = idx;
cc.type = slot_info[idx].type_right;
cc.color = slot_info[idx].color_right;
- cc.height = size.height;
- conn_output_cache.push_back(cc);
+
+ right_port_cache.push_back(cc);
}
}
@@ -830,46 +837,55 @@ int GraphNode::get_connection_input_count() {
_connpos_update();
}
- return conn_input_cache.size();
+ return left_port_cache.size();
}
-int GraphNode::get_connection_input_height(int p_idx) {
+int GraphNode::get_connection_input_height(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
- return conn_input_cache[p_idx].height;
+ ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
+ return left_port_cache[p_port].height;
}
-Vector2 GraphNode::get_connection_input_position(int p_idx) {
+Vector2 GraphNode::get_connection_input_position(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Vector2());
- Vector2 pos = conn_input_cache[p_idx].pos;
+ ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Vector2());
+ Vector2 pos = left_port_cache[p_port].position;
pos.x *= get_scale().x;
pos.y *= get_scale().y;
return pos;
}
-int GraphNode::get_connection_input_type(int p_idx) {
+int GraphNode::get_connection_input_type(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
- return conn_input_cache[p_idx].type;
+ ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
+ return left_port_cache[p_port].type;
}
-Color GraphNode::get_connection_input_color(int p_idx) {
+Color GraphNode::get_connection_input_color(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Color());
- return conn_input_cache[p_idx].color;
+ ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Color());
+ return left_port_cache[p_port].color;
+}
+
+int GraphNode::get_connection_input_slot(int p_port) {
+ if (connpos_dirty) {
+ _connpos_update();
+ }
+
+ ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), -1);
+ return left_port_cache[p_port].slot_idx;
}
int GraphNode::get_connection_output_count() {
@@ -877,46 +893,55 @@ int GraphNode::get_connection_output_count() {
_connpos_update();
}
- return conn_output_cache.size();
+ return right_port_cache.size();
}
-int GraphNode::get_connection_output_height(int p_idx) {
+int GraphNode::get_connection_output_height(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
- return conn_output_cache[p_idx].height;
+ ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
+ return right_port_cache[p_port].height;
}
-Vector2 GraphNode::get_connection_output_position(int p_idx) {
+Vector2 GraphNode::get_connection_output_position(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Vector2());
- Vector2 pos = conn_output_cache[p_idx].pos;
+ ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Vector2());
+ Vector2 pos = right_port_cache[p_port].position;
pos.x *= get_scale().x;
pos.y *= get_scale().y;
return pos;
}
-int GraphNode::get_connection_output_type(int p_idx) {
+int GraphNode::get_connection_output_type(int p_port) {
+ if (connpos_dirty) {
+ _connpos_update();
+ }
+
+ ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
+ return right_port_cache[p_port].type;
+}
+
+Color GraphNode::get_connection_output_color(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
- return conn_output_cache[p_idx].type;
+ ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Color());
+ return right_port_cache[p_port].color;
}
-Color GraphNode::get_connection_output_color(int p_idx) {
+int GraphNode::get_connection_output_slot(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
- ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Color());
- return conn_output_cache[p_idx].color;
+ ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), -1);
+ return right_port_cache[p_port].slot_idx;
}
void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
@@ -1012,6 +1037,9 @@ bool GraphNode::is_draggable() {
}
void GraphNode::set_selectable(bool p_selectable) {
+ if (!p_selectable) {
+ set_selected(false);
+ }
selectable = p_selectable;
}
@@ -1046,30 +1074,30 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language);
- ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right", "enable"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot);
+ ClassDB::bind_method(D_METHOD("set_slot", "slot_index", "enable_left_port", "type_left", "color_left", "enable_right_port", "type_right", "color_right", "custom_icon_left", "custom_icon_right", "draw_stylebox"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("clear_slot", "slot_index"), &GraphNode::clear_slot);
ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
- ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "idx"), &GraphNode::is_slot_enabled_left);
- ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "idx", "enable_left"), &GraphNode::set_slot_enabled_left);
+ ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "slot_index", "enable"), &GraphNode::set_slot_enabled_left);
+ ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "slot_index"), &GraphNode::is_slot_enabled_left);
- ClassDB::bind_method(D_METHOD("set_slot_type_left", "idx", "type_left"), &GraphNode::set_slot_type_left);
- ClassDB::bind_method(D_METHOD("get_slot_type_left", "idx"), &GraphNode::get_slot_type_left);
+ ClassDB::bind_method(D_METHOD("set_slot_type_left", "slot_index", "type"), &GraphNode::set_slot_type_left);
+ ClassDB::bind_method(D_METHOD("get_slot_type_left", "slot_index"), &GraphNode::get_slot_type_left);
- ClassDB::bind_method(D_METHOD("set_slot_color_left", "idx", "color_left"), &GraphNode::set_slot_color_left);
- ClassDB::bind_method(D_METHOD("get_slot_color_left", "idx"), &GraphNode::get_slot_color_left);
+ ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left);
+ ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left);
- ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "idx"), &GraphNode::is_slot_enabled_right);
- ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "idx", "enable_right"), &GraphNode::set_slot_enabled_right);
+ ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right);
+ ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right);
- ClassDB::bind_method(D_METHOD("set_slot_type_right", "idx", "type_right"), &GraphNode::set_slot_type_right);
- ClassDB::bind_method(D_METHOD("get_slot_type_right", "idx"), &GraphNode::get_slot_type_right);
+ ClassDB::bind_method(D_METHOD("set_slot_type_right", "slot_index", "type"), &GraphNode::set_slot_type_right);
+ ClassDB::bind_method(D_METHOD("get_slot_type_right", "slot_index"), &GraphNode::get_slot_type_right);
- ClassDB::bind_method(D_METHOD("set_slot_color_right", "idx", "color_right"), &GraphNode::set_slot_color_right);
- ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right);
+ ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right);
+ ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right);
- ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "idx"), &GraphNode::is_slot_draw_stylebox);
- ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "idx", "draw_stylebox"), &GraphNode::set_slot_draw_stylebox);
+ ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox);
+ ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset);
@@ -1090,16 +1118,18 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
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_input_height", "port"), &GraphNode::get_connection_input_height);
+ ClassDB::bind_method(D_METHOD("get_connection_input_position", "port"), &GraphNode::get_connection_input_position);
+ ClassDB::bind_method(D_METHOD("get_connection_input_type", "port"), &GraphNode::get_connection_input_type);
+ ClassDB::bind_method(D_METHOD("get_connection_input_color", "port"), &GraphNode::get_connection_input_color);
+ ClassDB::bind_method(D_METHOD("get_connection_input_slot", "port"), &GraphNode::get_connection_input_slot);
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_output_height", "port"), &GraphNode::get_connection_output_height);
+ ClassDB::bind_method(D_METHOD("get_connection_output_position", "port"), &GraphNode::get_connection_output_position);
+ ClassDB::bind_method(D_METHOD("get_connection_output_type", "port"), &GraphNode::get_connection_output_type);
+ ClassDB::bind_method(D_METHOD("get_connection_output_color", "port"), &GraphNode::get_connection_output_color);
+ ClassDB::bind_method(D_METHOD("get_connection_output_slot", "port"), &GraphNode::get_connection_output_slot);
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);
@@ -1123,6 +1153,8 @@ void GraphNode::_bind_methods() {
ADD_GROUP("", "");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
+ ADD_SIGNAL(MethodInfo("selected"));
+ ADD_SIGNAL(MethodInfo("deselected"));
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
ADD_SIGNAL(MethodInfo("raise_request"));
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 9c8f926403..e66b0cfc20 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -78,15 +78,17 @@ private:
Vector<int> cache_y;
- struct ConnCache {
- Vector2 pos;
+ struct PortCache {
+ Vector2 position;
+ int height;
+
+ int slot_idx;
int type = 0;
Color color;
- int height;
};
- Vector<ConnCache> conn_input_cache;
- Vector<ConnCache> conn_output_cache;
+ Vector<PortCache> left_port_cache;
+ Vector<PortCache> right_port_cache;
HashMap<int, Slot> slot_info;
@@ -165,16 +167,18 @@ public:
bool is_close_button_visible() const;
int get_connection_input_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_input_height(int p_port);
+ Vector2 get_connection_input_position(int p_port);
+ int get_connection_input_type(int p_port);
+ Color get_connection_input_color(int p_port);
+ int get_connection_input_slot(int p_port);
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);
+ int get_connection_output_height(int p_port);
+ Vector2 get_connection_output_position(int p_port);
+ int get_connection_output_type(int p_port);
+ Color get_connection_output_color(int p_port);
+ int get_connection_output_slot(int p_port);
void set_overlay(Overlay p_overlay);
Overlay get_overlay() const;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 8c49353105..008109da65 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -596,7 +596,7 @@ ItemList::IconMode ItemList::get_icon_mode() const {
return icon_mode;
}
-void ItemList::set_fixed_icon_size(const Size2 &p_size) {
+void ItemList::set_fixed_icon_size(const Size2i &p_size) {
if (fixed_icon_size == p_size) {
return;
}
@@ -605,7 +605,7 @@ void ItemList::set_fixed_icon_size(const Size2 &p_size) {
queue_redraw();
}
-Size2 ItemList::get_fixed_icon_size() const {
+Size2i ItemList::get_fixed_icon_size() const {
return fixed_icon_size;
}
@@ -655,7 +655,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
- pos -= theme_cache.bg_style->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -679,7 +679,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (closest != -1 && (mb->get_button_index() == MouseButton::LEFT || (allow_rmb_select && mb->get_button_index() == MouseButton::RIGHT))) {
int i = closest;
- if (select_mode == SELECT_MULTI && items[i].selected && mb->is_command_pressed()) {
+ if (select_mode == SELECT_MULTI && items[i].selected && mb->is_command_or_control_pressed()) {
deselect(i);
emit_signal(SNAME("multi_selected"), i, false);
@@ -702,13 +702,13 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("item_clicked"), i, get_local_mouse_position(), mb->get_button_index());
} else {
- if (!mb->is_double_click() && !mb->is_command_pressed() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MouseButton::LEFT) {
+ if (!mb->is_double_click() && !mb->is_command_or_control_pressed() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MouseButton::LEFT) {
defer_select_single = i;
return;
}
if (!items[i].selected || allow_reselect) {
- select(i, select_mode == SELECT_SINGLE || !mb->is_command_pressed());
+ select(i, select_mode == SELECT_SINGLE || !mb->is_command_or_control_pressed());
if (select_mode == SELECT_SINGLE) {
emit_signal(SNAME("item_selected"), i);
@@ -985,8 +985,8 @@ void ItemList::_update_theme_item_cache() {
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
- theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
- theme_cache.bg_focus_style = get_theme_stylebox(SNAME("bg_focus"));
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
@@ -1025,13 +1025,13 @@ void ItemList::_notification(int p_what) {
int mw = scroll_bar->get_minimum_size().x;
scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw);
scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
- scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.bg_style->get_margin(SIDE_TOP));
- scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.bg_style->get_margin(SIDE_BOTTOM));
+ scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.panel_style->get_margin(SIDE_TOP));
+ scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
- int width = size.width - theme_cache.bg_style->get_minimum_size().width;
+ int width = size.width - theme_cache.panel_style->get_minimum_size().width;
- draw_style_box(theme_cache.bg_style, Rect2(Point2(), size));
+ draw_style_box(theme_cache.panel_style, Rect2(Point2(), size));
Ref<StyleBox> sbsel;
Ref<StyleBox> cursor;
@@ -1047,7 +1047,7 @@ void ItemList::_notification(int p_what) {
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
- draw_style_box(theme_cache.bg_focus_style, Rect2(Point2(), size));
+ draw_style_box(theme_cache.focus_style, Rect2(Point2(), size));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
}
@@ -1109,7 +1109,7 @@ void ItemList::_notification(int p_what) {
items.write[i].min_rect_cache.size = minsize;
}
- int fit_size = size.x - theme_cache.bg_style->get_minimum_size().width - mw;
+ int fit_size = size.x - theme_cache.panel_style->get_minimum_size().width - mw;
//2-attempt best fit
current_columns = 0x7FFFFFFF;
@@ -1160,10 +1160,10 @@ void ItemList::_notification(int p_what) {
}
if (all_fit) {
- float page = MAX(0, size.height - theme_cache.bg_style->get_minimum_size().height);
+ float page = MAX(0, size.height - theme_cache.panel_style->get_minimum_size().height);
float max = MAX(page, ofs.y + max_h);
if (auto_height) {
- auto_height_value = ofs.y + max_h + theme_cache.bg_style->get_minimum_size().height;
+ auto_height_value = ofs.y + max_h + theme_cache.panel_style->get_minimum_size().height;
}
scroll_bar->set_max(max);
scroll_bar->set_page(page);
@@ -1204,7 +1204,7 @@ void ItemList::_notification(int p_what) {
ensure_selected_visible = false;
- Vector2 base_ofs = theme_cache.bg_style->get_offset();
+ Vector2 base_ofs = theme_cache.panel_style->get_offset();
base_ofs.y -= int(scroll_bar->get_value());
const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
@@ -1442,7 +1442,7 @@ void ItemList::_notification(int p_what) {
}
const int y = base_ofs.y + separators[i];
- draw_line(Vector2(theme_cache.bg_style->get_margin(SIDE_LEFT), y), Vector2(width, y), theme_cache.guide_color);
+ draw_line(Vector2(theme_cache.panel_style->get_margin(SIDE_LEFT), y), Vector2(width, y), theme_cache.guide_color);
}
} break;
}
@@ -1454,7 +1454,7 @@ void ItemList::_scroll_changed(double) {
int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
Vector2 pos = p_pos;
- pos -= theme_cache.bg_style->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -1491,7 +1491,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
}
Vector2 pos = p_pos;
- pos -= theme_cache.bg_style->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -1830,7 +1830,7 @@ void ItemList::_bind_methods() {
ADD_GROUP("Icon", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "icon_scale"), "set_icon_scale", "get_icon_scale");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fixed_icon_size", PROPERTY_HINT_NONE, "suffix:px"), "set_fixed_icon_size", "get_fixed_icon_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "fixed_icon_size", PROPERTY_HINT_NONE, "suffix:px"), "set_fixed_icon_size", "get_fixed_icon_size");
BIND_ENUM_CONSTANT(ICON_MODE_TOP);
BIND_ENUM_CONSTANT(ICON_MODE_LEFT);
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 63bc771185..4b1b9d9282 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -123,8 +123,8 @@ private:
int h_separation = 0;
int v_separation = 0;
- Ref<StyleBox> bg_style;
- Ref<StyleBox> bg_focus_style;
+ Ref<StyleBox> panel_style;
+ Ref<StyleBox> focus_style;
Ref<Font> font;
int font_size = 0;
@@ -244,8 +244,8 @@ public:
void set_icon_mode(IconMode p_mode);
IconMode get_icon_mode() const;
- void set_fixed_icon_size(const Size2 &p_size);
- Size2 get_fixed_icon_size() const;
+ void set_fixed_icon_size(const Size2i &p_size);
+ Size2i get_fixed_icon_size() const;
void set_allow_rmb_select(bool p_allow);
bool get_allow_rmb_select() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index c2ce4bdb83..be94337c89 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -589,7 +589,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
// Allow unicode handling if:
// * No Modifiers are pressed (except shift)
- bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
// Handle Unicode (if no modifiers active)
@@ -734,7 +734,7 @@ void LineEdit::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
- set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
+ set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -777,7 +777,7 @@ void LineEdit::_notification(int p_what) {
if (caret_blinking) {
caret_blink_timer += get_process_delta_time();
- if (caret_blink_timer >= caret_blink_speed) {
+ if (caret_blink_timer >= caret_blink_interval) {
caret_blink_timer = 0.0;
_toggle_draw_caret();
}
@@ -1392,13 +1392,13 @@ void LineEdit::set_caret_force_displayed(const bool p_enabled) {
queue_redraw();
}
-float LineEdit::get_caret_blink_speed() const {
- return caret_blink_speed;
+float LineEdit::get_caret_blink_interval() const {
+ return caret_blink_interval;
}
-void LineEdit::set_caret_blink_speed(const float p_speed) {
- ERR_FAIL_COND(p_speed <= 0);
- caret_blink_speed = p_speed;
+void LineEdit::set_caret_blink_interval(const float p_interval) {
+ ERR_FAIL_COND(p_interval <= 0);
+ caret_blink_interval = p_interval;
}
void LineEdit::_reset_caret_blink_timer() {
@@ -2037,7 +2037,7 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
- set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
+ set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
#endif
}
@@ -2274,7 +2274,7 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) {
}
void LineEdit::_validate_property(PropertyInfo &p_property) const {
- if (!caret_blink_enabled && p_property.name == "caret_blink_speed") {
+ if (!caret_blink_enabled && p_property.name == "caret_blink_interval") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -2317,8 +2317,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled);
ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed);
ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed);
- ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed);
- ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &LineEdit::set_caret_blink_interval);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &LineEdit::get_caret_blink_interval);
ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length);
ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length);
ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret);
@@ -2419,7 +2419,7 @@ void LineEdit::_bind_methods() {
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_interval", "get_caret_blink_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_caret_column", "get_caret_column");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 0122a5da69..a4d5205f81 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -170,7 +170,7 @@ private:
bool caret_blink_enabled = false;
bool caret_force_displayed = false;
bool draw_caret = true;
- float caret_blink_speed = 0.65;
+ float caret_blink_interval = 0.65;
double caret_blink_timer = 0.0;
bool caret_blinking = false;
@@ -311,8 +311,8 @@ public:
bool is_caret_blink_enabled() const;
void set_caret_blink_enabled(const bool p_enabled);
- float get_caret_blink_speed() const;
- void set_caret_blink_speed(const float p_speed);
+ float get_caret_blink_interval() const;
+ void set_caret_blink_interval(const float p_interval);
void set_caret_force_displayed(const bool p_enabled);
bool is_caret_force_displayed() const;
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 0613652bdf..d6bf84ea5a 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -137,7 +137,7 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) {
if (p_focus_item) {
for (int i = 0; i < pm->get_item_count(); i++) {
if (!pm->is_item_disabled(i)) {
- pm->set_current_index(i);
+ pm->set_focused_item(i);
break;
}
}
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index f779f87ae7..67a36240a2 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -107,7 +107,7 @@ void MenuButton::pressed() {
if (!_was_pressed_by_mouse()) {
for (int i = 0; i < popup->get_item_count(); i++) {
if (!popup->is_item_disabled(i)) {
- popup->set_current_index(i);
+ popup->set_focused_item(i);
break;
}
}
@@ -169,7 +169,7 @@ void MenuButton::_notification(int p_what) {
menu_btn_other->pressed();
// As the popup wasn't triggered by a mouse click, the item focus needs to be removed manually.
- menu_btn_other->get_popup()->set_current_index(-1);
+ menu_btn_other->get_popup()->set_focused_item(-1);
}
} break;
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 0dd9666858..08f5e0bbfb 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -238,7 +238,7 @@ void OptionButton::pressed() {
// If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused.
if (current != NONE_SELECTED && !popup->is_item_disabled(current)) {
if (!_was_pressed_by_mouse()) {
- popup->set_current_index(current);
+ popup->set_focused_item(current);
} else {
popup->scroll_to_item(current);
}
@@ -246,7 +246,7 @@ void OptionButton::pressed() {
for (int i = 0; i < popup->get_item_count(); i++) {
if (!popup->is_item_disabled(i)) {
if (!_was_pressed_by_mouse()) {
- popup->set_current_index(i);
+ popup->set_focused_item(i);
} else {
popup->scroll_to_item(i);
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 9afcd566b9..d4a4efd578 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -209,7 +209,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
if (p_by_keyboard) {
for (int i = 0; i < submenu_pum->get_item_count(); i++) {
if (!submenu_pum->is_item_disabled(i)) {
- submenu_pum->set_current_index(i);
+ submenu_pum->set_focused_item(i);
break;
}
}
@@ -1547,7 +1547,7 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
return items[p_idx].shortcut_is_disabled;
}
-void PopupMenu::set_current_index(int p_idx) {
+void PopupMenu::set_focused_item(int p_idx) {
if (p_idx != -1) {
ERR_FAIL_INDEX(p_idx, items.size());
}
@@ -1564,7 +1564,7 @@ void PopupMenu::set_current_index(int p_idx) {
control->queue_redraw();
}
-int PopupMenu::get_current_index() const {
+int PopupMenu::get_focused_item() const {
return mouse_over;
}
@@ -2057,8 +2057,8 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut);
ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent);
- ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index);
- ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index);
+ ClassDB::bind_method(D_METHOD("set_focused_item", "index"), &PopupMenu::set_focused_item);
+ ClassDB::bind_method(D_METHOD("get_focused_item"), &PopupMenu::get_focused_item);
ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count);
ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index c8c598bd50..ad7909842e 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -261,8 +261,8 @@ public:
int get_item_max_states(int p_idx) const;
int get_item_state(int p_idx) const;
- void set_current_index(int p_idx);
- int get_current_index() const;
+ void set_focused_item(int p_idx);
+ int get_focused_item() const;
void set_item_count(int p_count);
int get_item_count() const;
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index fe609dd834..8369eaa227 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -33,13 +33,13 @@
#include "scene/resources/text_line.h"
Size2 ProgressBar::get_minimum_size() const {
- Size2 minimum_size = theme_cache.bg_style->get_minimum_size();
- minimum_size.height = MAX(minimum_size.height, theme_cache.fg_style->get_minimum_size().height);
- minimum_size.width = MAX(minimum_size.width, theme_cache.fg_style->get_minimum_size().width);
- if (percent_visible) {
+ Size2 minimum_size = theme_cache.background_style->get_minimum_size();
+ minimum_size.height = MAX(minimum_size.height, theme_cache.fill_style->get_minimum_size().height);
+ minimum_size.width = MAX(minimum_size.width, theme_cache.fill_style->get_minimum_size().width);
+ if (show_percentage) {
String txt = "100%";
TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
- minimum_size.height = MAX(minimum_size.height, theme_cache.bg_style->get_minimum_size().height + tl.get_size().y);
+ minimum_size.height = MAX(minimum_size.height, theme_cache.background_style->get_minimum_size().height + tl.get_size().y);
} else { // this is needed, else the progressbar will collapse
minimum_size.width = MAX(minimum_size.width, 1);
minimum_size.height = MAX(minimum_size.height, 1);
@@ -50,8 +50,8 @@ Size2 ProgressBar::get_minimum_size() const {
void ProgressBar::_update_theme_item_cache() {
Range::_update_theme_item_cache();
- theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
- theme_cache.fg_style = get_theme_stylebox(SNAME("fg"));
+ theme_cache.background_style = get_theme_stylebox(SNAME("background"));
+ theme_cache.fill_style = get_theme_stylebox(SNAME("fill"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
@@ -63,14 +63,14 @@ void ProgressBar::_update_theme_item_cache() {
void ProgressBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- draw_style_box(theme_cache.bg_style, Rect2(Point2(), get_size()));
+ draw_style_box(theme_cache.background_style, Rect2(Point2(), get_size()));
float r = get_as_ratio();
switch (mode) {
case FILL_BEGIN_TO_END:
case FILL_END_TO_BEGIN: {
- int mp = theme_cache.fg_style->get_minimum_size().width;
+ int mp = theme_cache.fill_style->get_minimum_size().width;
int p = round(r * (get_size().width - mp));
// We want FILL_BEGIN_TO_END to map to right to left when UI layout is RTL,
// and left to right otherwise. And likewise for FILL_END_TO_BEGIN.
@@ -78,23 +78,23 @@ void ProgressBar::_notification(int p_what) {
if (p > 0) {
if (right_to_left) {
int p_remaining = round((1.0 - r) * (get_size().width - mp));
- draw_style_box(theme_cache.fg_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
+ draw_style_box(theme_cache.fill_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fill_style->get_minimum_size().width, get_size().height)));
} else {
- draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
+ draw_style_box(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fill_style->get_minimum_size().width, get_size().height)));
}
}
} break;
case FILL_TOP_TO_BOTTOM:
case FILL_BOTTOM_TO_TOP: {
- int mp = theme_cache.fg_style->get_minimum_size().height;
+ int mp = theme_cache.fill_style->get_minimum_size().height;
int p = round(r * (get_size().height - mp));
if (p > 0) {
if (mode == FILL_TOP_TO_BOTTOM) {
- draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
+ draw_style_box(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height)));
} else {
int p_remaining = round((1.0 - r) * (get_size().height - mp));
- draw_style_box(theme_cache.fg_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
+ draw_style_box(theme_cache.fill_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height)));
}
}
} break;
@@ -102,7 +102,7 @@ void ProgressBar::_notification(int p_what) {
break;
}
- if (percent_visible) {
+ if (show_percentage) {
String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign();
TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
@@ -127,27 +127,27 @@ int ProgressBar::get_fill_mode() {
return mode;
}
-void ProgressBar::set_percent_visible(bool p_visible) {
- if (percent_visible == p_visible) {
+void ProgressBar::set_show_percentage(bool p_visible) {
+ if (show_percentage == p_visible) {
return;
}
- percent_visible = p_visible;
+ show_percentage = p_visible;
update_minimum_size();
queue_redraw();
}
-bool ProgressBar::is_percent_visible() const {
- return percent_visible;
+bool ProgressBar::is_percentage_shown() const {
+ return show_percentage;
}
void ProgressBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &ProgressBar::set_fill_mode);
ClassDB::bind_method(D_METHOD("get_fill_mode"), &ProgressBar::get_fill_mode);
- ClassDB::bind_method(D_METHOD("set_percent_visible", "visible"), &ProgressBar::set_percent_visible);
- ClassDB::bind_method(D_METHOD("is_percent_visible"), &ProgressBar::is_percent_visible);
+ ClassDB::bind_method(D_METHOD("set_show_percentage", "visible"), &ProgressBar::set_show_percentage);
+ ClassDB::bind_method(D_METHOD("is_percentage_shown"), &ProgressBar::is_percentage_shown);
ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Begin to End,End to Begin,Top to Bottom,Bottom to Top"), "set_fill_mode", "get_fill_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "percent_visible"), "set_percent_visible", "is_percent_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_percentage"), "set_show_percentage", "is_percentage_shown");
BIND_ENUM_CONSTANT(FILL_BEGIN_TO_END);
BIND_ENUM_CONSTANT(FILL_END_TO_BEGIN);
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index c79b901928..b6d7d2c7cf 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -36,11 +36,11 @@
class ProgressBar : public Range {
GDCLASS(ProgressBar, Range);
- bool percent_visible = true;
+ bool show_percentage = true;
struct ThemeCache {
- Ref<StyleBox> bg_style;
- Ref<StyleBox> fg_style;
+ Ref<StyleBox> background_style;
+ Ref<StyleBox> fill_style;
Ref<Font> font;
int font_size = 0;
@@ -67,8 +67,8 @@ public:
void set_fill_mode(int p_fill);
int get_fill_mode();
- void set_percent_visible(bool p_visible);
- bool is_percent_visible() const;
+ void set_show_percentage(bool p_visible);
+ bool is_percentage_shown() const;
Size2 get_minimum_size() const override;
ProgressBar();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 99cad80cde..c936fe9738 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1028,8 +1028,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
n_time = (n_time > 1.0) ? 1.0 : n_time;
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
@@ -1243,8 +1243,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
n_time = (n_time > 1.0) ? 1.0 : n_time;
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
@@ -1676,8 +1676,8 @@ void RichTextLabel::_update_theme_item_cache() {
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
- theme_cache.progress_bg_style = get_theme_stylebox(SNAME("bg"), SNAME("ProgressBar"));
- theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fg"), SNAME("ProgressBar"));
+ theme_cache.progress_bg_style = get_theme_stylebox(SNAME("background"), SNAME("ProgressBar"));
+ theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fill"), SNAME("ProgressBar"));
theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
@@ -1693,7 +1693,6 @@ void RichTextLabel::_update_theme_item_cache() {
theme_cache.shadow_offset_x = get_theme_constant(SNAME("shadow_offset_x"));
theme_cache.shadow_offset_y = get_theme_constant(SNAME("shadow_offset_y"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.outline_color = get_theme_color(SNAME("outline_color"));
theme_cache.bold_font = get_theme_font(SNAME("bold_font"));
theme_cache.bold_font_size = get_theme_font_size(SNAME("bold_font_size"));
@@ -2564,7 +2563,9 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) {
void RichTextLabel::_thread_function(void *self) {
RichTextLabel *rtl = reinterpret_cast<RichTextLabel *>(self);
+ rtl->set_physics_process_internal(true);
rtl->_process_line_caches();
+ rtl->set_physics_process_internal(false);
rtl->updating.store(false);
rtl->call_deferred(SNAME("queue_redraw"));
}
@@ -2680,7 +2681,6 @@ bool RichTextLabel::_validate_line_caches() {
loaded.store(true);
thread.start(RichTextLabel::_thread_function, reinterpret_cast<void *>(this));
loading_started = OS::get_singleton()->get_ticks_msec();
- set_physics_process_internal(true);
return false;
} else {
_process_line_caches();
@@ -3941,7 +3941,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
int fs = theme_cache.normal_font_size * 3;
Ref<Font> f = theme_cache.normal_font;
Color color = theme_cache.default_color;
- Color outline_color = theme_cache.outline_color;
+ Color outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.outline_size;
Rect2 dropcap_margins = Rect2();
@@ -4368,12 +4368,12 @@ int RichTextLabel::get_visible_paragraph_count() const {
}
void RichTextLabel::scroll_to_line(int p_line) {
- _validate_line_caches();
-
if (p_line <= 0) {
vscroll->set_value(0);
return;
}
+ _validate_line_caches();
+
int line_count = 0;
int to_line = main->first_invalid_line.load();
for (int i = 0; i < to_line; i++) {
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 374ce6feea..6c05b171e3 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -321,7 +321,7 @@ void ScrollBar::_notification(int p_what) {
if (drag_node) {
drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input));
- drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONESHOT);
+ drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT);
}
} break;
@@ -613,7 +613,7 @@ void ScrollBar::set_drag_node(const NodePath &p_path) {
if (drag_node) {
drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input));
- drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONESHOT);
+ drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT);
}
}
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index f68cebd657..c12ac115b7 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -76,14 +76,14 @@ Size2 ScrollContainer::get_minimum_size() const {
min_size.x += v_scroll->get_minimum_size().x;
}
- min_size += theme_cache.bg_style->get_minimum_size();
+ min_size += theme_cache.panel_style->get_minimum_size();
return min_size;
}
void ScrollContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
- theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
}
void ScrollContainer::_cancel_drag() {
@@ -276,8 +276,8 @@ void ScrollContainer::_reposition_children() {
Size2 size = get_size();
Point2 ofs;
- size -= theme_cache.bg_style->get_minimum_size();
- ofs += theme_cache.bg_style->get_offset();
+ size -= theme_cache.panel_style->get_minimum_size();
+ ofs += theme_cache.panel_style->get_offset();
bool rtl = is_layout_rtl();
if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons
@@ -341,7 +341,7 @@ void ScrollContainer::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- draw_style_box(theme_cache.bg_style, Rect2(Vector2(), get_size()));
+ draw_style_box(theme_cache.panel_style, Rect2(Vector2(), get_size()));
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -416,7 +416,7 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
- size -= theme_cache.bg_style->get_minimum_size();
+ size -= theme_cache.panel_style->get_minimum_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index fa1f09ab3f..f4899846f4 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -70,7 +70,7 @@ private:
bool follow_focus = false;
struct ThemeCache {
- Ref<StyleBox> bg_style;
+ Ref<StyleBox> panel_style;
} theme_cache;
void _cancel_drag();
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 04bd5b3282..2ca1d6239e 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -33,11 +33,99 @@
#include "label.h"
#include "margin_container.h"
+void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+
+ if (sc->collapsed || !sc->_getch(0) || !sc->_getch(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) {
+ return;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ sc->_compute_middle_sep(true);
+ dragging = true;
+ drag_ofs = sc->split_offset;
+ if (sc->vertical) {
+ drag_from = get_transform().xform(mb->get_position()).y;
+ } else {
+ drag_from = get_transform().xform(mb->get_position()).x;
+ }
+ } else {
+ dragging = false;
+ queue_redraw();
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+ if (!dragging) {
+ return;
+ }
+
+ Vector2i in_parent_pos = get_transform().xform(mm->get_position());
+ if (!sc->vertical && is_layout_rtl()) {
+ sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
+ } else {
+ sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
+ }
+ sc->_compute_middle_sep(true);
+ sc->queue_sort();
+ sc->emit_signal(SNAME("dragged"), sc->get_split_offset());
+ }
+}
+
+Control::CursorShape SplitContainerDragger::get_cursor_shape(const Point2 &p_pos) const {
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+
+ if (!sc->collapsed && sc->dragger_visibility == SplitContainer::DRAGGER_VISIBLE) {
+ return (sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
+ }
+
+ return Control::get_cursor_shape(p_pos);
+}
+
+void SplitContainerDragger::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_MOUSE_ENTER: {
+ mouse_inside = true;
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (sc->get_theme_constant(SNAME("autohide"))) {
+ queue_redraw();
+ }
+ } break;
+
+ case NOTIFICATION_MOUSE_EXIT: {
+ mouse_inside = false;
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (sc->get_theme_constant(SNAME("autohide"))) {
+ queue_redraw();
+ }
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (!dragging && !mouse_inside && sc->get_theme_constant(SNAME("autohide"))) {
+ return;
+ }
+
+ Ref<Texture2D> tex = sc->get_theme_icon(SNAME("grabber"));
+ draw_texture(tex, (get_size() - tex->get_size()) / 2);
+ } break;
+ }
+}
+
Control *SplitContainer::_getch(int p_idx) const {
int idx = 0;
- for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ for (int i = 0; i < get_child_count(false); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i, false));
if (!c || !c->is_visible()) {
continue;
}
@@ -67,57 +155,72 @@ Ref<Texture2D> SplitContainer::_get_grabber_icon() const {
}
}
-void SplitContainer::_resort() {
- int axis = vertical ? 1 : 0;
-
+void SplitContainer::_compute_middle_sep(bool p_clamp) {
Control *first = _getch(0);
Control *second = _getch(1);
- // If we have only one element
- if (!first || !second) {
- if (first) {
- fit_child_in_rect(first, Rect2(Point2(), get_size()));
- } else if (second) {
- fit_child_in_rect(second, Rect2(Point2(), get_size()));
- }
- return;
- }
-
- // Determine expanded children
+ // Determine expanded children.
bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND;
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
- // Determine the separation between items
+ // Compute the minimum size.
+ int axis = vertical ? 1 : 0;
+ int size = get_size()[axis];
+ int ms_first = first->get_combined_minimum_size()[axis];
+ int ms_second = second->get_combined_minimum_size()[axis];
+
+ // Determine the separation between items.
Ref<Texture2D> g = _get_grabber_icon();
int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
- // Compute the minimum size
- Size2 ms_first = first->get_combined_minimum_size();
- Size2 ms_second = second->get_combined_minimum_size();
-
- // Compute the separator position without the split offset
- float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
- int no_offset_middle_sep = 0;
+ // Compute the wished separation_point.
+ int wished_middle_sep = 0;
+ int split_offset_with_collapse = 0;
+ if (!collapsed) {
+ split_offset_with_collapse = split_offset;
+ }
if (first_expanded && second_expanded) {
- no_offset_middle_sep = get_size()[axis] * ratio - sep / 2;
+ float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
+ wished_middle_sep = size * ratio - sep / 2 + split_offset_with_collapse;
} else if (first_expanded) {
- no_offset_middle_sep = get_size()[axis] - ms_second[axis] - sep;
+ wished_middle_sep = size - sep + split_offset_with_collapse;
} else {
- no_offset_middle_sep = ms_first[axis];
+ wished_middle_sep = split_offset_with_collapse;
}
- // Compute the final middle separation.
- middle_sep = no_offset_middle_sep;
- if (!collapsed) {
- int clamped_split_offset = CLAMP(split_offset, ms_first[axis] - no_offset_middle_sep, (get_size()[axis] - ms_second[axis] - sep) - no_offset_middle_sep);
- middle_sep += clamped_split_offset;
- if (should_clamp_split_offset) {
- split_offset = clamped_split_offset;
+ // Clamp the middle sep to acceptatble values.
+ middle_sep = CLAMP(wished_middle_sep, ms_first, size - sep - ms_second);
+
+ // Clamp the split_offset if requested.
+ if (p_clamp) {
+ split_offset -= wished_middle_sep - middle_sep;
+ p_clamp = false;
+ }
+}
+
+void SplitContainer::_resort() {
+ Control *first = _getch(0);
+ Control *second = _getch(1);
- should_clamp_split_offset = false;
+ // If we have only one element.
+ if (!first || !second) {
+ if (first) {
+ fit_child_in_rect(first, Rect2(Point2(), get_size()));
+ } else if (second) {
+ fit_child_in_rect(second, Rect2(Point2(), get_size()));
}
+ dragging_area_control->hide();
+ return;
}
+ // If we have more that one.
+ _compute_middle_sep(false);
+
+ // Determine the separation between items.
+ Ref<Texture2D> g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
+
+ // Move the children, including the dragger.
if (vertical) {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
@@ -135,7 +238,21 @@ void SplitContainer::_resort() {
}
}
- queue_redraw();
+ // Handle the dragger visibility and position.
+ if (dragger_visibility == DRAGGER_VISIBLE && !collapsed) {
+ dragging_area_control->show();
+
+ int dragger_ctrl_size = MAX(sep, theme_cache.minimum_grab_thickness);
+ if (vertical) {
+ dragging_area_control->set_rect(Rect2(Point2(0, middle_sep - (dragger_ctrl_size - sep) / 2), Size2(get_size().width, dragger_ctrl_size)));
+ } else {
+ dragging_area_control->set_rect(Rect2(Point2(middle_sep - (dragger_ctrl_size - sep) / 2, 0), Size2(dragger_ctrl_size, get_size().height)));
+ }
+
+ dragging_area_control->queue_redraw();
+ } else {
+ dragging_area_control->hide();
+ }
}
Size2 SplitContainer::get_minimum_size() const {
@@ -170,10 +287,17 @@ Size2 SplitContainer::get_minimum_size() const {
return minimum;
}
+void SplitContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void SplitContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.separation = get_theme_constant(SNAME("separation"));
+ theme_cache.minimum_grab_thickness = get_theme_constant(SNAME("minimum_grab_thickness"));
theme_cache.autohide = get_theme_constant(SNAME("autohide"));
theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber"));
@@ -191,132 +315,12 @@ void SplitContainer::_notification(int p_what) {
_resort();
} break;
- case NOTIFICATION_MOUSE_EXIT: {
- mouse_inside = false;
- if (theme_cache.autohide) {
- queue_redraw();
- }
- } break;
-
- case NOTIFICATION_DRAW: {
- if (!_getch(0) || !_getch(1)) {
- return;
- }
-
- if (collapsed || (!dragging && !mouse_inside && theme_cache.autohide)) {
- return;
- }
-
- if (dragger_visibility != DRAGGER_VISIBLE) {
- return;
- }
-
- int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? theme_cache.separation : 0;
- Ref<Texture2D> tex = theme_cache.grabber_icon;
- Size2 size = get_size();
-
- if (vertical) {
- draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2));
- } else {
- draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2));
- }
- } break;
-
case NOTIFICATION_THEME_CHANGED: {
update_minimum_size();
} break;
}
}
-void SplitContainer::_validate_property(PropertyInfo &p_property) const {
- if (is_fixed && p_property.name == "vertical") {
- p_property.usage = PROPERTY_USAGE_NONE;
- }
-}
-
-void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND(p_event.is_null());
-
- if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) {
- return;
- }
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_pressed()) {
- if (vertical) {
- if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + theme_cache.separation) {
- dragging = true;
- drag_from = mb->get_position().y;
- drag_ofs = split_offset;
- }
- } else {
- if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + theme_cache.separation) {
- dragging = true;
- drag_from = mb->get_position().x;
- drag_ofs = split_offset;
- }
- }
- } else {
- dragging = false;
- }
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
- bool mouse_inside_state = false;
- if (vertical) {
- mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + theme_cache.separation;
- } else {
- mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + theme_cache.separation;
- }
-
- if (mouse_inside != mouse_inside_state) {
- mouse_inside = mouse_inside_state;
- if (theme_cache.autohide) {
- queue_redraw();
- }
- }
-
- if (!dragging) {
- return;
- }
-
- if (!vertical && is_layout_rtl()) {
- split_offset = drag_ofs + (drag_from - (vertical ? mm->get_position().y : mm->get_position().x));
- } else {
- split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
- }
- should_clamp_split_offset = true;
- queue_sort();
- emit_signal(SNAME("dragged"), get_split_offset());
- }
-}
-
-Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const {
- if (dragging) {
- return (vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
- }
-
- if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
- if (vertical) {
- if (p_pos.y > middle_sep && p_pos.y < middle_sep + theme_cache.separation) {
- return CURSOR_VSPLIT;
- }
- } else {
- if (p_pos.x > middle_sep && p_pos.x < middle_sep + theme_cache.separation) {
- return CURSOR_HSPLIT;
- }
- }
- }
-
- return Control::get_cursor_shape(p_pos);
-}
-
void SplitContainer::set_split_offset(int p_offset) {
if (split_offset == p_offset) {
return;
@@ -332,8 +336,11 @@ int SplitContainer::get_split_offset() const {
}
void SplitContainer::clamp_split_offset() {
- should_clamp_split_offset = true;
+ if (!_getch(0) || !_getch(1)) {
+ return;
+ }
+ _compute_middle_sep(true);
queue_sort();
}
@@ -353,7 +360,6 @@ void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
dragger_visibility = p_visibility;
queue_sort();
- queue_redraw();
}
SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
@@ -427,4 +433,7 @@ void SplitContainer::_bind_methods() {
SplitContainer::SplitContainer(bool p_vertical) {
vertical = p_vertical;
+
+ dragging_area_control = memnew(SplitContainerDragger);
+ add_child(dragging_area_control, false, Node::INTERNAL_MODE_BACK);
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 8ab0779d4b..d297e3a3ea 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -33,8 +33,26 @@
#include "scene/gui/container.h"
+class SplitContainerDragger : public Control {
+ GDCLASS(SplitContainerDragger, Control);
+
+protected:
+ void _notification(int p_what);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+private:
+ bool dragging = false;
+ int drag_from = 0;
+ int drag_ofs = 0;
+ bool mouse_inside = false;
+
+public:
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
+};
+
class SplitContainer : public Container {
GDCLASS(SplitContainer, Container);
+ friend class SplitContainerDragger;
public:
enum DraggerVisibility {
@@ -44,19 +62,17 @@ public:
};
private:
- bool should_clamp_split_offset = false;
int split_offset = 0;
int middle_sep = 0;
bool vertical = false;
- bool dragging = false;
- int drag_from = 0;
- int drag_ofs = 0;
bool collapsed = false;
DraggerVisibility dragger_visibility = DRAGGER_VISIBLE;
- bool mouse_inside = false;
+
+ SplitContainerDragger *dragging_area_control = nullptr;
struct ThemeCache {
int separation = 0;
+ int minimum_grab_thickness = 0;
int autohide = 0;
Ref<Texture2D> grabber_icon;
Ref<Texture2D> grabber_icon_h;
@@ -66,12 +82,14 @@ private:
Control *_getch(int p_idx) const;
Ref<Texture2D> _get_grabber_icon() const;
+ void _compute_middle_sep(bool p_clamp);
void _resort();
+ void _dragging_area_gui_input(const Ref<InputEvent> &p_event);
+
protected:
bool is_fixed = false;
- virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
@@ -92,8 +110,6 @@ public:
void set_vertical(bool p_vertical);
bool is_vertical() const;
- virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
-
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 4d18af7743..cf6681f809 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -162,7 +162,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_pressed()) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_or_control_pressed()) {
if (scrolling_enabled && buttons_visible) {
if (offset > 0) {
offset--;
@@ -172,7 +172,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_pressed()) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_or_control_pressed()) {
if (scrolling_enabled && buttons_visible) {
if (missing_right && offset < tabs.size()) {
offset++;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 95338c7b8c..318447ecd8 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1614,7 +1614,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (mb->is_pressed()) {
- if (mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_or_control_pressed()) {
if (mb->is_shift_pressed()) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
} else if (mb->is_alt_pressed()) {
@@ -1625,7 +1625,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
_scroll_up(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_or_control_pressed()) {
if (mb->is_shift_pressed()) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
} else if (mb->is_alt_pressed()) {
@@ -1920,7 +1920,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
// Allow unicode handling if:
// * No Modifiers are pressed (except shift)
- bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
selection.selecting_text = false;
@@ -3990,13 +3990,13 @@ bool TextEdit::is_caret_blink_enabled() const {
return caret_blink_enabled;
}
-float TextEdit::get_caret_blink_speed() const {
+float TextEdit::get_caret_blink_interval() const {
return caret_blink_timer->get_wait_time();
}
-void TextEdit::set_caret_blink_speed(const float p_speed) {
- ERR_FAIL_COND(p_speed <= 0);
- caret_blink_timer->set_wait_time(p_speed);
+void TextEdit::set_caret_blink_interval(const float p_interval) {
+ ERR_FAIL_COND(p_interval <= 0);
+ caret_blink_timer->set_wait_time(p_interval);
}
void TextEdit::set_move_caret_on_right_click_enabled(const bool p_enabled) {
@@ -4786,6 +4786,9 @@ void TextEdit::add_gutter(int p_at) {
}
text.add_gutter(p_at);
+
+ _update_gutter_width();
+
emit_signal(SNAME("gutter_added"));
queue_redraw();
}
@@ -4796,6 +4799,9 @@ void TextEdit::remove_gutter(int p_gutter) {
gutters.remove_at(p_gutter);
text.remove_gutter(p_gutter);
+
+ _update_gutter_width();
+
emit_signal(SNAME("gutter_removed"));
queue_redraw();
}
@@ -5288,8 +5294,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enable"), &TextEdit::set_caret_blink_enabled);
ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &TextEdit::is_caret_blink_enabled);
- ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &TextEdit::set_caret_blink_speed);
- ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &TextEdit::get_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &TextEdit::set_caret_blink_interval);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &TextEdit::get_caret_blink_interval);
ClassDB::bind_method(D_METHOD("set_move_caret_on_right_click_enabled", "enable"), &TextEdit::set_move_caret_on_right_click_enabled);
ClassDB::bind_method(D_METHOD("is_move_caret_on_right_click_enabled"), &TextEdit::is_move_caret_on_right_click_enabled);
@@ -5518,7 +5524,7 @@ void TextEdit::_bind_methods() {
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_type", PROPERTY_HINT_ENUM, "Line,Block"), "set_caret_type", "get_caret_type");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_interval", "get_caret_blink_interval");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_move_on_right_click"), "set_move_caret_on_right_click_enabled", "is_move_caret_on_right_click_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index f97f99075c..a8da878ede 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -762,8 +762,8 @@ public:
void set_caret_blink_enabled(const bool p_enabled);
bool is_caret_blink_enabled() const;
- void set_caret_blink_speed(const float p_speed);
- float get_caret_blink_speed() const;
+ void set_caret_blink_interval(const float p_interval);
+ float get_caret_blink_interval() const;
void set_move_caret_on_right_click_enabled(const bool p_enabled);
bool is_move_caret_on_right_click_enabled() const;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 2efb6593d3..d9ab1c2c55 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -67,7 +67,7 @@ bool TextureButton::has_point(const Point2 &p_point) const {
Rect2 rect = Rect2();
Size2 mask_size = click_mask->get_size();
- if (_position_rect.has_no_area()) {
+ if (!_position_rect.has_area()) {
rect.size = mask_size;
} else if (_tile) {
// if the stretch mode is tile we offset the point to keep it inside the mask size
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index da53da20b0..459e67091d 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -94,7 +94,7 @@ void TextureRect::_notification(int p_what) {
Ref<AtlasTexture> p_atlas = texture;
- if (p_atlas.is_valid() && region.has_no_area()) {
+ if (p_atlas.is_valid() && !region.has_area()) {
Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height());
offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0;
@@ -104,10 +104,10 @@ void TextureRect::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
- if (region.has_no_area()) {
- draw_texture_rect(texture, Rect2(offset, size), tile);
- } else {
+ if (region.has_area()) {
draw_texture_rect_region(texture, Rect2(offset, size), region);
+ } else {
+ draw_texture_rect(texture, Rect2(offset, size), tile);
}
} break;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index e8164b5728..237c78407b 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1538,12 +1538,14 @@ TreeItem::~TreeItem() {
void Tree::_update_theme_item_cache() {
Control::_update_theme_item_cache();
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
+
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.tb_font = get_theme_font(SNAME("title_button_font"));
theme_cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size"));
- theme_cache.bg = get_theme_stylebox(SNAME("bg"));
- theme_cache.bg_focus = get_theme_stylebox(SNAME("bg_focus"));
+
theme_cache.selected = get_theme_stylebox(SNAME("selected"));
theme_cache.selected_focus = get_theme_stylebox(SNAME("selected_focus"));
theme_cache.cursor = get_theme_stylebox(SNAME("cursor"));
@@ -1955,7 +1957,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (i == 0) {
if (p_item->cells[0].selected && select_mode == SELECT_ROW) {
- Rect2i row_rect = Rect2i(Point2i(theme_cache.bg->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - theme_cache.bg->get_minimum_size().width, item_rect.size.y));
+ Rect2i row_rect = Rect2i(Point2i(theme_cache.panel_style->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - theme_cache.panel_style->get_minimum_size().width, item_rect.size.y));
//Rect2 r = Rect2i(row_rect.pos,row_rect.size);
//r.grow(cache.selected->get_margin(SIDE_LEFT));
if (rtl) {
@@ -2502,7 +2504,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) {
void Tree::_range_click_timeout() {
if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
- Point2 pos = get_local_mouse_position() - theme_cache.bg->get_offset();
+ Point2 pos = get_local_mouse_position() - theme_cache.panel_style->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -2520,7 +2522,7 @@ void Tree::_range_click_timeout() {
Ref<InputEventMouseButton> mb;
mb.instantiate();
- int x_limit = get_size().width - theme_cache.bg->get_minimum_size().width;
+ int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width;
if (h_scroll->is_visible()) {
x_limit -= h_scroll->get_minimum_size().width;
}
@@ -2609,7 +2611,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return -1;
} else if (col == 0) {
int margin = x_ofs + theme_cache.item_margin; //-theme_cache.hseparation;
- //int lm = theme_cache.bg->get_margin(SIDE_LEFT);
+ //int lm = theme_cache.panel_style->get_margin(SIDE_LEFT);
col_width -= margin;
limit_w -= margin;
col_ofs += margin;
@@ -2684,7 +2686,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return -1;
}
- if (select_mode == SELECT_MULTI && p_mod->is_command_pressed() && c.selectable) {
+ if (select_mode == SELECT_MULTI && p_mod->is_command_or_control_pressed() && c.selectable) {
if (!c.selected || p_button == MouseButton::RIGHT) {
p_item->select(col);
emit_signal(SNAME("multi_selected"), p_item, col, true);
@@ -3125,7 +3127,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- bool is_command = k.is_valid() && k->is_command_pressed();
+ bool is_command = k.is_valid() && k->is_command_or_control_pressed();
if (p_event->is_action("ui_right") && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
@@ -3283,7 +3285,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (!k->is_pressed()) {
return;
}
- if (k->is_command_pressed() || (k->is_shift_pressed() && k->get_unicode() == 0) || k->is_meta_pressed()) {
+ if (k->is_command_or_control_pressed() || (k->is_shift_pressed() && k->get_unicode() == 0) || k->is_meta_pressed()) {
return;
}
if (!root) {
@@ -3308,14 +3310,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- Ref<StyleBox> bg = theme_cache.bg;
+ Ref<StyleBox> bg = theme_cache.panel_style;
bool rtl = is_layout_rtl();
Point2 pos = mm->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
}
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
Cache::ClickType old_hover = cache.hover_type;
int old_index = cache.hover_index;
@@ -3343,7 +3345,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (rtl) {
mpos.x = get_size().width - mpos.x;
}
- mpos -= theme_cache.bg->get_offset();
+ mpos -= theme_cache.panel_style->get_offset();
mpos.y -= _get_title_button_height();
if (mpos.y >= 0) {
if (h_scroll->is_visible_in_tree()) {
@@ -3443,7 +3445,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (rtl) {
pos.x = get_size().width - pos.x;
}
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -3537,7 +3539,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
switch (mb->get_button_index()) {
case MouseButton::RIGHT:
case MouseButton::LEFT: {
- Ref<StyleBox> bg = theme_cache.bg;
+ Ref<StyleBox> bg = theme_cache.panel_style;
Point2 pos = mb->get_position();
if (rtl) {
@@ -3572,7 +3574,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
pressing_for_editor = false;
propagate_mouse_activated = false;
- int x_limit = get_size().width - theme_cache.bg->get_minimum_size().width;
+ int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width;
if (h_scroll->is_visible()) {
x_limit -= h_scroll->get_minimum_size().width;
}
@@ -3613,7 +3615,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
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()) {
+ if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_or_control_pressed()) {
emit_signal(SNAME("nothing_selected"));
}
}
@@ -3766,7 +3768,7 @@ bool Tree::is_editing() {
}
Size2 Tree::get_internal_min_size() const {
- Size2i size = theme_cache.bg->get_offset();
+ Size2i size = theme_cache.panel_style->get_offset();
if (root) {
size.height += get_item_height(root);
}
@@ -3789,23 +3791,23 @@ void Tree::update_scrollbars() {
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
- v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.bg->get_margin(SIDE_TOP)));
- v_scroll->set_end(Point2(size.width, size.height - theme_cache.bg->get_margin(SIDE_TOP) - theme_cache.bg->get_margin(SIDE_BOTTOM)));
+ v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.panel_style->get_margin(SIDE_TOP)));
+ v_scroll->set_end(Point2(size.width, size.height - theme_cache.panel_style->get_margin(SIDE_TOP) - theme_cache.panel_style->get_margin(SIDE_BOTTOM)));
h_scroll->set_begin(Point2(0, size.height - hmin.height));
h_scroll->set_end(Point2(size.width - vmin.width, size.height));
Size2 internal_min_size = get_internal_min_size();
- bool display_vscroll = internal_min_size.height + theme_cache.bg->get_margin(SIDE_TOP) > size.height;
- bool display_hscroll = internal_min_size.width + theme_cache.bg->get_margin(SIDE_LEFT) > size.width;
+ bool display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) > size.height;
+ bool display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) > size.width;
for (int i = 0; i < 2; i++) {
// Check twice, as both values are dependent on each other.
if (display_hscroll) {
- display_vscroll = internal_min_size.height + theme_cache.bg->get_margin(SIDE_TOP) + hmin.height > size.height;
+ display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) + hmin.height > size.height;
}
if (display_vscroll) {
- display_hscroll = internal_min_size.width + theme_cache.bg->get_margin(SIDE_LEFT) + vmin.width > size.width;
+ display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) + vmin.width > size.width;
}
}
@@ -3941,7 +3943,7 @@ void Tree::_notification(int p_what) {
update_scrollbars();
RID ci = get_canvas_item();
- Ref<StyleBox> bg = theme_cache.bg;
+ Ref<StyleBox> bg = theme_cache.panel_style;
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3965,7 +3967,7 @@ void Tree::_notification(int p_what) {
if (show_column_titles) {
//title buttons
- int ofs2 = theme_cache.bg->get_margin(SIDE_LEFT);
+ int ofs2 = theme_cache.panel_style->get_margin(SIDE_LEFT);
for (int i = 0; i < columns.size(); i++) {
Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? theme_cache.title_button_hover : theme_cache.title_button);
Ref<Font> f = theme_cache.tb_font;
@@ -3987,11 +3989,11 @@ void Tree::_notification(int p_what) {
}
}
- // Draw the background focus outline last, so that it is drawn in front of the section headings.
+ // Draw the focus outline last, so that it is drawn in front of the section headings.
// Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling.
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
- theme_cache.bg_focus->draw(ci, Rect2(Point2(), get_size()));
+ theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size()));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
} break;
@@ -4033,7 +4035,7 @@ Size2 Tree::get_minimum_size() const {
return Size2();
} else {
Vector2 min_size = get_internal_min_size();
- Ref<StyleBox> bg = theme_cache.bg;
+ Ref<StyleBox> bg = theme_cache.panel_style;
if (bg.is_valid()) {
min_size.x += bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
min_size.y += bg->get_margin(SIDE_TOP) + bg->get_margin(SIDE_BOTTOM);
@@ -4329,7 +4331,7 @@ int Tree::get_column_minimum_width(int p_column) const {
// Check if the visible title of the column is wider.
if (show_column_titles) {
- min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.bg->get_margin(SIDE_LEFT) + theme_cache.bg->get_margin(SIDE_RIGHT), min_width);
+ min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT), min_width);
}
if (!columns[p_column].clip_content) {
@@ -4374,7 +4376,7 @@ int Tree::get_column_width(int p_column) const {
if (columns[p_column].expand) {
int expand_area = get_size().width;
- Ref<StyleBox> bg = theme_cache.bg;
+ Ref<StyleBox> bg = theme_cache.panel_style;
if (bg.is_valid()) {
expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
@@ -4482,7 +4484,7 @@ void Tree::ensure_cursor_is_visible() {
return; // Nothing under cursor.
}
- const Size2 area_size = get_size() - theme_cache.bg->get_minimum_size();
+ const Size2 area_size = get_size() - theme_cache.panel_style->get_minimum_size();
int y_offset = get_item_offset(selected_item);
if (y_offset != -1) {
@@ -4831,7 +4833,7 @@ int Tree::get_column_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4861,7 +4863,7 @@ int Tree::get_drop_section_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -100;
@@ -4891,7 +4893,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return nullptr;
@@ -4918,7 +4920,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
int Tree::get_button_id_at_position(const Point2 &p_pos) const {
if (root) {
Point2 pos = p_pos;
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4959,7 +4961,7 @@ int Tree::get_button_id_at_position(const Point2 &p_pos) const {
String Tree::get_tooltip(const Point2 &p_pos) const {
if (root) {
Point2 pos = p_pos;
- pos -= theme_cache.bg->get_offset();
+ pos -= theme_cache.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return Control::get_tooltip(p_pos);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index b4ee686bab..450943c048 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -483,12 +483,14 @@ private:
void propagate_set_columns(TreeItem *p_item);
struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ Ref<StyleBox> focus_style;
+
Ref<Font> font;
Ref<Font> tb_font;
int font_size = 0;
int tb_font_size = 0;
- Ref<StyleBox> bg;
- Ref<StyleBox> bg_focus;
+
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
Ref<StyleBox> cursor;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 65e7ba3e67..05d86f77f2 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -369,6 +369,13 @@ void CanvasItem::queue_redraw() {
MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback));
}
+void CanvasItem::move_to_front() {
+ if (!get_parent()) {
+ return;
+ }
+ get_parent()->move_child(this, -1);
+}
+
void CanvasItem::set_modulate(const Color &p_modulate) {
if (modulate == p_modulate) {
return;
@@ -897,6 +904,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
ClassDB::bind_method(D_METHOD("queue_redraw"), &CanvasItem::queue_redraw);
+ ClassDB::bind_method(D_METHOD("move_to_front"), &CanvasItem::move_to_front);
ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level);
ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level);
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 1abb4edec9..b80289fdb4 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -198,6 +198,7 @@ public:
void hide();
void queue_redraw();
+ void move_to_front();
void set_clip_children(bool p_enabled);
bool is_clipping_children() const;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 4890db995a..214efe432b 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -329,14 +329,14 @@ void CanvasLayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px"), "set_transform", "get_transform");
ADD_GROUP("", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
ADD_GROUP("Follow Viewport", "follow_viewport");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enabled"), "set_follow_viewport", "is_following_viewport");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_less"), "set_follow_viewport_scale", "get_follow_viewport_scale");
ADD_SIGNAL(MethodInfo("visibility_changed"));
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 9a23bc65bf..bec378dd91 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -36,11 +36,11 @@ void HTTPRequest::_redirect_request(const String &p_new_url) {
}
Error HTTPRequest::_request() {
- return client->connect_to_host(url, port, use_ssl, validate_ssl);
+ return client->connect_to_host(url, port, use_tls, validate_tls);
}
Error HTTPRequest::_parse_url(const String &p_url) {
- use_ssl = false;
+ use_tls = false;
request_string = "";
port = 80;
request_sent = false;
@@ -54,12 +54,12 @@ Error HTTPRequest::_parse_url(const String &p_url) {
Error err = p_url.parse_url(scheme, url, port, request_string);
ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
if (scheme == "https://") {
- use_ssl = true;
+ use_tls = true;
} else if (scheme != "http://") {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
if (port == 0) {
- port = use_ssl ? 443 : 80;
+ port = use_tls ? 443 : 80;
}
if (request_string.is_empty()) {
request_string = "/";
@@ -98,7 +98,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S
return value;
}
-Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
+Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
// Copy the string into a raw buffer.
Vector<uint8_t> raw_data;
@@ -110,10 +110,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
memcpy(w, charstr.ptr(), len);
}
- return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
+ return request_raw(p_url, p_custom_headers, p_tls_validate_domain, p_method, raw_data);
}
-Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
+Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
@@ -129,7 +129,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
return err;
}
- validate_ssl = p_ssl_validate_domain;
+ validate_tls = p_tls_validate_domain;
headers = p_custom_headers;
@@ -413,8 +413,8 @@ bool HTTPRequest::_update_connection() {
call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
- case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
+ case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR: {
+ call_deferred(SNAME("_request_done"), RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
}
@@ -570,8 +570,8 @@ void HTTPRequest::_timeout() {
}
void HTTPRequest::_bind_methods() {
- ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
- ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "ssl_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
+ ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "tls_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "tls_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request);
ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status);
@@ -621,7 +621,7 @@ void HTTPRequest::_bind_methods() {
BIND_ENUM_CONSTANT(RESULT_CANT_CONNECT);
BIND_ENUM_CONSTANT(RESULT_CANT_RESOLVE);
BIND_ENUM_CONSTANT(RESULT_CONNECTION_ERROR);
- BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR);
+ BIND_ENUM_CONSTANT(RESULT_TLS_HANDSHAKE_ERROR);
BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE);
BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED);
BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED);
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 4b32188377..290bacd9d2 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -48,7 +48,7 @@ public:
RESULT_CANT_CONNECT,
RESULT_CANT_RESOLVE,
RESULT_CONNECTION_ERROR,
- RESULT_SSL_HANDSHAKE_ERROR,
+ RESULT_TLS_HANDSHAKE_ERROR,
RESULT_NO_RESPONSE,
RESULT_BODY_SIZE_LIMIT_EXCEEDED,
RESULT_BODY_DECOMPRESS_FAILED,
@@ -67,8 +67,8 @@ private:
String url;
int port = 80;
Vector<String> headers;
- bool validate_ssl = false;
- bool use_ssl = false;
+ bool validate_tls = false;
+ bool use_tls = false;
HTTPClient::Method method;
Vector<uint8_t> request_data;
@@ -121,8 +121,8 @@ protected:
static void _bind_methods();
public:
- Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
- Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
+ Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
+ Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
void cancel_request();
HTTPClient::Status get_http_client_status() const;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 289e963077..29f4d4fb1c 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -328,12 +328,21 @@ void Node::move_child(Node *p_child, int p_pos) {
// We need to check whether node is internal and move it only in the relevant node range.
if (p_child->_is_internal_front()) {
+ if (p_pos < 0) {
+ p_pos += data.internal_children_front;
+ }
ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
_move_child(p_child, p_pos);
} else if (p_child->_is_internal_back()) {
+ if (p_pos < 0) {
+ p_pos += data.internal_children_back;
+ }
ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
_move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
} else {
+ if (p_pos < 0) {
+ p_pos += get_child_count(false);
+ }
ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
_move_child(p_child, p_pos + data.internal_children_front);
}
@@ -389,21 +398,6 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked--;
}
-void Node::raise() {
- if (!data.parent) {
- return;
- }
-
- // Internal children move within a different index range.
- if (_is_internal_front()) {
- data.parent->move_child(this, data.parent->data.internal_children_front - 1);
- } else if (_is_internal_back()) {
- data.parent->move_child(this, data.parent->data.internal_children_back - 1);
- } else {
- data.parent->move_child(this, data.parent->get_child_count(false) - 1);
- }
-}
-
void Node::_propagate_groups_dirty() {
for (const KeyValue<StringName, GroupData> &E : data.grouped) {
if (E.value.group) {
@@ -1131,7 +1125,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
add_child_notify(p_child);
}
-void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) {
+void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
@@ -1140,7 +1134,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
#endif
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
- _validate_child_name(p_child, p_legible_unique_name);
+ _validate_child_name(p_child, p_force_readable_name);
_add_child_nocheck(p_child, p_child->data.name);
if (p_internal == INTERNAL_MODE_FRONT) {
@@ -1154,7 +1148,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
}
}
-void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
+void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
ERR_FAIL_NULL(p_sibling);
ERR_FAIL_NULL(data.parent);
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
@@ -1167,7 +1161,7 @@ void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
internal = INTERNAL_MODE_BACK;
}
- data.parent->add_child(p_sibling, p_legible_unique_name, internal);
+ data.parent->add_child(p_sibling, p_force_readable_name, internal);
data.parent->_move_child(p_sibling, get_index() + 1);
}
@@ -1922,43 +1916,6 @@ Ref<Tween> Node::create_tween() {
return tween;
}
-void Node::remove_and_skip() {
- ERR_FAIL_COND(!data.parent);
-
- Node *new_owner = get_owner();
-
- List<Node *> children;
-
- while (true) {
- bool clear = true;
- for (int i = 0; i < data.children.size(); i++) {
- Node *c_node = data.children[i];
- if (!c_node->get_owner()) {
- continue;
- }
-
- remove_child(c_node);
- c_node->_propagate_replace_owner(this, nullptr);
- children.push_back(c_node);
- clear = false;
- break;
- }
-
- if (clear) {
- break;
- }
- }
-
- while (!children.is_empty()) {
- Node *c_node = children.front()->get();
- data.parent->add_child(c_node);
- c_node->_propagate_replace_owner(nullptr, new_owner);
- children.pop_front();
- }
-
- data.parent->remove_child(this);
-}
-
void Node::set_scene_file_path(const String &p_scene_file_path) {
data.scene_file_path = p_scene_file_path;
}
@@ -2787,11 +2744,11 @@ void Node::_bind_methods() {
GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
- ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
- ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_child", "node", "force_readable_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
@@ -2816,10 +2773,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group);
ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child);
ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups);
- ClassDB::bind_method(D_METHOD("raise"), &Node::raise);
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
- ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip);
ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false));
ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree);
ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty);
diff --git a/scene/main/node.h b/scene/main/node.h
index ae6a997579..13a938ef97 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -303,8 +303,8 @@ public:
StringName get_name() const;
void set_name(const String &p_name);
- void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
- void add_sibling(Node *p_sibling, bool p_legible_unique_name = false);
+ void add_child(Node *p_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
+ void add_sibling(Node *p_sibling, bool p_force_readable_name = false);
void remove_child(Node *p_child);
int get_child_count(bool p_include_internal = true) const;
@@ -348,7 +348,6 @@ public:
void move_child(Node *p_child, int p_pos);
void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
- void raise();
void set_owner(Node *p_owner);
Node *get_owner() const;
@@ -357,7 +356,6 @@ public:
void set_unique_name_in_owner(bool p_enabled);
bool is_unique_name_in_owner() const;
- void remove_and_skip();
int get_index(bool p_include_internal = true) const;
Ref<Tween> create_tween();
@@ -531,4 +529,8 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args)
return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
+// Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.
+#define DEPRECATED_NODE_WARNING warnings.push_back(RTR("This node is marked as deprecated and will be removed in future versions.\nPlease check the Godot documentation for information about migration."));
+#define EXPERIMENTAL_NODE_WARNING warnings.push_back(RTR("This node is marked as experimental and may be subject to removal or major changes in future versions."));
+
#endif // NODE_H
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 268b381029..c18aa5aaa2 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -88,6 +88,14 @@ bool SceneTreeTimer::is_process_always() {
return process_always;
}
+void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) {
+ process_in_physics = p_process_in_physics;
+}
+
+bool SceneTreeTimer::is_process_in_physics() {
+ return process_in_physics;
+}
+
void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
ignore_time_scale = p_ignore;
}
@@ -420,6 +428,8 @@ bool SceneTree::physics_process(double p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
+ process_timers(p_time, true); //go through timers
+
process_tweens(p_time, true);
flush_transform_notifications();
@@ -462,37 +472,7 @@ bool SceneTree::process(double p_time) {
_flush_delete_queue();
- //go through timers
-
- List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
-
- for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
- List<Ref<SceneTreeTimer>>::Element *N = E->next();
- if (paused && !E->get()->is_process_always()) {
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- continue;
- }
-
- double time_left = E->get()->get_time_left();
- if (E->get()->is_ignore_time_scale()) {
- time_left -= Engine::get_singleton()->get_process_step();
- } else {
- time_left -= p_time;
- }
- E->get()->set_time_left(time_left);
-
- if (time_left <= 0) {
- E->get()->emit_signal(SNAME("timeout"));
- timers.erase(E);
- }
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- }
+ process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
@@ -530,6 +510,38 @@ bool SceneTree::process(double p_time) {
return _quit;
}
+void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
+ List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
+
+ for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
+ List<Ref<SceneTreeTimer>>::Element *N = E->next();
+ if ((paused && !E->get()->is_process_always()) || (E->get()->is_process_in_physics() != p_physics_frame)) {
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ continue;
+ }
+
+ double time_left = E->get()->get_time_left();
+ if (E->get()->is_ignore_time_scale()) {
+ time_left -= Engine::get_singleton()->get_process_step();
+ } else {
+ time_left -= p_delta;
+ }
+ E->get()->set_time_left(time_left);
+
+ if (time_left <= 0) {
+ E->get()->emit_signal(SNAME("timeout"));
+ timers.erase(E);
+ }
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ }
+}
+
void SceneTree::process_tweens(float p_delta, bool p_physics) {
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
@@ -710,22 +722,6 @@ float SceneTree::get_debug_paths_width() const {
return debug_paths_width;
}
-void SceneTree::set_debug_navigation_color(const Color &p_color) {
- debug_navigation_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_color() const {
- return debug_navigation_color;
-}
-
-void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) {
- debug_navigation_disabled_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_disabled_color() const {
- return debug_navigation_disabled_color;
-}
-
Ref<Material> SceneTree::get_debug_paths_material() {
if (debug_paths_material.is_valid()) {
return debug_paths_material;
@@ -743,40 +739,6 @@ Ref<Material> SceneTree::get_debug_paths_material() {
return debug_paths_material;
}
-Ref<Material> SceneTree::get_debug_navigation_material() {
- if (navigation_material.is_valid()) {
- return navigation_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_color());
-
- navigation_material = line_material;
-
- return navigation_material;
-}
-
-Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
- if (navigation_disabled_material.is_valid()) {
- return navigation_disabled_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_disabled_color());
-
- navigation_disabled_material = line_material;
-
- return navigation_disabled_material;
-}
-
Ref<Material> SceneTree::get_debug_collision_material() {
if (collision_material.is_valid()) {
return collision_material;
@@ -1126,16 +1088,16 @@ void SceneTree::_change_scene(Node *p_to) {
}
}
-Error SceneTree::change_scene(const String &p_path) {
+Error SceneTree::change_scene_to_file(const String &p_path) {
Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
if (new_scene.is_null()) {
return ERR_CANT_OPEN;
}
- return change_scene_to(new_scene);
+ return change_scene_to_packed(new_scene);
}
-Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
+Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
Node *new_scene = nullptr;
if (p_scene.is_valid()) {
new_scene = p_scene->instantiate();
@@ -1149,7 +1111,7 @@ Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
Error SceneTree::reload_current_scene() {
ERR_FAIL_COND_V(!current_scene, ERR_UNCONFIGURED);
String fname = current_scene->get_scene_file_path();
- return change_scene(fname);
+ return change_scene_to_file(fname);
}
void SceneTree::add_current_scene(Node *p_current) {
@@ -1157,11 +1119,13 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) {
+Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
Ref<SceneTreeTimer> stt;
stt.instantiate();
stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
+ stt->set_process_in_physics(p_process_in_physics);
+ stt->set_ignore_time_scale(p_ignore_time_scale);
timers.push_back(stt);
return stt;
}
@@ -1259,7 +1223,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always", "process_in_physics", "ignore_time_scale"), &SceneTree::create_timer, DEFVAL(true), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);
@@ -1296,8 +1260,8 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
- ClassDB::bind_method(D_METHOD("change_scene", "path"), &SceneTree::change_scene);
- ClassDB::bind_method(D_METHOD("change_scene_to", "packed_scene"), &SceneTree::change_scene_to);
+ ClassDB::bind_method(D_METHOD("change_scene_to_file", "path"), &SceneTree::change_scene_to_file);
+ ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed);
ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene);
@@ -1352,7 +1316,7 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
}
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
- if (p_function == "change_scene") {
+ if (p_function == "change_scene_to_file") {
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
@@ -1390,8 +1354,6 @@ SceneTree::SceneTree() {
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_paths_width = GLOBAL_DEF("debug/shapes/paths/geometry_width", 2.0);
- debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
- debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index e66363ab33..031a331a99 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -53,6 +53,7 @@ class SceneTreeTimer : public RefCounted {
double time_left = 0.0;
bool process_always = true;
+ bool process_in_physics = false;
bool ignore_time_scale = false;
protected:
@@ -65,6 +66,9 @@ public:
void set_process_always(bool p_process_always);
bool is_process_always();
+ void set_process_in_physics(bool p_process_in_physics);
+ bool is_process_in_physics();
+
void set_ignore_time_scale(bool p_ignore);
bool is_ignore_time_scale();
@@ -176,6 +180,7 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
+ void process_timers(float p_delta, bool p_physics_frame);
void process_tweens(float p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
@@ -329,15 +334,7 @@ public:
void set_debug_paths_width(float p_width);
float get_debug_paths_width() const;
- void set_debug_navigation_color(const Color &p_color);
- Color get_debug_navigation_color() const;
-
- void set_debug_navigation_disabled_color(const Color &p_color);
- Color get_debug_navigation_disabled_color() const;
-
Ref<Material> get_debug_paths_material();
- Ref<Material> get_debug_navigation_material();
- Ref<Material> get_debug_navigation_disabled_material();
Ref<Material> get_debug_collision_material();
Ref<ArrayMesh> get_debug_contact_mesh();
@@ -361,11 +358,11 @@ public:
void set_current_scene(Node *p_scene);
Node *get_current_scene() const;
- Error change_scene(const String &p_path);
- Error change_scene_to(const Ref<PackedScene> &p_scene);
+ Error change_scene_to_file(const String &p_path);
+ Error change_scene_to_packed(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
- Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true);
+ Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
Ref<Tween> create_tween();
TypedArray<Tween> get_processed_tweens();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e901f76c0a..5295de5c09 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2103,7 +2103,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
p_control->set_as_top_level(true);
p_control->set_position(gui.last_mouse_pos);
p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport.
- p_control->raise();
+ p_control->move_to_front();
gui.drag_preview_id = p_control->get_instance_id();
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 79a1c71064..04f56bb874 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -38,6 +38,7 @@
#include "scene/gui/control.h"
#include "scene/scene_string_names.h"
#include "scene/theme/theme_db.h"
+#include "scene/theme/theme_owner.h"
void Window::set_title(const String &p_title) {
title = p_title;
@@ -804,6 +805,14 @@ void Window::_notification(int p_what) {
_update_theme_item_cache();
} break;
+ case NOTIFICATION_PARENTED: {
+ theme_owner->assign_theme_on_parented(this);
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ theme_owner->clear_theme_on_unparented(this);
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
bool embedded = false;
{
@@ -856,9 +865,7 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
- // Need to defer here, because theme owner information might be set in
- // add_child_notify, which doesn't get called until right after this.
- call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ notification(NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -1289,28 +1296,29 @@ Rect2i Window::get_usable_parent_rect() const {
}
void Window::add_child_notify(Node *p_child) {
- // We propagate when this node uses a custom theme, so it can pass it on to its children.
- if (theme_owner || theme_owner_window) {
- // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
- Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true);
- }
-
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
}
}
void Window::remove_child_notify(Node *p_child) {
- // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
- if (theme_owner || theme_owner_window) {
- Control::_propagate_theme_changed(this, nullptr, nullptr, false, true);
- }
-
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
}
}
+void Window::set_theme_owner_node(Node *p_node) {
+ theme_owner->set_owner_node(p_node);
+}
+
+Node *Window::get_theme_owner_node() const {
+ return theme_owner->get_owner_node();
+}
+
+bool Window::has_theme_owner_node() const {
+ return theme_owner->has_owner_node();
+}
+
void Window::set_theme(const Ref<Theme> &p_theme) {
if (theme == p_theme) {
return;
@@ -1322,24 +1330,24 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
theme = p_theme;
if (theme.is_valid()) {
- Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true);
+ theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
return;
}
Control *parent_c = Object::cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
return;
}
Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
return;
}
- Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
+ theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Window::get_theme() const {
@@ -1348,7 +1356,7 @@ Ref<Theme> Window::get_theme() const {
void Window::_theme_changed() {
if (is_inside_tree()) {
- Control::_propagate_theme_changed(this, nullptr, this, true, false);
+ theme_owner->propagate_theme_changed(this, this, true, false);
}
}
@@ -1375,26 +1383,14 @@ StringName Window::get_theme_type_variation() const {
return theme_type_variation;
}
-void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) {
- if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(theme_type_variation) != StringName()) {
- ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
- } else {
- ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
- }
- } else {
- ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
- }
-}
-
Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) {
return theme_icon_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Texture2D> icon = Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
theme_icon_cache[p_theme_type][p_name] = icon;
return icon;
}
@@ -1405,8 +1401,8 @@ Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringN
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<StyleBox> style = Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
theme_style_cache[p_theme_type][p_name] = style;
return style;
}
@@ -1417,8 +1413,8 @@ Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Font> font = Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
theme_font_cache[p_theme_type][p_name] = font;
return font;
}
@@ -1429,8 +1425,8 @@ int Window::get_theme_font_size(const StringName &p_name, const StringName &p_th
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int font_size = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
theme_font_size_cache[p_theme_type][p_name] = font_size;
return font_size;
}
@@ -1441,8 +1437,8 @@ Color Window::get_theme_color(const StringName &p_name, const StringName &p_them
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Color color = Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
theme_color_cache[p_theme_type][p_name] = color;
return color;
}
@@ -1453,58 +1449,58 @@ int Window::get_theme_constant(const StringName &p_name, const StringName &p_the
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int constant = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
theme_constant_cache[p_theme_type][p_name] = constant;
return constant;
}
bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
float Window::get_theme_default_base_scale() const {
- return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_base_scale();
}
Ref<Font> Window::get_theme_default_font() const {
- return Control::fetch_theme_default_font(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_font();
}
int Window::get_theme_default_font_size() const {
- return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_font_size();
}
Rect2i Window::get_parent_rect() const {
@@ -1834,8 +1830,10 @@ void Window::_bind_methods() {
}
Window::Window() {
+ theme_owner = memnew(ThemeOwner);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
Window::~Window() {
+ memdelete(theme_owner);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 5a42c5bb83..8113117103 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -38,6 +38,7 @@ class Control;
class Font;
class Shortcut;
class StyleBox;
+class ThemeOwner;
class Window : public Viewport {
GDCLASS(Window, Viewport)
@@ -135,10 +136,8 @@ private:
Window *exclusive_child = nullptr;
HashSet<Window *> transient_children;
- friend class Control;
+ ThemeOwner *theme_owner = nullptr;
Ref<Theme> theme;
- Control *theme_owner = nullptr;
- Window *theme_owner_window = nullptr;
StringName theme_type_variation;
mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache;
@@ -148,8 +147,6 @@ private:
mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache;
mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache;
- _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
-
void _theme_changed();
void _invalidate_theme_cache();
@@ -271,6 +268,10 @@ public:
void popup_centered(const Size2i &p_minsize = Size2i());
void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
+ void set_theme_owner_node(Node *p_node);
+ Node *get_theme_owner_node() const;
+ bool has_theme_owner_node() const;
+
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index a9470596b2..72c57f1bfc 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -1130,6 +1130,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("StreamTexture2DArray", "CompressedTexture2DArray");
ClassDB::add_compatibility_class("StreamTexture3D", "CompressedTexture3D");
ClassDB::add_compatibility_class("StreamTextureLayered", "CompressedTextureLayered");
+ ClassDB::add_compatibility_class("VisualShaderNodeFloatUniform", "VisualShaderNodeFloatParameter");
#endif /* DISABLE_DEPRECATED */
OS::get_singleton()->yield(); // may take time to init
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 208e28f17a..869d582935 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -51,10 +51,7 @@ static const int default_corner_radius = 3;
static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
style->set_corner_radius_all(p_corner_radius);
style->set_anti_aliased(true);
@@ -93,12 +90,7 @@ static Ref<ImageTexture> generate_icon(int p_index) {
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
-
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
-
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
return style;
}
@@ -139,7 +131,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
- theme->set_stylebox("panel_fg", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
// Button
@@ -280,15 +271,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// CheckBox
Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty);
- cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_empty->set_default_margin_all(4 * scale);
Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_focus->set_default_margin_all(4 * scale);
theme->set_stylebox("normal", "CheckBox", cbx_empty);
theme->set_stylebox("pressed", "CheckBox", cbx_empty);
@@ -318,16 +303,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckBox", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckBox", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckBox", 0 * scale);
theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty);
- cb_empty->set_default_margin(SIDE_LEFT, 6 * scale);
- cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale);
- cb_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
theme->set_stylebox("normal", "CheckButton", cb_empty);
theme->set_stylebox("pressed", "CheckButton", cb_empty);
@@ -336,15 +318,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("hover_pressed", "CheckButton", cb_empty);
theme->set_stylebox("focus", "CheckButton", focus);
- theme->set_icon("on", "CheckButton", icons["toggle_on"]);
- theme->set_icon("on_disabled", "CheckButton", icons["toggle_on_disabled"]);
- theme->set_icon("off", "CheckButton", icons["toggle_off"]);
- theme->set_icon("off_disabled", "CheckButton", icons["toggle_off_disabled"]);
+ theme->set_icon("checked", "CheckButton", icons["toggle_on"]);
+ theme->set_icon("checked_disabled", "CheckButton", icons["toggle_on_disabled"]);
+ theme->set_icon("unchecked", "CheckButton", icons["toggle_off"]);
+ theme->set_icon("unchecked_disabled", "CheckButton", icons["toggle_off_disabled"]);
- theme->set_icon("on_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
- theme->set_icon("on_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
- theme->set_icon("off_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
- theme->set_icon("off_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
+ theme->set_icon("checked_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
+ theme->set_icon("checked_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
+ theme->set_icon("unchecked_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
+ theme->set_icon("unchecked_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
theme->set_font("font", "CheckButton", Ref<Font>());
theme->set_font_size("font_size", "CheckButton", -1);
@@ -358,7 +340,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckButton", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckButton", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckButton", 0 * scale);
theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -423,8 +405,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ProgressBar
- theme->set_stylebox("bg", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
- theme->set_stylebox("fg", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("background", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("fill", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
theme->set_font("font", "ProgressBar", Ref<Font>());
theme->set_font_size("font_size", "ProgressBar", -1);
@@ -588,7 +570,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxEmpty> empty;
empty.instantiate();
- theme->set_stylebox("bg", "ScrollContainer", empty);
+ theme->set_stylebox("panel", "ScrollContainer", empty);
// Window
@@ -610,9 +592,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
// AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
- theme->set_constant("margin", "AcceptDialog", 8 * scale);
- theme->set_constant("button_margin", "AcceptDialog", 32 * scale);
- theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0));
+ theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 8 * scale, 8 * scale, 8 * scale, 8 * scale));
+ theme->set_constant("buttons_separation", "AcceptDialog", 10 * scale);
// File Dialog
@@ -623,9 +604,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]);
theme->set_icon("folder", "FileDialog", icons["folder"]);
theme->set_icon("file", "FileDialog", icons["file"]);
- theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("files_disabled", "FileDialog", Color(1, 1, 1, 0.25));
+ theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25));
// Popup
@@ -640,16 +621,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine);
separator_horizontal->set_thickness(Math::round(scale));
separator_horizontal->set_color(style_separator_color);
- separator_horizontal->set_default_margin(SIDE_LEFT, default_margin);
- separator_horizontal->set_default_margin(SIDE_TOP, 0);
- separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin);
- separator_horizontal->set_default_margin(SIDE_BOTTOM, 0);
+ separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0);
Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate();
separator_vertical->set_vertical(true);
- separator_vertical->set_default_margin(SIDE_LEFT, 0);
- separator_vertical->set_default_margin(SIDE_TOP, default_margin);
- separator_vertical->set_default_margin(SIDE_RIGHT, 0);
- separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin);
+ separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin);
// Always display a border for PopupMenus so they can be distinguished from their background.
Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color);
@@ -737,8 +712,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Tree
- theme->set_stylebox("bg", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
- theme->set_stylebox("bg_focus", "Tree", focus);
+ theme->set_stylebox("panel", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
+ theme->set_stylebox("focus", "Tree", focus);
theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "Tree", focus);
@@ -791,8 +766,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ItemList
- theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color));
- theme->set_stylebox("bg_focus", "ItemList", focus);
+ theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color));
+ theme->set_stylebox("focus", "ItemList", focus);
theme->set_constant("h_separation", "ItemList", 4);
theme->set_constant("v_separation", "ItemList", 2);
theme->set_constant("icon_margin", "ItemList", 4);
@@ -1013,6 +988,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("separation", "SplitContainer", 12 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
+ theme->set_constant("minimum_grab_thickness", "SplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * scale);
theme->set_constant("autohide", "SplitContainer", 1 * scale);
theme->set_constant("autohide", "HSplitContainer", 1 * scale);
theme->set_constant("autohide", "VSplitContainer", 1 * scale);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 18df59a7aa..ebdaaaa95f 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1184,7 +1184,7 @@ void Environment::_bind_methods() {
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
// Ambient light
@@ -1420,8 +1420,8 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_fog_density", "get_fog_density");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_sky_affect", "get_fog_sky_affect");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater,suffix:m"), "set_fog_height", "get_fog_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_less,or_greater,suffix:m"), "set_fog_height", "get_fog_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_less,or_greater"), "set_fog_height_density", "get_fog_height_density");
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index 39ade85af6..0395ed0346 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -122,7 +122,7 @@ void FogMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture);
ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_lesser"), "set_density", "get_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_less"), "set_density", "get_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff");
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 6c9c8ffdba..90ea879012 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -32,7 +32,7 @@
#ifdef DEBUG_ENABLED
#include "servers/navigation_server_3d.h"
-#endif
+#endif // DEBUG_ENABLED
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND(p_mesh.is_null());
@@ -341,94 +341,8 @@ void NavigationMesh::clear_polygons() {
polygons.clear();
}
-#ifndef DISABLE_DEPRECATED
-Ref<Mesh> NavigationMesh::get_debug_mesh() {
- if (debug_mesh.is_valid()) {
- return debug_mesh;
- }
-
- Vector<Vector3> vertices = get_vertices();
- const Vector3 *vr = vertices.ptr();
- List<Face3> faces;
- for (int i = 0; i < get_polygon_count(); i++) {
- Vector<int> p = get_polygon(i);
-
- for (int j = 2; j < p.size(); j++) {
- Face3 f;
- f.vertex[0] = vr[p[0]];
- f.vertex[1] = vr[p[j - 1]];
- f.vertex[2] = vr[p[j]];
-
- faces.push_back(f);
- }
- }
-
- HashMap<_EdgeKey, bool, _EdgeKey> edge_map;
- Vector<Vector3> tmeshfaces;
- tmeshfaces.resize(faces.size() * 3);
-
- {
- Vector3 *tw = tmeshfaces.ptrw();
- int tidx = 0;
-
- for (const Face3 &f : faces) {
- for (int j = 0; j < 3; j++) {
- tw[tidx++] = f.vertex[j];
- _EdgeKey ek;
- ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- if (ek.from < ek.to) {
- SWAP(ek.from, ek.to);
- }
-
- HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek);
-
- if (F) {
- F->value = false;
-
- } else {
- edge_map[ek] = true;
- }
- }
- }
- }
- List<Vector3> lines;
-
- for (const KeyValue<_EdgeKey, bool> &E : edge_map) {
- if (E.value) {
- lines.push_back(E.key.from);
- lines.push_back(E.key.to);
- }
- }
-
- Vector<Vector3> varr;
- varr.resize(lines.size());
- {
- Vector3 *w = varr.ptrw();
- int idx = 0;
- for (const Vector3 &E : lines) {
- w[idx++] = E;
- }
- }
-
- debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
-
- if (!lines.size()) {
- return debug_mesh;
- }
-
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = varr;
-
- debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
-
- return debug_mesh;
-}
-#endif // DISABLE_DEPRECATED
-
#ifdef DEBUG_ENABLED
-Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
+Ref<ArrayMesh> NavigationMesh::get_debug_mesh() {
if (debug_mesh.is_valid()) {
// Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change.
return debug_mesh;
@@ -479,8 +393,6 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
for (int i = 0; i < polygon_count; i++) {
polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
- Vector<int> polygon = get_polygon(i);
-
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
@@ -490,7 +402,7 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
- debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material);
+ debug_mesh->surface_set_material(0, debug_geometry_face_material);
// if enabled build geometry edge line surface
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
@@ -515,12 +427,12 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
- debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_edge_material);
+ debug_mesh->surface_set_material(1, debug_geometry_edge_material);
}
return debug_mesh;
}
-#endif
+#endif // DEBUG_ENABLED
void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index c66025dc6d..5ddbd75dcb 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -202,11 +202,9 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
-#ifndef DISABLE_DEPRECATED
- Ref<Mesh> get_debug_mesh();
-#endif // DISABLE_DEPRECATED
-
- Ref<ArrayMesh> _get_debug_mesh();
+#ifdef DEBUG_ENABLED
+ Ref<ArrayMesh> get_debug_mesh();
+#endif // DEBUG_ENABLED
NavigationMesh();
};
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index ed19101de4..e51c786786 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -1684,35 +1684,35 @@ void ParticleProcessMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1741,11 +1741,11 @@ void ParticleProcessMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_GROUP("Sub Emitter", "sub_emitter_");
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 727f7a4e09..c017c90370 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -2663,9 +2663,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
vertices_ptr[p_idx] = point;
normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
if (has_depth) {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
} else {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
}
tangents_ptr[p_idx * 4 + 0] = 1.0;
tangents_ptr[p_idx * 4 + 1] = 0.0;
@@ -2680,7 +2680,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
vertices_ptr[p_idx] = point;
normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4)));
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4)));
tangents_ptr[p_idx * 4 + 0] = -1.0;
tangents_ptr[p_idx * 4 + 1] = 0.0;
tangents_ptr[p_idx * 4 + 2] = 0.0;
@@ -2721,9 +2721,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
vertices_ptr[p_idx + m] = quad_faces[m];
normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
if (m < 2) {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
} else {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
}
tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
@@ -2760,9 +2760,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
vertices_ptr[p_idx + k] = quad_faces[k];
normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
if (has_depth) {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
} else {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
}
tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 4b151eed12..cd893d8c23 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -41,6 +41,7 @@ float StyleBox::get_style_margin(Side p_side) const {
}
return 0;
}
+
bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
bool ret;
if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) {
@@ -63,6 +64,21 @@ void StyleBox::set_default_margin(Side p_side, float p_value) {
emit_changed();
}
+void StyleBox::set_default_margin_all(float p_value) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_value;
+ }
+ emit_changed();
+}
+
+void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBox::get_default_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -112,6 +128,7 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask);
ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
+ ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all);
ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);
ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
@@ -165,6 +182,21 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) {
emit_changed();
}
+void StyleBoxTexture::set_margin_size_all(float p_size) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBoxTexture::get_margin_size(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -292,11 +324,11 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size);
+ ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all);
ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxTexture::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
@@ -864,7 +896,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend);
ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend);
- ClassDB::bind_method(D_METHOD("set_corner_radius_individual", "radius_top_left", "radius_top_right", "radius_bottom_right", "radius_bottom_left"), &StyleBoxFlat::set_corner_radius_individual);
ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all);
ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
@@ -872,7 +903,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxFlat::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 88db4f5fbd..2c72446567 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -57,7 +57,10 @@ public:
virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
void set_default_margin(Side p_side, float p_value);
+ void set_default_margin_all(float p_value);
+ void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_default_margin(Side p_side) const;
+
float get_margin(Side p_side) const;
virtual Size2 get_center_size() const;
@@ -112,6 +115,8 @@ public:
float get_expand_margin_size(Side p_expand_side) const;
void set_margin_size(Side p_side, float p_size);
+ void set_margin_size_all(float p_size);
+ void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_margin_size(Side p_side) const;
void set_region_rect(const Rect2 &p_region_rect);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index a269416d8b..d53dc1a8fc 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2617,26 +2617,30 @@ void AnimatedTexture::_update_proxy() {
time += delta;
- float limit;
-
- if (fps == 0) {
- limit = 0;
- } else {
- limit = 1.0 / fps;
- }
+ float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale);
int iter_max = frame_count;
while (iter_max && !pause) {
- float frame_limit = limit + frames[current_frame].delay_sec;
+ float frame_limit = frames[current_frame].duration * speed;
if (time > frame_limit) {
- current_frame++;
+ if (speed_scale > 0.0) {
+ current_frame++;
+ } else {
+ current_frame--;
+ }
if (current_frame >= frame_count) {
- if (oneshot) {
+ if (one_shot) {
current_frame = frame_count - 1;
} else {
current_frame = 0;
}
+ } else if (current_frame < 0) {
+ if (one_shot) {
+ current_frame = 0;
+ } else {
+ current_frame = frame_count - 1;
+ }
}
time -= frame_limit;
@@ -2684,13 +2688,13 @@ bool AnimatedTexture::get_pause() const {
return pause;
}
-void AnimatedTexture::set_oneshot(bool p_oneshot) {
+void AnimatedTexture::set_one_shot(bool p_one_shot) {
RWLockWrite r(rw_lock);
- oneshot = p_oneshot;
+ one_shot = p_one_shot;
}
-bool AnimatedTexture::get_oneshot() const {
- return oneshot;
+bool AnimatedTexture::get_one_shot() const {
+ return one_shot;
}
void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) {
@@ -2710,30 +2714,30 @@ Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
return frames[p_frame].texture;
}
-void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
+void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
RWLockRead r(rw_lock);
- frames[p_frame].delay_sec = p_delay_sec;
+ frames[p_frame].duration = p_duration;
}
-float AnimatedTexture::get_frame_delay(int p_frame) const {
+float AnimatedTexture::get_frame_duration(int p_frame) const {
ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
RWLockRead r(rw_lock);
- return frames[p_frame].delay_sec;
+ return frames[p_frame].duration;
}
-void AnimatedTexture::set_fps(float p_fps) {
- ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000);
+void AnimatedTexture::set_speed_scale(float p_scale) {
+ ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
- fps = p_fps;
+ speed_scale = p_scale;
}
-float AnimatedTexture::get_fps() const {
- return fps;
+float AnimatedTexture::get_speed_scale() const {
+ return speed_scale;
}
int AnimatedTexture::get_width() const {
@@ -2809,27 +2813,27 @@ void AnimatedTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
- ClassDB::bind_method(D_METHOD("set_oneshot", "oneshot"), &AnimatedTexture::set_oneshot);
- ClassDB::bind_method(D_METHOD("get_oneshot"), &AnimatedTexture::get_oneshot);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
- ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
- ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale);
ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
- ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay);
- ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay);
+ ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration);
ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_greater,or_lesser"), "set_speed_scale", "get_speed_scale");
for (int i = 0; i < MAX_FRAMES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i);
}
BIND_CONSTANT(MAX_FRAMES);
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 430c73dbc6..da4b8046a5 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -922,15 +922,15 @@ private:
struct Frame {
Ref<Texture2D> texture;
- float delay_sec = 0.0;
+ float duration = 1.0;
};
Frame frames[MAX_FRAMES];
int frame_count = 1.0;
int current_frame = 0;
bool pause = false;
- bool oneshot = false;
- float fps = 4.0;
+ bool one_shot = false;
+ float speed_scale = 1.0;
float time = 0.0;
@@ -952,17 +952,17 @@ public:
void set_pause(bool p_pause);
bool get_pause() const;
- void set_oneshot(bool p_oneshot);
- bool get_oneshot() const;
+ void set_one_shot(bool p_one_shot);
+ bool get_one_shot() const;
void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_frame_texture(int p_frame) const;
- void set_frame_delay(int p_frame, float p_delay_sec);
- float get_frame_delay(int p_frame) const;
+ void set_frame_duration(int p_frame, float p_duration);
+ float get_frame_duration(int p_frame) const;
- void set_fps(float p_fps);
- float get_fps() const;
+ void set_speed_scale(float p_scale);
+ float get_speed_scale() const;
virtual int get_width() const override;
virtual int get_height() const override;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 70a73186bc..262dbe28ed 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3718,6 +3718,17 @@ bool VisualShaderNodeParameter::is_global_code_generated() const {
return global_code_generated;
}
+#ifndef DISABLE_DEPRECATED
+// Kept for compatibility from 3.x to 4.0.
+bool VisualShaderNodeParameter::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "uniform_name") {
+ set_parameter_name(p_value);
+ return true;
+ }
+ return false;
+}
+#endif
+
void VisualShaderNodeParameter::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameter::set_parameter_name);
ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameter::get_parameter_name);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 88e92f15cf..4116eaa196 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -519,6 +519,10 @@ protected:
static void _bind_methods();
String _get_qual_str() const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
+
public:
void set_parameter_name(const String &p_name);
String get_parameter_name() const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 72e55ac47d..de13912b75 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1636,10 +1636,14 @@ String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const
return "linear depth";
}
+bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
- code += " float _log_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n";
+ code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
code += " _depth_view.xyz /= _depth_view.w;";
@@ -6115,6 +6119,13 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shade
return code;
}
+String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
+ return code;
+}
+
String VisualShaderNodeTextureParameterTriplanar::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String id = get_parameter_name();
@@ -7194,6 +7205,10 @@ String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const {
return "amount";
}
+bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
@@ -7235,6 +7250,10 @@ String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const {
return "fade";
}
+bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index ecba412fcb..4b883c25cc 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -636,6 +636,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
@@ -2278,6 +2279,7 @@ public:
virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTextureParameterTriplanar();
@@ -2643,6 +2645,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
@@ -2662,6 +2665,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp
new file mode 100644
index 0000000000..e89aa1b28d
--- /dev/null
+++ b/scene/theme/theme_owner.cpp
@@ -0,0 +1,410 @@
+/*************************************************************************/
+/* theme_owner.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "theme_owner.h"
+
+#include "scene/gui/control.h"
+#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
+
+// Theme owner node.
+
+void ThemeOwner::set_owner_node(Node *p_node) {
+ owner_control = nullptr;
+ owner_window = nullptr;
+
+ Control *c = Object::cast_to<Control>(p_node);
+ if (c) {
+ owner_control = c;
+ return;
+ }
+
+ Window *w = Object::cast_to<Window>(p_node);
+ if (w) {
+ owner_window = w;
+ return;
+ }
+}
+
+Node *ThemeOwner::get_owner_node() const {
+ if (owner_control) {
+ return owner_control;
+ } else if (owner_window) {
+ return owner_window;
+ }
+ return nullptr;
+}
+
+bool ThemeOwner::has_owner_node() const {
+ return bool(owner_control || owner_window);
+}
+
+// Theme propagation.
+
+void ThemeOwner::assign_theme_on_parented(Node *p_for_node) {
+ // We check if there are any themes affecting the parent. If that's the case
+ // its children also need to be affected.
+ // We don't notify here because `NOTIFICATION_THEME_CHANGED` will be handled
+ // a bit later by `NOTIFICATION_ENTER_TREE`.
+
+ Node *parent = p_for_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, parent_c->get_theme_owner_node(), false, true);
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, parent_w->get_theme_owner_node(), false, true);
+ }
+ }
+}
+
+void ThemeOwner::clear_theme_on_unparented(Node *p_for_node) {
+ // We check if there were any themes affecting the parent. If that's the case
+ // its children need were also affected and need to be updated.
+ // We don't notify because we're exiting the tree, and it's not important.
+
+ Node *parent = p_for_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, nullptr, false, true);
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, nullptr, false, true);
+ }
+ }
+}
+
+void ThemeOwner::propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign) {
+ Control *c = Object::cast_to<Control>(p_to_node);
+ Window *w = c == nullptr ? Object::cast_to<Window>(p_to_node) : nullptr;
+
+ if (!c && !w) {
+ // Theme inheritance chains are broken by nodes that aren't Control or Window.
+ return;
+ }
+
+ bool assign = p_assign;
+ if (c) {
+ if (c != p_owner_node && c->get_theme().is_valid()) {
+ // Has a theme, so we don't want to change the theme owner,
+ // but we still want to propagate in case this child has theme items
+ // it inherits from the theme this node uses.
+ // See https://github.com/godotengine/godot/issues/62844.
+ assign = false;
+ }
+
+ if (assign) {
+ c->set_theme_owner_node(p_owner_node);
+ }
+
+ if (p_notify) {
+ c->notification(Control::NOTIFICATION_THEME_CHANGED);
+ }
+ } else if (w) {
+ if (w != p_owner_node && w->get_theme().is_valid()) {
+ // Same as above.
+ assign = false;
+ }
+
+ if (assign) {
+ w->set_theme_owner_node(p_owner_node);
+ }
+
+ if (p_notify) {
+ w->notification(Window::NOTIFICATION_THEME_CHANGED);
+ }
+ }
+
+ for (int i = 0; i < p_to_node->get_child_count(); i++) {
+ propagate_theme_changed(p_to_node->get_child(i), p_owner_node, p_notify, assign);
+ }
+}
+
+// Theme lookup.
+
+void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const {
+ const Control *for_c = Object::cast_to<Control>(p_for_node);
+ const Window *for_w = Object::cast_to<Window>(p_for_node);
+ ERR_FAIL_COND_MSG(!for_c && !for_w, "Only Control and Window nodes and derivatives can be polled for theming.");
+
+ Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme();
+ Ref<Theme> project_theme = ThemeDB::get_singleton()->get_project_theme();
+
+ StringName type_variation;
+ if (for_c) {
+ type_variation = for_c->get_theme_type_variation();
+ } else if (for_w) {
+ type_variation = for_w->get_theme_type_variation();
+ }
+
+ if (p_theme_type == StringName() || p_theme_type == p_for_node->get_class_name() || p_theme_type == type_variation) {
+ if (project_theme.is_valid() && project_theme->get_type_variation_base(type_variation) != StringName()) {
+ project_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
+ } else {
+ default_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
+ }
+ } else {
+ default_theme->get_type_dependencies(p_theme_type, StringName(), r_list);
+ }
+}
+
+Node *ThemeOwner::_get_next_owner_node(Node *p_from_node) const {
+ Node *parent = p_from_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c) {
+ return parent_c->get_theme_owner_node();
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ return parent_w->get_theme_owner_node();
+ }
+ }
+
+ return nullptr;
+}
+
+Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
+ for (const StringName &E : p_theme_types) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
+ return owner_theme->get_theme_item(p_data_type, p_name, E);
+ }
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E);
+ }
+ }
+ }
+
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E);
+ }
+ }
+
+ // If they don't exist, use any type to return the default/empty value.
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
+}
+
+bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
+ for (const StringName &E : p_theme_types) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+ }
+
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+float ThemeOwner::get_theme_default_base_scale() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) {
+ return owner_theme->get_default_base_scale();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
+ }
+ return ThemeDB::get_singleton()->get_fallback_base_scale();
+}
+
+Ref<Font> ThemeOwner::get_theme_default_font() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_font()) {
+ return owner_theme->get_default_font();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
+ }
+ return ThemeDB::get_singleton()->get_fallback_font();
+}
+
+int ThemeOwner::get_theme_default_font_size() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_font_size()) {
+ return owner_theme->get_default_font_size();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
+ }
+ return ThemeDB::get_singleton()->get_fallback_font_size();
+}
diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h
new file mode 100644
index 0000000000..59b72c1627
--- /dev/null
+++ b/scene/theme/theme_owner.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* theme_owner.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef THEME_OWNER_H
+#define THEME_OWNER_H
+
+#include "core/object/object.h"
+#include "scene/resources/theme.h"
+
+class Control;
+class Node;
+class Window;
+
+class ThemeOwner : public Object {
+ Control *owner_control = nullptr;
+ Window *owner_window = nullptr;
+
+ Node *_get_next_owner_node(Node *p_from_node) const;
+
+public:
+ // Theme owner node.
+
+ void set_owner_node(Node *p_node);
+ Node *get_owner_node() const;
+ bool has_owner_node() const;
+
+ // Theme propagation.
+
+ void assign_theme_on_parented(Node *p_for_node);
+ void clear_theme_on_unparented(Node *p_for_node);
+ void propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign);
+
+ // Theme lookup.
+
+ void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const;
+
+ Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+ bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+
+ float get_theme_default_base_scale();
+ Ref<Font> get_theme_default_font();
+ int get_theme_default_font_size();
+
+ ThemeOwner() {}
+ ~ThemeOwner() {}
+};
+
+#endif // THEME_OWNER_H