summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/string/translation_server.cpp2
-rw-r--r--core/string/translation_server.h2
-rw-r--r--core/variant/callable.cpp25
-rw-r--r--core/variant/callable.h6
-rw-r--r--core/variant/callable_bind.cpp67
-rw-r--r--core/variant/callable_bind.h6
-rw-r--r--core/variant/variant.cpp16
-rw-r--r--core/variant/variant_call.cpp1
-rw-r--r--doc/classes/Callable.xml19
-rw-r--r--doc/classes/EditorSettings.xml2
-rw-r--r--doc/classes/Tween.xml20
-rw-r--r--editor/animation_track_editor.cpp9
-rw-r--r--editor/editor_settings_dialog.cpp4
-rw-r--r--editor/filesystem_dock.cpp126
-rw-r--r--editor/filesystem_dock.h5
-rw-r--r--platform/windows/os_windows.cpp89
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--scene/main/node.cpp9
-rw-r--r--tests/core/variant/test_callable.h64
19 files changed, 302 insertions, 172 deletions
diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp
index 4f09360ba8..31c221dad7 100644
--- a/core/string/translation_server.cpp
+++ b/core/string/translation_server.cpp
@@ -411,8 +411,6 @@ StringName TranslationServer::translate_plural(const StringName &p_message, cons
return main_domain->translate_plural(p_message, p_message_plural, p_n, p_context);
}
-TranslationServer *TranslationServer::singleton = nullptr;
-
bool TranslationServer::_load_translations(const String &p_from) {
if (ProjectSettings::get_singleton()->has_setting(p_from)) {
const Vector<String> &translation_names = GLOBAL_GET(p_from);
diff --git a/core/string/translation_server.h b/core/string/translation_server.h
index fac41035ae..bc59c34a38 100644
--- a/core/string/translation_server.h
+++ b/core/string/translation_server.h
@@ -50,7 +50,7 @@ class TranslationServer : public Object {
bool enabled = true;
- static TranslationServer *singleton;
+ static inline TranslationServer *singleton = nullptr;
bool _load_translations(const String &p_from);
String _standardize_locale(const String &p_locale, bool p_add_defaults) const;
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 5ce90cd8ff..ddeea27118 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -206,19 +206,17 @@ int Callable::get_bound_arguments_count() const {
}
}
-void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const {
+void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments) const {
if (!is_null() && is_custom()) {
- custom->get_bound_arguments(r_arguments, r_argcount);
+ custom->get_bound_arguments(r_arguments);
} else {
r_arguments.clear();
- r_argcount = 0;
}
}
Array Callable::get_bound_arguments() const {
Vector<Variant> arr;
- int ac;
- get_bound_arguments_ref(arr, ac);
+ get_bound_arguments_ref(arr);
Array ret;
ret.resize(arr.size());
for (int i = 0; i < arr.size(); i++) {
@@ -227,6 +225,14 @@ Array Callable::get_bound_arguments() const {
return ret;
}
+int Callable::get_unbound_arguments_count() const {
+ if (!is_null() && is_custom()) {
+ return custom->get_unbound_arguments_count();
+ } else {
+ return 0;
+ }
+}
+
CallableCustom *Callable::get_custom() const {
ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
@@ -464,9 +470,12 @@ int CallableCustom::get_bound_arguments_count() const {
return 0;
}
-void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- r_arguments = Vector<Variant>();
- r_argcount = 0;
+void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ r_arguments.clear();
+}
+
+int CallableCustom::get_unbound_arguments_count() const {
+ return 0;
}
CallableCustom::CallableCustom() {
diff --git a/core/variant/callable.h b/core/variant/callable.h
index e3c940a0e5..e76b888ac2 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -111,8 +111,9 @@ public:
CallableCustom *get_custom() const;
int get_argument_count(bool *r_is_valid = nullptr) const;
int get_bound_arguments_count() const;
- void get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const; // Internal engine use, the exposed one is below.
+ void get_bound_arguments_ref(Vector<Variant> &r_arguments) const; // Internal engine use, the exposed one is below.
Array get_bound_arguments() const;
+ int get_unbound_arguments_count() const;
uint32_t hash() const;
@@ -158,7 +159,8 @@ public:
virtual const Callable *get_base_comparator() const;
virtual int get_argument_count(bool &r_is_valid) const;
virtual int get_bound_arguments_count() const;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const;
+ virtual int get_unbound_arguments_count() const;
CallableCustom();
virtual ~CallableCustom() {}
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index afb889551e..43cac263c1 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -100,44 +100,42 @@ int CallableCustomBind::get_argument_count(bool &r_is_valid) const {
}
int CallableCustomBind::get_bound_arguments_count() const {
- return callable.get_bound_arguments_count() + binds.size();
+ return callable.get_bound_arguments_count() + MAX(0, binds.size() - callable.get_unbound_arguments_count());
}
-void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- Vector<Variant> sub_args;
- int sub_count;
- callable.get_bound_arguments_ref(sub_args, sub_count);
+void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ Vector<Variant> sub_bound_args;
+ callable.get_bound_arguments_ref(sub_bound_args);
+ int sub_bound_count = sub_bound_args.size();
- if (sub_count == 0) {
+ int sub_unbound_count = callable.get_unbound_arguments_count();
+
+ if (sub_bound_count == 0 && sub_unbound_count == 0) {
r_arguments = binds;
- r_argcount = binds.size();
return;
}
- int new_count = sub_count + binds.size();
- r_argcount = new_count;
+ int added_count = MAX(0, binds.size() - sub_unbound_count);
+ int new_count = sub_bound_count + added_count;
- if (new_count <= 0) {
- // Removed more arguments than it adds.
- r_arguments = Vector<Variant>();
+ if (added_count <= 0) {
+ // All added arguments are consumed by `sub_unbound_count`.
+ r_arguments = sub_bound_args;
return;
}
r_arguments.resize(new_count);
-
- if (sub_count > 0) {
- for (int i = 0; i < sub_count; i++) {
- r_arguments.write[i] = sub_args[i];
- }
- for (int i = 0; i < binds.size(); i++) {
- r_arguments.write[i + sub_count] = binds[i];
- }
- r_argcount = new_count;
- } else {
- for (int i = 0; i < binds.size() + sub_count; i++) {
- r_arguments.write[i] = binds[i - sub_count];
- }
+ Variant *args = r_arguments.ptrw();
+ for (int i = 0; i < added_count; i++) {
+ args[i] = binds[i];
}
+ for (int i = 0; i < sub_bound_count; i++) {
+ args[i + added_count] = sub_bound_args[i];
+ }
+}
+
+int CallableCustomBind::get_unbound_arguments_count() const {
+ return MAX(0, callable.get_unbound_arguments_count() - binds.size());
}
void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
@@ -242,22 +240,15 @@ int CallableCustomUnbind::get_argument_count(bool &r_is_valid) const {
}
int CallableCustomUnbind::get_bound_arguments_count() const {
- return callable.get_bound_arguments_count() - argcount;
+ return callable.get_bound_arguments_count();
}
-void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- Vector<Variant> sub_args;
- int sub_count;
- callable.get_bound_arguments_ref(sub_args, sub_count);
-
- r_argcount = sub_args.size() - argcount;
+void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ callable.get_bound_arguments_ref(r_arguments);
+}
- if (argcount >= sub_args.size()) {
- r_arguments = Vector<Variant>();
- } else {
- sub_args.resize(sub_args.size() - argcount);
- r_arguments = sub_args;
- }
+int CallableCustomUnbind::get_unbound_arguments_count() const {
+ return callable.get_unbound_arguments_count() + argcount;
}
void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index 43cebb45f0..1346277197 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -55,7 +55,8 @@ public:
virtual const Callable *get_base_comparator() const override;
virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
+ virtual int get_unbound_arguments_count() const override;
Callable get_callable() { return callable; }
Vector<Variant> get_binds() { return binds; }
@@ -84,7 +85,8 @@ public:
virtual const Callable *get_base_comparator() const override;
virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
+ virtual int get_unbound_arguments_count() const override;
Callable get_callable() { return callable; }
int get_unbinds() { return argcount; }
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 54936eb8a2..3e74dc4e67 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3664,18 +3664,20 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
Vector<Variant> binds;
- int args_bound;
- p_callable.get_bound_arguments_ref(binds, args_bound);
- if (args_bound <= 0) {
- return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, MAX(0, p_argcount + args_bound), ce);
+ p_callable.get_bound_arguments_ref(binds);
+
+ int args_unbound = p_callable.get_unbound_arguments_count();
+
+ if (p_argcount - args_unbound < 0) {
+ return "Callable unbinds " + itos(args_unbound) + " arguments, but called with " + itos(p_argcount);
} else {
Vector<const Variant *> argptrs;
- argptrs.resize(p_argcount + binds.size());
- for (int i = 0; i < p_argcount; i++) {
+ argptrs.resize(p_argcount - args_unbound + binds.size());
+ for (int i = 0; i < p_argcount - args_unbound; i++) {
argptrs.write[i] = p_argptrs[i];
}
for (int i = 0; i < binds.size(); i++) {
- argptrs.write[i + p_argcount] = &binds[i];
+ argptrs.write[i + p_argcount - args_unbound] = &binds[i];
}
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), (const Variant **)argptrs.ptr(), argptrs.size(), ce);
}
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 29e11462c9..381b848b2b 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -2116,6 +2116,7 @@ static void _register_variant_builtin_methods_misc() {
bind_function(Callable, get_argument_count, _VariantCall::func_Callable_get_argument_count, sarray(), varray());
bind_method(Callable, get_bound_arguments_count, sarray(), varray());
bind_method(Callable, get_bound_arguments, sarray(), varray());
+ bind_method(Callable, get_unbound_arguments_count, sarray(), varray());
bind_method(Callable, hash, sarray(), varray());
bind_method(Callable, bindv, sarray("arguments"), varray());
bind_method(Callable, unbind, sarray("argcount"), varray());
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 0c8f3c66f5..cf3c3e06fd 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -155,13 +155,21 @@
<method name="get_bound_arguments" qualifiers="const">
<return type="Array" />
<description>
- Return the bound arguments (as long as [method get_bound_arguments_count] is greater than zero), or empty (if [method get_bound_arguments_count] is less than or equal to zero).
+ Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
+ [codeblock]
+ func get_effective_arguments(callable, call_args):
+ assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0)
+ var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
+ result.append_array(callable.get_bound_arguments())
+ return result
+ [/codeblock]
</description>
</method>
<method name="get_bound_arguments_count" qualifiers="const">
<return type="int" />
<description>
- Returns the total amount of arguments bound (or unbound) via successive [method bind] or [method unbind] calls. If the amount of arguments unbound is greater than the ones bound, this function returns a value less than zero.
+ Returns the total amount of arguments bound via successive [method bind] or [method unbind] calls. This is the same as the size of the array returned by [method get_bound_arguments]. See [method get_bound_arguments] for details.
+ [b]Note:[/b] The [method get_bound_arguments_count] and [method get_unbound_arguments_count] methods can both return positive values.
</description>
</method>
<method name="get_method" qualifiers="const">
@@ -182,6 +190,13 @@
Returns the ID of this [Callable]'s object (see [method Object.get_instance_id]).
</description>
</method>
+ <method name="get_unbound_arguments_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the total amount of arguments unbound via successive [method bind] or [method unbind] calls. See [method get_bound_arguments] for details.
+ [b]Note:[/b] The [method get_bound_arguments_count] and [method get_unbound_arguments_count] methods can both return positive values.
+ </description>
+ </method>
<method name="hash" qualifiers="const">
<return type="int" />
<description>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 15b03ddbd8..c35a376c85 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -359,7 +359,7 @@
<member name="editors/3d/navigation/navigation_scheme" type="int" setter="" getter="">
The navigation scheme preset to use in the 3D editor. Changing this setting will affect the mouse button and modifier controls used to navigate the 3D editor viewport.
All schemes can use [kbd]Mouse wheel[/kbd] to zoom.
- - [b]Godot:[/b] [kbd]Middle mouse button[/kbd] to orbit. [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Ctrl + Shift + Middle mouse button[/kbd] to zoom.
+ - [b]Godot:[/b] [kbd]Middle mouse button[/kbd] to orbit. [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Ctrl + Middle mouse button[/kbd] to zoom.
- [b]Maya:[/b] [kbd]Alt + Left mouse button[/kbd] to orbit. [kbd]Middle mouse button[/kbd] to pan, [kbd]Shift + Middle mouse button[/kbd] to pan 10 times faster. [kbd]Alt + Right mouse button[/kbd] to zoom.
- [b]Modo:[/b] [kbd]Alt + Left mouse button[/kbd] to orbit. [kbd]Alt + Shift + Left mouse button[/kbd] to pan. [kbd]Ctrl + Alt + Left mouse button[/kbd] to zoom.
See also [member editors/3d/navigation/orbit_mouse_button], [member editors/3d/navigation/pan_mouse_button], [member editors/3d/navigation/zoom_mouse_button], and [member editors/3d/freelook/freelook_navigation_scheme].
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 3ad0a73b41..147d9fa4bd 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -218,8 +218,14 @@
<return type="Tween" />
<param index="0" name="ease" type="int" enum="Tween.EaseType" />
<description>
- Sets the default ease type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
- If not specified, the default value is [constant EASE_IN_OUT].
+ Sets the default ease type for [PropertyTweener]s and [MethodTweener]s appended after this method.
+ Before this method is called, the default ease type is [constant EASE_IN_OUT].
+ [codeblock]
+ var tween = create_tween()
+ tween.tween_property(self, "position", Vector2(300, 0), 0.5) # Uses EASE_IN_OUT.
+ tween.set_ease(Tween.EASE_IN)
+ tween.tween_property(self, "rotation_degrees", 45.0, 0.5) # Uses EASE_IN.
+ [/codeblock]
</description>
</method>
<method name="set_loops">
@@ -271,8 +277,14 @@
<return type="Tween" />
<param index="0" name="trans" type="int" enum="Tween.TransitionType" />
<description>
- Sets the default transition type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
- If not specified, the default value is [constant TRANS_LINEAR].
+ Sets the default transition type for [PropertyTweener]s and [MethodTweener]s appended after this method.
+ Before this method is called, the default transition type is [constant TRANS_LINEAR].
+ [codeblock]
+ var tween = create_tween()
+ tween.tween_property(self, "position", Vector2(300, 0), 0.5) # Uses TRANS_LINEAR.
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.tween_property(self, "rotation_degrees", 45.0, 0.5) # Uses TRANS_SINE.
+ [/codeblock]
</description>
</method>
<method name="stop">
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 076ba6d905..55ea7c0082 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -7383,16 +7383,17 @@ void AnimationTrackEditor::_update_snap_unit() {
float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
if (is_snap_keys_enabled()) {
+ double current_snap = snap_unit;
if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
- snap_unit *= 0.25;
+ current_snap *= 0.25;
}
if (p_relative) {
- double rel = Math::fmod(timeline->get_value(), snap_unit);
- p_value = Math::snapped(p_value + rel, snap_unit) - rel;
+ double rel = Math::fmod(timeline->get_value(), current_snap);
+ p_value = Math::snapped(p_value + rel, current_snap) - rel;
} else {
- p_value = Math::snapped(p_value, snap_unit);
+ p_value = Math::snapped(p_value, current_snap);
}
}
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index d6742c9b55..8989b9cf9b 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -106,8 +106,8 @@ void EditorSettingsDialog::update_navigation_preset() {
orbit_mod_key_2 = InputEventKey::create_reference(Key::NONE);
pan_mod_key_1 = InputEventKey::create_reference(Key::SHIFT);
pan_mod_key_2 = InputEventKey::create_reference(Key::NONE);
- zoom_mod_key_1 = InputEventKey::create_reference(Key::SHIFT);
- zoom_mod_key_2 = InputEventKey::create_reference(Key::CTRL);
+ zoom_mod_key_1 = InputEventKey::create_reference(Key::CTRL);
+ zoom_mod_key_2 = InputEventKey::create_reference(Key::NONE);
} else if (nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA) {
set_preset = true;
set_orbit_mouse_button = Node3DEditorViewport::NAVIGATION_LEFT_MOUSE;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index fcd5a572b4..3921cde71e 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -203,9 +203,7 @@ Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String
}
}
-bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
- bool parent_should_expand = false;
-
+void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
// Create a tree item for the subdirectory.
TreeItem *subdirectory_item = tree->create_item(p_parent);
String dname = p_dir->get_name();
@@ -213,6 +211,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
if (dname.is_empty()) {
dname = "res://";
+ resources_item = subdirectory_item;
}
// Set custom folder color (if applicable).
@@ -258,16 +257,13 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
} else {
subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath));
}
- if (!searched_tokens.is_empty() && _matches_all_search_tokens(dname)) {
- parent_should_expand = true;
- }
// Create items for all subdirectories.
bool reversed = file_sort == FileSortOption::FILE_SORT_NAME_REVERSE;
for (int i = reversed ? p_dir->get_subdir_count() - 1 : 0;
reversed ? i >= 0 : i < p_dir->get_subdir_count();
reversed ? i-- : i++) {
- parent_should_expand = (_create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path) || parent_should_expand);
+ _create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path);
}
// Create all items for the files in the subdirectory.
@@ -283,17 +279,6 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
continue;
}
- String file_name = p_dir->get_file(i);
- if (!searched_tokens.is_empty()) {
- if (!_matches_all_search_tokens(file_name)) {
- // The searched string is not in the file name, we skip it.
- continue;
- } else {
- // We expand all parents.
- parent_should_expand = true;
- }
- }
-
FileInfo file_info;
file_info.name = p_dir->get_file(i);
file_info.type = p_dir->get_file_type(i);
@@ -346,24 +331,12 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_as_cursor(0);
}
}
-
- if (!searched_tokens.is_empty()) {
- if (parent_should_expand) {
- subdirectory_item->set_collapsed(false);
- } else if (dname != "res://") {
- subdirectory_item->get_parent()->remove_child(subdirectory_item);
- memdelete(subdirectory_item);
- }
- }
-
- return parent_should_expand;
}
Vector<String> FileSystemDock::get_uncollapsed_paths() const {
Vector<String> uncollapsed_paths;
TreeItem *root = tree->get_root();
if (root) {
- TreeItem *favorites_item = root->get_first_child();
if (!favorites_item->is_collapsed()) {
uncollapsed_paths.push_back(favorites_item->get_metadata(0));
}
@@ -400,7 +373,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
TreeItem *root = tree->create_item();
// Handles the favorites.
- TreeItem *favorites_item = tree->create_item(root);
+ favorites_item = tree->create_item(root);
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
favorites_item->set_text(0, TTR("Favorites:"));
favorites_item->set_metadata(0, "Favorites");
@@ -453,24 +426,22 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
color = Color(1, 1, 1);
}
- if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
- TreeItem *ti = tree->create_item(favorites_item);
- ti->set_text(0, text);
- ti->set_icon(0, icon);
- ti->set_icon_modulate(0, color);
- ti->set_tooltip_text(0, favorite);
- ti->set_selectable(0, true);
- ti->set_metadata(0, favorite);
- if (p_select_in_favorites && favorite == current_path) {
- ti->select(0);
- ti->set_as_cursor(0);
- }
- if (!favorite.ends_with("/")) {
- Array udata;
- udata.push_back(tree_update_id);
- udata.push_back(ti);
- EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
- }
+ TreeItem *ti = tree->create_item(favorites_item);
+ ti->set_text(0, text);
+ ti->set_icon(0, icon);
+ ti->set_icon_modulate(0, color);
+ ti->set_tooltip_text(0, favorite);
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, favorite);
+ if (p_select_in_favorites && favorite == current_path) {
+ ti->select(0);
+ ti->set_as_cursor(0);
+ }
+ if (!favorite.ends_with("/")) {
+ Array udata;
+ udata.push_back(tree_update_id);
+ udata.push_back(ti);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
}
}
@@ -676,7 +647,6 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
}
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed.
current_path = "Favorites";
@@ -771,6 +741,36 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
}
}
+bool FileSystemDock::_update_filtered_items(TreeItem *p_tree_item) {
+ TreeItem *item = p_tree_item;
+ if (!item) {
+ item = tree->get_root();
+ }
+ ERR_FAIL_NULL_V(item, false);
+
+ bool keep_visible = false;
+ for (TreeItem *child = item->get_first_child(); child; child = child->get_next()) {
+ keep_visible = _update_filtered_items(child) || keep_visible;
+ }
+
+ if (searched_tokens.is_empty()) {
+ item->set_visible(true);
+ // Always uncollapse root (the hidden item above res:// and favorites).
+ item->set_collapsed(item != tree->get_root() && !uncollapsed_paths_before_search.has(item->get_metadata(0)));
+ return true;
+ }
+
+ if (keep_visible) {
+ item->set_collapsed(false);
+ } else {
+ // res:// and favorites are always visible.
+ keep_visible = item == resources_item || item == favorites_item;
+ keep_visible = keep_visible || _matches_all_search_tokens(item->get_text(0));
+ }
+ item->set_visible(keep_visible);
+ return keep_visible;
+}
+
void FileSystemDock::navigate_to_path(const String &p_path) {
file_list_search_box->clear();
_navigate_to_path(p_path);
@@ -2028,7 +2028,6 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
if (cursor_item && (p_include_unselected_cursor || cursor_item->is_selected(0)) && cursor_item != favorites_item) {
selected_strings.push_back(cursor_item->get_metadata(0));
@@ -2637,16 +2636,12 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
tree_search_box->set_text(searched_string);
}
- bool unfold_path = (p_text.is_empty() && !current_path.is_empty());
- switch (display_mode) {
- case DISPLAY_MODE_TREE_ONLY: {
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
- case DISPLAY_MODE_HSPLIT:
- case DISPLAY_MODE_VSPLIT: {
- _update_file_list(false);
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
+ _update_filtered_items();
+ if (display_mode == DISPLAY_MODE_HSPLIT || display_mode == DISPLAY_MODE_VSPLIT) {
+ _update_file_list(false);
+ }
+ if (searched_tokens.is_empty()) {
+ _navigate_to_path(current_path);
}
}
@@ -2786,7 +2781,6 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
// Check if the first selected is in favorite.
TreeItem *selected = tree->get_next_selected(tree->get_root());
while (selected) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected == favorites_item) {
// The "Favorites" item is not draggable.
return Variant();
@@ -2838,10 +2832,6 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
}
int drop_section = tree->get_drop_section_at_position(p_point);
- TreeItem *favorites_item = tree->get_root()->get_first_child();
-
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
return (drop_section == 1); // The parent, first fav.
}
@@ -2922,9 +2912,6 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
int drop_position;
Vector<String> drag_files = drag_data["files"];
- TreeItem *favorites_item = tree->get_root()->get_first_child();
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
// Drop on the favorite folder.
drop_position = 0;
@@ -3352,7 +3339,6 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
[[maybe_unused]] bool added_separator = false;
if (favorites_list.has(fpath)) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
bool is_item_in_favorites = false;
while (cursor_item != nullptr) {
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index fe83129c07..d2e403a8af 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -232,6 +232,8 @@ private:
FileSystemTree *tree = nullptr;
FileSystemList *files = nullptr;
bool import_dock_needs_update = false;
+ TreeItem *resources_item = nullptr;
+ TreeItem *favorites_item = nullptr;
bool holding_branch = false;
Vector<TreeItem *> tree_items_selected_on_drag_begin;
@@ -245,9 +247,10 @@ private:
void _reselect_items_selected_on_drag_begin(bool reset = false);
Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path);
- bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
+ void _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false);
void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false);
+ bool _update_filtered_items(TreeItem *p_tree_item = nullptr);
void _file_list_gui_input(Ref<InputEvent> p_event);
void _tree_gui_input(Ref<InputEvent> p_event);
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 0d151668ba..294a34bb91 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -918,18 +918,10 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
sa.lpSecurityDescriptor = nullptr;
ERR_FAIL_COND_V(!CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0), ret);
- if (!SetHandleInformation(pipe_in[1], HANDLE_FLAG_INHERIT, 0)) {
- CLEAN_PIPES
- ERR_FAIL_V(ret);
- }
if (!CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0)) {
CLEAN_PIPES
ERR_FAIL_V(ret);
}
- if (!SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0)) {
- CLEAN_PIPES
- ERR_FAIL_V(ret);
- }
if (!CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0)) {
CLEAN_PIPES
ERR_FAIL_V(ret);
@@ -939,16 +931,37 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
// Create process.
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
- pi.si.dwFlags |= STARTF_USESTDHANDLES;
- pi.si.hStdInput = pipe_in[0];
- pi.si.hStdOutput = pipe_out[1];
- pi.si.hStdError = pipe_err[1];
+ pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+ pi.si.StartupInfo.hStdInput = pipe_in[0];
+ pi.si.StartupInfo.hStdOutput = pipe_out[1];
+ pi.si.StartupInfo.hStdError = pipe_err[1];
- DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW;
+ size_t attr_list_size = 0;
+ InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size);
+ pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size);
+ if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ HANDLE handles_to_inherit[] = { pipe_in[0], pipe_out[1], pipe_err[1] };
+ if (!UpdateProcThreadAttribute(
+ pi.si.lpAttributeList,
+ 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ handles_to_inherit,
+ sizeof(handles_to_inherit),
+ nullptr,
+ nullptr)) {
+ CLEAN_PIPES
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ ERR_FAIL_V(ret);
+ }
+
+ DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT;
Char16String current_dir_name;
size_t str_len = GetCurrentDirectoryW(0, nullptr);
@@ -964,11 +977,13 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi)) {
CLEAN_PIPES
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
ERR_FAIL_V_MSG(ret, "Could not create child process: " + command);
}
CloseHandle(pipe_in[0]);
CloseHandle(pipe_out[1]);
CloseHandle(pipe_err[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
ProcessID pid = pi.pi.dwProcessId;
process_map_mutex.lock();
@@ -1000,9 +1015,9 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
bool inherit_handles = false;
HANDLE pipe[2] = { nullptr, nullptr };
@@ -1014,16 +1029,40 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
sa.lpSecurityDescriptor = nullptr;
ERR_FAIL_COND_V(!CreatePipe(&pipe[0], &pipe[1], &sa, 0), ERR_CANT_FORK);
- ERR_FAIL_COND_V(!SetHandleInformation(pipe[0], HANDLE_FLAG_INHERIT, 0), ERR_CANT_FORK); // Read handle is for host process only and should not be inherited.
- pi.si.dwFlags |= STARTF_USESTDHANDLES;
- pi.si.hStdOutput = pipe[1];
+ pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+ pi.si.StartupInfo.hStdOutput = pipe[1];
if (read_stderr) {
- pi.si.hStdError = pipe[1];
+ pi.si.StartupInfo.hStdError = pipe[1];
+ }
+
+ size_t attr_list_size = 0;
+ InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size);
+ pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size);
+ if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) {
+ CloseHandle(pipe[0]); // Cleanup pipe handles.
+ CloseHandle(pipe[1]);
+ ERR_FAIL_V(ERR_CANT_FORK);
+ }
+ if (!UpdateProcThreadAttribute(
+ pi.si.lpAttributeList,
+ 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ &pipe[1],
+ sizeof(HANDLE),
+ nullptr,
+ nullptr)) {
+ CloseHandle(pipe[0]); // Cleanup pipe handles.
+ CloseHandle(pipe[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ ERR_FAIL_V(ERR_CANT_FORK);
}
inherit_handles = true;
}
DWORD creation_flags = NORMAL_PRIORITY_CLASS;
+ if (inherit_handles) {
+ creation_flags |= EXTENDED_STARTUPINFO_PRESENT;
+ }
if (p_open_console) {
creation_flags |= CREATE_NEW_CONSOLE;
} else {
@@ -1046,6 +1085,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
if (!ret && r_pipe) {
CloseHandle(pipe[0]); // Cleanup pipe handles.
CloseHandle(pipe[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
}
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
@@ -1101,6 +1141,9 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
CloseHandle(pi.pi.hProcess);
CloseHandle(pi.pi.hThread);
+ if (r_pipe) {
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ }
return OK;
}
@@ -1114,9 +1157,9 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si.StartupInfo);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
DWORD creation_flags = NORMAL_PRIORITY_CLASS;
if (p_open_console) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 34af004822..c200ba5b43 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -148,7 +148,7 @@ protected:
String _quote_command_line_argument(const String &p_text) const;
struct ProcessInfo {
- STARTUPINFO si;
+ STARTUPINFOEX si;
PROCESS_INFORMATION pi;
mutable bool is_running = true;
mutable int exit_code = -1;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 8dc7b4a87c..5063f0d6d0 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -3055,11 +3055,12 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
if (copy && copytarget && E.callable.get_method() != StringName()) {
Callable copy_callable = Callable(copytarget, E.callable.get_method());
if (!copy->is_connected(E.signal.get_name(), copy_callable)) {
- int arg_count = E.callable.get_bound_arguments_count();
- if (arg_count > 0) {
+ int unbound_arg_count = E.callable.get_unbound_arguments_count();
+ if (unbound_arg_count > 0) {
+ copy_callable = copy_callable.unbind(unbound_arg_count);
+ }
+ if (E.callable.get_bound_arguments_count() > 0) {
copy_callable = copy_callable.bindv(E.callable.get_bound_arguments());
- } else if (arg_count < 0) {
- copy_callable = copy_callable.unbind(-arg_count);
}
copy->connect(E.signal.get_name(), copy_callable, E.flags);
}
diff --git a/tests/core/variant/test_callable.h b/tests/core/variant/test_callable.h
index 3228e0a583..34ea8fad5c 100644
--- a/tests/core/variant/test_callable.h
+++ b/tests/core/variant/test_callable.h
@@ -135,6 +135,70 @@ TEST_CASE("[Callable] Argument count") {
memdelete(my_test);
}
+
+class TestBoundUnboundArgumentCount : public Object {
+ GDCLASS(TestBoundUnboundArgumentCount, Object);
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "test_func", &TestBoundUnboundArgumentCount::test_func, MethodInfo("test_func"));
+ }
+
+public:
+ Variant test_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ Array result;
+ result.resize(p_argcount);
+ for (int i = 0; i < p_argcount; i++) {
+ result[i] = *p_args[i];
+ }
+ return result;
+ }
+
+ static String get_output(const Callable &p_callable) {
+ Array effective_args;
+ effective_args.push_back(7);
+ effective_args.push_back(8);
+ effective_args.push_back(9);
+
+ effective_args.resize(3 - p_callable.get_unbound_arguments_count());
+ effective_args.append_array(p_callable.get_bound_arguments());
+
+ return vformat(
+ "%d %d %s %s %s",
+ p_callable.get_unbound_arguments_count(),
+ p_callable.get_bound_arguments_count(),
+ p_callable.get_bound_arguments(),
+ p_callable.call(7, 8, 9),
+ effective_args);
+ }
+};
+
+TEST_CASE("[Callable] Bound and unbound argument count") {
+ String (*get_output)(const Callable &) = TestBoundUnboundArgumentCount::get_output;
+
+ TestBoundUnboundArgumentCount *test_instance = memnew(TestBoundUnboundArgumentCount);
+
+ Callable test_func = Callable(test_instance, "test_func");
+
+ CHECK(get_output(test_func) == "0 0 [] [7, 8, 9] [7, 8, 9]");
+ CHECK(get_output(test_func.bind(1, 2)) == "0 2 [1, 2] [7, 8, 9, 1, 2] [7, 8, 9, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1)) == "1 2 [1, 2] [7, 8, 1, 2] [7, 8, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1).bind(3, 4)) == "0 3 [3, 1, 2] [7, 8, 9, 3, 1, 2] [7, 8, 9, 3, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1).bind(3, 4).unbind(1)) == "1 3 [3, 1, 2] [7, 8, 3, 1, 2] [7, 8, 3, 1, 2]");
+
+ CHECK(get_output(test_func.bind(1).bind(2).bind(3).unbind(1)) == "1 3 [3, 2, 1] [7, 8, 3, 2, 1] [7, 8, 3, 2, 1]");
+ CHECK(get_output(test_func.bind(1).bind(2).unbind(1).bind(3)) == "0 2 [2, 1] [7, 8, 9, 2, 1] [7, 8, 9, 2, 1]");
+ CHECK(get_output(test_func.bind(1).unbind(1).bind(2).bind(3)) == "0 2 [3, 1] [7, 8, 9, 3, 1] [7, 8, 9, 3, 1]");
+ CHECK(get_output(test_func.unbind(1).bind(1).bind(2).bind(3)) == "0 2 [3, 2] [7, 8, 9, 3, 2] [7, 8, 9, 3, 2]");
+
+ CHECK(get_output(test_func.unbind(1).unbind(1).unbind(1).bind(1, 2, 3)) == "0 0 [] [7, 8, 9] [7, 8, 9]");
+ CHECK(get_output(test_func.unbind(1).unbind(1).bind(1, 2, 3).unbind(1)) == "1 1 [1] [7, 8, 1] [7, 8, 1]");
+ CHECK(get_output(test_func.unbind(1).bind(1, 2, 3).unbind(1).unbind(1)) == "2 2 [1, 2] [7, 1, 2] [7, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2, 3).unbind(1).unbind(1).unbind(1)) == "3 3 [1, 2, 3] [1, 2, 3] [1, 2, 3]");
+
+ memdelete(test_instance);
+}
+
} // namespace TestCallable
#endif // TEST_CALLABLE_H