summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--doc/classes/NativeMenu.xml11
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml1
-rw-r--r--editor/animation_track_editor.cpp75
-rw-r--r--editor/animation_track_editor.h3
-rw-r--r--editor/connections_dialog.cpp9
-rw-r--r--editor/editor_inspector.cpp13
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_node.cpp22
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_properties_array_dict.cpp20
-rw-r--r--editor/editor_properties_array_dict.h11
-rw-r--r--editor/editor_resource_preview.cpp4
-rw-r--r--editor/editor_resource_preview.h3
-rw-r--r--editor/gui/editor_scene_tabs.cpp2
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp4
-rw-r--r--editor/project_settings_editor.cpp12
-rw-r--r--editor/property_selector.cpp17
-rw-r--r--editor/scene_tree_dock.cpp4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs8
-rw-r--r--modules/navigation/nav_map.cpp2
-rw-r--r--modules/openxr/extensions/openxr_hand_tracking_extension.cpp7
-rw-r--r--platform/android/api/jni_singleton.h17
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp3
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp12
-rw-r--r--platform/macos/display_server_macos.mm86
-rw-r--r--platform/macos/godot_menu_delegate.mm9
-rw-r--r--platform/macos/native_menu_macos.h5
-rw-r--r--platform/macos/native_menu_macos.mm49
-rw-r--r--platform/web/display_server_web.cpp11
-rw-r--r--platform/windows/display_server_windows.cpp21
-rw-r--r--platform/windows/native_menu_windows.cpp45
-rw-r--r--platform/windows/native_menu_windows.h2
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/container.cpp18
-rw-r--r--scene/gui/container.h8
-rw-r--r--scene/gui/graph_element.cpp4
-rw-r--r--scene/gui/graph_node.cpp8
-rw-r--r--scene/gui/margin_container.cpp4
-rw-r--r--scene/gui/panel_container.cpp2
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/tab_container.cpp16
-rw-r--r--scene/gui/text_edit.cpp13
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader_nodes.cpp2
-rw-r--r--servers/display/native_menu.cpp7
-rw-r--r--servers/display/native_menu.h2
-rw-r--r--servers/display_server.cpp24
-rw-r--r--servers/display_server.h24
-rw-r--r--tests/scene/test_code_edit.h39
-rw-r--r--tests/servers/test_navigation_server_3d.h6
-rw-r--r--thirdparty/embree/common/sys/sysinfo.cpp2
-rw-r--r--thirdparty/embree/patches/mingw-no-cpuidex.patch13
-rw-r--r--thirdparty/glslang/glslang/Include/InfoSink.h2
-rw-r--r--thirdparty/glslang/patches/disable-absolute-paths-for-apple-compat.patch (renamed from thirdparty/glslang/glslang/patches/disable-absolute-paths-for-apple-compat.patch)11
55 files changed, 425 insertions, 281 deletions
diff --git a/.gitignore b/.gitignore
index 3946cc96e5..32a43b8c63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -159,6 +159,7 @@ gmon.out
# Kate
*.kate-swp
+.kateproject.build
# Kdevelop
*.kdev4
diff --git a/doc/classes/NativeMenu.xml b/doc/classes/NativeMenu.xml
index 475874dee7..2b9e414106 100644
--- a/doc/classes/NativeMenu.xml
+++ b/doc/classes/NativeMenu.xml
@@ -473,6 +473,14 @@
[b]Note:[/b] This method is implemented on macOS and Windows.
</description>
</method>
+ <method name="is_opened" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="rid" type="RID" />
+ <description>
+ Returns [code]true[/code] if the menu is currently opened.
+ [b]Note:[/b] This method is implemented only on macOS.
+ </description>
+ </method>
<method name="is_system_menu" qualifiers="const">
<return type="bool" />
<param index="0" name="rid" type="RID" />
@@ -699,6 +707,7 @@
<param index="1" name="callback" type="Callable" />
<description>
Registers callable to emit when the menu is about to show.
+ [b]Note:[/b] The OS can simulate menu opening to track menu item changes and global shortcuts, in which case the corresponding close callback is not triggered. Use [method is_opened] to check if the menu is currently opened.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
@@ -707,7 +716,7 @@
<param index="0" name="rid" type="RID" />
<param index="1" name="callback" type="Callable" />
<description>
- Registers callable to emit when the menu is about to closed.
+ Registers callable to emit after the menu is closed.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
index 13f9d93e66..460134e5ba 100644
--- a/doc/classes/PhysicalSkyMaterial.xml
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -6,7 +6,6 @@
<description>
The [PhysicalSkyMaterial] uses the Preetham analytic daylight model to draw a sky based on physical properties. This results in a substantially more realistic sky than the [ProceduralSkyMaterial], but it is slightly slower and less flexible.
The [PhysicalSkyMaterial] only supports one sun. The color, energy, and direction of the sun are taken from the first [DirectionalLight3D] in the scene tree.
- As it is based on a daylight model, the sky fades to black as the sunset ends. If you want a full day/night cycle, you will have to add a night sky by converting this to a [ShaderMaterial] and adding a night sky directly into the resulting shader.
</description>
<tutorials>
</tutorials>
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 2d497a281f..58dd659e86 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -57,6 +57,9 @@
#include "scene/main/window.h"
#include "servers/audio/audio_stream.h"
+constexpr double FPS_DECIMAL = 1;
+constexpr double SECOND_DECIMAL = 0.0001;
+
void AnimationTrackKeyEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
@@ -1322,7 +1325,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
return;
}
- p_new_len = MAX(0.0001, p_new_len);
+ p_new_len = MAX(SECOND_DECIMAL, p_new_len);
if (use_fps && animation->get_step() > 0) {
p_new_len *= animation->get_step();
}
@@ -1442,7 +1445,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
float l = animation->get_length();
if (l <= 0) {
- l = 0.0001; // Avoid crashor.
+ l = SECOND_DECIMAL; // Avoid crashor.
}
Ref<Texture2D> hsize_icon = get_editor_theme_icon(SNAME("Hsize"));
@@ -1723,7 +1726,7 @@ void AnimationTimelineEdit::update_values() {
editing = true;
if (use_fps && animation->get_step() > 0) {
length->set_value(animation->get_length() / animation->get_step());
- length->set_step(1);
+ length->set_step(FPS_DECIMAL);
length->set_tooltip_text(TTR("Animation length (frames)"));
time_icon->set_tooltip_text(TTR("Animation length (frames)"));
if (track_edit) {
@@ -1731,7 +1734,7 @@ void AnimationTimelineEdit::update_values() {
}
} else {
length->set_value(animation->get_length());
- length->set_step(0.0001);
+ length->set_step(SECOND_DECIMAL);
length->set_tooltip_text(TTR("Animation length (seconds)"));
time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
}
@@ -1912,9 +1915,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider);
- length->set_min(0.0001);
+ length->set_min(SECOND_DECIMAL);
length->set_max(36000);
- length->set_step(0.0001);
+ length->set_step(SECOND_DECIMAL);
length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true);
@@ -2645,7 +2648,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (key_idx != -1) {
- String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), 0.0001))) + "\n";
+ String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), SECOND_DECIMAL))) + "\n";
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
@@ -4758,10 +4761,12 @@ void AnimationTrackEditor::_animation_changed() {
}
void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
- timeline->set_use_fps(p_mode == 1);
+ bool use_fps = p_mode == 1;
+ timeline->set_use_fps(use_fps);
if (key_edit) {
- key_edit->set_use_fps(p_mode == 1);
+ key_edit->set_use_fps(use_fps);
}
+ step->set_step(use_fps ? FPS_DECIMAL : SECOND_DECIMAL);
_update_step_spinbox();
}
@@ -4775,7 +4780,9 @@ void AnimationTrackEditor::_update_step_spinbox() {
if (animation->get_step() == 0) {
step->set_value(0);
} else {
- step->set_value(1.0 / animation->get_step());
+ // The value stored within tscn cannot restored the original FPS due to lack of precision,
+ // so the value should be limited to integer.
+ step->set_value(Math::round(1.0 / animation->get_step()));
}
} else {
@@ -4783,6 +4790,7 @@ void AnimationTrackEditor::_update_step_spinbox() {
}
step->set_block_signals(false);
+ _update_snap_unit();
}
void AnimationTrackEditor::_animation_update() {
@@ -4876,6 +4884,8 @@ void AnimationTrackEditor::_update_step(double p_new_step) {
return;
}
+ _update_snap_unit();
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Step"));
float step_value = p_new_step;
@@ -5162,7 +5172,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
p_ofs = snap_time(p_ofs);
}
while (animation->track_find_key(p_track, p_ofs, Animation::FIND_MODE_APPROX) != -1) { // Make sure insertion point is valid.
- p_ofs += 0.0001;
+ p_ofs += SECOND_DECIMAL;
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
@@ -7007,25 +7017,31 @@ void AnimationTrackEditor::_selection_changed() {
}
}
+void AnimationTrackEditor::_update_snap_unit() {
+ if (step->get_value() <= 0) {
+ snap_unit = 0;
+ return; // Avoid zero div.
+ }
+
+ if (timeline->is_using_fps()) {
+ snap_unit = 1.0 / step->get_value();
+ } else {
+ snap_unit = 1.0 / Math::round(1.0 / step->get_value()); // Follow the snap behavior of the timeline editor.
+ }
+}
+
float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
if (is_snap_enabled()) {
- double snap_increment;
- if (timeline->is_using_fps() && step->get_value() > 0) {
- snap_increment = 1.0 / step->get_value();
- } else {
- snap_increment = step->get_value();
- }
-
if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
- snap_increment *= 0.25;
+ snap_unit *= 0.25;
}
if (p_relative) {
- double rel = Math::fmod(timeline->get_value(), snap_increment);
- p_value = Math::snapped(p_value + rel, snap_increment) - rel;
+ double rel = Math::fmod(timeline->get_value(), snap_unit);
+ p_value = Math::snapped(p_value + rel, snap_unit) - rel;
} else {
- p_value = Math::snapped(p_value, snap_increment);
+ p_value = Math::snapped(p_value, snap_unit);
}
}
@@ -7282,7 +7298,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step = memnew(EditorSpinSlider);
step->set_min(0);
step->set_max(1000000);
- step->set_step(0.0001);
+ step->set_step(SECOND_DECIMAL);
step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
step->set_tooltip_text(TTR("Animation step value."));
@@ -7524,9 +7540,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
ease_selection->select(Tween::EASE_IN_OUT); // Default
ease_selection->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Translation context is needed.
ease_fps = memnew(SpinBox);
- ease_fps->set_min(1);
+ ease_fps->set_min(FPS_DECIMAL);
ease_fps->set_max(999);
- ease_fps->set_step(1);
+ ease_fps->set_step(FPS_DECIMAL);
ease_fps->set_value(30); // Default
ease_grid->add_child(memnew(Label(TTR("Transition Type:"))));
ease_grid->add_child(transition_selection);
@@ -7550,9 +7566,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
bake_value = memnew(CheckBox);
bake_value->set_pressed(true);
bake_fps = memnew(SpinBox);
- bake_fps->set_min(1);
+ bake_fps->set_min(FPS_DECIMAL);
bake_fps->set_max(999);
- bake_fps->set_step(1);
+ bake_fps->set_step(FPS_DECIMAL);
bake_fps->set_value(30); // Default
bake_grid->add_child(memnew(Label(TTR("3D Pos/Rot/Scl Track:"))));
bake_grid->add_child(bake_trs);
@@ -7671,15 +7687,14 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
spinner->set_allow_lesser(true);
if (use_fps) {
- spinner->set_step(1);
- spinner->set_hide_slider(true);
+ spinner->set_step(FPS_DECIMAL);
real_t fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
spinner->set_value(key_ofs * fps);
} else {
- spinner->set_step(0.0001);
+ spinner->set_step(SECOND_DECIMAL);
spinner->set_value(key_ofs);
spinner->set_max(animation->get_length());
}
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index f449b51b81..09f751c8dd 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -649,6 +649,9 @@ class AnimationTrackEditor : public VBoxContainer {
void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
void _pick_track_filter_input(const Ref<InputEvent> &p_ie);
+ double snap_unit;
+ void _update_snap_unit();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 1145a10f71..cede2c0ab6 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -294,6 +294,13 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
}
for (const MethodInfo &mi : p_methods) {
+ if (mi.name.begins_with("@")) {
+ // GH-92782. GDScript inline setters/getters are historically present in `get_method_list()`
+ // and can be called using `Object.call()`. However, these functions are meant to be internal
+ // and their names are not valid identifiers, so let's hide them from the user.
+ continue;
+ }
+
if (!p_search_string.is_empty() && !mi.name.containsn(p_search_string)) {
continue;
}
@@ -324,8 +331,10 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
continue;
}
}
+
ret.push_back(mi);
}
+
return ret;
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 80e2302e91..33f460e23d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -652,6 +652,19 @@ void EditorProperty::add_focusable(Control *p_control) {
focusables.push_back(p_control);
}
+void EditorProperty::grab_focus(int p_focusable) {
+ if (focusables.is_empty()) {
+ return;
+ }
+
+ if (p_focusable >= 0) {
+ ERR_FAIL_INDEX(p_focusable, focusables.size());
+ focusables[p_focusable]->grab_focus();
+ } else {
+ focusables[0]->grab_focus();
+ }
+}
+
void EditorProperty::select(int p_focusable) {
bool already_selected = selected;
if (!selectable) {
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index a0ced55bd8..f9b0d1f094 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -192,6 +192,7 @@ public:
void set_deletable(bool p_enable);
bool is_deletable() const;
void add_focusable(Control *p_control);
+ void grab_focus(int p_focusable = -1);
void select(int p_focusable = -1);
void deselect();
bool is_selected() const;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ebdad467ff..45d276dd79 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3706,12 +3706,15 @@ void EditorNode::_remove_scene(int index, bool p_change_tab) {
}
void EditorNode::set_edited_scene(Node *p_scene) {
+ set_edited_scene_root(p_scene, true);
+}
+
+void EditorNode::set_edited_scene_root(Node *p_scene, bool p_auto_add) {
Node *old_edited_scene_root = get_editor_data().get_edited_scene_root();
- if (old_edited_scene_root) {
- if (old_edited_scene_root->get_parent() == scene_root) {
- scene_root->remove_child(old_edited_scene_root);
- }
- old_edited_scene_root->disconnect(SNAME("replacing_by"), callable_mp(this, &EditorNode::set_edited_scene));
+ ERR_FAIL_COND_MSG(p_scene && p_scene != old_edited_scene_root && p_scene->get_parent(), "Non-null nodes that are set as edited scene should not have a parent node.");
+
+ if (p_auto_add && old_edited_scene_root && old_edited_scene_root->get_parent() == scene_root) {
+ scene_root->remove_child(old_edited_scene_root);
}
get_editor_data().set_edited_scene_root(p_scene);
@@ -3723,11 +3726,8 @@ void EditorNode::set_edited_scene(Node *p_scene) {
get_tree()->set_edited_scene_root(p_scene);
}
- if (p_scene) {
- if (p_scene->get_parent() != scene_root) {
- scene_root->add_child(p_scene, true);
- }
- p_scene->connect(SNAME("replacing_by"), callable_mp(this, &EditorNode::set_edited_scene));
+ if (p_auto_add && p_scene) {
+ scene_root->add_child(p_scene, true);
}
}
@@ -5967,6 +5967,8 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
instantiated_node->set_scene_file_path(String());
}
current_edited_scene = instantiated_node;
+
+ editor_data.set_edited_scene_root(current_edited_scene);
}
// Replace the original node with the instantiated version.
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 5d7bd5b4f8..899da99450 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -783,6 +783,7 @@ public:
SubViewport *get_scene_root() { return scene_root; } // Root of the scene being edited.
void set_edited_scene(Node *p_scene);
+ void set_edited_scene_root(Node *p_scene, bool p_auto_add);
Node *get_edited_scene() { return editor_data.get_edited_scene_root(); }
void fix_dependencies(const String &p_for_file);
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 555165c156..53a10a779f 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -255,6 +255,10 @@ void EditorPropertyArray::_change_type_menu(int p_index) {
return;
}
+ ERR_FAIL_COND_MSG(
+ changing_type_index == EditorPropertyArrayObject::NOT_CHANGING_TYPE,
+ "Tried to change type of an array item, but no item was selected.");
+
Variant value;
VariantInternal::initialize(&value, Variant::Type(p_index));
@@ -444,6 +448,10 @@ void EditorPropertyArray::update_property() {
slot.prop = new_prop;
slot.set_index(idx);
}
+ if (slot.index == changing_type_index) {
+ callable_mp(slot.prop, &EditorProperty::grab_focus).call_deferred(0);
+ changing_type_index = EditorPropertyArrayObject::NOT_CHANGING_TYPE;
+ }
slot.prop->update_property();
}
@@ -921,6 +929,10 @@ void EditorPropertyDictionary::_create_new_property_slot(int p_idx) {
}
void EditorPropertyDictionary::_change_type_menu(int p_index) {
+ ERR_FAIL_COND_MSG(
+ changing_type_index == EditorPropertyDictionaryObject::NOT_CHANGING_TYPE,
+ "Tried to change the type of a dict key or value, but nothing was selected.");
+
Variant value;
switch (changing_type_index) {
case EditorPropertyDictionaryObject::NEW_KEY_INDEX:
@@ -1062,6 +1074,14 @@ void EditorPropertyDictionary::update_property() {
new_prop->set_read_only(is_read_only());
slot.set_prop(new_prop);
}
+
+ // We need to grab the focus of the property that is being changed, even if the type didn't actually changed.
+ // Otherwise, focus will stay on the change type button, which is not very user friendly.
+ if (changing_type_index == slot.index) {
+ callable_mp(slot.prop, &EditorProperty::grab_focus).call_deferred(0);
+ changing_type_index = EditorPropertyDictionaryObject::NOT_CHANGING_TYPE; // Reset to avoid grabbing focus again.
+ }
+
slot.prop->update_property();
}
updating = false;
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 8b939ab0b0..267cb1e86d 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -49,6 +49,10 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
public:
+ enum {
+ NOT_CHANGING_TYPE = -1,
+ };
+
void set_array(const Variant &p_array);
Variant get_array();
@@ -68,7 +72,8 @@ protected:
public:
enum {
- NEW_KEY_INDEX = -2,
+ NOT_CHANGING_TYPE = -3,
+ NEW_KEY_INDEX,
NEW_VALUE_INDEX,
};
@@ -111,7 +116,7 @@ class EditorPropertyArray : public EditorProperty {
int page_length = 20;
int page_index = 0;
- int changing_type_index;
+ int changing_type_index = EditorPropertyArrayObject::NOT_CHANGING_TYPE;
Button *edit = nullptr;
PanelContainer *container = nullptr;
VBoxContainer *property_vbox = nullptr;
@@ -206,7 +211,7 @@ class EditorPropertyDictionary : public EditorProperty {
Ref<EditorPropertyDictionaryObject> object;
int page_length = 20;
int page_index = 0;
- int changing_type_index;
+ int changing_type_index = EditorPropertyDictionaryObject::NOT_CHANGING_TYPE;
Button *edit = nullptr;
PanelContainer *container = nullptr;
VBoxContainer *property_vbox = nullptr;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index dd698d74b6..742d29fef0 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -138,7 +138,6 @@ void EditorResourcePreview::_preview_ready(const String &p_path, int p_hash, con
}
Item item;
- item.order = order++;
item.preview = p_texture;
item.small_preview = p_small_texture;
item.last_hash = p_hash;
@@ -412,7 +411,6 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
String path_id = "ID:" + itos(p_res->get_instance_id());
if (cache.has(path_id) && cache[path_id].last_hash == p_res->hash_edited_version_for_preview()) {
- cache[path_id].order = order++;
p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
return;
}
@@ -439,7 +437,6 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
MutexLock lock(preview_mutex);
if (cache.has(p_path)) {
- cache[p_path].order = order++;
p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
return;
}
@@ -533,7 +530,6 @@ void EditorResourcePreview::stop() {
EditorResourcePreview::EditorResourcePreview() {
singleton = this;
- order = 0;
}
EditorResourcePreview::~EditorResourcePreview() {
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 6b67acceaa..2870f9a201 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -99,13 +99,10 @@ class EditorResourcePreview : public Node {
Ref<Texture2D> preview;
Ref<Texture2D> small_preview;
Dictionary preview_metadata;
- int order = 0;
uint32_t last_hash = 0;
uint64_t modified_time = 0;
};
- int order;
-
HashMap<String, Item> cache;
void _preview_ready(const String &p_path, int p_hash, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud, const Dictionary &p_metadata);
diff --git a/editor/gui/editor_scene_tabs.cpp b/editor/gui/editor_scene_tabs.cpp
index 2622645d7c..4862b3436e 100644
--- a/editor/gui/editor_scene_tabs.cpp
+++ b/editor/gui/editor_scene_tabs.cpp
@@ -405,7 +405,7 @@ EditorSceneTabs::EditorSceneTabs() {
scene_tabs->connect(SceneStringName(mouse_exited), callable_mp(this, &EditorSceneTabs::_scene_tab_exit));
scene_tabs->connect(SceneStringName(gui_input), callable_mp(this, &EditorSceneTabs::_scene_tab_input));
scene_tabs->connect("active_tab_rearranged", callable_mp(this, &EditorSceneTabs::_reposition_active_tab));
- scene_tabs->connect(SceneStringName(resized), callable_mp(this, &EditorSceneTabs::_scene_tabs_resized));
+ scene_tabs->connect(SceneStringName(resized), callable_mp(this, &EditorSceneTabs::_scene_tabs_resized), CONNECT_DEFERRED);
scene_tabs_context_menu = memnew(PopupMenu);
tabbar_container->add_child(scene_tabs_context_menu);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 202817f6ee..e4eaab7325 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -922,7 +922,7 @@ void vertex() {
VERTEX = VERTEX;
POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
- POSITION.z = mix(POSITION.z, 0.0, 0.999);
+ POSITION.z = mix(POSITION.z, POSITION.w, 0.999);
POINT_SIZE = point_size;
}
@@ -1201,7 +1201,7 @@ void vertex() {
}
VERTEX = VERTEX;
POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
- POSITION.z = mix(POSITION.z, 0, 0.998);
+ POSITION.z = mix(POSITION.z, POSITION.w, 0.998);
}
void fragment() {
ALBEDO = COLOR.rgb;
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index cf1ad36adc..6a6e2b83ab 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -743,20 +743,24 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
localization_editor->connect("localization_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
tab_container->add_child(localization_editor);
+ TabContainer *globals_container = memnew(TabContainer);
+ globals_container->set_name(TTR("Globals"));
+ tab_container->add_child(globals_container);
+
autoload_settings = memnew(EditorAutoloadSettings);
autoload_settings->set_name(TTR("Autoload"));
autoload_settings->connect("autoload_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
- tab_container->add_child(autoload_settings);
+ globals_container->add_child(autoload_settings);
shaders_global_shader_uniforms_editor = memnew(ShaderGlobalsEditor);
shaders_global_shader_uniforms_editor->set_name(TTR("Shader Globals"));
shaders_global_shader_uniforms_editor->connect("globals_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
- tab_container->add_child(shaders_global_shader_uniforms_editor);
+ globals_container->add_child(shaders_global_shader_uniforms_editor);
group_settings = memnew(GroupSettingsEditor);
- group_settings->set_name(TTR("Global Groups"));
+ group_settings->set_name(TTR("Groups"));
group_settings->connect("group_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
- tab_container->add_child(group_settings);
+ globals_container->add_child(group_settings);
plugin_settings = memnew(EditorPluginSettings);
plugin_settings->set_name(TTR("Plugins"));
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index d123d8ef59..a5157bd394 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -225,11 +225,24 @@ void PropertySelector::_update_search() {
} else {
Ref<Script> script_ref = Object::cast_to<Script>(ObjectDB::get_instance(script));
if (script_ref.is_valid()) {
- methods.push_back(MethodInfo("*Script Methods"));
if (script_ref->is_built_in()) {
script_ref->reload(true);
}
- script_ref->get_script_method_list(&methods);
+
+ List<MethodInfo> script_methods;
+ script_ref->get_script_method_list(&script_methods);
+
+ methods.push_back(MethodInfo("*Script Methods")); // TODO: Split by inheritance.
+
+ for (const MethodInfo &mi : script_methods) {
+ if (mi.name.begins_with("@")) {
+ // GH-92782. GDScript inline setters/getters are historically present in `get_method_list()`
+ // and can be called using `Object.call()`. However, these functions are meant to be internal
+ // and their names are not valid identifiers, so let's hide them from the user.
+ continue;
+ }
+ methods.push_back(mi);
+ }
}
StringName base = base_type;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 2f57dc5610..c71cb9d4ac 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2992,6 +2992,10 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro
to_erase.push_back(oldnode->get_child(i));
}
}
+
+ if (oldnode == edited_scene) {
+ EditorNode::get_singleton()->set_edited_scene_root(newnode, false);
+ }
oldnode->replace_by(newnode, true);
// Re-apply size of anchored control.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
index 04b6c2e743..6b5d7fed78 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
@@ -143,7 +143,7 @@ namespace Godot.NativeInterop
if (error.Error != godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_OK)
{
using godot_variant instanceVariant = VariantUtils.CreateFromGodotObjectPtr(instance);
- string where = GetCallErrorWhere(method, &instanceVariant, args, argCount);
+ string where = GetCallErrorWhere(ref error, method, &instanceVariant, args, argCount);
string errorText = GetCallErrorMessage(error, where, args);
GD.PushError(errorText);
}
@@ -161,7 +161,7 @@ namespace Godot.NativeInterop
}
}
- private unsafe static string GetCallErrorWhere(godot_string_name method, godot_variant* instance, godot_variant** args, int argCount)
+ private unsafe static string GetCallErrorWhere(ref godot_variant_call_error error, godot_string_name method, godot_variant* instance, godot_variant** args, int argCount)
{
string? methodstr = null;
string basestr = GetVariantTypeName(instance);
@@ -171,6 +171,10 @@ namespace Godot.NativeInterop
if (argCount >= 1)
{
methodstr = VariantUtils.ConvertToString(*args[0]);
+ if (error.Error == godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT)
+ {
+ error.Argument += 1;
+ }
}
}
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index dfbc92a919..1779be2cc2 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -617,7 +617,7 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector
const Face3 f(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
Vector3 inters;
if (f.intersects_segment(p_from, p_to, &inters)) {
- const real_t d = closest_point_d = p_from.distance_to(inters);
+ const real_t d = p_from.distance_to(inters);
if (use_collision == false) {
closest_point = inters;
use_collision = true;
diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
index b8a2f58935..d9a66aa827 100644
--- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
+++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp
@@ -293,7 +293,12 @@ void OpenXRHandTrackingExtension::on_process() {
}
godot_tracker->set_hand_tracking_source(source);
- godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity);
+ if (location.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
+ godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity);
+ } else {
+ godot_tracker->set_has_tracking_data(false);
+ godot_tracker->invalidate_pose("default");
+ }
}
}
} else {
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
index 01da0c7935..087fd1bace 100644
--- a/platform/android/api/jni_singleton.h
+++ b/platform/android/api/jni_singleton.h
@@ -219,19 +219,12 @@ public:
}
void add_signal(const StringName &p_name, const Vector<Variant::Type> &p_args) {
- if (p_args.size() == 0) {
- ADD_SIGNAL(MethodInfo(p_name));
- } else if (p_args.size() == 1) {
- ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1")));
- } else if (p_args.size() == 2) {
- ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2")));
- } else if (p_args.size() == 3) {
- ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3")));
- } else if (p_args.size() == 4) {
- ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4")));
- } else if (p_args.size() == 5) {
- ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4"), PropertyInfo(p_args[4], "arg5")));
+ MethodInfo mi;
+ mi.name = p_name;
+ for (int i = 0; i < p_args.size(); i++) {
+ mi.arguments.push_back(PropertyInfo(p_args[i], "arg" + itos(i + 1)));
}
+ ADD_SIGNAL(mi);
}
#endif
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index 12d3a6fd2f..aff83ddeee 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -1018,8 +1018,7 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor
wayland_thread.cursor_shape_clear_custom_image(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
CustomCursor &cursor = custom_cursors[p_shape];
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 34b6d0219a..4ca1b11094 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -3108,8 +3108,7 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
cursors_cache.erase(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
Vector2i texture_size = image->get_size();
@@ -3127,13 +3126,8 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
cursor_image->pixels = (XcursorPixel *)memalloc(size);
for (XcursorPixel index = 0; index < image_size; index++) {
- int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
- int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_rect.has_area()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
+ int row_index = floor(index / texture_size.width);
+ int column_index = index % int(texture_size.width);
*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
}
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 50313cfe67..1032766480 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -2845,8 +2845,7 @@ void DisplayServerMacOS::cursor_set_custom_image(const Ref<Resource> &p_cursor,
cursors_cache.erase(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
Vector2i texture_size = image->get_size();
@@ -2868,13 +2867,8 @@ void DisplayServerMacOS::cursor_set_custom_image(const Ref<Resource> &p_cursor,
int len = int(texture_size.width * texture_size.height);
for (int i = 0; i < len; i++) {
- int row_index = floor(i / texture_size.width) + atlas_rect.position.y;
- int column_index = (i % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_rect.has_area()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
+ int row_index = floor(i / texture_size.width);
+ int column_index = i % int(texture_size.width);
uint32_t color = image->get_pixel(column_index, row_index).to_argb32();
@@ -3172,42 +3166,13 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
DisplayServer::IndicatorID DisplayServerMacOS::create_status_indicator(const Ref<Texture2D> &p_icon, const String &p_tooltip, const Callable &p_callback) {
NSImage *nsimg = nullptr;
- if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
Ref<Image> img = p_icon->get_image();
img = img->duplicate();
- img->convert(Image::FORMAT_RGBA8);
-
- NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nullptr
- pixelsWide:img->get_width()
- pixelsHigh:img->get_height()
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:img->get_width() * 4
- bitsPerPixel:32];
- if (imgrep) {
- uint8_t *pixels = [imgrep bitmapData];
-
- int len = img->get_width() * img->get_height();
- const uint8_t *r = img->get_data().ptr();
-
- /* Premultiply the alpha channel */
- for (int i = 0; i < len; i++) {
- uint8_t alpha = r[i * 4 + 3];
- pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
- pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
- pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
- pixels[i * 4 + 3] = alpha;
- }
-
- nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
- if (nsimg) {
- [nsimg addRepresentation:imgrep];
- }
+ if (img->is_compressed()) {
+ img->decompress();
}
+ nsimg = _convert_to_nsimg(img);
}
IndicatorData idat;
@@ -3235,42 +3200,13 @@ void DisplayServerMacOS::status_indicator_set_icon(IndicatorID p_id, const Ref<T
ERR_FAIL_COND(!indicators.has(p_id));
NSImage *nsimg = nullptr;
- if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
Ref<Image> img = p_icon->get_image();
img = img->duplicate();
- img->convert(Image::FORMAT_RGBA8);
-
- NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nullptr
- pixelsWide:img->get_width()
- pixelsHigh:img->get_height()
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:img->get_width() * 4
- bitsPerPixel:32];
- if (imgrep) {
- uint8_t *pixels = [imgrep bitmapData];
-
- int len = img->get_width() * img->get_height();
- const uint8_t *r = img->get_data().ptr();
-
- /* Premultiply the alpha channel */
- for (int i = 0; i < len; i++) {
- uint8_t alpha = r[i * 4 + 3];
- pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
- pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
- pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
- pixels[i * 4 + 3] = alpha;
- }
-
- nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
- if (nsimg) {
- [nsimg addRepresentation:imgrep];
- }
+ if (img->is_compressed()) {
+ img->decompress();
}
+ nsimg = _convert_to_nsimg(img);
}
NSStatusItem *item = indicators[p_id].item;
diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm
index 5c1e849715..3f7dfac3de 100644
--- a/platform/macos/godot_menu_delegate.mm
+++ b/platform/macos/godot_menu_delegate.mm
@@ -40,13 +40,20 @@
- (void)doNothing:(id)sender {
}
-- (void)menuNeedsUpdate:(NSMenu *)menu {
+- (void)menuWillOpen:(NSMenu *)menu {
if (NativeMenu::get_singleton()) {
NativeMenuMacOS *nmenu = (NativeMenuMacOS *)NativeMenu::get_singleton();
nmenu->_menu_open(menu);
}
}
+- (void)menuNeedsUpdate:(NSMenu *)menu {
+ if (NativeMenu::get_singleton()) {
+ NativeMenuMacOS *nmenu = (NativeMenuMacOS *)NativeMenu::get_singleton();
+ nmenu->_menu_need_update(menu);
+ }
+}
+
- (void)menuDidClose:(NSMenu *)menu {
if (NativeMenu::get_singleton()) {
NativeMenuMacOS *nmenu = (NativeMenuMacOS *)NativeMenu::get_singleton();
diff --git a/platform/macos/native_menu_macos.h b/platform/macos/native_menu_macos.h
index b5dbb8b9b0..42cf6740d9 100644
--- a/platform/macos/native_menu_macos.h
+++ b/platform/macos/native_menu_macos.h
@@ -73,8 +73,11 @@ class NativeMenuMacOS : public NativeMenu {
public:
void _register_system_menus(NSMenu *p_main_menu, NSMenu *p_application_menu, NSMenu *p_window_menu, NSMenu *p_help_menu, NSMenu *p_dock_menu);
NSMenu *_get_dock_menu();
+
+ void _menu_need_update(NSMenu *p_menu);
void _menu_open(NSMenu *p_menu);
void _menu_close(NSMenu *p_menu);
+ void _menu_close_cb(const RID &p_rid);
virtual bool has_feature(Feature p_feature) const override;
@@ -98,6 +101,8 @@ public:
virtual void set_minimum_width(const RID &p_rid, float p_width) override;
virtual float get_minimum_width(const RID &p_rid) const override;
+ virtual bool is_opened(const RID &p_rid) const override;
+
virtual int add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag = Variant(), int p_index = -1) override;
virtual int add_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
virtual int add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
diff --git a/platform/macos/native_menu_macos.mm b/platform/macos/native_menu_macos.mm
index 1cf13a2d69..1ae1137ca0 100644
--- a/platform/macos/native_menu_macos.mm
+++ b/platform/macos/native_menu_macos.mm
@@ -91,11 +91,22 @@ void NativeMenuMacOS::_menu_open(NSMenu *p_menu) {
if (menu_lookup.has(p_menu)) {
MenuData *md = menus.get_or_null(menu_lookup[p_menu]);
if (md) {
+ // Note: Set "is_open" flag, but do not call callback, menu items can't be modified during this call and "_menu_need_update" will be called right before it.
md->is_open = true;
+ }
+ }
+}
+
+void NativeMenuMacOS::_menu_need_update(NSMenu *p_menu) {
+ if (menu_lookup.has(p_menu)) {
+ MenuData *md = menus.get_or_null(menu_lookup[p_menu]);
+ if (md) {
+ // Note: "is_open" flag is set by "_menu_open", this method is always called before menu is shown, but might be called for the other reasons as well.
if (md->open_cb.is_valid()) {
Variant ret;
Callable::CallError ce;
+ // Callback is called directly, since it's expected to modify menu items before it's shown.
md->open_cb.callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute menu open callback: %s.", Variant::get_callable_error_text(md->open_cb, nullptr, 0, ce)));
@@ -110,15 +121,22 @@ void NativeMenuMacOS::_menu_close(NSMenu *p_menu) {
MenuData *md = menus.get_or_null(menu_lookup[p_menu]);
if (md) {
md->is_open = false;
- if (md->close_cb.is_valid()) {
- Variant ret;
- Callable::CallError ce;
- md->close_cb.callp(nullptr, 0, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute menu close callback: %s.", Variant::get_callable_error_text(md->close_cb, nullptr, 0, ce)));
- }
- }
+ // Callback called deferred, since it should not modify menu items during "_menu_close" call.
+ callable_mp(this, &NativeMenuMacOS::_menu_close_cb).call_deferred(menu_lookup[p_menu]);
+ }
+ }
+}
+
+void NativeMenuMacOS::_menu_close_cb(const RID &p_rid) {
+ MenuData *md = menus.get_or_null(p_rid);
+ if (md->close_cb.is_valid()) {
+ Variant ret;
+ Callable::CallError ce;
+
+ md->close_cb.callp(nullptr, 0, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute menu close callback: %s.", Variant::get_callable_error_text(md->close_cb, nullptr, 0, ce)));
}
}
}
@@ -328,6 +346,13 @@ float NativeMenuMacOS::get_minimum_width(const RID &p_rid) const {
return md->menu.minimumWidth * DisplayServer::get_singleton()->screen_get_max_scale();
}
+bool NativeMenuMacOS::is_opened(const RID &p_rid) const {
+ const MenuData *md = menus.get_or_null(p_rid);
+ ERR_FAIL_NULL_V(md, false);
+
+ return md->is_open;
+}
+
int NativeMenuMacOS::add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag, int p_index) {
MenuData *md = menus.get_or_null(p_rid);
MenuData *md_sub = menus.get_or_null(p_submenu_rid);
@@ -436,7 +461,7 @@ int NativeMenuMacOS::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_ico
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds && p_icon.is_valid()) {
+ if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
if (obj->img->is_compressed()) {
@@ -467,7 +492,7 @@ int NativeMenuMacOS::add_icon_check_item(const RID &p_rid, const Ref<Texture2D>
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds && p_icon.is_valid()) {
+ if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
if (obj->img->is_compressed()) {
@@ -518,7 +543,7 @@ int NativeMenuMacOS::add_icon_radio_check_item(const RID &p_rid, const Ref<Textu
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds && p_icon.is_valid()) {
+ if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
if (obj->img->is_compressed()) {
@@ -1212,7 +1237,7 @@ void NativeMenuMacOS::set_item_icon(const RID &p_rid, int p_idx, const Ref<Textu
GodotMenuItem *obj = [menu_item representedObject];
ERR_FAIL_NULL(obj);
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds && p_icon.is_valid()) {
+ if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
if (obj->img->is_compressed()) {
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index fab92b1894..40de4e523b 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -517,19 +517,10 @@ DisplayServer::CursorShape DisplayServerWeb::cursor_get_shape() const {
void DisplayServerWeb::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
if (p_cursor.is_valid()) {
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
Vector2i texture_size = image->get_size();
- if (atlas_rect.has_area()) {
- image->crop_from_point(
- atlas_rect.position.x,
- atlas_rect.position.y,
- texture_size.width,
- texture_size.height);
- }
-
if (image->get_format() != Image::FORMAT_RGBA8) {
image->convert(Image::FORMAT_RGBA8);
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 4a482f560c..73987c44db 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2408,8 +2408,7 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
cursors_cache.erase(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
Vector2i texture_size = image->get_size();
@@ -2437,13 +2436,9 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
bool fully_transparent = true;
for (UINT index = 0; index < image_size; index++) {
- int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
- int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
+ int row_index = floor(index / texture_size.width);
+ int column_index = index % int(texture_size.width);
- if (atlas_rect.has_area()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
const Color &c = image->get_pixel(column_index, row_index);
fully_transparent = fully_transparent && (c.a == 0.f);
@@ -3171,9 +3166,12 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const Ref<Texture2D> &p_icon, const String &p_tooltip, const Callable &p_callback) {
HICON hicon = nullptr;
- if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
Ref<Image> img = p_icon->get_image();
img = img->duplicate();
+ if (img->is_compressed()) {
+ img->decompress();
+ }
img->convert(Image::FORMAT_RGBA8);
int w = img->get_width();
@@ -3241,9 +3239,12 @@ void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref
ERR_FAIL_COND(!indicators.has(p_id));
HICON hicon = nullptr;
- if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
Ref<Image> img = p_icon->get_image();
img = img->duplicate();
+ if (img->is_compressed()) {
+ img->decompress();
+ }
img->convert(Image::FORMAT_RGBA8);
int w = img->get_width();
diff --git a/platform/windows/native_menu_windows.cpp b/platform/windows/native_menu_windows.cpp
index 40a08f87df..d9dc28e9d9 100644
--- a/platform/windows/native_menu_windows.cpp
+++ b/platform/windows/native_menu_windows.cpp
@@ -35,6 +35,8 @@
#include "scene/resources/image_texture.h"
HBITMAP NativeMenuWindows::_make_bitmap(const Ref<Image> &p_img) const {
+ p_img->convert(Image::FORMAT_RGBA8);
+
Vector2i texture_size = p_img->get_size();
UINT image_size = texture_size.width * texture_size.height;
@@ -231,6 +233,11 @@ float NativeMenuWindows::get_minimum_width(const RID &p_rid) const {
return 0.f;
}
+bool NativeMenuWindows::is_opened(const RID &p_rid) const {
+ // Not supported.
+ return false;
+}
+
int NativeMenuWindows::add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag, int p_index) {
MenuData *md = menus.get_or_null(p_rid);
MenuData *md_sub = menus.get_or_null(p_submenu_rid);
@@ -349,12 +356,14 @@ int NativeMenuWindows::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_i
item_data->checkable_type = CHECKABLE_TYPE_NONE;
item_data->max_states = 0;
item_data->state = 0;
- item_data->img = p_icon->get_image();
- item_data->img = item_data->img->duplicate();
- if (item_data->img->is_compressed()) {
- item_data->img->decompress();
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
+ item_data->img = p_icon->get_image();
+ item_data->img = item_data->img->duplicate();
+ if (item_data->img->is_compressed()) {
+ item_data->img->decompress();
+ }
+ item_data->bmp = _make_bitmap(item_data->img);
}
- item_data->bmp = _make_bitmap(item_data->img);
Char16String label = p_label.utf16();
MENUITEMINFOW item;
@@ -389,12 +398,14 @@ int NativeMenuWindows::add_icon_check_item(const RID &p_rid, const Ref<Texture2D
item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
item_data->max_states = 0;
item_data->state = 0;
- item_data->img = p_icon->get_image();
- item_data->img = item_data->img->duplicate();
- if (item_data->img->is_compressed()) {
- item_data->img->decompress();
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
+ item_data->img = p_icon->get_image();
+ item_data->img = item_data->img->duplicate();
+ if (item_data->img->is_compressed()) {
+ item_data->img->decompress();
+ }
+ item_data->bmp = _make_bitmap(item_data->img);
}
- item_data->bmp = _make_bitmap(item_data->img);
Char16String label = p_label.utf16();
MENUITEMINFOW item;
@@ -462,12 +473,14 @@ int NativeMenuWindows::add_icon_radio_check_item(const RID &p_rid, const Ref<Tex
item_data->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
item_data->max_states = 0;
item_data->state = 0;
- item_data->img = p_icon->get_image();
- item_data->img = item_data->img->duplicate();
- if (item_data->img->is_compressed()) {
- item_data->img->decompress();
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
+ item_data->img = p_icon->get_image();
+ item_data->img = item_data->img->duplicate();
+ if (item_data->img->is_compressed()) {
+ item_data->img->decompress();
+ }
+ item_data->bmp = _make_bitmap(item_data->img);
}
- item_data->bmp = _make_bitmap(item_data->img);
Char16String label = p_label.utf16();
MENUITEMINFOW item;
@@ -1082,7 +1095,7 @@ void NativeMenuWindows::set_item_icon(const RID &p_rid, int p_idx, const Ref<Tex
if (item_data->bmp) {
DeleteObject(item_data->bmp);
}
- if (p_icon.is_valid()) {
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
item_data->img = p_icon->get_image();
item_data->img = item_data->img->duplicate();
if (item_data->img->is_compressed()) {
diff --git a/platform/windows/native_menu_windows.h b/platform/windows/native_menu_windows.h
index 74fd231903..5c4aaa52c8 100644
--- a/platform/windows/native_menu_windows.h
+++ b/platform/windows/native_menu_windows.h
@@ -90,6 +90,8 @@ public:
virtual void set_minimum_width(const RID &p_rid, float p_width) override;
virtual float get_minimum_width(const RID &p_rid) const override;
+ virtual bool is_opened(const RID &p_rid) const override;
+
virtual int add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag = Variant(), int p_index = -1) override;
virtual int add_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
virtual int add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index d8fcbbb883..b7db730b49 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -243,8 +243,8 @@ Size2 BoxContainer::get_minimum_size() const {
bool first = true;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible() || c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
+ if (!c) {
continue;
}
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index f1faf3e899..c328022d4f 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -139,9 +139,15 @@ void Container::queue_sort() {
pending_sort = true;
}
-Control *Container::as_sortable_control(Node *p_node) const {
+Control *Container::as_sortable_control(Node *p_node, SortableVisbilityMode p_visibility_mode) const {
Control *c = Object::cast_to<Control>(p_node);
- if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) {
+ if (!c || c->is_set_as_top_level()) {
+ return nullptr;
+ }
+ if (p_visibility_mode == SortableVisbilityMode::VISIBLE && !c->is_visible()) {
+ return nullptr;
+ }
+ if (p_visibility_mode == SortableVisbilityMode::VISIBLE_IN_TREE && !c->is_visible_in_tree()) {
return nullptr;
}
return c;
@@ -177,13 +183,9 @@ Vector<int> Container::get_allowed_size_flags_vertical() const {
void Container::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- pending_sort = false;
- queue_sort();
- } break;
-
case NOTIFICATION_RESIZED:
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
queue_sort();
} break;
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 405220cee6..0561d0d219 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -41,8 +41,14 @@ class Container : public Control {
void _child_minsize_changed();
protected:
+ enum class SortableVisbilityMode {
+ VISIBLE,
+ VISIBLE_IN_TREE,
+ IGNORE,
+ };
+
void queue_sort();
- Control *as_sortable_control(Node *p_node) const;
+ Control *as_sortable_control(Node *p_node, SortableVisbilityMode p_visibility_mode = SortableVisbilityMode::VISIBLE_IN_TREE) const;
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
diff --git a/scene/gui/graph_element.cpp b/scene/gui/graph_element.cpp
index e231b05d7f..b63ed8d1ad 100644
--- a/scene/gui/graph_element.cpp
+++ b/scene/gui/graph_element.cpp
@@ -60,8 +60,8 @@ void GraphElement::_resort() {
Size2 GraphElement::get_minimum_size() const {
Size2 minsize;
for (int i = 0; i < get_child_count(); i++) {
- Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i), SortableVisbilityMode::IGNORE);
+ if (!child) {
continue;
}
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index d804f83e1c..72e59bfc8a 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -130,8 +130,8 @@ bool GraphNode::_get(const StringName &p_name, Variant &r_ret) const {
void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
int idx = 0;
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false), SortableVisbilityMode::IGNORE);
+ if (!child) {
continue;
}
@@ -658,8 +658,8 @@ void GraphNode::_port_pos_update() {
int slot_index = 0;
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false), SortableVisbilityMode::IGNORE);
+ if (!child) {
continue;
}
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index 06e4a7cc13..a47b131708 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -36,8 +36,8 @@ Size2 MarginContainer::get_minimum_size() const {
Size2 max;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible() || c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
+ if (!c) {
continue;
}
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index 76fde26b26..2c39e148a0 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -35,7 +35,7 @@
Size2 PanelContainer::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
if (!c) {
continue;
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 1f4d1dbf52..824bb77694 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -42,7 +42,7 @@ Size2 ScrollContainer::get_minimum_size() const {
largest_child_min_size = Size2();
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
if (!c) {
continue;
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index d0c3f3d65e..58724cf4e9 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -362,8 +362,8 @@ void TabContainer::_on_mouse_exited() {
Vector<Control *> TabContainer::_get_tab_controls() const {
Vector<Control *> controls;
for (int i = 0; i < get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(get_child(i));
- if (!control || control->is_set_as_top_level() || control == tab_bar || children_removing.has(control)) {
+ Control *control = as_sortable_control(get_child(i), SortableVisbilityMode::IGNORE);
+ if (!control || control == tab_bar || children_removing.has(control)) {
continue;
}
@@ -539,8 +539,8 @@ void TabContainer::add_child_notify(Node *p_child) {
return;
}
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(p_child, SortableVisbilityMode::IGNORE);
+ if (!c) {
return;
}
c->hide();
@@ -569,8 +569,8 @@ void TabContainer::move_child_notify(Node *p_child) {
return;
}
- Control *c = Object::cast_to<Control>(p_child);
- if (c && !c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(p_child, SortableVisbilityMode::IGNORE);
+ if (c) {
tab_bar->move_tab(c->get_meta("_tab_index"), get_tab_idx_from_control(c));
}
@@ -584,8 +584,8 @@ void TabContainer::remove_child_notify(Node *p_child) {
return;
}
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(p_child, SortableVisbilityMode::IGNORE);
+ if (!c) {
return;
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index a46d77c61e..2b2ea54dde 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -286,6 +286,7 @@ void TextEdit::Text::invalidate_all_lines() {
}
tab_size_dirty = false;
+ max_width = -1;
_calculate_max_line_width();
}
@@ -404,10 +405,12 @@ void TextEdit::Text::remove_range(int p_from_line, int p_to_line) {
text.resize(text.size() - diff);
if (dirty_height) {
+ line_height = -1;
_calculate_line_height();
}
if (dirty_width) {
+ max_width = -1;
_calculate_max_line_width();
}
}
@@ -5174,7 +5177,7 @@ void TextEdit::add_selection_for_next_occurrence() {
const String &highlighted_text = get_selected_text(caret);
int column = get_selection_from_column(caret) + 1;
- int line = get_caret_line(caret);
+ int line = get_selection_from_line(caret);
const Point2i next_occurrence = search(highlighted_text, SEARCH_MATCH_CASE, line, column);
@@ -5188,6 +5191,7 @@ void TextEdit::add_selection_for_next_occurrence() {
if (new_caret != -1) {
select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret);
+ _unhide_carets();
adjust_viewport_to_caret(new_caret);
merge_overlapping_carets();
}
@@ -5211,8 +5215,8 @@ void TextEdit::skip_selection_for_next_occurrence() {
// Due to const and &(reference) presence, ternary operator is a way to avoid errors and warnings.
const String &searched_text = has_selection(caret) ? get_selected_text(caret) : get_word_under_caret(caret);
- int column = (has_selection(caret) ? get_selection_from_column(caret) : get_caret_column(caret)) + 1;
- int line = get_caret_line(caret);
+ int column = get_selection_from_column(caret) + 1;
+ int line = get_selection_from_line(caret);
const Point2i next_occurrence = search(searched_text, SEARCH_MATCH_CASE, line, column);
@@ -5220,12 +5224,13 @@ void TextEdit::skip_selection_for_next_occurrence() {
return;
}
- int to_column = (has_selection(caret) ? get_selection_to_column(caret) : get_caret_column(caret)) + 1;
+ 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);
+ _unhide_carets();
adjust_viewport_to_caret(new_caret);
merge_overlapping_carets();
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 601e8c52a4..277d568aaf 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -2204,6 +2204,10 @@ Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringB
Vector3 val = defval;
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
+ } else if (defval.get_type() == Variant::VECTOR4) {
+ Vector4 val = defval;
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
+ node_code += " vec4 " + inputs[i] + " = " + vformat("vec4(%.5f, %.5f, %.5f, %.5f);\n", val.x, val.y, val.z, val.w);
} else if (defval.get_type() == Variant::QUATERNION) {
Quaternion val = defval;
inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index d5394c8af5..cb8719fbef 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -7825,7 +7825,7 @@ bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const {
String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
- code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
+ code += vformat(" %s = clamp(smoothstep(%s, %s, length(VERTEX)), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
return code;
}
diff --git a/servers/display/native_menu.cpp b/servers/display/native_menu.cpp
index ca46560c7c..c7346637d8 100644
--- a/servers/display/native_menu.cpp
+++ b/servers/display/native_menu.cpp
@@ -56,6 +56,8 @@ void NativeMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_minimum_width", "rid", "width"), &NativeMenu::set_minimum_width);
ClassDB::bind_method(D_METHOD("get_minimum_width", "rid"), &NativeMenu::get_minimum_width);
+ ClassDB::bind_method(D_METHOD("is_opened", "rid"), &NativeMenu::is_opened);
+
ClassDB::bind_method(D_METHOD("add_submenu_item", "rid", "label", "submenu_rid", "tag", "index"), &NativeMenu::add_submenu_item, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_item", "rid", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_check_item", "rid", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
@@ -200,6 +202,11 @@ Callable NativeMenu::get_popup_close_callback(const RID &p_rid) const {
return Callable();
}
+bool NativeMenu::is_opened(const RID &p_rid) const {
+ WARN_PRINT("Global menus are not supported on this platform.");
+ return false;
+}
+
void NativeMenu::set_minimum_width(const RID &p_rid, float p_width) {
WARN_PRINT("Global menus are not supported on this platform.");
}
diff --git a/servers/display/native_menu.h b/servers/display/native_menu.h
index 2bc061a216..29d22e03aa 100644
--- a/servers/display/native_menu.h
+++ b/servers/display/native_menu.h
@@ -90,6 +90,8 @@ public:
virtual void set_minimum_width(const RID &p_rid, float p_width);
virtual float get_minimum_width(const RID &p_rid) const;
+ virtual bool is_opened(const RID &p_rid) const;
+
virtual int add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag = Variant(), int p_index = -1);
virtual int add_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
virtual int add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 2150a3038e..b6e0d58af7 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -31,7 +31,6 @@
#include "display_server.h"
#include "core/input/input.h"
-#include "scene/resources/atlas_texture.h"
#include "scene/resources/texture.h"
#include "servers/display_server_headless.h"
@@ -1124,35 +1123,22 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(TTS_UTTERANCE_BOUNDARY);
}
-Ref<Image> DisplayServer::_get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot, Rect2 &r_atlas_rect) {
+Ref<Image> DisplayServer::_get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot) {
Ref<Image> image;
ERR_FAIL_COND_V_MSG(p_hotspot.x < 0 || p_hotspot.y < 0, image, "Hotspot outside cursor image.");
- Size2 texture_size;
-
Ref<Texture2D> texture = p_cursor;
if (texture.is_valid()) {
- Ref<AtlasTexture> atlas_texture = p_cursor;
-
- if (atlas_texture.is_valid()) {
- texture = atlas_texture->get_atlas();
- r_atlas_rect.size = texture->get_size();
- r_atlas_rect.position = atlas_texture->get_region().position;
- texture_size = atlas_texture->get_region().size;
- } else {
- texture_size = texture->get_size();
- }
image = texture->get_image();
} else {
image = p_cursor;
- ERR_FAIL_COND_V(image.is_null(), image);
- texture_size = image->get_size();
}
+ ERR_FAIL_COND_V(image.is_null(), image);
- ERR_FAIL_COND_V_MSG(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height, image, "Hotspot outside cursor image.");
- ERR_FAIL_COND_V_MSG(texture_size.width > 256 || texture_size.height > 256, image, "Cursor image too big. Max supported size is 256x256.");
+ Size2 image_size = image->get_size();
+ ERR_FAIL_COND_V_MSG(p_hotspot.x > image_size.width || p_hotspot.y > image_size.height, image, "Hotspot outside cursor image.");
+ ERR_FAIL_COND_V_MSG(image_size.width > 256 || image_size.height > 256, image, "Cursor image too big. Max supported size is 256x256.");
- ERR_FAIL_COND_V(image.is_null(), image);
if (image->is_compressed()) {
image = image->duplicate(true);
Error err = image->decompress();
diff --git a/servers/display_server.h b/servers/display_server.h
index 5224d59c04..5d82b6c13c 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -101,7 +101,7 @@ private:
protected:
static void _bind_methods();
- static Ref<Image> _get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot, Rect2 &r_atlas_rect);
+ static Ref<Image> _get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot);
enum {
MAX_SERVERS = 64
@@ -248,8 +248,8 @@ public:
virtual void tts_set_utterance_callback(TTSUtteranceEvent p_event, const Callable &p_callable);
virtual void tts_post_utterance_event(TTSUtteranceEvent p_event, int p_id, int p_pos = 0);
- virtual bool is_dark_mode_supported() const { return false; };
- virtual bool is_dark_mode() const { return false; };
+ virtual bool is_dark_mode_supported() const { return false; }
+ virtual bool is_dark_mode() const { return false; }
virtual Color get_accent_color() const { return Color(0, 0, 0, 0); }
virtual Color get_base_color() const { return Color(0, 0, 0, 0); }
virtual void set_system_theme_change_callback(const Callable &p_callable) {}
@@ -338,8 +338,8 @@ public:
return scale;
}
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
- virtual Color screen_get_pixel(const Point2i &p_position) const { return Color(); };
- virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const { return Ref<Image>(); };
+ virtual Color screen_get_pixel(const Point2i &p_position) const { return Color(); }
+ virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const { return Ref<Image>(); }
virtual bool is_touchscreen_available() const;
// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
@@ -398,9 +398,9 @@ public:
virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id);
- virtual WindowID window_get_active_popup() const { return INVALID_WINDOW_ID; };
- virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect){};
- virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const { return Rect2i(); };
+ virtual WindowID window_get_active_popup() const { return INVALID_WINDOW_ID; }
+ virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {}
+ virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const { return Rect2i(); }
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const;
@@ -555,10 +555,10 @@ public:
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const;
virtual Key keyboard_get_label_from_physical(Key p_keycode) const;
- virtual int tablet_get_driver_count() const { return 1; };
- virtual String tablet_get_driver_name(int p_driver) const { return "default"; };
- virtual String tablet_get_current_driver() const { return "default"; };
- virtual void tablet_set_current_driver(const String &p_driver){};
+ virtual int tablet_get_driver_count() const { return 1; }
+ virtual String tablet_get_driver_name(int p_driver) const { return "default"; }
+ virtual String tablet_get_current_driver() const { return "default"; }
+ virtual void tablet_set_current_driver(const String &p_driver) {}
virtual void process_events() = 0;
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index c02830b6df..317dbe9ab9 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -3331,6 +3331,45 @@ TEST_CASE("[SceneTree][CodeEdit] folding") {
CHECK_FALSE(code_edit->is_line_folded(1));
}
+ SUBCASE("[CodeEdit] actions unfold") {
+ // add_selection_for_next_occurrence unfolds.
+ code_edit->set_text("test\n\tline1 test\n\t\tline 2\ntest2");
+ code_edit->select(0, 0, 0, 4);
+ code_edit->fold_line(0);
+ CHECK(code_edit->is_line_folded(0));
+ code_edit->add_selection_for_next_occurrence();
+
+ CHECK(code_edit->get_caret_count() == 2);
+ CHECK(code_edit->has_selection(0));
+ CHECK(code_edit->get_caret_line() == 0);
+ CHECK(code_edit->get_selection_origin_line() == 0);
+ CHECK(code_edit->get_caret_column() == 4);
+ CHECK(code_edit->get_selection_origin_column() == 0);
+ CHECK(code_edit->has_selection(1));
+ CHECK(code_edit->get_caret_line(1) == 1);
+ CHECK(code_edit->get_selection_origin_line(1) == 1);
+ CHECK(code_edit->get_caret_column(1) == 11);
+ CHECK(code_edit->get_selection_origin_column(1) == 7);
+ CHECK_FALSE(code_edit->is_line_folded(0));
+ code_edit->remove_secondary_carets();
+
+ // skip_selection_for_next_occurrence unfolds.
+ code_edit->select(0, 0, 0, 4);
+ code_edit->fold_line(0);
+ CHECK(code_edit->is_line_folded(0));
+ code_edit->skip_selection_for_next_occurrence();
+
+ CHECK(code_edit->get_caret_count() == 1);
+ CHECK(code_edit->has_selection(0));
+ CHECK(code_edit->get_caret_line() == 1);
+ CHECK(code_edit->get_selection_origin_line() == 1);
+ CHECK(code_edit->get_caret_column() == 11);
+ CHECK(code_edit->get_selection_origin_column() == 7);
+ CHECK_FALSE(code_edit->is_line_folded(0));
+ code_edit->remove_secondary_carets();
+ code_edit->deselect();
+ }
+
SUBCASE("[CodeEdit] toggle folding carets") {
code_edit->set_text("test\n\tline1\ntest2\n\tline2");
diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h
index 8778ea86a6..cf6b89c330 100644
--- a/tests/servers/test_navigation_server_3d.h
+++ b/tests/servers/test_navigation_server_3d.h
@@ -697,12 +697,16 @@ TEST_SUITE("[Navigation]") {
CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0));
CHECK_NE(navigation_server->map_get_closest_point_normal(map, Vector3(0, 0, 0)), Vector3());
CHECK(navigation_server->map_get_closest_point_owner(map, Vector3(0, 0, 0)).is_valid());
- // TODO: Test map_get_closest_point_to_segment() with p_use_collision=true as well.
CHECK_NE(navigation_server->map_get_closest_point_to_segment(map, Vector3(0, 0, 0), Vector3(1, 1, 1), false), Vector3());
+ CHECK_NE(navigation_server->map_get_closest_point_to_segment(map, Vector3(0, 0, 0), Vector3(1, 1, 1), true), Vector3());
CHECK_NE(navigation_server->map_get_path(map, Vector3(0, 0, 0), Vector3(10, 0, 10), true).size(), 0);
CHECK_NE(navigation_server->map_get_path(map, Vector3(0, 0, 0), Vector3(10, 0, 10), false).size(), 0);
}
+ SUBCASE("'map_get_closest_point_to_segment' with 'use_collision' should return default if segment doesn't intersect map") {
+ CHECK_EQ(navigation_server->map_get_closest_point_to_segment(map, Vector3(1, 2, 1), Vector3(1, 1, 1), true), Vector3());
+ }
+
SUBCASE("Elaborate query with 'CORRIDORFUNNEL' post-processing should yield non-empty result") {
Ref<NavigationPathQueryParameters3D> query_parameters = memnew(NavigationPathQueryParameters3D);
query_parameters->set_map(map);
diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp
index d01eab3c9d..4ecab05265 100644
--- a/thirdparty/embree/common/sys/sysinfo.cpp
+++ b/thirdparty/embree/common/sys/sysinfo.cpp
@@ -295,7 +295,7 @@ namespace embree
if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001);
#if _WIN32
#if _MSC_VER && (_MSC_FULL_VER < 160040219)
-#else
+#elif defined(_MSC_VER)
if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0);
#endif
#else
diff --git a/thirdparty/embree/patches/mingw-no-cpuidex.patch b/thirdparty/embree/patches/mingw-no-cpuidex.patch
new file mode 100644
index 0000000000..5480334ceb
--- /dev/null
+++ b/thirdparty/embree/patches/mingw-no-cpuidex.patch
@@ -0,0 +1,13 @@
+diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp
+index d01eab3c9d..4ecab05265 100644
+--- a/thirdparty/embree/common/sys/sysinfo.cpp
++++ b/thirdparty/embree/common/sys/sysinfo.cpp
+@@ -295,7 +295,7 @@ namespace embree
+ if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001);
+ #if _WIN32
+ #if _MSC_VER && (_MSC_FULL_VER < 160040219)
+-#else
++#elif defined(_MSC_VER)
+ if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0);
+ #endif
+ #else
diff --git a/thirdparty/glslang/glslang/Include/InfoSink.h b/thirdparty/glslang/glslang/Include/InfoSink.h
index b1b537df54..137ede8510 100644
--- a/thirdparty/glslang/glslang/Include/InfoSink.h
+++ b/thirdparty/glslang/glslang/Include/InfoSink.h
@@ -36,7 +36,7 @@
#define _INFOSINK_INCLUDED_
#include "../Include/Common.h"
-#include <filesystem>
+//#include <filesystem>
#include <cmath>
namespace glslang {
diff --git a/thirdparty/glslang/glslang/patches/disable-absolute-paths-for-apple-compat.patch b/thirdparty/glslang/patches/disable-absolute-paths-for-apple-compat.patch
index d15a531b7c..135020737e 100644
--- a/thirdparty/glslang/glslang/patches/disable-absolute-paths-for-apple-compat.patch
+++ b/thirdparty/glslang/patches/disable-absolute-paths-for-apple-compat.patch
@@ -1,7 +1,16 @@
diff --git a/thirdparty/glslang/glslang/Include/InfoSink.h b/thirdparty/glslang/glslang/Include/InfoSink.h
-index 23f495dcb7..b1b537df54 100644
+index 23f495dc..137ede85 100644
--- a/thirdparty/glslang/glslang/Include/InfoSink.h
+++ b/thirdparty/glslang/glslang/Include/InfoSink.h
+@@ -36,7 +36,7 @@
+ #define _INFOSINK_INCLUDED_
+
+ #include "../Include/Common.h"
+-#include <filesystem>
++//#include <filesystem>
+ #include <cmath>
+
+ namespace glslang {
@@ -101,14 +101,14 @@ public:
snprintf(locText, maxSize, ":%d", loc.line);