summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp2
-rw-r--r--scene/2d/camera_2d.cpp48
-rw-r--r--scene/2d/camera_2d.h12
-rw-r--r--scene/2d/light_2d.cpp7
-rw-r--r--scene/2d/navigation_agent_2d.cpp6
-rw-r--r--scene/2d/skeleton_2d.cpp20
-rw-r--r--scene/2d/sprite_2d.cpp6
-rw-r--r--scene/2d/tile_map.cpp192
-rw-r--r--scene/2d/tile_map.h6
-rw-r--r--scene/3d/area_3d.cpp12
-rw-r--r--scene/3d/area_3d.h7
-rw-r--r--scene/3d/audio_stream_player_3d.cpp20
-rw-r--r--scene/3d/audio_stream_player_3d.h6
-rw-r--r--scene/3d/bone_attachment_3d.cpp2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp6
-rw-r--r--scene/3d/light_3d.cpp14
-rw-r--r--scene/3d/light_3d.h1
-rw-r--r--scene/3d/lightmap_gi.cpp9
-rw-r--r--scene/3d/marker_3d.cpp19
-rw-r--r--scene/3d/marker_3d.h8
-rw-r--r--scene/3d/navigation_agent_3d.cpp4
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/node_3d.h5
-rw-r--r--scene/3d/ray_cast_3d.cpp2
-rw-r--r--scene/3d/shape_cast_3d.cpp2
-rw-r--r--scene/3d/skeleton_3d.cpp16
-rw-r--r--scene/3d/sprite_3d.cpp7
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp2
-rw-r--r--scene/3d/visual_instance_3d.cpp12
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/voxel_gi.cpp4
-rw-r--r--scene/3d/xr_nodes.cpp171
-rw-r--r--scene/3d/xr_nodes.h13
-rw-r--r--scene/animation/animation_player.cpp40
-rw-r--r--scene/animation/animation_tree.cpp45
-rw-r--r--scene/debugger/scene_debugger.cpp42
-rw-r--r--scene/debugger/scene_debugger.h13
-rw-r--r--scene/gui/base_button.cpp38
-rw-r--r--scene/gui/base_button.h4
-rw-r--r--scene/gui/code_edit.cpp67
-rw-r--r--scene/gui/code_edit.h1
-rw-r--r--scene/gui/color_mode.cpp84
-rw-r--r--scene/gui/color_picker.cpp75
-rw-r--r--scene/gui/color_picker.h2
-rw-r--r--scene/gui/control.cpp85
-rw-r--r--scene/gui/control.h14
-rw-r--r--scene/gui/graph_edit.cpp16
-rw-r--r--scene/gui/item_list.cpp22
-rw-r--r--scene/gui/label.cpp34
-rw-r--r--scene/gui/label.h1
-rw-r--r--scene/gui/line_edit.cpp38
-rw-r--r--scene/gui/line_edit.h7
-rw-r--r--scene/gui/menu_bar.cpp40
-rw-r--r--scene/gui/menu_bar.h5
-rw-r--r--scene/gui/menu_button.cpp4
-rw-r--r--scene/gui/popup.cpp38
-rw-r--r--scene/gui/popup.h1
-rw-r--r--scene/gui/popup_menu.cpp10
-rw-r--r--scene/gui/rich_text_effect.cpp6
-rw-r--r--scene/gui/rich_text_label.cpp97
-rw-r--r--scene/gui/rich_text_label.h4
-rw-r--r--scene/gui/scroll_bar.cpp14
-rw-r--r--scene/gui/slider.cpp4
-rw-r--r--scene/gui/spin_box.cpp17
-rw-r--r--scene/gui/spin_box.h3
-rw-r--r--scene/gui/text_edit.cpp237
-rw-r--r--scene/gui/text_edit.h13
-rw-r--r--scene/gui/texture_progress_bar.cpp26
-rw-r--r--scene/gui/tree.cpp17
-rw-r--r--scene/gui/view_panner.cpp4
-rw-r--r--scene/main/canvas_item.cpp59
-rw-r--r--scene/main/canvas_item.h23
-rw-r--r--scene/main/canvas_layer.cpp1
-rw-r--r--scene/main/instance_placeholder.cpp2
-rw-r--r--scene/main/multiplayer_api.cpp52
-rw-r--r--scene/main/multiplayer_peer.cpp20
-rw-r--r--scene/main/multiplayer_peer.h13
-rw-r--r--scene/main/node.cpp105
-rw-r--r--scene/main/node.h13
-rw-r--r--scene/main/scene_tree.cpp32
-rw-r--r--scene/main/viewport.cpp25
-rw-r--r--scene/main/window.cpp78
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/property_utils.cpp16
-rw-r--r--scene/resources/animation.cpp16
-rw-r--r--scene/resources/bit_map.cpp4
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp9
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/font.cpp203
-rw-r--r--scene/resources/material.cpp23
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/mesh.cpp5
-rw-r--r--scene/resources/navigation_mesh.cpp2
-rw-r--r--scene/resources/packed_scene.cpp6
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/particle_process_material.cpp46
-rw-r--r--scene/resources/particle_process_material.h5
-rw-r--r--scene/resources/primitive_meshes.cpp5
-rw-r--r--scene/resources/resource_format_text.cpp7
-rw-r--r--scene/resources/shape_2d.cpp1
-rw-r--r--scene/resources/skeleton_modification_2d.cpp4
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp2
-rw-r--r--scene/resources/style_box.cpp16
-rw-r--r--scene/resources/text_line.cpp43
-rw-r--r--scene/resources/text_paragraph.cpp86
-rw-r--r--scene/resources/texture.cpp35
-rw-r--r--scene/resources/texture.h10
-rw-r--r--scene/resources/tile_set.cpp8
-rw-r--r--scene/resources/tile_set.h3
-rw-r--r--scene/resources/visual_shader.cpp21
-rw-r--r--scene/resources/visual_shader_nodes.cpp59
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp12
116 files changed, 1891 insertions, 1014 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 85ec745aee..9ac3083718 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -477,7 +477,7 @@ void AudioStreamPlayer2D::_bind_methods() {
AudioStreamPlayer2D::AudioStreamPlayer2D() {
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed));
- cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/2d_panning_strength");
+ cached_global_panning_strength = GLOBAL_GET("audio/general/2d_panning_strength");
}
AudioStreamPlayer2D::~AudioStreamPlayer2D() {
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index aeaaaf3aec..4b31bbddac 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -155,11 +155,11 @@ Transform2D Camera2D::get_camera_transform() {
}
}
- if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
- real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
+ if (follow_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
+ real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
- //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
+ //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed;
} else {
ret_camera_pos = smoothed_camera_pos = camera_pos;
}
@@ -183,7 +183,7 @@ Transform2D Camera2D::get_camera_transform() {
Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom_scale);
- if (!smoothing_enabled || !limit_smoothing_enabled) {
+ if (!follow_smoothing_enabled || !limit_smoothing_enabled) {
if (screen_rect.position.x < limit[SIDE_LEFT]) {
screen_rect.position.x = limit[SIDE_LEFT];
}
@@ -428,7 +428,7 @@ void Camera2D::set_current(bool p_current) {
void Camera2D::_update_process_internal_for_smoothing() {
bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
- bool is_any_smoothing_valid = smoothing > 0 || rotation_smoothing_speed > 0;
+ bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor;
set_process_internal(enabled);
@@ -525,13 +525,13 @@ void Camera2D::align() {
_update_scroll();
}
-void Camera2D::set_follow_smoothing(real_t p_speed) {
- smoothing = p_speed;
+void Camera2D::set_position_smoothing_speed(real_t p_speed) {
+ position_smoothing_speed = p_speed;
_update_process_internal_for_smoothing();
}
-real_t Camera2D::get_follow_smoothing() const {
- return smoothing;
+real_t Camera2D::get_position_smoothing_speed() const {
+ return position_smoothing_speed;
}
void Camera2D::set_rotation_smoothing_speed(real_t p_speed) {
@@ -559,7 +559,7 @@ Point2 Camera2D::get_camera_screen_center() const {
Size2 Camera2D::_get_camera_screen_size() const {
// special case if the camera2D is in the root viewport
if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
- return Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
return get_viewport_rect().size;
}
@@ -607,18 +607,18 @@ real_t Camera2D::get_drag_horizontal_offset() const {
void Camera2D::_set_old_smoothing(real_t p_enable) {
//compatibility
if (p_enable > 0) {
- smoothing_enabled = true;
- set_follow_smoothing(p_enable);
+ follow_smoothing_enabled = true;
+ set_position_smoothing_speed(p_enable);
}
}
-void Camera2D::set_enable_follow_smoothing(bool p_enabled) {
- smoothing_enabled = p_enabled;
+void Camera2D::set_position_smoothing_enabled(bool p_enabled) {
+ follow_smoothing_enabled = p_enabled;
notify_property_list_changed();
}
-bool Camera2D::is_follow_smoothing_enabled() const {
- return smoothing_enabled;
+bool Camera2D::is_position_smoothing_enabled() const {
+ return follow_smoothing_enabled;
}
void Camera2D::set_custom_viewport(Node *p_viewport) {
@@ -689,7 +689,7 @@ bool Camera2D::is_margin_drawing_enabled() const {
}
void Camera2D::_validate_property(PropertyInfo &p_property) const {
- if (!smoothing_enabled && p_property.name == "smoothing_speed") {
+ if (!follow_smoothing_enabled && p_property.name == "smoothing_speed") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
if (!rotation_smoothing_enabled && p_property.name == "rotation_smoothing_speed") {
@@ -746,11 +746,11 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &Camera2D::set_custom_viewport);
ClassDB::bind_method(D_METHOD("get_custom_viewport"), &Camera2D::get_custom_viewport);
- ClassDB::bind_method(D_METHOD("set_follow_smoothing", "follow_smoothing"), &Camera2D::set_follow_smoothing);
- ClassDB::bind_method(D_METHOD("get_follow_smoothing"), &Camera2D::get_follow_smoothing);
+ ClassDB::bind_method(D_METHOD("set_position_smoothing_speed", "position_smoothing_speed"), &Camera2D::set_position_smoothing_speed);
+ ClassDB::bind_method(D_METHOD("get_position_smoothing_speed"), &Camera2D::get_position_smoothing_speed);
- ClassDB::bind_method(D_METHOD("set_enable_follow_smoothing", "follow_smoothing"), &Camera2D::set_enable_follow_smoothing);
- ClassDB::bind_method(D_METHOD("is_follow_smoothing_enabled"), &Camera2D::is_follow_smoothing_enabled);
+ ClassDB::bind_method(D_METHOD("set_position_smoothing_enabled", "position_smoothing_speed"), &Camera2D::set_position_smoothing_enabled);
+ ClassDB::bind_method(D_METHOD("is_position_smoothing_enabled"), &Camera2D::is_position_smoothing_enabled);
ClassDB::bind_method(D_METHOD("set_rotation_smoothing_enabled", "enabled"), &Camera2D::set_rotation_smoothing_enabled);
ClassDB::bind_method(D_METHOD("is_rotation_smoothing_enabled"), &Camera2D::is_rotation_smoothing_enabled);
@@ -788,9 +788,9 @@ void Camera2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_BOTTOM);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_smoothed"), "set_limit_smoothing_enabled", "is_limit_smoothing_enabled");
- ADD_GROUP("Smoothing", "smoothing_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_follow_smoothing", "get_follow_smoothing");
+ ADD_GROUP("Follow Smoothing", "follow_smoothing_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "position_smoothing_enabled"), "set_position_smoothing_enabled", "is_position_smoothing_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "position_smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_position_smoothing_speed", "get_position_smoothing_speed");
ADD_GROUP("Rotation Smoothing", "rotation_smoothing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotation_smoothing_enabled"), "set_rotation_smoothing_enabled", "is_rotation_smoothing_enabled");
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 1411175af2..ae172f47b1 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -65,8 +65,8 @@ protected:
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool ignore_rotation = true;
bool current = false;
- real_t smoothing = 5.0;
- bool smoothing_enabled = false;
+ real_t position_smoothing_speed = 5.0;
+ bool follow_smoothing_enabled = false;
real_t camera_angle = 0.0;
real_t rotation_smoothing_speed = 5.0;
@@ -140,11 +140,11 @@ public:
void set_drag_vertical_offset(real_t p_offset);
real_t get_drag_vertical_offset() const;
- void set_enable_follow_smoothing(bool p_enabled);
- bool is_follow_smoothing_enabled() const;
+ void set_position_smoothing_enabled(bool p_enabled);
+ bool is_position_smoothing_enabled() const;
- void set_follow_smoothing(real_t p_speed);
- real_t get_follow_smoothing() const;
+ void set_position_smoothing_speed(real_t p_speed);
+ real_t get_position_smoothing_speed() const;
void set_rotation_smoothing_speed(real_t p_speed);
real_t get_rotation_smoothing_speed() const;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 90402260ed..78b5199358 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -172,6 +172,7 @@ void Light2D::set_shadow_filter(ShadowFilter p_filter) {
ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX);
shadow_filter = p_filter;
RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter));
+ notify_property_list_changed();
}
Light2D::ShadowFilter Light2D::get_shadow_filter() const {
@@ -231,6 +232,10 @@ void Light2D::_validate_property(PropertyInfo &p_property) const {
if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+
+ if (shadow && p_property.name == "shadow_filter_smooth" && shadow_filter == SHADOW_FILTER_NONE) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Light2D::_bind_methods() {
@@ -454,7 +459,7 @@ void DirectionalLight2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01,suffix:px"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater,suffix:px"), "set_max_distance", "get_max_distance");
}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index f077f7f5e6..1a62c9bb6c 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -75,6 +75,7 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent2D::set_target_location);
ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location);
+
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity);
@@ -88,6 +89,7 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done);
ADD_GROUP("Pathfinding", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_path_desired_distance", "get_path_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance");
@@ -104,7 +106,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
ADD_SIGNAL(MethodInfo("navigation_finished"));
- ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+ ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity")));
}
void NavigationAgent2D::_notification(int p_what) {
@@ -478,8 +480,8 @@ void NavigationAgent2D::_request_repath() {
void NavigationAgent2D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal(SNAME("target_reached"));
target_reached = true;
+ emit_signal(SNAME("target_reached"));
}
}
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index dd016d5e92..02d8e20ce8 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -192,10 +192,8 @@ void Bone2D::_notification(int p_what) {
cache_transform = tmp_trans;
} break;
- // Bone2D Editor gizmo drawing:
-#ifndef _MSC_VER
-#warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin
-#endif
+ // Bone2D Editor gizmo drawing.
+ // TODO: Bone2D gizmo drawing needs to be moved to an editor plugin.
case NOTIFICATION_DRAW: {
// Only draw the gizmo in the editor!
if (Engine::get_singleton()->is_editor_hint() == false) {
@@ -219,11 +217,11 @@ void Bone2D::_notification(int p_what) {
editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale());
RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans);
- Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
- Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
- Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
- Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
- Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
+ Color bone_color1 = EDITOR_GET("editors/2d/bone_color1");
+ Color bone_color2 = EDITOR_GET("editors/2d/bone_color2");
+ Color bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
+ Color bone_outline_color = EDITOR_GET("editors/2d/bone_outline_color");
+ Color bone_selected_color = EDITOR_GET("editors/2d/bone_selected_color");
bool Bone2D_found = false;
for (int i = 0; i < get_child_count(); i++) {
@@ -319,8 +317,8 @@ void Bone2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
- int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
- int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
+ int bone_width = EDITOR_GET("editors/2d/bone_width");
+ int bone_outline_width = EDITOR_GET("editors/2d/bone_outline_size");
if (!is_inside_tree()) {
return false; //may have been removed
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 0ecf8333a0..0784318442 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -309,9 +309,7 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const {
q.y = 1.0f - q.y;
}
q = q * src_rect.size + src_rect.position;
-#ifndef _MSC_VER
-#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that)
-#endif
+ // TODO: This need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that).
bool is_repeat = false;
bool is_mirrored_repeat = false;
if (is_repeat) {
@@ -446,7 +444,7 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 26627a4fca..f7a66215b2 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1097,8 +1097,8 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled);
rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
rs->canvas_item_set_z_index(ci, layers[p_layer].z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
rs->canvas_item_set_light_mask(ci, get_light_mask());
}
@@ -1208,8 +1208,8 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
rs->canvas_item_set_z_as_relative_to_parent(ci, true);
rs->canvas_item_set_z_index(ci, tile_z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
q.canvas_items.push_back(ci);
@@ -1297,7 +1297,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
return;
}
- // Draw a placeholder for scenes needing one.
+ // Draw a placeholder for tiles needing one.
RenderingServer *rs = RenderingServer::get_singleton();
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
@@ -1330,9 +1330,9 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
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);
}
}
@@ -1632,13 +1632,13 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
color.push_back(debug_collision_color);
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();
+ Transform2D quadrant_to_local;
+ quadrant_to_local.set_origin(quadrant_pos);
+ Transform2D global_to_quadrant = (get_global_transform() * quadrant_to_local).affine_inverse();
for (RID body : p_quadrant->bodies) {
- Transform2D xform = Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM)) * global_transform_inv;
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, body_to_quadrant);
for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) {
const RID &shape = ps->body_get_shape(body, shape_index);
PhysicsServer2D::ShapeType type = ps->shape_get_type(shape);
@@ -1815,9 +1815,9 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
Ref<NavigationPolygon> navpoly = tile_data->get_navigation_polygon(layer_index);
@@ -1863,7 +1863,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
for (const KeyValue<Vector2i, String> &E : q.scenes) {
Node *node = get_node_or_null(E.value);
if (node) {
- node->queue_delete();
+ node->queue_free();
}
}
@@ -1911,7 +1911,7 @@ void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
Node *node = get_node_or_null(E.value);
if (node) {
- node->queue_delete();
+ node->queue_free();
}
}
@@ -1956,9 +1956,9 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
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);
}
}
@@ -2206,11 +2206,10 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
}
}
-TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) {
+TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern) {
if (!tile_set.is_valid()) {
return TileSet::TerrainsPattern();
}
-
// Returns all tiles compatible with the given constraints.
RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
@@ -2221,28 +2220,41 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
// Check the center bit constraint
TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain());
RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) {
+ continue; // Ignore a pattern that cannot keep bits without constraints unmodified.
}
// Check the surrounding bits
+ bool invalid_pattern = false;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
// Check if the bit is compatible with the constraints.
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) {
+ invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified.
+ break;
}
}
}
+ if (invalid_pattern) {
+ continue;
+ }
terrain_pattern_score[terrain_pattern] = score;
}
// Compute the minimum score
- TileSet::TerrainsPattern min_score_pattern;
+ TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
int min_score = INT32_MAX;
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
if (E.value < min_score) {
@@ -2274,7 +2286,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p
return output;
}
-RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const {
+RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
@@ -2284,8 +2296,8 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
// Build a set of dummy constraints to get the constrained points.
RBSet<TerrainConstraint> dummy_constraints;
- for (const Vector2i &E : p_cell_list) {
- for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
+ for (const Vector2i &E : p_painted) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
@@ -2342,7 +2354,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
}
// Add the centers as constraints
- for (Vector2i E_coords : p_cell_list) {
+ for (Vector2i E_coords : p_painted) {
TileData *tile_data = nullptr;
TileMapCell cell = get_cell(p_layer, E_coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
@@ -2362,7 +2374,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
return constraints;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
if (!tile_set.is_valid()) {
return HashMap<Vector2i, TileSet::TerrainsPattern>();
}
@@ -2378,7 +2390,20 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(co
const Vector2i &coords = p_to_replace[i];
// Select the best pattern for the given constraints
- TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints);
+ TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, coords);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ current_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
// Update the constraint set with the new ones
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
@@ -2492,12 +2517,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2527,10 +2552,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
// Build list and set of tiles that can be modified (painted and their surroundings)
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_path.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_path[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_path) {
// Find the adequate neighbor
@@ -2563,12 +2590,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2580,10 +2607,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
// Build list and set of tiles that can be modified (painted and their surroundings).
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_coords_array.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_coords_array[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_coords_array) {
// Find the adequate neighbor
@@ -2613,12 +2642,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
}
// Fills in the constraint list from modified tiles border.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2627,14 +2656,38 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
- Vector<Vector2i> vector_cells;
+ Vector<Vector2i> cells_vector;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_cells.size(); i++) {
- vector_cells.push_back(p_cells[i]);
- }
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ cells_vector.push_back(p_cells[i]);
+ painted_set.insert(p_cells[i]);
+ }
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -2644,13 +2697,38 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> vector_path;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_path.size(); i++) {
vector_path.push_back(p_path[i]);
+ painted_set.insert(p_path[i]);
}
+
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -3717,13 +3795,14 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) {
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
- // Set a default texture filter for the whole tilemap
+ // Set a default texture filter for the whole tilemap.
CanvasItem::set_texture_filter(p_texture_filter);
+ TextureFilter target_filter = get_texture_filter_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(p_texture_filter));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter));
_make_quadrant_dirty(F);
}
}
@@ -3732,13 +3811,14 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
- // Set a default texture repeat for the whole tilemap
+ // Set a default texture repeat for the whole tilemap.
CanvasItem::set_texture_repeat(p_texture_repeat);
+ TextureRepeat target_repeat = get_texture_repeat_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat));
_make_quadrant_dirty(F);
}
}
@@ -3976,9 +4056,5 @@ TileMap::TileMap() {
}
TileMap::~TileMap() {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
-
_clear_internals();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index d468675e91..7f3e241871 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -266,9 +266,9 @@ private:
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
// Terrains.
- TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints);
+ TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern);
RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
- RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const;
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const;
// Set and get tiles from data arrays.
void _set_tile_data(int p_layer, const Vector<int> &p_data);
@@ -352,7 +352,7 @@ public:
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
// Terrains.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index cefa9eceff..c6433e773d 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -578,11 +578,11 @@ bool Area3D::is_using_reverb_bus() const {
return use_reverb_bus;
}
-void Area3D::set_reverb_bus(const StringName &p_audio_bus) {
+void Area3D::set_reverb_bus_name(const StringName &p_audio_bus) {
reverb_bus = p_audio_bus;
}
-StringName Area3D::get_reverb_bus() const {
+StringName Area3D::get_reverb_bus_name() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
return reverb_bus;
@@ -711,8 +711,8 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
- ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area3D::set_reverb_bus);
- ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area3D::get_reverb_bus);
+ ClassDB::bind_method(D_METHOD("set_reverb_bus_name", "name"), &Area3D::set_reverb_bus_name);
+ ClassDB::bind_method(D_METHOD("get_reverb_bus_name"), &Area3D::get_reverb_bus_name);
ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area3D::set_reverb_amount);
ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area3D::get_reverb_amount);
@@ -760,8 +760,8 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
ADD_GROUP("Reverb Bus", "reverb_bus_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enabled"), "set_use_reverb_bus", "is_using_reverb_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus_name", "get_reverb_bus_name");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 0f0bcc7ce0..195f9f0d9e 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -141,13 +141,12 @@ private:
float reverb_amount = 0.0;
float reverb_uniformity = 0.0;
- void _validate_property(PropertyInfo &p_property) const;
-
void _initialize_wind();
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_gravity_space_override_mode(SpaceOverride p_mode);
@@ -216,8 +215,8 @@ public:
void set_use_reverb_bus(bool p_enable);
bool is_using_reverb_bus() const;
- void set_reverb_bus(const StringName &p_audio_bus);
- StringName get_reverb_bus() const;
+ void set_reverb_bus_name(const StringName &p_audio_bus);
+ StringName get_reverb_bus_name() const;
void set_reverb_amount(float p_amount);
float get_reverb_amount() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 21cf3bdb3b..b9d95672fe 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -231,7 +231,7 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
}
}
- att += unit_db;
+ att += volume_db;
if (att > max_db) {
att = max_db;
}
@@ -485,7 +485,7 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
}
if (area->is_using_reverb_bus()) {
- StringName reverb_bus_name = area->get_reverb_bus();
+ StringName reverb_bus_name = area->get_reverb_bus_name();
Vector<AudioFrame> reverb_vol;
_calc_reverb_vol(area, listener_area_pos, output_volume_vector, reverb_vol);
bus_volumes[reverb_bus_name] = reverb_vol;
@@ -538,12 +538,12 @@ Ref<AudioStream> AudioStreamPlayer3D::get_stream() const {
return stream;
}
-void AudioStreamPlayer3D::set_unit_db(float p_volume) {
- unit_db = p_volume;
+void AudioStreamPlayer3D::set_volume_db(float p_volume) {
+ volume_db = p_volume;
}
-float AudioStreamPlayer3D::get_unit_db() const {
- return unit_db;
+float AudioStreamPlayer3D::get_volume_db() const {
+ return volume_db;
}
void AudioStreamPlayer3D::set_unit_size(float p_volume) {
@@ -810,8 +810,8 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream);
- ClassDB::bind_method(D_METHOD("set_unit_db", "unit_db"), &AudioStreamPlayer3D::set_unit_db);
- ClassDB::bind_method(D_METHOD("get_unit_db"), &AudioStreamPlayer3D::get_unit_db);
+ ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer3D::set_volume_db);
+ ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer3D::get_volume_db);
ClassDB::bind_method(D_METHOD("set_unit_size", "unit_size"), &AudioStreamPlayer3D::set_unit_size);
ClassDB::bind_method(D_METHOD("get_unit_size"), &AudioStreamPlayer3D::get_unit_size);
@@ -878,7 +878,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Logarithmic,Disabled"), "set_attenuation_model", "get_attenuation_model");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80,suffix:dB"), "set_unit_db", "get_unit_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,80,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6,suffix:dB"), "set_max_db", "get_max_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
@@ -916,7 +916,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
velocity_tracker.instantiate();
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed));
set_disable_scale(true);
- cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/3d_panning_strength");
+ cached_global_panning_strength = GLOBAL_GET("audio/general/3d_panning_strength");
}
AudioStreamPlayer3D::~AudioStreamPlayer3D() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index ef48269544..913cc9fc00 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -71,7 +71,7 @@ private:
SafeNumeric<float> setplay{ -1.0 };
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
- float unit_db = 0.0;
+ float volume_db = 0.0;
float unit_size = 10.0;
float max_db = 3.0;
float pitch_scale = 1.0;
@@ -128,8 +128,8 @@ public:
void set_stream(Ref<AudioStream> p_stream);
Ref<AudioStream> get_stream() const;
- void set_unit_db(float p_volume);
- float get_unit_db() const;
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
void set_unit_size(float p_volume);
float get_unit_size() const;
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 7b0a6c7e3e..d8524a7392 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -91,7 +91,7 @@ bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "override_pose", PROPERTY_HINT_NONE, ""));
if (override_pose) {
- p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override, Local Pose Override, Custom Pose"));
+ p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override,Local Pose Override,Custom Pose"));
}
p_list->push_back(PropertyInfo(Variant::BOOL, "use_external_skeleton", PROPERTY_HINT_NONE, ""));
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index b3437c4810..2c5df48b75 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -490,9 +490,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
params.thickness = th;
_compute_sdf(&params);
- Ref<Image> ret;
- ret.instantiate();
- ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data);
+ Ref<Image> ret = Image::create_from_data(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data);
ret->convert(Image::FORMAT_RH); //convert to half, save space
ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function
@@ -532,7 +530,7 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 23fd091be6..198dba7811 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -165,6 +165,16 @@ AABB Light3D::get_aabb() const {
return AABB();
}
+PackedStringArray Light3D::get_configuration_warnings() const {
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
+
+ if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
+ warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
+ }
+
+ return warnings;
+}
+
void Light3D::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
RS::get_singleton()->light_set_bake_mode(light, RS::LightBakeMode(p_mode));
@@ -579,7 +589,7 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
}
PackedStringArray OmniLight3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Light3D::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
warnings.push_back(RTR("Projector texture only works with shadows active."));
@@ -609,7 +619,7 @@ OmniLight3D::OmniLight3D() :
}
PackedStringArray SpotLight3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Light3D::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
warnings.push_back(RTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 8da45bee79..84d214030b 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -147,6 +147,7 @@ public:
Color get_correlated_color() const;
virtual AABB get_aabb() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
Light3D();
~Light3D();
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 3ea1de57cd..1b5427c80d 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -145,10 +145,7 @@ Array LightmapGIData::_get_light_textures_data() const {
for (int i = 0; i < texture_count; i++) {
int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
- Ref<Image> texture_image;
- texture_image.instantiate();
-
- texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
+ Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
for (int j = 0; j < texture_slice_count; j++) {
texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
@@ -818,7 +815,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
md.albedo_on_uv2.instantiate();
- md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
+ md.albedo_on_uv2->set_data(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
}
md.emission_on_uv2 = images[RS::BAKE_CHANNEL_EMISSION];
@@ -1054,7 +1051,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
} break;
case ENVIRONMENT_MODE_CUSTOM_COLOR: {
environment_image.instantiate();
- environment_image->create(128, 64, false, Image::FORMAT_RGBAF);
+ environment_image->initialize_data(128, 64, false, Image::FORMAT_RGBAF);
Color c = environment_custom_color;
c.r *= environment_custom_energy;
c.g *= environment_custom_energy;
diff --git a/scene/3d/marker_3d.cpp b/scene/3d/marker_3d.cpp
index 3987172561..8e5998d14f 100644
--- a/scene/3d/marker_3d.cpp
+++ b/scene/3d/marker_3d.cpp
@@ -30,5 +30,24 @@
#include "marker_3d.h"
+void Marker3D::set_gizmo_extents(real_t p_extents) {
+ if (Math::is_equal_approx(gizmo_extents, p_extents)) {
+ return;
+ }
+ gizmo_extents = p_extents;
+ update_gizmos();
+}
+
+real_t Marker3D::get_gizmo_extents() const {
+ return gizmo_extents;
+}
+
+void Marker3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Marker3D::set_gizmo_extents);
+ ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Marker3D::get_gizmo_extents);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater,suffix:m"), "set_gizmo_extents", "get_gizmo_extents");
+}
+
Marker3D::Marker3D() {
}
diff --git a/scene/3d/marker_3d.h b/scene/3d/marker_3d.h
index 95caa101c5..a9bd993476 100644
--- a/scene/3d/marker_3d.h
+++ b/scene/3d/marker_3d.h
@@ -36,7 +36,15 @@
class Marker3D : public Node3D {
GDCLASS(Marker3D, Node3D);
+ real_t gizmo_extents = 0.25;
+
+protected:
+ static void _bind_methods();
+
public:
+ void set_gizmo_extents(real_t p_extents);
+ real_t get_gizmo_extents() const;
+
Marker3D();
};
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 39068fe83c..36350d251e 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -79,6 +79,7 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent3D::set_target_location);
ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent3D::get_target_location);
+
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity);
@@ -92,6 +93,7 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done);
ADD_GROUP("Pathfinding", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_path_desired_distance", "get_path_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset");
@@ -495,8 +497,8 @@ void NavigationAgent3D::_request_repath() {
void NavigationAgent3D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal(SNAME("target_reached"));
target_reached = true;
+ emit_signal(SNAME("target_reached"));
}
}
}
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 5f515acead..1743fa1838 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -253,9 +253,7 @@ Vector3 Node3D::get_global_rotation() const {
void Node3D::set_global_rotation(const Vector3 &p_euler_rad) {
Transform3D transform = get_global_transform();
- Basis new_basis = transform.get_basis();
- new_basis.set_euler(p_euler_rad);
- transform.set_basis(new_basis);
+ transform.basis = Basis::from_euler(p_euler_rad);
set_global_transform(transform);
}
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 90c7bc89ef..457f634c34 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -71,8 +71,8 @@ public:
};
private:
- // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale.
- // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
+ // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale.
+ // Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
// Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users
// editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support
// "redundant" rotations for animation interpolation, like going from 0 to 720 degrees).
@@ -96,6 +96,7 @@ private:
mutable SelfList<Node> xform_change;
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
mutable Transform3D global_transform;
mutable Transform3D local_transform;
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index a45ef52452..45ff0a4b45 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -516,7 +516,7 @@ void RayCast3D::_clear_debug_shape() {
MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
if (mi->is_inside_tree()) {
- mi->queue_delete();
+ mi->queue_free();
} else {
memdelete(mi);
}
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index e7d1a8ec7d..03cbd984cd 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -619,7 +619,7 @@ void ShapeCast3D::_clear_debug_shape() {
MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
if (mi->is_inside_tree()) {
- mi->queue_delete();
+ mi->queue_free();
} else {
memdelete(mi);
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 85b2c5154b..a1f962c690 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -888,10 +888,14 @@ void _pb_start_simulation(const Skeleton3D *p_skeleton, Node *p_node, const Vect
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
- for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
- if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
- pb->set_simulate_physics(true);
- break;
+ if (p_sim_bones.is_empty()) { // If no bones is specified, activate ragdoll on full body.
+ pb->set_simulate_physics(true);
+ } else {
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ pb->set_simulate_physics(true);
+ break;
+ }
}
}
}
@@ -901,9 +905,7 @@ void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName>
set_physics_process_internal(false);
Vector<int> sim_bones;
- if (p_bones.size() <= 0) {
- sim_bones.push_back(0); // If no bones is specified, activate ragdoll on full body.
- } else {
+ if (p_bones.size() > 0) {
sim_bones.resize(p_bones.size());
int c = 0;
for (int i = sim_bones.size() - 1; 0 <= i; --i) {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index cc69a1cc51..d69953fee5 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -680,6 +680,7 @@ void Sprite3D::set_region_enabled(bool p_region) {
region = p_region;
_queue_redraw();
+ notify_property_list_changed();
}
bool Sprite3D::is_region_enabled() const {
@@ -781,6 +782,10 @@ void Sprite3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "frame_coords") {
p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (!region && (p_property.name == "region_rect")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Sprite3D::_bind_methods() {
@@ -810,7 +815,7 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
index 2013a93e26..6d4c18a69e 100644
--- a/scene/3d/visible_on_screen_notifier_3d.cpp
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -189,7 +189,7 @@ void VisibleOnScreenEnabler3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler3D::get_enable_node_path);
ADD_GROUP("Enabling", "enable_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,When Paused"), "set_enable_mode", "get_enable_mode");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index e93ad5ecbf..8f5a51eff6 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -34,14 +34,8 @@
AABB VisualInstance3D::get_aabb() const {
AABB ret;
- if (GDVIRTUAL_CALL(_get_aabb, ret)) {
- return ret;
- }
- return AABB();
-}
-
-AABB VisualInstance3D::get_transformed_aabb() const {
- return get_global_transform().xform(get_aabb());
+ GDVIRTUAL_CALL(_get_aabb, ret);
+ return ret;
}
void VisualInstance3D::_update_visibility() {
@@ -121,8 +115,6 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
- ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
-
GDVIRTUAL_BIND(_get_aabb);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 4755545516..06a8c05faa 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -60,8 +60,6 @@ public:
RID get_instance() const;
virtual AABB get_aabb() const;
- virtual AABB get_transformed_aabb() const; // helper
-
void set_base(const RID &p_base);
RID get_base() const;
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index 3dba0221bb..7caf2f4874 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -77,9 +77,7 @@ Dictionary VoxelGIData::_get_data() const {
d["octree_cells"] = get_octree_cells();
d["octree_data"] = get_data_cells();
if (otsize != Vector3i()) {
- Ref<Image> img;
- img.instantiate();
- img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
+ Ref<Image> img = Image::create_from_data(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
Vector<uint8_t> df_png = img->save_png_to_buffer();
ERR_FAIL_COND_V(df_png.size() == 0, Dictionary());
d["octree_df_png"] = df_png;
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 4401d22f30..f5d30c584f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -36,49 +36,37 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
-void XRCamera3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- // need to find our XROrigin3D parent and let it know we're its camera!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin != nullptr) {
- origin->set_tracked_camera(this);
- }
- } break;
+void XRCamera3D::_bind_tracker() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
- case NOTIFICATION_EXIT_TREE: {
- // need to find our XROrigin3D parent and let it know we're no longer its camera!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin != nullptr && origin->get_tracked_camera() == this) {
- origin->set_tracked_camera(nullptr);
- }
- } break;
+ tracker = xr_server->get_tracker(tracker_name);
+ if (tracker.is_valid()) {
+ tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+
+ Ref<XRPose> pose = tracker->get_pose(pose_name);
+ if (pose.is_valid()) {
+ set_transform(pose->get_adjusted_transform());
+ }
}
}
+void XRCamera3D::_unbind_tracker() {
+ if (tracker.is_valid()) {
+ tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+ }
+ tracker.unref();
+}
+
void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
-
- tracker = xr_server->get_tracker(p_tracker_name);
- if (tracker.is_valid()) {
- tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
-
- Ref<XRPose> pose = tracker->get_pose(pose_name);
- if (pose.is_valid()) {
- set_transform(pose->get_adjusted_transform());
- }
- }
+ _bind_tracker();
}
}
void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
- if (tracker.is_valid()) {
- tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
- }
- tracker.unref();
+ _unbind_tracker();
}
}
@@ -213,6 +201,9 @@ XRCamera3D::XRCamera3D() {
xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
+
+ // check if our tracker already exists and if so, bind it...
+ _bind_tracker();
}
XRCamera3D::~XRCamera3D() {
@@ -372,7 +363,7 @@ void XRNode3D::_unbind_tracker() {
}
void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// just in case unref our current tracker
_unbind_tracker();
@@ -382,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t
}
void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// unref our tracker, it's no longer available
_unbind_tracker();
}
@@ -582,11 +573,22 @@ Plane XRAnchor3D::get_plane() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
+Vector<XROrigin3D *> XROrigin3D::origin_nodes;
+
PackedStringArray XROrigin3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
- if (tracked_camera == nullptr) {
+ bool has_camera = false;
+ for (int i = 0; !has_camera && i < get_child_count(); i++) {
+ XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_child(i));
+ if (camera) {
+ // found it!
+ has_camera = true;
+ }
+ }
+
+ if (!has_camera) {
warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node."));
}
}
@@ -603,14 +605,10 @@ void XROrigin3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
-}
-void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
- tracked_camera = p_tracked_camera;
-}
-
-XRCamera3D *XROrigin3D::get_tracked_camera() const {
- return tracked_camera;
+ ClassDB::bind_method(D_METHOD("set_current", "enabled"), &XROrigin3D::set_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &XROrigin3D::is_current);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
}
real_t XROrigin3D::get_world_scale() const {
@@ -629,6 +627,44 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) {
xr_server->set_world_scale(p_world_scale);
}
+void XROrigin3D::set_current(bool p_enabled) {
+ current = p_enabled;
+
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ // Notify us of any transform changes
+ set_notify_local_transform(current);
+ set_notify_transform(current);
+
+ if (current) {
+ for (int i = 0; i < origin_nodes.size(); i++) {
+ if (origin_nodes[i] != this) {
+ origin_nodes[i]->set_current(false);
+ }
+ }
+ } else {
+ bool found = false;
+ // We no longer have a current origin so find the first one we can make current
+ for (int i = 0; !found && i < origin_nodes.size(); i++) {
+ if (origin_nodes[i] != this) {
+ origin_nodes[i]->set_current(true);
+ found = true;
+ }
+ }
+ }
+}
+
+bool XROrigin3D::is_current() const {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // return as is
+ return current;
+ } else {
+ return current && is_inside_tree();
+ }
+}
+
void XROrigin3D::_notification(int p_what) {
// get our XRServer
XRServer *xr_server = XRServer::get_singleton();
@@ -636,34 +672,47 @@ void XROrigin3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ if (origin_nodes.is_empty()) {
+ // first entry always becomes current
+ current = true;
+ }
+
+ origin_nodes.push_back(this);
+
+ if (current) {
+ // set this again so we do whatever setup is needed.
+ set_current(true);
+ }
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- } break;
-
- case NOTIFICATION_INTERNAL_PROCESS: {
- // set our world origin to our node transform
- xr_server->set_world_origin(get_global_transform());
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ origin_nodes.erase(this);
- // check if we have a primary interface
- Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
- if (xr_interface.is_valid() && tracked_camera != nullptr) {
- // get our positioning transform for our headset
- Transform3D t = xr_interface->get_camera_transform();
+ if (current) {
+ // We are no longer current
+ set_current(false);
+ }
+ }
+ } break;
- // now apply this to our camera
- tracked_camera->set_transform(t);
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED:
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (current && !Engine::get_singleton()->is_editor_hint()) {
+ xr_server->set_world_origin(get_global_transform());
}
} break;
}
- // send our notification to all active XE interfaces, they may need to react to it also
- for (int i = 0; i < xr_server->get_interface_count(); i++) {
- Ref<XRInterface> interface = xr_server->get_interface(i);
- if (interface.is_valid() && interface->is_initialized()) {
- interface->notification(p_what);
+ if (current) {
+ // send our notification to all active XE interfaces, they may need to react to it also
+ for (int i = 0; i < xr_server->get_interface_count(); i++) {
+ Ref<XRInterface> interface = xr_server->get_interface(i);
+ if (interface.is_valid() && interface->is_initialized()) {
+ interface->notification(p_what);
+ }
}
}
}
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index ef846cc3a3..990fb61983 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -48,8 +48,8 @@ protected:
StringName pose_name = "default";
Ref<XRPositionalTracker> tracker;
- void _notification(int p_what);
-
+ void _bind_tracker();
+ void _unbind_tracker();
void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
void _pose_changed(const Ref<XRPose> &p_pose);
@@ -180,7 +180,8 @@ class XROrigin3D : public Node3D {
GDCLASS(XROrigin3D, Node3D);
private:
- XRCamera3D *tracked_camera = nullptr;
+ bool current = false;
+ static Vector<XROrigin3D *> origin_nodes; // all origin nodes in tree
protected:
void _notification(int p_what);
@@ -189,12 +190,12 @@ protected:
public:
PackedStringArray get_configuration_warnings() const override;
- void set_tracked_camera(XRCamera3D *p_tracked_camera);
- XRCamera3D *get_tracked_camera() const;
-
real_t get_world_scale() const;
void set_world_scale(real_t p_world_scale);
+ void set_current(bool p_enabled);
+ bool is_current() const;
+
XROrigin3D() {}
~XROrigin3D() {}
};
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index fe67c0886f..59930a3fbb 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -109,7 +109,7 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
Ref<AnimationLibrary> lib = d[lib_name];
add_animation_library(lib_name, lib);
}
-
+ emit_signal("animation_libraries_updated");
} else if (name.begins_with("next/")) {
String which = name.get_slicec('/', 1);
animation_set_next(which, p_value);
@@ -1274,6 +1274,23 @@ void AnimationPlayer::_animation_set_cache_update() {
}
void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
+ {
+ int at_pos = -1;
+
+ for (uint32_t i = 0; i < animation_libraries.size(); i++) {
+ if (animation_libraries[i].name == p_library) {
+ at_pos = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(at_pos == -1);
+
+ ERR_FAIL_COND(!animation_libraries[at_pos].library->animations.has(p_name));
+
+ _ref_anim(animation_libraries[at_pos].library->animations[p_name]);
+ }
+
_animation_set_cache_update();
}
@@ -1283,6 +1300,12 @@ void AnimationPlayer::_animation_removed(const StringName &p_name, const StringN
if (!animation_set.has(name)) {
return; // No need to update because not the one from the library being used.
}
+
+ AnimationData animation_data = animation_set[name];
+ if (animation_data.animation_library == p_library) {
+ _unref_anim(animation_data.animation);
+ }
+
_animation_set_cache_update();
// Erase blends if needed
@@ -1376,9 +1399,13 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref
animation_libraries.insert(insert_pos, ald);
ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name));
- ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name));
+ ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_name));
ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_name));
+ for (const KeyValue<StringName, Ref<Animation>> &K : ald.library->animations) {
+ _ref_anim(K.value);
+ }
+
_animation_set_cache_update();
notify_property_list_changed();
@@ -1399,7 +1426,7 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) {
ERR_FAIL_COND(at_pos == -1);
animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
- animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added));
+ animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
stop();
@@ -1438,11 +1465,11 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S
animation_libraries[i].name = p_new_name;
// rename connections
animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
- animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added));
+ animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
- animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
+ animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name));
animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name));
for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) {
@@ -2039,7 +2066,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
// Forcing the use of the original root because the scene where original player belongs may be not the active one
Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(get_node(get_root()));
aux_player->seek(0.0f, true);
- aux_player->queue_delete();
+ aux_player->queue_free();
if (p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
@@ -2151,6 +2178,7 @@ void AnimationPlayer::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_list_changed"));
+ ADD_SIGNAL(MethodInfo("animation_libraries_updated"));
ADD_SIGNAL(MethodInfo("caches_cleared"));
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 4d09fa619c..517908077d 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -50,10 +50,8 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
Variant ret;
- if (GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret)) {
- return ret;
- }
- return Variant();
+ GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret);
+ return ret;
}
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
@@ -312,12 +310,9 @@ String AnimationNode::get_input_name(int p_input) {
}
String AnimationNode::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_caption, ret)) {
- return ret;
- }
-
- return "Node";
+ String ret = "Node";
+ GDVIRTUAL_CALL(_get_caption, ret);
+ return ret;
}
void AnimationNode::add_input(const String &p_name) {
@@ -344,12 +339,9 @@ void AnimationNode::remove_input(int p_index) {
}
double AnimationNode::process(double p_time, bool p_seek, bool p_seek_root) {
- double ret;
- if (GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret)) {
- return ret;
- }
-
- return 0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret);
+ return ret;
}
void AnimationNode::set_filter_path(const NodePath &p_path, bool p_enable) {
@@ -373,12 +365,9 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
}
bool AnimationNode::has_filter() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_filter, ret)) {
- return ret;
- }
-
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_has_filter, ret);
+ return ret;
}
Array AnimationNode::_get_filters() const {
@@ -407,10 +396,8 @@ void AnimationNode::_validate_property(PropertyInfo &p_property) const {
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
Ref<AnimationNode> ret;
- if (GDVIRTUAL_CALL(_get_child_by_name, p_name, ret)) {
- return ret;
- }
- return Ref<AnimationNode>();
+ GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);
+ return ret;
}
void AnimationNode::_bind_methods() {
@@ -1565,11 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
real_t db = Math::linear_to_db(MAX(blend, 0.00001));
- if (t->object->has_method(SNAME("set_unit_db"))) {
- t->object->call(SNAME("set_unit_db"), db);
- } else {
- t->object->call(SNAME("set_volume_db"), db);
- }
+ t->object->call(SNAME("set_volume_db"), db);
} break;
case Animation::TYPE_ANIMATION: {
if (blend < CMP_EPSILON) {
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index bfc3c25fe6..b4bdda9ecb 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -548,14 +548,36 @@ SceneDebuggerTree::SceneDebuggerTree(Node *p_root) {
// Flatten tree into list, depth first, use stack to avoid recursion.
List<Node *> stack;
stack.push_back(p_root);
+ bool is_root = true;
+ const StringName &is_visible_sn = SNAME("is_visible");
+ const StringName &is_visible_in_tree_sn = SNAME("is_visible_in_tree");
while (stack.size()) {
Node *n = stack[0];
stack.pop_front();
+
int count = n->get_child_count();
- nodes.push_back(RemoteNode(count, n->get_name(), n->get_class(), n->get_instance_id()));
for (int i = 0; i < count; i++) {
stack.push_front(n->get_child(count - i - 1));
}
+
+ int view_flags = 0;
+ if (is_root) {
+ // Prevent root window visibility from being changed.
+ is_root = false;
+ } else if (n->has_method(is_visible_sn)) {
+ const Variant visible = n->call(is_visible_sn);
+ if (visible.get_type() == Variant::BOOL) {
+ view_flags = RemoteNode::VIEW_HAS_VISIBLE_METHOD;
+ view_flags |= uint8_t(visible) * RemoteNode::VIEW_VISIBLE;
+ }
+ if (n->has_method(is_visible_in_tree_sn)) {
+ const Variant visible_in_tree = n->call(is_visible_in_tree_sn);
+ if (visible_in_tree.get_type() == Variant::BOOL) {
+ view_flags |= uint8_t(visible_in_tree) * RemoteNode::VIEW_VISIBLE_IN_TREE;
+ }
+ }
+ }
+ nodes.push_back(RemoteNode(count, n->get_name(), n->get_class(), n->get_instance_id(), n->get_scene_file_path(), view_flags));
}
}
@@ -565,19 +587,23 @@ void SceneDebuggerTree::serialize(Array &p_arr) {
p_arr.push_back(n.name);
p_arr.push_back(n.type_name);
p_arr.push_back(n.id);
+ p_arr.push_back(n.scene_file_path);
+ p_arr.push_back(n.view_flags);
}
}
void SceneDebuggerTree::deserialize(const Array &p_arr) {
int idx = 0;
while (p_arr.size() > idx) {
- ERR_FAIL_COND(p_arr.size() < 4);
- CHECK_TYPE(p_arr[idx], INT);
- CHECK_TYPE(p_arr[idx + 1], STRING);
- CHECK_TYPE(p_arr[idx + 2], STRING);
- CHECK_TYPE(p_arr[idx + 3], INT);
- nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3]));
- idx += 4;
+ ERR_FAIL_COND(p_arr.size() < 6);
+ CHECK_TYPE(p_arr[idx], INT); // child_count.
+ CHECK_TYPE(p_arr[idx + 1], STRING); // name.
+ CHECK_TYPE(p_arr[idx + 2], STRING); // type_name.
+ CHECK_TYPE(p_arr[idx + 3], INT); // id.
+ CHECK_TYPE(p_arr[idx + 4], STRING); // scene_file_path.
+ CHECK_TYPE(p_arr[idx + 5], INT); // view_flags.
+ nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5]));
+ idx += 6;
}
}
diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h
index 911363f45d..fe35446aae 100644
--- a/scene/debugger/scene_debugger.h
+++ b/scene/debugger/scene_debugger.h
@@ -110,12 +110,23 @@ public:
String name;
String type_name;
ObjectID id;
+ String scene_file_path;
+ uint8_t view_flags = 0;
- RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id) {
+ enum ViewFlags {
+ VIEW_HAS_VISIBLE_METHOD = 1 << 1,
+ VIEW_VISIBLE = 1 << 2,
+ VIEW_VISIBLE_IN_TREE = 1 << 3,
+ };
+
+ RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id, const String p_scene_file_path, int p_view_flags) {
child_count = p_child;
name = p_name;
type_name = p_type;
id = p_id;
+
+ scene_file_path = p_scene_file_path;
+ view_flags = p_view_flags;
}
RemoteNode() {}
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index af6a99ca62..552345e4fe 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -60,7 +60,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mouse_button = p_event;
- bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo();
+ bool ui_accept = p_event->is_action("ui_accept", true) && !p_event->is_echo();
bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE;
if (button_masked || ui_accept) {
@@ -349,10 +349,6 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) {
on_action_event(p_event);
accept_event();
@@ -389,34 +385,6 @@ Ref<ButtonGroup> BaseButton::get_button_group() const {
return button_group;
}
-void BaseButton::set_shortcut_context(Node *p_node) {
- if (p_node != nullptr) {
- shortcut_context = p_node->get_instance_id();
- } else {
- shortcut_context = ObjectID();
- }
-}
-
-Node *BaseButton::get_shortcut_context() const {
- Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
- Node *ctx_node = Object::cast_to<Node>(ctx_obj);
-
- return ctx_node;
-}
-
-bool BaseButton::_is_focus_owner_in_shortcut_context() const {
- if (shortcut_context == ObjectID()) {
- // No context, therefore global - always "in" context.
- return true;
- }
-
- Node *ctx_node = get_shortcut_context();
- Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
-
- // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
- return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
-}
-
bool BaseButton::_was_pressed_by_mouse() const {
return was_mouse_pressed;
}
@@ -446,9 +414,6 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group);
ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group);
- ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context);
- ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context);
-
GDVIRTUAL_BIND(_pressed);
GDVIRTUAL_BIND(_toggled, "button_pressed");
@@ -466,7 +431,6 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
BIND_ENUM_CONSTANT(DRAW_PRESSED);
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index c83b08aadf..7839239800 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -81,7 +81,6 @@ protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
- bool _is_focus_owner_in_shortcut_context() const;
bool _was_pressed_by_mouse() const;
GDVIRTUAL0(_pressed)
@@ -132,9 +131,6 @@ public:
void set_button_group(const Ref<ButtonGroup> &p_group);
Ref<ButtonGroup> get_button_group() const;
- void set_shortcut_context(Node *p_node);
- Node *get_shortcut_context() const;
-
BaseButton();
~BaseButton();
};
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 70707dba11..5f8f25154c 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -138,7 +138,7 @@ void CodeEdit::_notification(int p_what) {
code_completion_scroll_rect.position = code_completion_rect.position + Vector2(code_completion_rect.size.width, 0);
code_completion_scroll_rect.size = Vector2(scroll_width, code_completion_rect.size.height);
- code_completion_line_ofs = CLAMP(code_completion_current_selected - lines / 2, 0, code_completion_options_count - lines);
+ code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines);
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), code_completion_selected_color);
for (int i = 0; i < lines; i++) {
@@ -281,16 +281,22 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
case MouseButton::WHEEL_UP: {
if (code_completion_current_selected > 0) {
code_completion_current_selected--;
+ code_completion_force_item_center = -1;
queue_redraw();
}
} break;
case MouseButton::WHEEL_DOWN: {
if (code_completion_current_selected < code_completion_options.size() - 1) {
code_completion_current_selected++;
+ code_completion_force_item_center = -1;
queue_redraw();
}
} break;
case MouseButton::LEFT: {
+ if (code_completion_force_item_center == -1) {
+ code_completion_force_item_center = code_completion_current_selected;
+ }
+
code_completion_current_selected = CLAMP(code_completion_line_ofs + (mb->get_position().y - code_completion_rect.position.y) / get_line_height(), 0, code_completion_options.size() - 1);
if (mb->is_double_click()) {
confirm_code_completion();
@@ -300,6 +306,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
default:
break;
}
+
return;
} else if (code_completion_active && code_completion_scroll_rect.has_point(mb->get_position())) {
if (mb->get_button_index() != MouseButton::LEFT) {
@@ -448,6 +455,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = code_completion_options.size() - 1;
}
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
@@ -458,30 +466,35 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = 0;
}
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_up", true)) {
code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines);
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_down", true)) {
code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_home", true)) {
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_end", true)) {
code_completion_current_selected = code_completion_options.size() - 1;
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
@@ -1248,37 +1261,41 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
}
void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
- bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
-
if (draw_breakpoints && breakpoint_icon.is_valid()) {
- bool hovering = p_region.has_point(get_local_mouse_pos());
bool breakpointed = is_line_breakpointed(p_line);
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
+
+ Color use_color = breakpoint_color;
+ if (hovering && !shift_pressed) {
+ use_color = breakpointed ? use_color.lightened(0.3) : use_color.darkened(0.5);
+ }
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
-
- // Darken icon when hovering, shift not pressed & not yet breakpointed.
- Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color;
breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
if (draw_bookmarks && bookmark_icon.is_valid()) {
- bool hovering = p_region.has_point(get_local_mouse_pos());
bool bookmarked = is_line_bookmarked(p_line);
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
int horizontal_padding = p_region.size.x / 2;
int vertical_padding = p_region.size.y / 4;
+
+ Color use_color = bookmark_color;
+ if (hovering && shift_pressed) {
+ use_color = bookmarked ? use_color.lightened(0.3) : use_color.darkened(0.5);
+ }
Rect2 icon_region = p_region;
icon_region.position += Point2(horizontal_padding, 0);
icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
-
- // Darken icon when hovering, shift pressed & not yet bookmarked.
- Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color;
bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
@@ -1287,10 +1304,10 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
int horizontal_padding = p_region.size.x / 10;
int vertical_padding = p_region.size.y / 4;
- Rect2 executing_line_region = p_region;
- executing_line_region.position += Point2(horizontal_padding, vertical_padding);
- executing_line_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- executing_line_icon->draw_rect(get_canvas_item(), executing_line_region, false, executing_line_color);
+ Rect2 icon_region = p_region;
+ icon_region.position += Point2(horizontal_padding, vertical_padding);
+ icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
+ executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, executing_line_color);
}
}
@@ -1974,6 +1991,7 @@ void CodeEdit::set_code_completion_selected_index(int p_index) {
}
ERR_FAIL_INDEX(p_index, code_completion_options.size());
code_completion_current_selected = p_index;
+ code_completion_force_item_center = -1;
queue_redraw();
}
@@ -2804,6 +2822,7 @@ void CodeEdit::_update_scroll_selected_line(float p_mouse_y) {
percent = CLAMP(percent, 0.0f, 1.0f);
code_completion_current_selected = (int)(percent * (code_completion_options.size() - 1));
+ code_completion_force_item_center = -1;
}
void CodeEdit::_filter_code_completion_candidates_impl() {
@@ -2855,12 +2874,15 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
offset = line_height;
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
code_completion_options.push_back(option);
}
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
return;
@@ -2966,7 +2988,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (string_to_complete.length() == 0) {
code_completion_options.push_back(option);
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
continue;
}
@@ -3072,7 +3096,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_matches);
completion_options_subseq.push_back(option);
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
} else if (!*ssq_lower) { // Matched the whole subsequence in s_lower.
option.matches.clear();
@@ -3089,7 +3115,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_lower_matches);
completion_options_subseq_casei.push_back(option);
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
}
}
@@ -3111,6 +3139,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
}
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 09c7ef80bf..cbbc13480e 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -214,6 +214,7 @@ private:
Vector<ScriptLanguage::CodeCompletionOption> code_completion_options;
int code_completion_line_ofs = 0;
int code_completion_current_selected = 0;
+ int code_completion_force_item_center = -1;
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
Rect2i code_completion_scroll_rect;
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index 3a5013dabe..a063cd344a 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -284,46 +284,68 @@ Color ColorModeOKHSL::get_color() const {
}
void ColorModeOKHSL::slider_draw(int p_which) {
- Vector<Vector2> pos;
- pos.resize(4);
- Vector<Color> col;
- col.resize(4);
HSlider *slider = color_picker->get_slider(p_which);
Size2 size = slider->get_size();
- Color left_color;
- Color right_color;
- Color color = color_picker->get_pick_color();
const real_t margin = 16 * color_picker->get_theme_default_base_scale();
- if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
-
- left_color = color;
- left_color.a = 0;
- right_color = color;
- right_color.a = 1;
- } else if (p_which == 0) {
+ if (p_which == 0) { // H
Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
slider->draw_texture_rect(hue, Rect2(Vector2(margin * -1, 0), Vector2(margin, size.x)), false);
return;
- } else {
- Color s_col;
- Color v_col;
- s_col.set_ok_hsl(color.get_h(), 0, color.get_v());
- left_color = (p_which == 1) ? s_col : Color(0, 0, 0);
- s_col.set_ok_hsl(color.get_h(), 1, color.get_v());
- v_col.set_ok_hsl(color.get_h(), color.get_s(), 1);
- right_color = (p_which == 1) ? s_col : v_col;
}
- col.set(0, left_color);
- col.set(1, right_color);
- col.set(2, right_color);
- col.set(3, left_color);
- pos.set(0, Vector2(0, 0));
- pos.set(1, Vector2(size.x, 0));
- pos.set(2, Vector2(size.x, margin));
- pos.set(3, Vector2(0, margin));
+
+ Vector<Vector2> pos;
+ Vector<Color> col;
+ Color left_color;
+ Color right_color;
+ Color color = color_picker->get_pick_color();
+
+ if (p_which == 2) { // L
+ pos.resize(6);
+ col.resize(6);
+ left_color = Color(0, 0, 0);
+ Color middle_color;
+ middle_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 0.5);
+ right_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 1);
+
+ col.set(0, left_color);
+ col.set(1, middle_color);
+ col.set(2, right_color);
+ col.set(3, right_color);
+ col.set(4, middle_color);
+ col.set(5, left_color);
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x * 0.5, 0));
+ pos.set(2, Vector2(size.x, 0));
+ pos.set(3, Vector2(size.x, margin));
+ pos.set(4, Vector2(size.x * 0.5, margin));
+ pos.set(5, Vector2(0, margin));
+ } else { // A / S
+ pos.resize(4);
+ col.resize(4);
+
+ if (p_which == ColorPicker::SLIDER_COUNT) {
+ slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+
+ left_color = color;
+ left_color.a = 0;
+ right_color = color;
+ right_color.a = 1;
+ } else {
+ left_color.set_ok_hsl(color.get_ok_hsl_h(), 0, color.get_ok_hsl_l());
+ right_color.set_ok_hsl(color.get_ok_hsl_h(), 1, color.get_ok_hsl_l());
+ }
+
+ col.set(0, left_color);
+ col.set(1, right_color);
+ col.set(2, right_color);
+ col.set(3, left_color);
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x, 0));
+ pos.set(2, Vector2(size.x, margin));
+ pos.set(3, Vector2(0, margin));
+ }
slider->draw_polygon(pos, col);
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index f1e18640e6..1b87c1d709 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -368,11 +368,10 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
SpinBox *val = memnew(SpinBox);
slider->share(val);
+ val->set_select_all_on_focus(true);
gc->add_child(val);
LineEdit *vle = val->get_line_edit();
- vle->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter), CONNECT_DEFERRED);
- vle->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit));
vle->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
vle->connect("gui_input", callable_mp(this, &ColorPicker::_line_edit_input));
vle->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
@@ -744,7 +743,7 @@ void ColorPicker::add_recent_preset(const Color &p_color) {
if (recent_preset_hbc->get_child_count() >= PRESET_COLUMN_COUNT) {
recent_preset_cache.pop_front();
recent_presets.pop_front();
- recent_preset_hbc->get_child(PRESET_COLUMN_COUNT - 1)->queue_delete();
+ recent_preset_hbc->get_child(PRESET_COLUMN_COUNT - 1)->queue_free();
}
recent_presets.push_back(p_color);
recent_preset_cache.push_back(p_color);
@@ -770,7 +769,7 @@ void ColorPicker::erase_preset(const Color &p_color) {
for (int i = 1; i < preset_container->get_child_count(); i++) {
ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
if (current_btn && p_color == current_btn->get_preset_color()) {
- current_btn->queue_delete();
+ current_btn->queue_free();
break;
}
}
@@ -794,7 +793,7 @@ void ColorPicker::erase_recent_preset(const Color &p_color) {
for (int i = 1; i < recent_preset_hbc->get_child_count(); i++) {
ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(recent_preset_hbc->get_child(i));
if (current_btn && p_color == current_btn->get_preset_color()) {
- current_btn->queue_delete();
+ current_btn->queue_free();
break;
}
}
@@ -1087,16 +1086,24 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
Vector<Color> colors;
Color col;
col.set_ok_hsl(h, s, 1);
- points.resize(4);
- colors.resize(4);
- points.set(0, Vector2());
- points.set(1, Vector2(c->get_size().x, 0));
+ Color col2;
+ col2.set_ok_hsl(h, s, 0.5);
+ Color col3;
+ col3.set_ok_hsl(h, s, 0);
+ points.resize(6);
+ colors.resize(6);
+ points.set(0, Vector2(c->get_size().x, 0));
+ points.set(1, Vector2(c->get_size().x, c->get_size().y * 0.5));
points.set(2, c->get_size());
points.set(3, Vector2(0, c->get_size().y));
+ points.set(4, Vector2(0, c->get_size().y * 0.5));
+ points.set(5, Vector2());
colors.set(0, col);
- colors.set(1, col);
- colors.set(2, Color(0, 0, 0));
- colors.set(3, Color(0, 0, 0));
+ colors.set(1, col2);
+ colors.set(2, col3);
+ colors.set(3, col3);
+ colors.set(4, col2);
+ colors.set(5, col);
c->draw_polygon(points, colors);
int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
col.set_ok_hsl(h, 1, v);
@@ -1367,7 +1374,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
Ref<Image> img = r->get_texture()->get_image();
if (img.is_valid() && !img->is_empty()) {
- Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
+ Vector2 ofs = mev->get_global_position();
Color c = img->get_pixel(ofs.x, ofs.y);
set_pick_color(c);
@@ -1403,53 +1410,15 @@ void ColorPicker::_screen_pick_pressed() {
screen->show();
}
screen->move_to_front();
-#ifndef _MSC_VER
-#warning show modal no longer works, needs to be converted to a popup
-#endif
+ // TODO: show modal no longer works, needs to be converted to a popup.
//screen->show_modal();
}
-void ColorPicker::_focus_enter() {
- bool has_ctext_focus = c_text->has_focus();
- if (has_ctext_focus) {
- c_text->select_all();
- } else {
- c_text->select(0, 0);
- }
-
- for (int i = 0; i < current_slider_count; i++) {
- if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) {
- values[i]->get_line_edit()->select_all();
- } else {
- values[i]->get_line_edit()->select(0, 0);
- }
- }
- if (alpha_value->get_line_edit()->has_focus() && !has_ctext_focus) {
- alpha_value->get_line_edit()->select_all();
- } else {
- alpha_value->get_line_edit()->select(0, 0);
- }
-}
-
-void ColorPicker::_focus_exit() {
- for (int i = 0; i < current_slider_count; i++) {
- if (!values[i]->get_line_edit()->get_menu()->is_visible()) {
- values[i]->get_line_edit()->select(0, 0);
- }
- }
- if (!alpha_value->get_line_edit()->get_menu()->is_visible()) {
- alpha_value->get_line_edit()->select(0, 0);
- }
-
- c_text->select(0, 0);
-}
-
void ColorPicker::_html_focus_exit() {
if (c_text->is_menu_visible()) {
return;
}
_html_submitted(c_text->get_text());
- _focus_exit();
}
void ColorPicker::set_presets_enabled(bool p_enabled) {
@@ -1660,9 +1629,9 @@ ColorPicker::ColorPicker() :
c_text = memnew(LineEdit);
hhb->add_child(c_text);
+ c_text->set_select_all_on_focus(true);
c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted));
c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
- c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter), CONNECT_DEFERRED);
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
wheel_edit = memnew(AspectRatioContainer);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 6c91575893..a0843d6fa2 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -202,8 +202,6 @@ private:
void _text_changed(const String &p_new_text);
void _add_preset_pressed();
void _screen_pick_pressed();
- void _focus_enter();
- void _focus_exit();
void _html_focus_exit();
inline int _get_preset_size();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 2dcae2553c..c5cb7157e8 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -633,7 +633,7 @@ Rect2 Control::get_parent_anchorable_rect() const {
#ifdef TOOLS_ENABLED
Node *edited_root = get_tree()->get_edited_scene_root();
if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) {
- parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ parent_rect.size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
} else {
parent_rect = get_viewport()->get_visible_rect();
}
@@ -1436,13 +1436,6 @@ Rect2 Control::get_screen_rect() const {
return r;
}
-Rect2 Control::get_window_rect() const {
- ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2 gr = get_global_rect();
- gr.position += get_viewport()->get_visible_rect().position;
- return gr;
-}
-
Rect2 Control::get_anchorable_rect() const {
return Rect2(Point2(), get_size());
}
@@ -1558,13 +1551,11 @@ bool Control::is_minimum_size_adjust_blocked() const {
Size2 Control::get_minimum_size() const {
Vector2 ms;
- if (GDVIRTUAL_CALL(_get_minimum_size, ms)) {
- return ms;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_get_minimum_size, ms);
+ return ms;
}
-void Control::set_custom_minimum_size(const Size2i &p_custom) {
+void Control::set_custom_minimum_size(const Size2 &p_custom) {
if (p_custom == data.custom_minimum_size) {
return;
}
@@ -1572,7 +1563,7 @@ void Control::set_custom_minimum_size(const Size2i &p_custom) {
update_minimum_size();
}
-Size2i Control::get_custom_minimum_size() const {
+Size2 Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
@@ -1759,6 +1750,34 @@ void Control::warp_mouse(const Point2 &p_position) {
get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position));
}
+void Control::set_shortcut_context(const Node *p_node) {
+ if (p_node != nullptr) {
+ data.shortcut_context = p_node->get_instance_id();
+ } else {
+ data.shortcut_context = ObjectID();
+ }
+}
+
+Node *Control::get_shortcut_context() const {
+ Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context);
+ Node *ctx_node = Object::cast_to<Node>(ctx_obj);
+
+ return ctx_node;
+}
+
+bool Control::is_focus_owner_in_shortcut_context() const {
+ if (data.shortcut_context == ObjectID()) {
+ // No context, therefore global - always "in" context.
+ return true;
+ }
+
+ const Node *ctx_node = get_shortcut_context();
+ const Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
+
+ // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
+ return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+}
+
// Drag and drop handling.
void Control::set_drag_forwarding(Object *p_target) {
@@ -1778,11 +1797,8 @@ Variant Control::get_drag_data(const Point2 &p_point) {
}
Variant dd;
- if (GDVIRTUAL_CALL(_get_drag_data, p_point, dd)) {
- return dd;
- }
-
- return Variant();
+ GDVIRTUAL_CALL(_get_drag_data, p_point, dd);
+ return dd;
}
bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
@@ -1794,10 +1810,8 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
}
bool ret = false;
- if (GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret)) {
- return ret;
- }
- return false;
+ GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret);
+ return ret;
}
void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
@@ -2704,11 +2718,8 @@ void Control::end_bulk_theme_override() {
TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
TypedArray<Vector2i> ret;
- if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) {
- return ret;
- } else {
- return TypedArray<Vector2i>();
- }
+ GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
+ return ret;
} else {
return TS->parse_structured_text(p_parser_type, p_args, p_text);
}
@@ -2793,10 +2804,8 @@ String Control::get_tooltip(const Point2 &p_pos) const {
Control *Control::make_custom_tooltip(const String &p_text) const {
Object *ret = nullptr;
- if (GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret)) {
- return Object::cast_to<Control>(ret);
- }
- return nullptr;
+ GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret);
+ return Object::cast_to<Control>(ret);
}
// Base object overrides.
@@ -2885,8 +2894,8 @@ void Control::_notification(int p_notification) {
if (data.parent_canvas_item) {
data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed));
data.parent_canvas_item = nullptr;
- } else if (!is_set_as_top_level()) {
- //disconnect viewport
+ } else {
+ // Disconnect viewport.
Viewport *viewport = get_viewport();
ERR_FAIL_COND(!viewport);
viewport->disconnect("size_changed", callable_mp(this, &Control::_size_changed));
@@ -3133,6 +3142,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse);
+ ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context);
+ ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context);
+
ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size);
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Control::set_layout_direction);
@@ -3144,7 +3156,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::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
+ 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::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);
@@ -3206,6 +3218,9 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
+ ADD_GROUP("Input", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+
ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
diff --git a/scene/gui/control.h b/scene/gui/control.h
index ee6443c81c..72e870930d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -159,6 +159,7 @@ private:
}
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
// Global relations.
@@ -200,7 +201,7 @@ private:
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
real_t expand = 1.0;
- Point2i custom_minimum_size;
+ Point2 custom_minimum_size;
// Input events and rendering.
@@ -218,6 +219,8 @@ private:
NodePath focus_next;
NodePath focus_prev;
+ ObjectID shortcut_context;
+
// Theming.
ThemeOwner *theme_owner = nullptr;
@@ -442,7 +445,6 @@ public:
Rect2 get_rect() const;
Rect2 get_global_rect() const;
Rect2 get_screen_rect() const;
- Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the rendering server
Rect2 get_anchorable_rect() const override;
void set_scale(const Vector2 &p_scale);
@@ -460,8 +462,8 @@ public:
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
- void set_custom_minimum_size(const Size2i &p_custom);
- Size2i get_custom_minimum_size() const;
+ void set_custom_minimum_size(const Size2 &p_custom);
+ Size2 get_custom_minimum_size() const;
// Container sizing.
@@ -487,6 +489,10 @@ public:
void warp_mouse(const Point2 &p_position);
+ bool is_focus_owner_in_shortcut_context() const;
+ void set_shortcut_context(const Node *p_node);
+ Node *get_shortcut_context() const;
+
// Drag and drop handling.
virtual void set_drag_forwarding(Object *p_target);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 90552c32c2..46b712379d 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1385,16 +1385,16 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (p_ev->is_pressed()) {
- if (p_ev->is_action("ui_graph_duplicate")) {
+ if (p_ev->is_action("ui_graph_duplicate", true)) {
emit_signal(SNAME("duplicate_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_copy")) {
+ } else if (p_ev->is_action("ui_copy", true)) {
emit_signal(SNAME("copy_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_paste")) {
+ } else if (p_ev->is_action("ui_paste", true)) {
emit_signal(SNAME("paste_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_graph_delete")) {
+ } else if (p_ev->is_action("ui_graph_delete", true)) {
TypedArray<StringName> nodes;
for (int i = 0; i < get_child_count(); i++) {
@@ -1475,11 +1475,9 @@ void GraphEdit::force_connection_drag_end() {
}
bool GraphEdit::is_node_hover_valid(const StringName &p_from, const int p_from_port, const StringName &p_to, const int p_to_port) {
- bool valid = false;
- if (GDVIRTUAL_CALL(_is_node_hover_valid, p_from, p_from_port, p_to, p_to_port, valid)) {
- return valid;
- }
- return true;
+ bool valid = true;
+ GDVIRTUAL_CALL(_is_node_hover_valid, p_from, p_from_port, p_to, p_to_port, valid);
+ return valid;
}
void GraphEdit::set_panning_scheme(PanningScheme p_scheme) {
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 0dc791f71d..d6b5557a3f 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -728,12 +728,12 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
if (p_event->is_pressed() && items.size() > 0) {
- if (p_event->is_action("ui_up")) {
+ if (p_event->is_action("ui_up", true)) {
if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
+ if (diff < uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec")) * 2) {
for (int i = current - 1; i >= 0; i--) {
if (CAN_SELECT(i) && items[i].text.begins_with(search_string)) {
set_current(i);
@@ -766,12 +766,12 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_down")) {
+ } else if (p_event->is_action("ui_down", true)) {
if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
+ if (diff < uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec")) * 2) {
for (int i = current + 1; i < items.size(); i++) {
if (CAN_SELECT(i) && items[i].text.begins_with(search_string)) {
set_current(i);
@@ -803,7 +803,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_page_up")) {
+ } else if (p_event->is_action("ui_page_up", true)) {
search_string = ""; //any mousepress cancels
for (int i = 4; i > 0; i--) {
@@ -817,7 +817,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
break;
}
}
- } else if (p_event->is_action("ui_page_down")) {
+ } else if (p_event->is_action("ui_page_down", true)) {
search_string = ""; //any mousepress cancels
for (int i = 4; i > 0; i--) {
@@ -832,7 +832,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
break;
}
}
- } else if (p_event->is_action("ui_left")) {
+ } else if (p_event->is_action("ui_left", true)) {
search_string = ""; //any mousepress cancels
if (current % current_columns != 0) {
@@ -852,7 +852,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_right")) {
+ } else if (p_event->is_action("ui_right", true)) {
search_string = ""; //any mousepress cancels
if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
@@ -872,9 +872,9 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_cancel")) {
+ } else if (p_event->is_action("ui_cancel", true)) {
search_string = "";
- } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) {
+ } else if (p_event->is_action("ui_select", true) && select_mode == SELECT_MULTI) {
if (current >= 0 && current < items.size()) {
if (items[current].selectable && !items[current].disabled && !items[current].selected) {
select(current, false);
@@ -884,7 +884,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("multi_selected"), current, false);
}
}
- } else if (p_event->is_action("ui_accept")) {
+ } else if (p_event->is_action("ui_accept", true)) {
search_string = ""; //any mousepress cancels
if (current >= 0 && current < items.size()) {
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index bf7c59d1cd..2203573bbc 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -117,7 +117,7 @@ void Label::_shape() {
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
+ TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, txt));
dirty = false;
font_dirty = false;
lines_dirty = true;
@@ -288,6 +288,36 @@ void Label::_update_theme_item_cache() {
theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
}
+PackedStringArray Label::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
+
+ // Ensure that the font can render all of the required glyphs.
+ Ref<Font> font;
+ if (settings.is_valid()) {
+ font = settings->get_font();
+ }
+ if (font.is_null()) {
+ font = theme_cache.font;
+ }
+
+ if (font.is_valid()) {
+ if (dirty || font_dirty || lines_dirty) {
+ const_cast<Label *>(this)->_shape();
+ }
+
+ const Glyph *glyph = TS->shaped_text_get_glyphs(text_rid);
+ int64_t glyph_count = TS->shaped_text_get_glyph_count(text_rid);
+ for (int64_t i = 0; i < glyph_count; i++) {
+ if (glyph[i].font_rid == RID()) {
+ warnings.push_back(RTR("The current font does not support rendering one or more characters used in this Label's text."));
+ break;
+ }
+ }
+ }
+
+ return warnings;
+}
+
void Label::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -302,6 +332,7 @@ void Label::_notification(int p_what) {
dirty = true;
queue_redraw();
+ update_configuration_warnings();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
@@ -674,6 +705,7 @@ void Label::set_text(const String &p_string) {
}
queue_redraw();
update_minimum_size();
+ update_configuration_warnings();
}
void Label::_invalidate() {
diff --git a/scene/gui/label.h b/scene/gui/label.h
index b79c94a5ba..41d7049b22 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -93,6 +93,7 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 36e85b5d02..fb5ab9f923 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -372,6 +372,11 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.drag_attempt = false;
}
+ if (pending_select_all_on_focus) {
+ select_all();
+ pending_select_all_on_focus = false;
+ }
+
show_virtual_keyboard();
}
@@ -1056,6 +1061,15 @@ void LineEdit::_notification(int p_what) {
}
}
+ if (select_all_on_focus) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+ // Select all when the mouse button is up.
+ pending_select_all_on_focus = true;
+ } else {
+ select_all();
+ }
+ }
+
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
Point2 column = Point2(get_caret_column(), 1) * get_minimum_size().height;
@@ -2164,6 +2178,18 @@ bool LineEdit::is_flat() const {
return flat;
}
+void LineEdit::set_select_all_on_focus(bool p_enabled) {
+ select_all_on_focus = p_enabled;
+}
+
+bool LineEdit::is_select_all_on_focus() const {
+ return select_all_on_focus;
+}
+
+void LineEdit::clear_pending_select_all_on_focus() {
+ pending_select_all_on_focus = false;
+}
+
void LineEdit::_text_changed() {
_emit_text_change();
_clear_redo();
@@ -2175,6 +2201,12 @@ void LineEdit::_emit_text_change() {
}
void LineEdit::_shape() {
+ const Ref<Font> &font = theme_cache.font;
+ int font_size = theme_cache.font_size;
+ if (font.is_null()) {
+ return;
+ }
+
Size2 old_size = TS->shaped_text_get_size(text_rid);
TS->shaped_text_clear(text_rid);
@@ -2197,9 +2229,6 @@ void LineEdit::_shape() {
}
TS->shaped_text_set_preserve_control(text_rid, draw_control_chars);
- const Ref<Font> &font = theme_cache.font;
- int font_size = theme_cache.font_size;
- ERR_FAIL_COND(font.is_null());
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
@@ -2364,6 +2393,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon);
ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &LineEdit::set_flat);
ClassDB::bind_method(D_METHOD("is_flat"), &LineEdit::is_flat);
+ ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &LineEdit::set_select_all_on_focus);
+ ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &LineEdit::is_select_all_on_focus);
ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
ADD_SIGNAL(MethodInfo("text_change_rejected", PropertyInfo(Variant::STRING, "rejected_substring")));
@@ -2427,6 +2458,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 861c7f273b..e0a079b623 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -174,6 +174,9 @@ private:
double caret_blink_timer = 0.0;
bool caret_blinking = false;
+ bool pending_select_all_on_focus = false;
+ bool select_all_on_focus = false;
+
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> read_only;
@@ -365,6 +368,10 @@ public:
void set_flat(bool p_enabled);
bool is_flat() const;
+ void set_select_all_on_focus(bool p_enabled);
+ bool is_select_all_on_focus() const;
+ void clear_pending_select_all_on_focus(); // For other controls, e.g. SpinBox.
+
virtual bool is_text_field() const override;
void show_virtual_keyboard();
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 742042f65f..82ef53e317 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -41,7 +41,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
}
MutexLock lock(mutex);
- if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
int new_sel = selected_menu;
int old_sel = (selected_menu < 0) ? 0 : selected_menu;
do {
@@ -63,7 +63,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
_open_popup(selected_menu, true);
}
return;
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
int new_sel = selected_menu;
int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu;
do {
@@ -149,10 +149,6 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) {
void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (disable_shortcuts) {
return;
}
@@ -175,34 +171,6 @@ void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
-void MenuBar::set_shortcut_context(Node *p_node) {
- if (p_node != nullptr) {
- shortcut_context = p_node->get_instance_id();
- } else {
- shortcut_context = ObjectID();
- }
-}
-
-Node *MenuBar::get_shortcut_context() const {
- Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
- Node *ctx_node = Object::cast_to<Node>(ctx_obj);
-
- return ctx_node;
-}
-
-bool MenuBar::_is_focus_owner_in_shortcut_context() const {
- if (shortcut_context == ObjectID()) {
- // No context, therefore global - always "in" context.
- return true;
- }
-
- Node *ctx_node = get_shortcut_context();
- Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
-
- // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
- return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
-}
-
void MenuBar::_popup_visibility_changed(bool p_visible) {
if (!p_visible) {
active_menu = -1;
@@ -694,16 +662,12 @@ void MenuBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden);
ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden);
- ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context);
- ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context);
-
ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
index f7ef19e98b..c057a7c96f 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -118,8 +118,6 @@ class MenuBar : public Control {
void _clear_menu();
void _update_menu();
- bool _is_focus_owner_in_shortcut_context() const;
-
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
@@ -170,9 +168,6 @@ public:
void set_menu_hidden(int p_menu, bool p_hidden);
bool is_menu_hidden(int p_menu) const;
- void set_shortcut_context(Node *p_node);
- Node *get_shortcut_context() const;
-
PopupMenu *get_menu_popup(int p_menu) const;
virtual void get_translatable_strings(List<String> *p_strings) const override;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 78aeab9457..786f23873e 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -36,10 +36,6 @@
void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (disable_shortcuts) {
return;
}
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index a6915f9e61..434eb87e7a 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -77,28 +77,36 @@ void Popup::_update_theme_item_cache() {
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible()) {
- _initialize_visible_parents();
- } else {
- _deinitialize_visible_parents();
- emit_signal(SNAME("popup_hide"));
- popped_up = false;
+ if (!is_in_edited_scene_root()) {
+ if (is_visible()) {
+ _initialize_visible_parents();
+ } else {
+ _deinitialize_visible_parents();
+ emit_signal(SNAME("popup_hide"));
+ popped_up = false;
+ }
}
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
- if (has_focus()) {
- popped_up = true;
+ if (!is_in_edited_scene_root()) {
+ if (has_focus()) {
+ popped_up = true;
+ }
}
} break;
case NOTIFICATION_EXIT_TREE: {
- _deinitialize_visible_parents();
+ if (!is_in_edited_scene_root()) {
+ _deinitialize_visible_parents();
+ }
} break;
case NOTIFICATION_WM_CLOSE_REQUEST:
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
- _close_pressed();
+ if (!is_in_edited_scene_root()) {
+ _close_pressed();
+ }
} break;
}
}
@@ -126,6 +134,16 @@ void Popup::_bind_methods() {
ADD_SIGNAL(MethodInfo("popup_hide"));
}
+void Popup::_validate_property(PropertyInfo &p_property) const {
+ if (
+ p_property.name == "transient" ||
+ p_property.name == "exclusive" ||
+ p_property.name == "popup_window" ||
+ p_property.name == "unfocusable") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
Rect2i Popup::_popup_adjust_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
Rect2i parent_rect = get_usable_parent_rect();
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 0d6ca25c18..57b811cadb 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -59,6 +59,7 @@ protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
virtual void _parent_focused();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 4cdde5902e..9a411ef7ed 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -273,7 +273,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!items.is_empty()) {
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_down", true) && p_event->is_pressed()) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
search_from = 0;
@@ -305,7 +305,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_up", true) && p_event->is_pressed()) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
@@ -337,7 +337,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
Node *n = get_parent();
if (n) {
if (Object::cast_to<PopupMenu>(n)) {
@@ -349,7 +349,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
set_input_as_handled();
@@ -361,7 +361,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index c9516ed6b9..0dece1c287 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -56,10 +56,8 @@ Variant RichTextEffect::get_bbcode() const {
bool RichTextEffect::_process_effect_impl(Ref<CharFXTransform> p_cfx) {
bool return_value = false;
- if (GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value)) {
- return return_value;
- }
- return false;
+ GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value);
+ return return_value;
}
RichTextEffect::RichTextEffect() {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 5060bacba5..7f487175dc 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1087,7 +1087,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
_draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0);
// Draw main text.
- Color selection_fg = theme_cache.font_selected_color;
Color selection_bg = theme_cache.selection_color;
int sel_start = -1;
@@ -1276,8 +1275,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
- if (selected) {
- font_color = override_selected_font_color ? selection_fg : font_color;
+ if (selected && use_selected_font_color) {
+ font_color = theme_cache.font_selected_color;
}
// Draw glyphs.
@@ -1286,9 +1285,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (txt_visible) {
if (!skip) {
if (frid != RID()) {
- TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
}
}
r_processed_glyphs++;
@@ -1688,6 +1687,7 @@ void RichTextLabel::_update_theme_item_cache() {
theme_cache.default_color = get_theme_color(SNAME("default_color"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ use_selected_font_color = theme_cache.font_selected_color != Color(0, 0, 0, 0);
theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
@@ -2019,36 +2019,36 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
if (k->is_pressed()) {
bool handled = false;
- if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_page_up", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() - vscroll->get_page());
handled = true;
}
- if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_page_down", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() + vscroll->get_page());
handled = true;
}
- if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_up", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
- if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
- if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(0);
handled = true;
}
- if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_end", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_max());
handled = true;
}
if (is_shortcut_keys_enabled()) {
- if (k->is_action("ui_text_select_all")) {
+ if (k->is_action("ui_text_select_all", true)) {
select_all();
handled = true;
}
- if (k->is_action("ui_copy")) {
+ if (k->is_action("ui_copy", true)) {
selection_copy();
handled = true;
}
@@ -2956,7 +2956,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
memdelete(p_item);
}
-void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment) {
+void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment, const Rect2 &p_region) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -2969,7 +2969,15 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
ERR_FAIL_COND(p_image->get_height() == 0);
ItemImage *item = memnew(ItemImage);
- item->image = p_image;
+ if (p_region.has_area()) {
+ Ref<AtlasTexture> atlas_tex = memnew(AtlasTexture);
+ atlas_tex->set_atlas(p_image);
+ atlas_tex->set_region(p_region);
+ item->image = atlas_tex;
+ } else {
+ item->image = p_image;
+ }
+
item->color = p_color;
item->inline_align = p_alignment;
@@ -2981,17 +2989,30 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
item->size.height = p_height;
} else {
// calculate height to keep aspect ratio
- item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ if (p_region.has_area()) {
+ item->size.height = p_region.get_size().height * p_width / p_region.get_size().width;
+ } else {
+ item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ }
}
} else {
if (p_height > 0) {
// custom height
item->size.height = p_height;
// calculate width to keep aspect ratio
- item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ if (p_region.has_area()) {
+ item->size.width = p_region.get_size().width * p_height / p_region.get_size().height;
+ } else {
+ item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ }
} else {
- // keep original width and height
- item->size = p_image->get_size();
+ if (p_region.has_area()) {
+ // if the image has a region, keep the region size
+ item->size = p_region.get_size();
+ } else {
+ // keep original width and height
+ item->size = p_image->get_size();
+ }
}
}
@@ -3543,14 +3564,6 @@ bool RichTextLabel::is_hint_underlined() const {
return underline_hint;
}
-void RichTextLabel::set_override_selected_font_color(bool p_override_selected_font_color) {
- override_selected_font_color = p_override_selected_font_color;
-}
-
-bool RichTextLabel::is_overriding_selected_font_color() const {
- return override_selected_font_color;
-}
-
void RichTextLabel::set_offset(int p_pixel) {
vscroll->set_value(p_pixel);
}
@@ -4126,6 +4139,18 @@ void RichTextLabel::append_text(const String &p_bbcode) {
Ref<Texture2D> texture = ResourceLoader::load(image, "Texture2D");
if (texture.is_valid()) {
+ Rect2 region;
+ OptionMap::Iterator region_option = bbcode_options.find("region");
+ if (region_option) {
+ Vector<String> region_values = region_option->value.split(",", false);
+ if (region_values.size() == 4) {
+ region.position.x = region_values[0].to_float();
+ region.position.y = region_values[1].to_float();
+ region.size.x = region_values[2].to_float();
+ region.size.y = region_values[3].to_float();
+ }
+ }
+
Color color = Color(1.0, 1.0, 1.0);
OptionMap::Iterator color_option = bbcode_options.find("color");
if (color_option) {
@@ -4154,7 +4179,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
}
- add_image(texture, width, height, color, (InlineAlignment)alignment);
+ add_image(texture, width, height, color, (InlineAlignment)alignment, region);
}
pos = end;
@@ -5209,7 +5234,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_parsed_text"), &RichTextLabel::get_parsed_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
- ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER));
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
@@ -5261,9 +5286,6 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hint_underline", "enable"), &RichTextLabel::set_hint_underline);
ClassDB::bind_method(D_METHOD("is_hint_underlined"), &RichTextLabel::is_hint_underlined);
- ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &RichTextLabel::set_override_selected_font_color);
- ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &RichTextLabel::is_overriding_selected_font_color);
-
ClassDB::bind_method(D_METHOD("set_scroll_active", "active"), &RichTextLabel::set_scroll_active);
ClassDB::bind_method(D_METHOD("is_scroll_active"), &RichTextLabel::is_scroll_active);
@@ -5373,7 +5395,6 @@ void RichTextLabel::_bind_methods() {
ADD_GROUP("Text Selection", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
ADD_GROUP("Displayed Text", "");
@@ -5622,6 +5643,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
Vector2i fbg_index = Vector2i(end, start);
Color last_color = Color(0, 0, 0, 0);
bool draw_box = false;
+ int hpad = get_theme_constant(SNAME("text_highlight_h_padding"));
+ int vpad = get_theme_constant(SNAME("text_highlight_v_padding"));
// Draw a box based on color tags associated with glyphs
for (int i = start; i < end; i++) {
Item *it = _get_item_at_pos(it_from, it_to, i);
@@ -5651,8 +5674,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (draw_box) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, fbg_index.y);
for (int j = 0; j < sel.size(); j++) {
- Vector2 rect_off = line_off + Vector2(sel[j].x, -TS->shaped_text_get_ascent(p_rid));
- Vector2 rect_size = Vector2(sel[j].y - sel[j].x, TS->shaped_text_get_size(p_rid).y);
+ Vector2 rect_off = line_off + Vector2(sel[j].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
+ Vector2 rect_size = Vector2(sel[j].y - sel[j].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
fbg_index = Vector2i(end, start);
@@ -5670,8 +5693,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (last_color.a > 0) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, end);
for (int i = 0; i < sel.size(); i++) {
- Vector2 rect_off = line_off + Vector2(sel[i].x, -TS->shaped_text_get_ascent(p_rid));
- Vector2 rect_size = Vector2(sel[i].y - sel[i].x, TS->shaped_text_get_size(p_rid).y);
+ Vector2 rect_off = line_off + Vector2(sel[i].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
+ Vector2 rect_size = Vector2(sel[i].y - sel[i].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 73b7676c22..d30baaa8d3 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -396,7 +396,7 @@ private:
int tab_size = 4;
bool underline_meta = true;
bool underline_hint = true;
- bool override_selected_font_color = false;
+ bool use_selected_font_color = false;
HorizontalAlignment default_alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -569,7 +569,7 @@ private:
public:
String get_parsed_text() const;
void add_text(const String &p_text);
- void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER);
+ void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0));
void add_newline();
bool remove_line(const int p_line);
void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 6c05b171e3..6899178885 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -183,35 +183,35 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
if (p_event->is_pressed()) {
- if (p_event->is_action("ui_left")) {
+ if (p_event->is_action("ui_left", true)) {
if (orientation != HORIZONTAL) {
return;
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_right")) {
+ } else if (p_event->is_action("ui_right", true)) {
if (orientation != HORIZONTAL) {
return;
}
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_up")) {
+ } else if (p_event->is_action("ui_up", true)) {
if (orientation != VERTICAL) {
return;
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_down")) {
+ } else if (p_event->is_action("ui_down", true)) {
if (orientation != VERTICAL) {
return;
}
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_home")) {
+ } else if (p_event->is_action("ui_home", true)) {
set_value(get_min());
- } else if (p_event->is_action("ui_end")) {
+ } else if (p_event->is_action("ui_end", true)) {
set_value(get_max());
}
}
@@ -338,7 +338,7 @@ void ScrollBar::_notification(int p_what) {
if (scrolling) {
if (get_value() != target_scroll) {
double target = target_scroll - get_value();
- double dist = sqrt(target * target);
+ double dist = abs(target);
double vel = ((target / dist) * 500) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index a7d44c0f3c..6cbacf0dd3 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -138,10 +138,10 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
accept_event();
- } else if (p_event->is_action("ui_home") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_home", true) && p_event->is_pressed()) {
set_value(get_min());
accept_event();
- } else if (p_event->is_action("ui_end") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_end", true) && p_event->is_pressed()) {
set_value(get_max());
accept_event();
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index fe14049d93..c4000120c8 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -168,6 +168,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
range_click_timer->stop();
_release_mouse();
drag.allowed = false;
+ line_edit->clear_pending_select_all_on_focus();
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -190,6 +191,11 @@ void SpinBox::_line_edit_focus_enter() {
int col = line_edit->get_caret_column();
_value_changed(0); // Update the LineEdit's text.
line_edit->set_caret_column(col);
+
+ // LineEdit text might change and it clears any selection. Have to re-select here.
+ if (line_edit->is_select_all_on_focus() && !Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+ line_edit->select_all();
+ }
}
void SpinBox::_line_edit_focus_exit() {
@@ -308,6 +314,14 @@ bool SpinBox::get_update_on_text_changed() const {
return update_on_text_changed;
}
+void SpinBox::set_select_all_on_focus(bool p_enabled) {
+ line_edit->set_select_all_on_focus(p_enabled);
+}
+
+bool SpinBox::is_select_all_on_focus() const {
+ return line_edit->is_select_all_on_focus();
+}
+
void SpinBox::set_editable(bool p_enabled) {
line_edit->set_editable(p_enabled);
}
@@ -341,6 +355,8 @@ void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable);
ClassDB::bind_method(D_METHOD("set_update_on_text_changed", "enabled"), &SpinBox::set_update_on_text_changed);
ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed);
+ ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &SpinBox::set_select_all_on_focus);
+ ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &SpinBox::is_select_all_on_focus);
ClassDB::bind_method(D_METHOD("apply"), &SpinBox::apply);
ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit);
@@ -350,6 +366,7 @@ void SpinBox::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step"), "set_custom_arrow_step", "get_custom_arrow_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
}
SpinBox::SpinBox() {
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index c2f2ac3f5a..00f5a95699 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -101,6 +101,9 @@ public:
void set_update_on_text_changed(bool p_enabled);
bool get_update_on_text_changed() const;
+ void set_select_all_on_focus(bool p_enabled);
+ bool is_select_all_on_focus() const;
+
void apply();
void set_custom_arrow_step(const double p_custom_arrow_step);
double get_custom_arrow_step() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index f8501f3570..cc9fc99b9c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -464,7 +464,7 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (scrolling && get_v_scroll() != target_v_scroll) {
double target_y = target_v_scroll - get_v_scroll();
- double dist = sqrt(target_y * target_y);
+ double dist = abs(target_y);
// To ensure minimap is responsive override the speed setting.
double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time();
@@ -1219,7 +1219,7 @@ void TextEdit::_notification(int p_what) {
int sel_from = (line > get_selection_from_line(c)) ? TS->shaped_text_get_range(rid).x : get_selection_from_column(c);
int sel_to = (line < get_selection_to_line(c)) ? TS->shaped_text_get_range(rid).y : get_selection_to_column(c);
- if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
+ if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && use_selected_font_color) {
gl_color = font_selected_color;
}
}
@@ -1692,7 +1692,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
continue;
}
- if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) {
+ if (mpos.x >= left_margin && mpos.x <= left_margin + gutters[i].width) {
emit_signal(SNAME("gutter_clicked"), row, i);
return;
}
@@ -1933,7 +1933,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
continue;
}
- if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) {
+ if (mpos.x >= left_margin && mpos.x < left_margin + gutters[i].width) {
// We are in this gutter i's horizontal area.
current_hovered_gutter = Vector2i(i, hovered_row);
break;
@@ -2051,7 +2051,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (is_shortcut_keys_enabled()) {
- // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE.
+ // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, CUT, COPY, PASTE.
if (k->is_action("ui_text_select_all", true)) {
select_all();
accept_event();
@@ -2062,6 +2062,16 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+ if (k->is_action("ui_text_add_selection_for_next_occurrence", true)) {
+ add_selection_for_next_occurrence();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_remove_secondary_carets", true) && _should_remove_secondary_carets()) {
+ remove_secondary_carets();
+ accept_event();
+ return;
+ }
if (k->is_action("ui_cut", true)) {
cut();
accept_event();
@@ -2089,6 +2099,17 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+
+ if (k->is_action("ui_text_caret_add_below", true)) {
+ add_caret_at_carets(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_add_above", true)) {
+ add_caret_at_carets(false);
+ accept_event();
+ return;
+ }
}
// MISC.
@@ -2192,8 +2213,17 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- // Handle Unicode (if no modifiers active). Tab has a value of 0x09.
- if (allow_unicode_handling && editable && (k->get_unicode() >= 32 || k->get_keycode() == Key::TAB)) {
+ // Handle tab as it has no set unicode value.
+ if (k->is_action("ui_text_indent", true)) {
+ if (editable) {
+ insert_text_at_caret("\t");
+ }
+ accept_event();
+ return;
+ }
+
+ // Handle Unicode (if no modifiers active).
+ if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
handle_unicode_input(k->get_unicode());
accept_event();
return;
@@ -2794,6 +2824,55 @@ void TextEdit::_move_caret_document_end(bool p_select) {
}
}
+bool TextEdit::_should_remove_secondary_carets() {
+ return carets.size() > 1;
+}
+
+void TextEdit::_get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x) const {
+ if (p_last_fit_x == -1) {
+ p_last_fit_x = _get_column_x_offset_for_line(p_old_column, p_old_line, p_old_column);
+ }
+
+ // Calculate the new line and wrap index
+ p_new_line = p_old_line;
+ int caret_wrap_index = p_old_wrap_index;
+ if (p_below) {
+ if (caret_wrap_index < get_line_wrap_count(p_new_line)) {
+ caret_wrap_index++;
+ } else {
+ p_new_line++;
+ caret_wrap_index = 0;
+ }
+ } else {
+ if (caret_wrap_index == 0) {
+ p_new_line--;
+ caret_wrap_index = get_line_wrap_count(p_new_line);
+ } else {
+ caret_wrap_index--;
+ }
+ }
+
+ // Boundary checks
+ if (p_new_line < 0) {
+ p_new_line = 0;
+ }
+ if (p_new_line >= text.size()) {
+ p_new_line = text.size() - 1;
+ }
+
+ p_new_column = _get_char_pos_for_line(p_last_fit_x, p_new_line, caret_wrap_index);
+ if (p_new_column != 0 && get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && caret_wrap_index < get_line_wrap_count(p_new_line)) {
+ Vector<String> rows = get_line_wrapped_text(p_new_line);
+ int row_end_col = 0;
+ for (int i = 0; i < caret_wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (p_new_column >= row_end_col) {
+ p_new_column -= 1;
+ }
+ }
+}
+
void TextEdit::_update_placeholder() {
if (font.is_null() || font_size <= 0) {
return; // Not in tree?
@@ -2852,6 +2931,7 @@ void TextEdit::_update_caches() {
/* Selection */
font_selected_color = get_theme_color(SNAME("font_selected_color"));
selection_color = get_theme_color(SNAME("selection_color"));
+ use_selected_font_color = font_selected_color != Color(0, 0, 0, 0);
/* Visual. */
style_normal = get_theme_stylebox(SNAME("normal"));
@@ -2997,7 +3077,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
continue;
}
- if (p_pos.x > left_margin && p_pos.x <= (left_margin + gutters[i].width) - 3) {
+ if (p_pos.x >= left_margin && p_pos.x < left_margin + gutters[i].width) {
if (gutters[i].clickable || is_line_gutter_clickable(row, i)) {
return CURSOR_POINTING_HAND;
}
@@ -3801,6 +3881,9 @@ void TextEdit::undo() {
return;
}
+ if (in_action) {
+ pending_action_end = true;
+ }
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -3854,7 +3937,7 @@ void TextEdit::undo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::redo() {
@@ -3862,6 +3945,9 @@ void TextEdit::redo() {
return;
}
+ if (in_action) {
+ pending_action_end = true;
+ }
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -3906,7 +3992,7 @@ void TextEdit::redo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::clear_undo_history() {
@@ -4380,7 +4466,7 @@ int TextEdit::add_caret(int p_line, int p_col) {
}
void TextEdit::remove_caret(int p_caret) {
- ERR_FAIL_COND(carets.size() <= 0);
+ ERR_FAIL_COND_MSG(carets.size() <= 1, "The main caret should not be removed.");
ERR_FAIL_INDEX(p_caret, carets.size());
carets.remove_at(p_caret);
caret_index_edit_dirty = true;
@@ -4495,6 +4581,68 @@ int TextEdit::get_caret_count() const {
return carets.size();
}
+void TextEdit::add_caret_at_carets(bool p_below) {
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &caret_index : caret_edit_order) {
+ const int caret_line = get_caret_line(caret_index);
+ const int caret_column = get_caret_column(caret_index);
+
+ // The last fit x will be cleared if the caret has a selection,
+ // but if it does not have a selection the last fit x will be
+ // transferred to the new caret
+ int caret_from_column = 0, caret_to_column = 0, caret_last_fit_x = carets[caret_index].last_fit_x;
+ if (has_selection(caret_index)) {
+ // If the selection goes over multiple lines, deselect it.
+ if (get_selection_from_line(caret_index) != get_selection_to_line(caret_index)) {
+ deselect(caret_index);
+ } else {
+ caret_from_column = get_selection_from_column(caret_index);
+ caret_to_column = get_selection_to_column(caret_index);
+ caret_last_fit_x = -1;
+ carets.write[caret_index].last_fit_x = _get_column_x_offset_for_line(caret_column, caret_line, caret_column);
+ }
+ }
+
+ // Get the line and column of the new caret as if you would move the caret by pressing the arrow keys
+ int new_caret_line, new_caret_column, new_caret_from_column = 0, new_caret_to_column = 0;
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_column, p_below, new_caret_line, new_caret_column, caret_last_fit_x);
+
+ // If the caret does have a selection calculate the new from and to columns
+ if (caret_from_column != caret_to_column) {
+ // We only need to calculate the selection columns if the column of the caret changed
+ if (caret_column != new_caret_column) {
+ int _; // unused placeholder for p_new_line
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_from_column, p_below, _, new_caret_from_column);
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_to_column, p_below, _, new_caret_to_column);
+ } else {
+ new_caret_from_column = caret_from_column;
+ new_caret_to_column = caret_to_column;
+ }
+ }
+
+ // Add the new caret
+ const int new_caret_index = add_caret(new_caret_line, new_caret_column);
+
+ if (new_caret_index == -1) {
+ continue;
+ }
+ // Also add the selection if there should be one
+ if (new_caret_from_column != new_caret_to_column) {
+ select(new_caret_line, new_caret_from_column, new_caret_line, new_caret_to_column, new_caret_index);
+ // Necessary to properly modify the selection after adding the new caret
+ carets.write[new_caret_index].selection.selecting_line = new_caret_line;
+ carets.write[new_caret_index].selection.selecting_column = new_caret_column == new_caret_from_column ? new_caret_to_column : new_caret_from_column;
+ continue;
+ }
+
+ // Copy the last fit x over
+ carets.write[new_caret_index].last_fit_x = carets[caret_index].last_fit_x;
+ }
+
+ merge_overlapping_carets();
+ queue_redraw();
+}
+
Vector<int> TextEdit::get_caret_index_edit_order() {
if (!caret_index_edit_dirty) {
return caret_index_edit_order;
@@ -4730,14 +4878,6 @@ bool TextEdit::is_drag_and_drop_selection_enabled() const {
return drag_and_drop_selection_enabled;
}
-void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
- override_selected_font_color = p_override_selected_font_color;
-}
-
-bool TextEdit::is_overriding_selected_font_color() const {
- return override_selected_font_color;
-}
-
void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column, int p_caret) {
ERR_FAIL_INDEX(p_caret, carets.size());
@@ -4816,10 +4956,50 @@ void TextEdit::select_word_under_caret(int p_caret) {
continue;
}
- select(get_caret_line(c), begin, get_caret_column(c), end, c);
+ select(get_caret_line(c), begin, get_caret_line(c), end, c);
// Move the caret to the end of the word for easier editing.
set_caret_column(end, false, c);
}
+ merge_overlapping_carets();
+}
+
+void TextEdit::add_selection_for_next_occurrence() {
+ if (!selecting_enabled || !is_multiple_carets_enabled()) {
+ return;
+ }
+
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
+ }
+
+ // Always use the last caret, to correctly search for
+ // the next occurrence that comes after this caret.
+ int caret = get_caret_count() - 1;
+
+ if (!has_selection(caret)) {
+ select_word_under_caret(caret);
+ return;
+ }
+
+ const String &highlighted_text = get_selected_text(caret);
+ int column = get_selection_from_column(caret) + 1;
+ int line = get_caret_line(caret);
+
+ const Point2i next_occurrence = search(highlighted_text, SEARCH_MATCH_CASE, line, column);
+
+ if (next_occurrence.x == -1 || next_occurrence.y == -1) {
+ return;
+ }
+
+ int to_column = get_selection_to_column(caret) + 1;
+ int end = next_occurrence.x + (to_column - column);
+ int new_caret = add_caret(next_occurrence.y, end);
+
+ if (new_caret != -1) {
+ select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret);
+ adjust_viewport_to_caret(new_caret);
+ merge_overlapping_carets();
+ }
}
void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret) {
@@ -5088,6 +5268,14 @@ bool TextEdit::is_scroll_past_end_of_file_enabled() const {
return scroll_past_end_of_file_enabled;
}
+VScrollBar *TextEdit::get_v_scroll_bar() const {
+ return v_scroll;
+}
+
+HScrollBar *TextEdit::get_h_scroll_bar() const {
+ return h_scroll;
+}
+
void TextEdit::set_v_scroll(double p_scroll) {
v_scroll->set_value(p_scroll);
int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
@@ -5941,6 +6129,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_secondary_carets"), &TextEdit::remove_secondary_carets);
ClassDB::bind_method(D_METHOD("merge_overlapping_carets"), &TextEdit::merge_overlapping_carets);
ClassDB::bind_method(D_METHOD("get_caret_count"), &TextEdit::get_caret_count);
+ ClassDB::bind_method(D_METHOD("add_caret_at_carets", "below"), &TextEdit::add_caret_at_carets);
ClassDB::bind_method(D_METHOD("get_caret_index_edit_order"), &TextEdit::get_caret_index_edit_order);
ClassDB::bind_method(D_METHOD("adjust_carets_after_edit", "caret", "from_line", "from_col", "to_line", "to_col"), &TextEdit::adjust_carets_after_edit);
@@ -5974,14 +6163,12 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_and_drop_selection_enabled", "enable"), &TextEdit::set_drag_and_drop_selection_enabled);
ClassDB::bind_method(D_METHOD("is_drag_and_drop_selection_enabled"), &TextEdit::is_drag_and_drop_selection_enabled);
- ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &TextEdit::set_override_selected_font_color);
- ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &TextEdit::is_overriding_selected_font_color);
-
ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column", "caret_index"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_selection_mode"), &TextEdit::get_selection_mode);
ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
ClassDB::bind_method(D_METHOD("select_word_under_caret", "caret_index"), &TextEdit::select_word_under_caret, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_selection_for_next_occurrence"), &TextEdit::add_selection_for_next_occurrence);
ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column", "caret_index"), &TextEdit::select, DEFVAL(0));
ClassDB::bind_method(D_METHOD("has_selection", "caret_index"), &TextEdit::has_selection, DEFVAL(-1));
@@ -6020,6 +6207,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_scroll_enabled", "enable"), &TextEdit::set_smooth_scroll_enabled);
ClassDB::bind_method(D_METHOD("is_smooth_scroll_enabled"), &TextEdit::is_smooth_scroll_enabled);
+ ClassDB::bind_method(D_METHOD("get_v_scroll_bar"), &TextEdit::get_v_scroll_bar);
+ ClassDB::bind_method(D_METHOD("get_h_scroll_bar"), &TextEdit::get_h_scroll_bar);
+
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &TextEdit::set_v_scroll);
ClassDB::bind_method(D_METHOD("get_v_scroll"), &TextEdit::get_v_scroll);
@@ -6142,7 +6332,6 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a8e087909e..263a36aba8 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -443,9 +443,9 @@ private:
bool deselect_on_focus_loss_enabled = true;
bool drag_and_drop_selection_enabled = true;
- Color font_selected_color = Color(1, 1, 1);
+ Color font_selected_color = Color(0, 0, 0, 0);
Color selection_color = Color(1, 1, 1);
- bool override_selected_font_color = false;
+ bool use_selected_font_color = false;
bool selection_drag_attempt = false;
bool dragging_selection = false;
@@ -597,6 +597,10 @@ private:
void _delete(bool p_word = false, bool p_all_to_right = false);
void _move_caret_document_start(bool p_select);
void _move_caret_document_end(bool p_select);
+ bool _should_remove_secondary_carets();
+
+ // Used in add_caret_at_carets
+ void _get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x = -1) const;
protected:
void _notification(int p_what);
@@ -816,6 +820,7 @@ public:
void remove_secondary_carets();
void merge_overlapping_carets();
int get_caret_count() const;
+ void add_caret_at_carets(bool p_below);
Vector<int> get_caret_index_edit_order();
void adjust_carets_after_edit(int p_caret, int p_from_line, int p_from_col, int p_to_line, int p_to_col);
@@ -851,6 +856,7 @@ public:
void select_all();
void select_word_under_caret(int p_caret = -1);
+ void add_selection_for_next_occurrence();
void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0);
bool has_selection(int p_caret = -1) const;
@@ -886,6 +892,9 @@ public:
void set_scroll_past_end_of_file_enabled(const bool p_enabled);
bool is_scroll_past_end_of_file_enabled() const;
+ VScrollBar *get_v_scroll_bar() const;
+ HScrollBar *get_h_scroll_bar() const;
+
void set_v_scroll(double p_scroll);
double get_v_scroll() const;
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index a9982b3ece..48c6dc5cfc 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -510,18 +510,38 @@ void TextureProgressBar::_notification(int p_what) {
}
pts.append(to);
+ Ref<AtlasTexture> atlas_progress = progress;
+ bool valid_atlas_progress = atlas_progress.is_valid() && atlas_progress->get_atlas().is_valid();
+ Rect2 region_rect;
+ Size2 atlas_size;
+ if (valid_atlas_progress) {
+ region_rect = atlas_progress->get_region();
+ atlas_size = atlas_progress->get_atlas()->get_size();
+ }
+
Vector<Point2> uvs;
Vector<Point2> points;
- uvs.push_back(get_relative_center());
- points.push_back(progress_offset + s * get_relative_center());
for (int i = 0; i < pts.size(); i++) {
Point2 uv = unit_val_to_uv(pts[i]);
if (uvs.find(uv) >= 0) {
continue;
}
- uvs.push_back(uv);
points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y));
+ if (valid_atlas_progress) {
+ uv.x = Math::remap(uv.x, 0, 1, region_rect.position.x / atlas_size.x, (region_rect.position.x + region_rect.size.x) / atlas_size.x);
+ uv.y = Math::remap(uv.y, 0, 1, region_rect.position.y / atlas_size.y, (region_rect.position.y + region_rect.size.y) / atlas_size.y);
+ }
+ uvs.push_back(uv);
+ }
+
+ Point2 center_point = get_relative_center();
+ points.push_back(progress_offset + s * center_point);
+ if (valid_atlas_progress) {
+ center_point.x = Math::remap(center_point.x, 0, 1, region_rect.position.x / atlas_size.x, (region_rect.position.x + region_rect.size.x) / atlas_size.x);
+ center_point.y = Math::remap(center_point.y, 0, 1, region_rect.position.y / atlas_size.y, (region_rect.position.y + region_rect.size.y) / atlas_size.y);
}
+ uvs.push_back(center_point);
+
Vector<Color> colors;
colors.push_back(tint_progress);
draw_polygon(points, colors, uvs, progress);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index acf398305c..6f9a9a5141 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1504,6 +1504,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button);
ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button);
ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
+ ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_idx", "color"), &TreeItem::set_button_color);
ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text);
@@ -3190,7 +3191,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
bool is_command = k.is_valid() && k->is_command_or_control_pressed();
- if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3208,7 +3209,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
} else {
_go_right();
}
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3228,21 +3229,21 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
_go_left();
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed() && !is_command) {
+ } else if (p_event->is_action("ui_up", true) && p_event->is_pressed() && !is_command) {
if (!cursor_can_exit_tree) {
accept_event();
}
_go_up();
- } else if (p_event->is_action("ui_down") && p_event->is_pressed() && !is_command) {
+ } else if (p_event->is_action("ui_down", true) && p_event->is_pressed() && !is_command) {
if (!cursor_can_exit_tree) {
accept_event();
}
_go_down();
- } else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_page_down", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3280,7 +3281,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
ensure_cursor_is_visible();
- } else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_page_up", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3317,7 +3318,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
prev->select(selected_col);
}
ensure_cursor_is_visible();
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) {
if (selected_item) {
//bring up editor if possible
if (!edit_selected()) {
@@ -3326,7 +3327,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
}
accept_event();
- } else if (p_event->is_action("ui_select") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_select", true) && p_event->is_pressed()) {
if (select_mode == SELECT_MULTI) {
if (!selected_item) {
return;
diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp
index 3b7f499a07..e8e3e3e556 100644
--- a/scene/gui/view_panner.cpp
+++ b/scene/gui/view_panner.cpp
@@ -38,7 +38,9 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect)
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
Vector2 scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP));
- if (scroll_vec != Vector2()) {
+ // Moving the scroll wheel sends two events: one with pressed as true,
+ // and one with pressed as false. Make sure we only process one of them.
+ if (scroll_vec != Vector2() && mb->is_pressed()) {
if (control_scheme == SCROLL_PANS) {
if (mb->is_ctrl_pressed()) {
scroll_vec.y *= mb->get_factor();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 05d86f77f2..0d3389c13d 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -168,9 +168,6 @@ Transform2D CanvasItem::get_screen_transform() const {
}
Transform2D CanvasItem::get_global_transform() const {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
-#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
if (pi) {
@@ -986,8 +983,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
- ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
- ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
+ ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
+ ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
GDVIRTUAL_BIND(_draw);
@@ -997,7 +994,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only,Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
@@ -1035,6 +1032,11 @@ void CanvasItem::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
}
Transform2D CanvasItem::get_canvas_transform() const {
@@ -1092,7 +1094,7 @@ int CanvasItem::get_canvas_layer() const {
}
}
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_filter_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1107,6 +1109,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_filter_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
@@ -1133,7 +1143,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
return texture_filter;
}
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_repeat_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1148,6 +1158,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_repeat_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
@@ -1169,26 +1187,39 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
notify_property_list_changed();
}
-void CanvasItem::set_clip_children(bool p_enabled) {
- if (clip_children == p_enabled) {
+void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
+ ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
+
+ if (clip_children_mode == p_clip_mode) {
return;
}
- clip_children = p_enabled;
+ clip_children_mode = p_clip_mode;
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
//avoid accidental bugs, make this not work on CanvasGroup
return;
}
- RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
+
+ RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
}
-bool CanvasItem::is_clipping_children() const {
- return clip_children;
+CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
+ return clip_children_mode;
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
return texture_repeat;
}
+CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+ _refresh_texture_filter_cache();
+ return (TextureFilter)texture_filter_cache;
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+ _refresh_texture_repeat_cache();
+ return (TextureRepeat)texture_repeat_cache;
+}
+
CanvasItem::CanvasItem() :
xform_change(this) {
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index b80289fdb4..565ea930ce 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -66,8 +66,16 @@ public:
TEXTURE_REPEAT_MAX,
};
+ enum ClipChildrenMode {
+ CLIP_CHILDREN_DISABLED,
+ CLIP_CHILDREN_ONLY,
+ CLIP_CHILDREN_AND_DRAW,
+ CLIP_CHILDREN_MAX,
+ };
+
private:
- mutable SelfList<Node> xform_change;
+ mutable SelfList<Node>
+ xform_change;
RID canvas_item;
StringName canvas_group;
@@ -85,7 +93,6 @@ private:
Window *window = nullptr;
bool visible = true;
bool parent_visible_in_tree = false;
- bool clip_children = false;
bool pending_update = false;
bool top_level = false;
bool drawing = false;
@@ -95,6 +102,8 @@ private:
bool notify_local_transform = false;
bool notify_transform = false;
+ ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
+
RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
@@ -121,7 +130,9 @@ private:
static CanvasItem *current_item_drawn;
friend class Viewport;
+ void _refresh_texture_repeat_cache();
void _update_texture_repeat_changed(bool p_propagate);
+ void _refresh_texture_filter_cache();
void _update_texture_filter_changed(bool p_propagate);
protected:
@@ -200,8 +211,8 @@ public:
void queue_redraw();
void move_to_front();
- void set_clip_children(bool p_enabled);
- bool is_clipping_children() const;
+ void set_clip_children_mode(ClipChildrenMode p_clip_mode);
+ ClipChildrenMode get_clip_children_mode() const;
virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
@@ -310,6 +321,9 @@ public:
virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
+ TextureFilter get_texture_filter_in_tree();
+ TextureRepeat get_texture_repeat_in_tree();
+
// Used by control nodes to retrieve the parent's anchorable area
virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
@@ -321,6 +335,7 @@ public:
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode)
class CanvasTexture : public Texture2D {
GDCLASS(CanvasTexture, Texture2D);
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 214efe432b..be5788739b 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -38,6 +38,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ vp->_gui_set_root_order_dirty();
}
}
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 6dd83e4636..56e719968b 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -100,7 +100,7 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
}
if (p_replace) {
- queue_delete();
+ queue_free();
base->remove_child(this);
}
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index 7e2c82c88d..946929aa89 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -329,11 +329,9 @@ void MultiplayerAPI::_bind_methods() {
/// MultiplayerAPIExtension
Error MultiplayerAPIExtension::poll() {
- int err;
- if (GDVIRTUAL_CALL(_poll, err)) {
- return (Error)err;
- }
- return OK;
+ int err = OK;
+ GDVIRTUAL_CALL(_poll, err);
+ return (Error)err;
}
void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) {
@@ -342,26 +340,20 @@ void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p
Ref<MultiplayerPeer> MultiplayerAPIExtension::get_multiplayer_peer() {
Ref<MultiplayerPeer> peer;
- if (GDVIRTUAL_CALL(_get_multiplayer_peer, peer)) {
- return peer;
- }
- return nullptr;
+ GDVIRTUAL_CALL(_get_multiplayer_peer, peer);
+ return peer;
}
int MultiplayerAPIExtension::get_unique_id() {
- int id;
- if (GDVIRTUAL_CALL(_get_unique_id, id)) {
- return id;
- }
- return 1;
+ int id = 1;
+ GDVIRTUAL_CALL(_get_unique_id, id);
+ return id;
}
Vector<int> MultiplayerAPIExtension::get_peer_ids() {
Vector<int> ids;
- if (GDVIRTUAL_CALL(_get_peer_ids, ids)) {
- return ids;
- }
- return Vector<int>();
+ GDVIRTUAL_CALL(_get_peer_ids, ids);
+ return ids;
}
Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
@@ -373,34 +365,26 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
args.push_back(*p_arg[i]);
}
int ret = FAILED;
- if (GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret)) {
- return (Error)ret;
- }
- return FAILED;
+ GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret);
+ return (Error)ret;
}
int MultiplayerAPIExtension::get_remote_sender_id() {
int id = 0;
- if (GDVIRTUAL_CALL(_get_remote_sender_id, id)) {
- return id;
- }
- return 0;
+ GDVIRTUAL_CALL(_get_remote_sender_id, id);
+ return id;
}
Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) {
int err = ERR_UNAVAILABLE;
- if (GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err)) {
- return (Error)err;
- }
- return ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err);
+ return (Error)err;
}
Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) {
int err = ERR_UNAVAILABLE;
- if (GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err)) {
- return (Error)err;
- }
- return ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err);
+ return (Error)err;
}
void MultiplayerAPIExtension::_bind_methods() {
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 9b63118f7c..b4e5b11abd 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -78,6 +78,10 @@ bool MultiplayerPeer::is_refusing_new_connections() const {
return refuse_connections;
}
+bool MultiplayerPeer::is_server_relay_supported() const {
+ return false;
+}
+
void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel);
ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel);
@@ -86,8 +90,12 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer);
ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer);
+ ClassDB::bind_method(D_METHOD("get_packet_channel"), &MultiplayerPeer::get_packet_channel);
+ ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode);
ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll);
+ ClassDB::bind_method(D_METHOD("close"), &MultiplayerPeer::close);
+ ClassDB::bind_method(D_METHOD("disconnect_peer", "peer", "force"), &MultiplayerPeer::disconnect_peer, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status);
ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id);
@@ -96,6 +104,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections);
+ ClassDB::bind_method(D_METHOD("is_server_relay_supported"), &MultiplayerPeer::is_server_relay_supported);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel");
@@ -177,6 +187,14 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const {
return MultiplayerPeer::is_refusing_new_connections();
}
+bool MultiplayerPeerExtension::is_server_relay_supported() const {
+ bool can_relay;
+ if (GDVIRTUAL_CALL(_is_server_relay_supported, can_relay)) {
+ return can_relay;
+ }
+ return MultiplayerPeer::is_server_relay_supported();
+}
+
void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
@@ -197,6 +215,8 @@ void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet_peer);
GDVIRTUAL_BIND(_is_server);
GDVIRTUAL_BIND(_poll);
+ GDVIRTUAL_BIND(_close);
+ GDVIRTUAL_BIND(_disconnect_peer, "p_peer", "p_force");
GDVIRTUAL_BIND(_get_unique_id);
GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable");
GDVIRTUAL_BIND(_is_refusing_new_connections);
diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h
index ab7483ece5..4b5909538e 100644
--- a/scene/main/multiplayer_peer.h
+++ b/scene/main/multiplayer_peer.h
@@ -74,14 +74,20 @@ public:
virtual TransferMode get_transfer_mode() const;
virtual void set_refuse_new_connections(bool p_enable);
virtual bool is_refusing_new_connections() const;
+ virtual bool is_server_relay_supported() const;
virtual void set_target_peer(int p_peer_id) = 0;
virtual int get_packet_peer() const = 0;
+ virtual TransferMode get_packet_mode() const = 0;
+ virtual int get_packet_channel() const = 0;
+
+ virtual void disconnect_peer(int p_peer, bool p_force = false) = 0;
virtual bool is_server() const = 0;
virtual void poll() = 0;
+ virtual void close() = 0;
virtual int get_unique_id() const = 0;
@@ -123,14 +129,21 @@ public:
virtual bool is_refusing_new_connections() const override;
GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional.
+ virtual bool is_server_relay_supported() const override;
+ GDVIRTUAL0RC(bool, _is_server_relay_supported); // Optional.
+
EXBIND1(set_transfer_channel, int);
EXBIND0RC(int, get_transfer_channel);
EXBIND1(set_transfer_mode, TransferMode);
EXBIND0RC(TransferMode, get_transfer_mode);
EXBIND1(set_target_peer, int);
EXBIND0RC(int, get_packet_peer);
+ EXBIND0RC(TransferMode, get_packet_mode);
+ EXBIND0RC(int, get_packet_channel);
EXBIND0RC(bool, is_server);
EXBIND0(poll);
+ EXBIND0(close);
+ EXBIND2(disconnect_peer, int, bool);
EXBIND0RC(int, get_unique_id);
EXBIND0RC(ConnectionStatus, get_connection_status);
};
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 101a63db1b..304504a82e 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -322,62 +322,62 @@ void Node::_propagate_exit_tree() {
data.depth = -1;
}
-void Node::move_child(Node *p_child, int p_pos) {
+void Node::move_child(Node *p_child, int p_index) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
// 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;
+ if (p_index < 0) {
+ p_index += 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);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, p_index);
} else if (p_child->_is_internal_back()) {
- if (p_pos < 0) {
- p_pos += data.internal_children_back;
+ if (p_index < 0) {
+ p_index += 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);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, data.children.size() - data.internal_children_back + p_index);
} else {
- if (p_pos < 0) {
- p_pos += get_child_count(false);
+ if (p_index < 0) {
+ p_index += 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);
+ ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index));
+ _move_child(p_child, p_index + data.internal_children_front);
}
}
-void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
+void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
// Specifying one place beyond the end
- // means the same as moving to the last position
+ // means the same as moving to the last index
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
if (p_child->_is_internal_front()) {
- if (p_pos == data.internal_children_front) {
- p_pos--;
+ if (p_index == data.internal_children_front) {
+ p_index--;
}
} else if (p_child->_is_internal_back()) {
- if (p_pos == data.children.size()) {
- p_pos--;
+ if (p_index == data.children.size()) {
+ p_index--;
}
} else {
- if (p_pos == data.children.size() - data.internal_children_back) {
- p_pos--;
+ if (p_index == data.children.size() - data.internal_children_back) {
+ p_index--;
}
}
}
- if (p_child->data.pos == p_pos) {
+ if (p_child->data.index == p_index) {
return; //do nothing
}
- int motion_from = MIN(p_pos, p_child->data.pos);
- int motion_to = MAX(p_pos, p_child->data.pos);
+ int motion_from = MIN(p_index, p_child->data.index);
+ int motion_to = MAX(p_index, p_child->data.index);
- data.children.remove_at(p_child->data.pos);
- data.children.insert(p_pos, p_child);
+ data.children.remove_at(p_child->data.index);
+ data.children.insert(p_index, p_child);
if (data.tree) {
data.tree->tree_changed();
@@ -386,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked++;
//new pos first
for (int i = motion_from; i <= motion_to; i++) {
- data.children[i]->data.pos = i;
+ data.children[i]->data.index = i;
}
// notification second
move_child_notify(p_child);
@@ -1024,11 +1024,9 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new name is needed, create one.
+ // No name and a new name is needed, create one.
name = p_child->get_class();
- // Adjust casing according to project setting.
- name = adjust_name_casing(name);
}
//quickly test if proposed name exists
@@ -1106,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
//add a child node quickly, without name validation
p_child->data.name = p_name;
- p_child->data.pos = data.children.size();
+ p_child->data.index = data.children.size();
data.children.push_back(p_child);
p_child->data.parent = this;
@@ -1173,9 +1171,9 @@ void Node::remove_child(Node *p_child) {
Node **children = data.children.ptrw();
int idx = -1;
- if (p_child->data.pos >= 0 && p_child->data.pos < child_count) {
- if (children[p_child->data.pos] == p_child) {
- idx = p_child->data.pos;
+ if (p_child->data.index >= 0 && p_child->data.index < child_count) {
+ if (children[p_child->data.index] == p_child) {
+ idx = p_child->data.index;
}
}
@@ -1211,12 +1209,12 @@ void Node::remove_child(Node *p_child) {
children = data.children.ptrw();
for (int i = idx; i < child_count; i++) {
- children[i]->data.pos = i;
+ children[i]->data.index = i;
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
p_child->data.parent = nullptr;
- p_child->data.pos = -1;
+ p_child->data.index = -1;
if (data.inside_tree) {
p_child->_propagate_after_exit_tree();
@@ -1343,12 +1341,23 @@ Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
if (unlikely(!node)) {
+ // Try to get a clear description of this node in the error message.
+ String desc;
+ if (is_inside_tree()) {
+ desc = get_path();
+ } else {
+ desc = get_name();
+ if (desc.is_empty()) {
+ desc = get_class();
+ }
+ }
+
if (p_path.is_absolute()) {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, desc));
} else {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, desc));
}
}
@@ -1475,7 +1484,7 @@ bool Node::is_greater_than(const Node *p_node) const {
int idx = data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, data.depth, false);
- this_stack[idx--] = n->data.pos;
+ this_stack[idx--] = n->data.index;
n = n->data.parent;
}
ERR_FAIL_COND_V(idx != -1, false);
@@ -1483,7 +1492,7 @@ bool Node::is_greater_than(const Node *p_node) const {
idx = p_node->data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, p_node->data.depth, false);
- that_stack[idx--] = n->data.pos;
+ that_stack[idx--] = n->data.index;
n = n->data.parent;
}
@@ -1894,9 +1903,9 @@ int Node::get_index(bool p_include_internal) const {
ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
if (data.parent && !p_include_internal) {
- return data.pos - data.parent->data.internal_children_front;
+ return data.index - data.parent->data.internal_children_front;
}
- return data.pos;
+ return data.index;
}
Ref<Tween> Node::create_tween() {
@@ -2391,12 +2400,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
}
Node *parent = data.parent;
- int pos_in_parent = data.pos;
+ int index_in_parent = data.index;
if (data.parent) {
parent->remove_child(this);
parent->add_child(p_node);
- parent->move_child(p_node, pos_in_parent);
+ parent->move_child(p_node, index_in_parent);
}
while (get_child_count()) {
@@ -2571,7 +2580,7 @@ void Node::print_orphan_nodes() {
#endif
}
-void Node::queue_delete() {
+void Node::queue_free() {
if (is_inside_tree()) {
get_tree()->queue_delete(this);
} else {
@@ -2759,7 +2768,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group);
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("move_child", "child_node", "to_index"), &Node::move_child);
ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups);
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
@@ -2813,7 +2822,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport);
- ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_delete);
+ ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_free);
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
@@ -2949,7 +2958,7 @@ void Node::_bind_methods() {
}
String Node::_get_name_num_separator() {
- switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_num_separator").operator int()) {
+ switch (GLOBAL_GET("editor/node_naming/name_num_separator").operator int()) {
case 0:
return "";
case 1:
diff --git a/scene/main/node.h b/scene/main/node.h
index 4e6530cccd..4a3ec253b1 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -91,6 +91,7 @@ private:
SceneTree::Group *group = nullptr;
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
String scene_file_path;
Ref<SceneState> instance_state;
@@ -104,7 +105,7 @@ private:
int internal_children_front = 0;
int internal_children_back = 0;
- int pos = -1;
+ int index = -1;
int depth = -1;
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
@@ -186,8 +187,8 @@ private:
Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
- _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
+ _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; }
+ _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
friend class SceneTree;
@@ -346,8 +347,8 @@ public:
void get_groups(List<GroupInfo> *p_groups) const;
int get_persistent_group_count() const;
- void move_child(Node *p_child, int p_pos);
- void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
+ void move_child(Node *p_child, int p_index);
+ void _move_child(Node *p_child, int p_index, bool p_ignore_end = false);
void set_owner(Node *p_owner);
Node *get_owner() const;
@@ -459,7 +460,7 @@ public:
#endif
static String adjust_name_casing(const String &p_name);
- void queue_delete();
+ void queue_free();
//hacks for speed
static void init_node_hrcr();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index af481749d5..41eefe0f85 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -44,6 +44,7 @@
#include "node.h"
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
+#include "scene/gui/control.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
@@ -484,7 +485,7 @@ bool SceneTree::process(double p_time) {
#ifndef _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
//simple hack to reload fallback environment if it changed from editor
- String env_path = ProjectSettings::get_singleton()->get(SNAME("rendering/environment/defaults/default_environment"));
+ String env_path = GLOBAL_GET(SNAME("rendering/environment/defaults/default_environment"));
env_path = env_path.strip_edges(); //user may have added a space or two
String cpath;
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
@@ -895,6 +896,8 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
call_lock++;
+ Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input.
+
for (int i = gr_node_count - 1; i >= 0; i--) {
if (p_viewport->is_input_handled()) {
break;
@@ -913,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_INPUT:
n->_call_input(p_input);
break;
- case CALL_INPUT_TYPE_SHORTCUT_INPUT:
+ case CALL_INPUT_TYPE_SHORTCUT_INPUT: {
+ const Control *c = Object::cast_to<Control>(n);
+ if (c) {
+ // If calling shortcut input on a control, ensure it respects the shortcut context.
+ // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
+ if (c->get_shortcut_context() == nullptr) {
+ no_context_node_ids.append(n->get_instance_id());
+ continue;
+ }
+ if (!c->is_focus_owner_in_shortcut_context()) {
+ continue;
+ }
+ }
n->_call_shortcut_input(p_input);
break;
+ }
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
n->_call_unhandled_input(p_input);
break;
@@ -925,6 +941,13 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
}
+ for (const ObjectID &id : no_context_node_ids) {
+ Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
+ if (n) {
+ n->_call_shortcut_input(p_input);
+ }
+ }
+
call_lock--;
if (call_lock == 0) {
call_skip.clear();
@@ -1367,7 +1390,7 @@ SceneTree::SceneTree() {
root = memnew(Window);
root->set_process_mode(Node::PROCESS_MODE_PAUSABLE);
root->set_name("root");
- root->set_title(ProjectSettings::get_singleton()->get("application/config/name"));
+ root->set_title(GLOBAL_GET("application/config/name"));
#ifndef _3D_DISABLED
if (!root->get_world_3d().is_valid()) {
@@ -1390,6 +1413,9 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
+ const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false);
+ root->set_transparent_background(transparent_background);
+
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f7a515dc1d..6af96a4147 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1161,7 +1161,7 @@ void Viewport::_gui_cancel_tooltip() {
gui.tooltip_timer = Ref<SceneTreeTimer>();
}
if (gui.tooltip_popup) {
- gui.tooltip_popup->queue_delete();
+ gui.tooltip_popup->queue_free();
}
}
@@ -1261,11 +1261,17 @@ void Viewport::_gui_show_tooltip() {
tooltip_owner->add_child(gui.tooltip_popup);
- Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
+ Point2 tooltip_offset = GLOBAL_GET("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
+ r.size = r.size.min(panel->get_max_size());
Window *window = gui.tooltip_popup->get_parent_visible_window();
- Rect2i vr = window->get_usable_parent_rect();
+ Rect2i vr;
+ if (gui.tooltip_popup->is_embedded()) {
+ vr = gui.tooltip_popup->_get_embedder()->get_visible_rect();
+ } else {
+ vr = window->get_usable_parent_rect();
+ }
if (r.size.x + r.position.x > vr.size.x + vr.position.x) {
// Place it in the opposite direction. If it fails, just hug the border.
@@ -1403,10 +1409,6 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
- if (Object::cast_to<Viewport>(p_node)) {
- return nullptr;
- }
-
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1490,7 +1492,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mb->get_position();
- gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask != MouseButton::NONE) {
@@ -1644,8 +1645,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mm->get_position();
- gui.last_mouse_pos = mpos;
-
// Drag & drop.
if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
gui.drag_accum += mm->get_relative();
@@ -2759,6 +2758,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ev = p_event;
}
+ Ref<InputEventMouse> me = ev;
+ if (me.is_valid()) {
+ gui.last_mouse_pos = me->get_position();
+ }
+
if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) {
set_input_as_handled();
return;
@@ -3727,6 +3731,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 7fb3f32d36..ebb11ecee8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -157,26 +157,18 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
}
-#else
- DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
-#endif
}
}
bool Window::get_flag(Flags p_flag) const {
ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
}
-#else
- flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
-#endif
}
return flags[p_flag];
}
@@ -232,6 +224,14 @@ bool Window::is_embedded() const {
return _get_embedder() != nullptr;
}
+bool Window::is_in_edited_scene_root() const {
+#ifdef TOOLS_ENABLED
+ return (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this));
+#else
+ return false;
+#endif
+}
+
void Window::_make_window() {
ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
@@ -259,15 +259,12 @@ void Window::_make_window() {
#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
_update_window_size();
@@ -465,14 +462,10 @@ void Window::set_visible(bool p_visible) {
//update transient exclusive
if (transient_parent) {
if (exclusive && visible) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -519,13 +512,9 @@ void Window::_make_transient() {
window->transient_children.insert(this);
if (is_inside_tree() && is_visible() && exclusive) {
if (transient_parent->exclusive_child == nullptr) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else if (transient_parent->exclusive_child != this) {
ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
}
@@ -568,27 +557,19 @@ void Window::set_exclusive(bool p_exclusive) {
exclusive = p_exclusive;
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
}
if (transient_parent) {
if (p_exclusive && is_inside_tree() && is_visible()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -606,6 +587,18 @@ bool Window::is_visible() const {
}
void Window::_update_window_size() {
+ // Force window to respect size limitations of rendering server
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ if (rendering_server) {
+ Size2i max_window_size = rendering_server->get_maximum_viewport_size();
+
+ if (max_window_size != Size2i()) {
+ size = size.min(max_window_size);
+ min_size = min_size.min(max_window_size);
+ max_size = max_size.min(max_window_size);
+ }
+ }
+
Size2i size_limit;
if (wrap_controls) {
size_limit = get_contents_minimum_size();
@@ -651,9 +644,9 @@ void Window::_update_window_size() {
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
}
- DisplayServer::get_singleton()->window_set_size(size, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
}
//update the viewport
@@ -1847,6 +1840,11 @@ void Window::_bind_methods() {
}
Window::Window() {
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ if (rendering_server) {
+ max_size = rendering_server->get_maximum_viewport_size();
+ }
+
theme_owner = memnew(ThemeOwner);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 786f0ada38..03597b309a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -234,6 +234,8 @@ public:
void set_clamp_to_embedder(bool p_enable);
bool is_clamped_to_embedder() const;
+ bool is_in_edited_scene_root() const;
+
bool can_draw() const;
void set_ime_active(bool p_active);
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index a9b7e9acbe..f445634a45 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -169,8 +169,10 @@ static bool _collect_inheritance_chain(const Ref<SceneState> &p_state, const Nod
state = state->get_base_scene_state();
}
- for (int i = inheritance_states.size() - 1; i >= 0; --i) {
- r_states_stack.push_back(inheritance_states[i]);
+ if (inheritance_states.size() > 0) {
+ for (int i = inheritance_states.size() - 1; i >= 0; --i) {
+ r_states_stack.push_back(inheritance_states[i]);
+ }
}
return found;
@@ -214,10 +216,12 @@ Vector<SceneState::PackState> PropertyUtils::get_node_states_stack(const Node *p
{
states_stack_ret.resize(states_stack.size());
_FastPackState *ps = states_stack.ptr();
- for (int i = states_stack.size() - 1; i >= 0; --i) {
- states_stack_ret.write[i].state.reference_ptr(ps->state);
- states_stack_ret.write[i].node = ps->node;
- ++ps;
+ if (states_stack.size() > 0) {
+ for (int i = states_stack.size() - 1; i >= 0; --i) {
+ states_stack_ret.write[i].state.reference_ptr(ps->state);
+ states_stack_ret.write[i].node = ps->node;
+ ++ps;
+ }
}
}
return states_stack_ret;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 2bcf569f4e..dfd9c6eb2f 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -5239,9 +5239,7 @@ bool Animation::_fetch_compressed(uint32_t p_compressed_track, double p_time, Ve
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5384,9 +5382,7 @@ void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5456,9 +5452,7 @@ int Animation::_get_compressed_key_count(uint32_t p_compressed_track) const {
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5492,9 +5486,7 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 0505f6b559..1b06e09bb8 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -639,9 +639,7 @@ void BitMap::resize(const Size2i &p_new_size) {
}
Ref<Image> BitMap::convert_to_image() const {
- Ref<Image> image;
- image.instantiate();
- image->create(width, height, false, Image::FORMAT_L8);
+ Ref<Image> image = Image::create_empty(width, height, false, Image::FORMAT_L8);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index 4eaae111a1..5bcefcd0e4 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -42,9 +42,9 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ for (uint32_t i = 0; i < md.edges.size(); i++) {
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
return lines;
}
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index c9d92cea3f..aa271e6f4b 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -433,7 +433,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_color", "TextEdit", control_font_color);
- theme->set_color("font_selected_color", "TextEdit", control_font_pressed_color);
+ theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", control_font_disabled_color);
theme->set_color("font_placeholder_color", "TextEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
@@ -476,7 +476,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("completion_scroll_hovered_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.4));
theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "CodeEdit", control_font_color);
- theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
+ theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_placeholder_color", "CodeEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
@@ -959,7 +959,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font_size("mono_font_size", "RichTextLabel", -1);
theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
- theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0));
+ theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
@@ -980,6 +980,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_constant("text_highlight_h_padding", "RichTextLabel", 3 * scale);
+ theme->set_constant("text_highlight_v_padding", "RichTextLabel", 3 * scale);
+
// Containers
theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index ebdaaaa95f..23bd8a4be4 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -78,7 +78,7 @@ float Environment::get_sky_custom_fov() const {
void Environment::set_sky_rotation(const Vector3 &p_rotation) {
bg_sky_rotation = p_rotation;
- RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation));
+ RS::get_singleton()->environment_set_sky_orientation(environment, Basis::from_euler(p_rotation));
}
Vector3 Environment::get_sky_rotation() const {
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index cbecab62b3..1eb94dcb94 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1341,6 +1341,19 @@ void FontFile::reset_state() {
/*************************************************************************/
+// OEM encoding mapping for 0x80..0xFF range.
+static const char32_t _oem_to_unicode[][129] = {
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\u0160\u2039\u015a\u0164\u017d\u0179\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0161\u203a\u015b\u0165\u017e\u017a\xa0\u02c7\u02d8\u0141\xa4\u0104\xa6\xa7\xa8\xa9\u015e\xab\xac\xad\xae\u017b\xb0\xb1\u02db\u0142\xb4\xb5\xb6\xb7\xb8\u0105\u015f\xbb\u013d\u02dd\u013e\u017c\u0154\xc1\xc2\u0102\xc4\u0139\u0106\xc7\u010c\xc9\u0118\xcb\u011a\xcd\xce\u010e\u0110\u0143\u0147\xd3\xd4\u0150\xd6\xd7\u0158\u016e\xda\u0170\xdc\xdd\u0162\xdf\u0155\xe1\xe2\u0103\xe4\u013a\u0107\xe7\u010d\xe9\u0119\xeb\u011b\xed\xee\u010f\u0111\u0144\u0148\xf3\xf4\u0151\xf6\xf7\u0159\u016f\xfa\u0171\xfc\xfd\u0163\u02d9", // 1250 - Latin 2
+ U"\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", // 1251 - Cyrillic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\u017d\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", // 1252 - Latin 1
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\u0385\u0386\xa3\xa4\xa5\xa6\xa7\xa8\xa9\ufffe\xab\xac\xad\xae\u2015\xb0\xb1\xb2\xb3\u0384\xb5\xb6\xb7\u0388\u0389\u038a\xbb\u038c\xbd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffe\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffe", // 1253 - Greek
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\u011e\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\u0130\u015e\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\u011f\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u0131\u015f\xff", // 1254 - Turkish
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\xa1\xa2\xa3\u20aa\xa5\xa6\xa7\xa8\xa9\xd7\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xf7\xbb\xbc\xbd\xbe\xbf\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\ufffe\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05f0\u05f1\u05f2\u05f3\u05f4\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffe\ufffe\u200e\u200f\ufffe", // 1255 - Hebrew
+ U"\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\xa0\u060c\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\u06be\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\u061b\xbb\xbc\xbd\xbe\u061f\u06c1\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\xd7\u0637\u0638\u0639\u063a\u0640\u0641\u0642\u0643\xe0\u0644\xe2\u0645\u0646\u0647\u0648\xe7\xe8\xe9\xea\xeb\u0649\u064a\xee\xef\u064b\u064c\u064d\u064e\xf4\u064f\u0650\xf7\u0651\xf9\u0652\xfb\xfc\u200e\u200f\u06d2", // 1256 - Arabic
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\xa8\u02c7\xb8\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\xaf\u02db\ufffe\xa0\ufffe\xa2\xa3\xa4\ufffe\xa6\xa7\xd8\xa9\u0156\xab\xac\xad\xae\xc6\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xf8\xb9\u0157\xbb\xbc\xbd\xbe\xe6\u0104\u012e\u0100\u0106\xc4\xc5\u0118\u0112\u010c\xc9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\xd3\u014c\xd5\xd6\xd7\u0172\u0141\u015a\u016a\xdc\u017b\u017d\xdf\u0105\u012f\u0101\u0107\xe4\xe5\u0119\u0113\u010d\xe9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\xf3\u014d\xf5\xf6\xf7\u0173\u0142\u015b\u016b\xfc\u017c\u017e\u02d9", // 1257 - Baltic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\u0102\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\u0300\xcd\xce\xcf\u0110\xd1\u0309\xd3\xd4\u01a0\xd6\xd7\xd8\xd9\xda\xdb\xdc\u01af\u0303\xdf\xe0\xe1\xe2\u0103\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\u0301\xed\xee\xef\u0111\xf1\u0323\xf3\xf4\u01a1\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u01b0\u20ab\xff", // 1258 - Vietnamese
+};
+
Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
@@ -1371,10 +1384,12 @@ Error FontFile::load_bitmap_font(const String &p_path) {
f->get_buffer((unsigned char *)&magic, 4);
if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') {
// Binary BMFont file.
- ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported."), (int)magic[3]));
+ ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported (should be 3)."), (int)magic[3]));
uint8_t block_type = f->get_8();
uint32_t block_size = f->get_32();
+ bool unicode = false;
+ uint8_t encoding = 9;
while (!f->eof_reached()) {
uint64_t off = f->get_position();
switch (block_type) {
@@ -1382,14 +1397,48 @@ Error FontFile::load_bitmap_font(const String &p_path) {
ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, RTR("Invalid BMFont info block size."));
base_size = f->get_16();
uint8_t flags = f->get_8();
- ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
if (flags & (1 << 3)) {
st_flags.set_flag(TextServer::FONT_BOLD);
}
if (flags & (1 << 2)) {
st_flags.set_flag(TextServer::FONT_ITALIC);
}
- f->get_8(); // non-unicode charset, skip
+ unicode = (flags & 0x02);
+ uint8_t encoding_id = f->get_8(); // non-unicode charset
+ if (!unicode) {
+ switch (encoding_id) {
+ case 0x00: {
+ encoding = 2;
+ } break;
+ case 0xB2: {
+ encoding = 6;
+ } break;
+ case 0xBA: {
+ encoding = 7;
+ } break;
+ case 0xEE: {
+ encoding = 0;
+ } break;
+ case 0xA1: {
+ encoding = 3;
+ } break;
+ case 0xB1: {
+ encoding = 5;
+ } break;
+ case 0xCC: {
+ encoding = 1;
+ } break;
+ case 0xA2: {
+ encoding = 4;
+ } break;
+ case 0xA3: {
+ encoding = 8;
+ } break;
+ default: {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %x, parsing as Unicode (should be 0x00 - Latin 1, 0xB2 - Arabic, 0xBA - Baltic, 0xEE - Latin 2, 0xA1 - Greek, 0xB1 - Hebrew, 0xCC - Cyrillic, 0xA2 - Turkish, 0xA3 - Vietnamese).", encoding_id));
+ } break;
+ };
+ }
f->get_16(); // stretch_h, skip
f->get_8(); // aa, skip
f->get_32(); // padding, skip
@@ -1492,6 +1541,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Rect2 uv_rect;
char32_t idx = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
uv_rect.position.x = (int16_t)f->get_16();
uv_rect.position.y = (int16_t)f->get_16();
uv_rect.size.width = (int16_t)f->get_16();
@@ -1508,24 +1565,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
int texture_idx = f->get_8();
uint8_t channel = f->get_8();
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1546,6 +1604,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Vector2i kpk;
kpk.x = f->get_32();
kpk.y = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.y));
+ kpk.y = 0x00;
+ }
+ }
set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0));
}
} break;
@@ -1561,6 +1633,8 @@ Error FontFile::load_bitmap_font(const String &p_path) {
} else {
// Text BMFont file.
f->seek(0);
+ bool unicode = false;
+ uint8_t encoding = 9;
while (true) {
String line = f->get_line();
@@ -1625,7 +1699,37 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("face")) {
font_name = keys["face"];
}
- ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
+ if (keys.has("unicode")) {
+ unicode = keys["unicode"].to_int();
+ }
+ if (!unicode) {
+ if (keys.has("charset")) {
+ String encoding_name = keys["charset"].to_upper();
+ if (encoding_name == "" || encoding_name == "ASCII" || encoding_name == "ANSI") {
+ encoding = 2;
+ } else if (encoding_name == "ARABIC") {
+ encoding = 6;
+ } else if (encoding_name == "BALTIC") {
+ encoding = 7;
+ } else if (encoding_name == "EASTEUROPE") {
+ encoding = 0;
+ } else if (encoding_name == "GREEK") {
+ encoding = 3;
+ } else if (encoding_name == "HEBREW") {
+ encoding = 5;
+ } else if (encoding_name == "RUSSIAN") {
+ encoding = 1;
+ } else if (encoding_name == "TURKISH") {
+ encoding = 4;
+ } else if (encoding_name == "VIETNAMESE") {
+ encoding = 8;
+ } else {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %s, parsing as Unicode (should be ANSI, ASCII, ARABIC, BALTIC, EASTEUROPE, GREEK, HEBREW, RUSSIAN, TURKISH or VIETNAMESE).", encoding_name));
+ }
+ } else {
+ encoding = 2;
+ }
+ }
} else if (type == "common") {
if (keys.has("lineHeight")) {
height = keys["lineHeight"].to_int();
@@ -1719,6 +1823,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("id")) {
idx = keys["id"].to_int();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
}
if (keys.has("x")) {
uv_rect.position.x = keys["x"].to_int();
@@ -1753,24 +1865,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
channel = keys["chnl"].to_int();
}
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1791,6 +1904,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("second")) {
kpk.y = keys["second"].to_int();
}
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.y = 0x00;
+ }
+ }
if (keys.has("amount")) {
set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0));
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 838927e34f..10d193f950 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -107,18 +107,15 @@ Shader::Mode Material::get_shader_mode() const {
}
bool Material::_can_do_next_pass() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_do_next_pass, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_do_next_pass, ret);
+ return ret;
}
+
bool Material::_can_use_render_priority() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_use_render_priority, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_use_render_priority, ret);
+ return ret;
}
void Material::_bind_methods() {
@@ -2348,7 +2345,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
set_flag(FLAG_DISABLE_DEPTH_TEST, true);
}
-void BaseMaterial3D::set_proximity_fade(bool p_enable) {
+void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) {
proximity_fade_enabled = p_enable;
_queue_shader_change();
notify_property_list_changed();
@@ -2624,7 +2621,7 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refraction_texture_channel", "channel"), &BaseMaterial3D::set_refraction_texture_channel);
ClassDB::bind_method(D_METHOD("get_refraction_texture_channel"), &BaseMaterial3D::get_refraction_texture_channel);
- ClassDB::bind_method(D_METHOD("set_proximity_fade", "enabled"), &BaseMaterial3D::set_proximity_fade);
+ ClassDB::bind_method(D_METHOD("set_proximity_fade_enabled", "enabled"), &BaseMaterial3D::set_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("is_proximity_fade_enabled"), &BaseMaterial3D::is_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &BaseMaterial3D::set_proximity_fade_distance);
@@ -2808,7 +2805,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1,suffix:px"), "set_point_size", "get_point_size");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enabled"), "set_proximity_fade_enabled", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("MSDF", "msdf_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
diff --git a/scene/resources/material.h b/scene/resources/material.h
index dd9589c577..b3c2159e70 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -719,7 +719,7 @@ public:
void set_on_top_of_alpha();
- void set_proximity_fade(bool p_enable);
+ void set_proximity_fade_enabled(bool p_enable);
bool is_proximity_fade_enabled() const;
void set_proximity_fade_distance(float p_distance);
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 03ccae5b74..706db3af16 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1576,9 +1576,8 @@ void ArrayMesh::_recompute_aabb() {
}
}
}
-#ifndef _MSC_VER
-#warning need to add binding to add_surface using future MeshSurfaceData object
-#endif
+
+// TODO: Need to add binding to add_surface using future MeshSurfaceData object.
void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index a93e70ecd4..de97498674 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -527,7 +527,7 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
ADD_GROUP("Cells", "cell_");
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 1f71d583b1..1c99fa5554 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1546,7 +1546,7 @@ Array SceneState::get_connection_binds(int p_idx) const {
return binds;
}
-bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method) {
+bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance) {
// this method cannot be const because of this
Ref<SceneState> ss = this;
@@ -1578,6 +1578,10 @@ bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p
}
}
+ if (p_no_inheritance) {
+ break;
+ }
+
ss = ss->get_base_scene_state();
} while (ss.is_valid());
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 8e1a1d29b6..c6f82ddd5e 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -176,7 +176,7 @@ public:
int get_connection_unbinds(int p_idx) const;
Array get_connection_binds(int p_idx) const;
- bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method);
+ bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance = false);
Vector<NodePath> get_editable_instances() const;
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index e51c786786..b77430c154 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -115,6 +115,7 @@ void ParticleProcessMaterial::init_shaders() {
shader_names->sub_emitter_frequency = "sub_emitter_frequency";
shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end";
+ shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision";
shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity";
shader_names->collision_friction = "collision_friction";
@@ -235,6 +236,9 @@ void ParticleProcessMaterial::_update_shader() {
if (sub_emitter_mode == SUB_EMITTER_AT_END) {
code += "uniform int sub_emitter_amount_at_end;\n";
}
+ if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) {
+ code += "uniform int sub_emitter_amount_at_collision;\n";
+ }
code += "uniform bool sub_emitter_keep_velocity;\n";
}
@@ -830,6 +834,13 @@ void ParticleProcessMaterial::_update_shader() {
code += " TRANSFORM[3].z = 0.0;\n";
}
+ // scale by scale
+ code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
+ code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
+ code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
+ code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
+ code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
+
if (collision_mode == COLLISION_RIGID) {
code += " if (COLLIDED) {\n";
code += " if (length(VELOCITY) > 3.0) {\n";
@@ -844,21 +855,6 @@ void ParticleProcessMaterial::_update_shader() {
}
code += " }\n";
code += " }\n";
- }
-
- // scale by scale
- code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
- code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
- code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
- code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
- code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
-
- if (collision_mode == COLLISION_RIGID) {
- code += " if (COLLIDED) {\n";
- code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n";
- code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
- code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n";
- code += " }\n";
} else if (collision_mode == COLLISION_HIDE_ON_CONTACT) {
code += " if (COLLIDED) {\n";
code += " ACTIVE = false;\n";
@@ -874,7 +870,7 @@ void ParticleProcessMaterial::_update_shader() {
code += " if (DELTA >= interval_rem) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_COLLISION: {
- code += " if (COLLIDED) emit_count = 1;\n";
+ code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n";
} break;
case SUB_EMITTER_AT_END: {
code += " float unit_delta = DELTA/LIFETIME;\n";
@@ -1433,6 +1429,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const
p_property.usage = PROPERTY_USAGE_NONE;
}
+ if (p_property.name == "sub_emitter_amount_at_collision" && sub_emitter_mode != SUB_EMITTER_AT_COLLISION) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -1488,6 +1488,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const {
return sub_emitter_amount_at_end;
}
+void ParticleProcessMaterial::set_sub_emitter_amount_at_collision(int p_amount) {
+ sub_emitter_amount_at_collision = p_amount;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_collision, p_amount);
+}
+
+int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const {
+ return sub_emitter_amount_at_collision;
+}
+
void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
sub_emitter_keep_velocity = p_enable;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable);
@@ -1640,6 +1649,9 @@ void ParticleProcessMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end);
ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision);
+
ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity);
ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity);
@@ -1752,6 +1764,7 @@ void ParticleProcessMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
ADD_GROUP("Attractor Interaction", "attractor_interaction_");
@@ -1859,6 +1872,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() :
set_sub_emitter_mode(SUB_EMITTER_DISABLED);
set_sub_emitter_frequency(4);
set_sub_emitter_amount_at_end(1);
+ set_sub_emitter_amount_at_collision(1);
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h
index 8fe9223a47..64d828b3e7 100644
--- a/scene/resources/particle_process_material.h
+++ b/scene/resources/particle_process_material.h
@@ -246,6 +246,7 @@ private:
StringName sub_emitter_frequency;
StringName sub_emitter_amount_at_end;
+ StringName sub_emitter_amount_at_collision;
StringName sub_emitter_keep_velocity;
StringName collision_friction;
@@ -304,6 +305,7 @@ private:
SubEmitterMode sub_emitter_mode;
double sub_emitter_frequency = 0.0;
int sub_emitter_amount_at_end = 0;
+ int sub_emitter_amount_at_collision = 0;
bool sub_emitter_keep_velocity = false;
//do not save emission points here
@@ -418,6 +420,9 @@ public:
void set_sub_emitter_amount_at_end(int p_amount);
int get_sub_emitter_amount_at_end() const;
+ void set_sub_emitter_amount_at_collision(int p_amount);
+ int get_sub_emitter_amount_at_collision() const;
+
void set_sub_emitter_keep_velocity(bool p_enable);
bool get_sub_emitter_keep_velocity() const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 67d4b14b04..eb83a37c7b 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -771,6 +771,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = 0;
prevrow = 0;
+ const real_t side_normal_y = (bottom_radius - top_radius) / height;
for (j = 0; j <= (rings + 1); j++) {
v = j;
v /= (rings + 1);
@@ -789,7 +790,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
Vector3 p = Vector3(x * radius, y, z * radius);
points.push_back(p);
- normals.push_back(Vector3(x, 0.0, z));
+ normals.push_back(Vector3(x, side_normal_y, z).normalized());
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * 0.5));
point++;
@@ -1078,7 +1079,7 @@ void PlaneMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X, Face Y, Face Z"), "set_orientation", "get_orientation");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X,Face Y,Face Z"), "set_orientation", "get_orientation");
BIND_ENUM_CONSTANT(FACE_X)
BIND_ENUM_CONSTANT(FACE_Y)
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index c0d65fb445..85b538b1d9 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -445,7 +445,14 @@ Error ResourceLoaderText::load() {
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
path = ResourceUID::get_singleton()->get_id_path(uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(path) != uid) {
+ WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+#endif
}
}
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index fe43f345d4..61daf801e8 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -105,6 +105,7 @@ void Shape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts);
ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts);
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw);
+ ClassDB::bind_method(D_METHOD("get_rect"), &Shape2D::get_rect);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
}
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index 885cf0f1b8..1b7354853d 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -127,7 +127,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
@@ -230,7 +230,7 @@ void SkeletonModification2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_draw_gizmo"), &SkeletonModification2D::get_editor_draw_gizmo);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification2D::SkeletonModification2D() {
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index d3c62e441f..6593f476f5 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -212,7 +212,7 @@ void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() {
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index 2c0f6e779e..fa487cb061 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -142,7 +142,7 @@ void SkeletonModification3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification3D::clamp_angle);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification3D::SkeletonModification3D() {
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
index 3251ee4189..82dc30ec5f 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_3d_ccdik.cpp
@@ -98,7 +98,7 @@ void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list)
p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::INT, base_string + "ccdik_axis",
- PROPERTY_HINT_ENUM, "X Axis, Y Axis, Z Axis", PROPERTY_USAGE_DEFAULT));
+ PROPERTY_HINT_ENUM, "X Axis,Y Axis,Z Axis", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_joint_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (ccdik_data_chain[i].enable_constraint) {
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
index 69167cb308..8ada7d0a5b 100644
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ b/scene/resources/skeleton_modification_3d_lookat.cpp
@@ -67,7 +67,7 @@ bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret
void SkeletonModification3DLookAt::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "lock_rotation_to_plane", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (lock_rotation_to_plane) {
- p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane, Y plane, Z plane", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane,Y plane,Z plane", PROPERTY_USAGE_DEFAULT));
}
p_list->push_back(PropertyInfo(Variant::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
}
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index cd893d8c23..f379f88bed 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -43,12 +43,9 @@ float StyleBox::get_style_margin(Side p_side) const {
}
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)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret);
+ return ret;
}
void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
@@ -109,11 +106,8 @@ Point2 StyleBox::get_offset() const {
Size2 StyleBox::get_center_size() const {
Size2 ret;
- if (GDVIRTUAL_CALL(_get_center_size, ret)) {
- return ret;
- }
-
- return Size2();
+ GDVIRTUAL_CALL(_get_center_size, ret);
+ return ret;
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 823d742d72..ca1cd54349 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -218,7 +218,48 @@ Array TextLine::get_objects() const {
}
Rect2 TextLine::get_object_rect(Variant p_key) const {
- return TS->shaped_text_get_object_rect(rid, p_key);
+ Vector2 ofs;
+
+ float length = TS->shaped_text_get_width(rid);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ } break;
+ }
+ }
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(rid);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(rid);
+ }
+
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, p_key);
+ rect.position += ofs;
+
+ return rect;
}
void TextLine::set_horizontal_alignment(HorizontalAlignment p_alignment) {
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 7e9a2591e4..59bb24c8b8 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -540,16 +540,90 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
- Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
- for (int i = 0; i < p_line; i++) {
- Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
+
+ Vector2 ofs;
+
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ for (int i = 0; i <= p_line; i++) {
+ float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y;
+ ofs.x = 0.f;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
} else {
- xrect.position.x += lsize.x;
+ ofs.y = 0.f;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ }
+ float length = TS->shaped_text_get_width(lines_rid[i]);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ } break;
+ }
+ }
+ if (i != p_line) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = 0.f;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ } else {
+ ofs.y = 0.f;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ }
}
}
- return xrect;
+
+ Rect2 rect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
+ rect.position += ofs;
+
+ return rect;
}
Size2 TextParagraph::get_line_size(int p_line) const {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 4085aa8ec2..5232e8fcab 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -60,20 +60,14 @@ Size2 Texture2D::get_size() const {
}
bool Texture2D::is_pixel_opaque(int p_x, int p_y) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret);
+ return ret;
}
bool Texture2D::has_alpha() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_alpha, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_has_alpha, ret);
+ return ret;
}
void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
@@ -122,7 +116,7 @@ void Texture2D::_bind_methods() {
GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose")
GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose")
- GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
+ GDVIRTUAL_BIND(_draw_rect_region, "to_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
}
Texture2D::Texture2D() {
@@ -653,7 +647,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
Image::Format format = Image::Format(f->get_32());
if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
- //look for a PNG or WEBP file inside
+ //look for a PNG or WebP file inside
int sw = w;
int sh = h;
@@ -740,7 +734,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
}
}
- image->create(w, h, true, mipmap_images[0]->get_format(), img_data);
+ image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);
return image;
}
@@ -766,10 +760,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
f->get_buffer(wr, data.size());
}
- Ref<Image> image;
- image.instantiate();
-
- image->create(tw, th, mipmaps - i ? true : false, format, data);
+ Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);
return image;
}
@@ -2336,11 +2327,11 @@ void GradientTexture2D::_update() {
image.instantiate();
if (gradient->get_points_count() <= 1) { // No need to interpolate.
- image->create(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
+ image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
} else {
if (use_hdr) {
- image->create(width, height, false, Image::FORMAT_RGBAF);
+ image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
Gradient &g = **gradient;
// `create()` isn't available for non-uint8_t data, so fill in the data manually.
for (int y = 0; y < height; y++) {
@@ -2367,7 +2358,7 @@ void GradientTexture2D::_update() {
}
}
}
- image->create(width, height, false, Image::FORMAT_RGBA8, data);
+ image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
}
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 4e529de8ee..9a9f0ad1af 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -238,7 +238,7 @@ private:
Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
mutable Ref<BitMap> alpha_cache;
@@ -415,7 +415,7 @@ class ImageTextureLayered : public TextureLayered {
LayeredType layered_type;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 0;
int height = 0;
@@ -495,7 +495,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int layers = 0;
@@ -587,7 +587,7 @@ class ImageTexture3D : public Texture3D {
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 1;
int height = 1;
int depth = 1;
@@ -641,7 +641,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int d = 0;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index d7d7b5fe31..3caf6484d9 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1801,11 +1801,11 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
// Get the best tile.
Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
Rect2i region = counts[terrain_set][terrain].region;
- image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
+ image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
image->blit_rect(texture->get_image(), region, Point2i());
image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
} else {
- image->create(1, 1, false, Image::FORMAT_RGBA8);
+ image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
@@ -4602,9 +4602,7 @@ void TileSetAtlasSource::_update_padded_texture() {
return;
}
- Ref<Image> image;
- image.instantiate();
- image->create(size.x, size.y, false, src->get_format());
+ Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format());
for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index e156679711..8f175e99a6 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -277,6 +277,9 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
+ bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
+ return !operator==(p_terrains_pattern);
+ };
void set_terrain(int p_terrain);
int get_terrain() const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index df9addb6bb..b30ca3e721 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -456,11 +456,9 @@ void VisualShaderNodeCustom::update_ports() {
}
String VisualShaderNodeCustom::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_name, ret)) {
- return ret;
- }
- return "Unnamed";
+ String ret = "Unnamed";
+ GDVIRTUAL_CALL(_get_name, ret);
+ return ret;
}
int VisualShaderNodeCustom::get_input_port_count() const {
@@ -559,11 +557,9 @@ String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, Vis
}
bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) {
- return ret;
- }
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret);
+ return ret;
}
void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
@@ -1509,11 +1505,10 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
void VisualShader::reset_state() {
-#ifndef _MSC_VER
-#warning everything needs to be cleared here
-#endif
+ // TODO: Everything needs to be cleared here.
emit_changed();
}
+
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index de13912b75..04637983b5 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1642,17 +1642,20 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const
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 += " {\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;";
- code += vformat(" %s = -_depth_view.z;", p_output_vars[0]);
+ 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;\n";
+ code += vformat(" %s = -__depth_view.z;\n", p_output_vars[0]);
+ code += " }\n";
return code;
}
VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+ simple_decl = false;
}
////////////// Float Op
@@ -3204,6 +3207,7 @@ String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
String VisualShaderNodeUVPolarCoord::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 += " {\n";
String uv;
if (p_input_vars[0].is_empty()) {
@@ -3220,17 +3224,18 @@ String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualSh
String repeat = vformat("%s", p_input_vars[3]);
if (p_mode == Shader::MODE_CANVAS_ITEM) {
- code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
- code += " float __radius = length(__dir) * 2.0;\n";
- code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
- code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n";
+ code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
} else {
- code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
- code += " float __radius = length(__dir) * 2.0;\n";
- code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
- code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n";
+ code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
}
+ code += " }\n";
return code;
}
@@ -3238,6 +3243,8 @@ VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() {
set_input_port_default_value(1, Vector2(0.5, 0.5)); // center
set_input_port_default_value(2, 1.0); // zoom
set_input_port_default_value(3, 1.0); // repeat
+
+ simple_decl = false;
}
////////////// Dot Product
@@ -7256,22 +7263,26 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
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;
+ code += " {\n";
String proximity_fade_distance = vformat("%s", p_input_vars[0]);
- code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
if (!RenderingServer::get_singleton()->is_low_end()) {
- code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
} else {
- code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
}
- code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
- code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+ code += " __depth_world_pos.xyz /= __depth_world_pos.w;\n";
+ code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+ code += " }\n";
return code;
}
VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
set_input_port_default_value(0, 1.0);
+
+ simple_decl = false;
}
////////////// Random Range
@@ -7416,11 +7427,11 @@ String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
String VisualShaderNodeRemap::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(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
- code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
- code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
-
+ code += " {\n";
+ code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
+ code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
+ code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
+ code += " }\n";
return code;
}
@@ -7429,4 +7440,6 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() {
set_input_port_default_value(2, 1.0);
set_input_port_default_value(3, 0.0);
set_input_port_default_value(4, 1.0);
+
+ simple_decl = false;
}
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index ab7354f6e7..f125b05a26 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -460,9 +460,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -481,9 +481,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -502,9 +502,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBA8);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
}
for (int i = 0; i < p_array.size(); i++) {