summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/variant/variant_utility.cpp6
-rw-r--r--core/variant/variant_utility.h1
-rw-r--r--doc/classes/@GlobalScope.xml14
-rw-r--r--doc/classes/AcceptDialog.xml1
-rw-r--r--doc/classes/DisplayServer.xml17
-rw-r--r--doc/classes/SubViewportContainer.xml9
-rw-r--r--doc/classes/Window.xml19
-rw-r--r--editor/animation_track_editor.cpp16
-rw-r--r--editor/animation_track_editor.h2
-rw-r--r--editor/export/editor_export_platform.cpp24
-rw-r--r--editor/filesystem_dock.cpp71
-rw-r--r--editor/filesystem_dock.h10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp43
-rw-r--r--editor/plugins/path_3d_editor_plugin.h9
-rw-r--r--editor/scene_tree_dock.cpp26
-rw-r--r--modules/gdscript/tests/scripts/utils.notest.gd84
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp10
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp6
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.h3
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp4
-rw-r--r--platform/macos/display_server_macos.h1
-rw-r--r--platform/macos/display_server_macos.mm53
-rw-r--r--platform/macos/export/export_plugin.cpp6
-rw-r--r--platform/windows/display_server_windows.cpp52
-rw-r--r--platform/windows/display_server_windows.h3
-rw-r--r--platform/windows/platform_windows_builders.py16
-rw-r--r--scene/2d/node_2d.cpp5
-rw-r--r--scene/3d/node_3d.cpp11
-rw-r--r--scene/gui/code_edit.cpp45
-rw-r--r--scene/gui/code_edit.h1
-rw-r--r--scene/gui/dialogs.cpp1
-rw-r--r--scene/gui/subviewport_container.cpp16
-rw-r--r--scene/gui/subviewport_container.h2
-rw-r--r--scene/main/canvas_item.cpp11
-rw-r--r--scene/main/window.cpp70
-rw-r--r--scene/main/window.h5
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/rendering/shader_compiler.cpp26
-rw-r--r--servers/rendering/shader_language.cpp103
-rw-r--r--servers/rendering/shader_language.h3
-rw-r--r--tests/scene/test_code_edit.h61
42 files changed, 606 insertions, 262 deletions
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index d80bc473e5..6f334d1859 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -875,6 +875,11 @@ String VariantUtilityFunctions::error_string(Error error) {
return String(error_names[error]);
}
+String VariantUtilityFunctions::type_string(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V_MSG((int)p_type, (int)Variant::VARIANT_MAX, "<invalid type>", "Invalid type argument to type_string(), use the TYPE_* constants.");
+ return Variant::get_type_name(p_type);
+}
+
void VariantUtilityFunctions::print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
String s;
for (int i = 0; i < p_arg_count; i++) {
@@ -1713,6 +1718,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(type_convert, sarray("variant", "type"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(error_string, sarray("error"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(type_string, sarray("type"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(print_rich, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h
index 8130f30881..a56c84a8e9 100644
--- a/core/variant/variant_utility.h
+++ b/core/variant/variant_utility.h
@@ -130,6 +130,7 @@ struct VariantUtilityFunctions {
static Variant type_convert(const Variant &p_variant, const Variant::Type p_type);
static String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
static String error_string(Error error);
+ static String type_string(Variant::Type p_type);
static void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
static void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
#undef print_verbose
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index a077900a9c..e84ed82241 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1403,6 +1403,19 @@
[/codeblock]
</description>
</method>
+ <method name="type_string">
+ <return type="String" />
+ <param index="0" name="type" type="int" />
+ <description>
+ Returns a human-readable name of the given [param type], using the [enum Variant.Type] values.
+ [codeblock]
+ print(TYPE_INT) # Prints 2.
+ print(type_string(TYPE_INT)) # Prints "int".
+ print(type_string(TYPE_STRING)) # Prints "String".
+ [/codeblock]
+ See also [method typeof].
+ </description>
+ </method>
<method name="typeof">
<return type="int" />
<param index="0" name="variable" type="Variant" />
@@ -1417,6 +1430,7 @@
else:
print("Unexpected result")
[/codeblock]
+ See also [method type_string].
</description>
</method>
<method name="var_to_bytes">
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index 202a84fb58..59cbb38036 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -72,6 +72,7 @@
The text displayed by the dialog.
</member>
<member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" overrides="Window" default="true" />
+ <member name="keep_title_visible" type="bool" setter="set_keep_title_visible" getter="get_keep_title_visible" overrides="Window" default="true" />
<member name="ok_button_text" type="String" setter="set_ok_button_text" getter="get_ok_button_text" default="&quot;OK&quot;">
The text displayed by the OK button (see [method get_ok_button]).
</member>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 6cb049e0e4..7bbfd8077a 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1291,6 +1291,15 @@
Returns the size of the window specified by [param window_id] (in pixels), including the borders drawn by the operating system. See also [method window_get_size].
</description>
</method>
+ <method name="window_get_title_size" qualifiers="const">
+ <return type="Vector2i" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="window_id" type="int" default="0" />
+ <description>
+ Returns the estimated window title bar size (including text and window buttons) for the window specified by [param window_id] (in pixels). This method does not change the window title.
+ [b]Note:[/b] This method is implemented on macOS and Windows.
+ </description>
+ </method>
<method name="window_get_vsync_mode" qualifiers="const">
<return type="int" enum="DisplayServer.VSyncMode" />
<param index="0" name="window_id" type="int" default="0" />
@@ -1787,14 +1796,16 @@
</constant>
<constant name="WINDOW_MODE_FULLSCREEN" value="3" enum="WindowMode">
Full screen mode with full multi-window support.
- Full screen window cover the entire display area of a screen, have no border or decorations. Display video mode is not changed.
+ Full screen window covers the entire display area of a screen and has no decorations. The display's video mode is not changed.
+ [b]On Windows:[/b] Multi-window full-screen mode has a 1px border of the [member ProjectSettings.rendering/environment/defaults/default_clear_color] color.
+ [b]On macOS:[/b] A new desktop is used to display the running project.
[b]Note:[/b] Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
</constant>
<constant name="WINDOW_MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="WindowMode">
A single window full screen mode. This mode has less overhead, but only one window can be open on a given screen at a time (opening a child window or application switching will trigger a full screen transition).
- Full screen window cover the entire display area of a screen, have no border or decorations. Display video mode is not changed.
+ Full screen window covers the entire display area of a screen and has no border or decorations. The display's video mode is not changed.
[b]On Windows:[/b] Depending on video driver, full screen transition might cause screens to go black for a moment.
- [b]On macOS:[/b] Exclusive full screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
+ [b]On macOS:[/b] A new desktop is used to display the running project. Exclusive full screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
[b]On Linux (X11):[/b] Exclusive full screen mode bypasses compositor.
[b]Note:[/b] Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
</constant>
diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml
index 08e7ca23f7..e7d7883c78 100644
--- a/doc/classes/SubViewportContainer.xml
+++ b/doc/classes/SubViewportContainer.xml
@@ -10,6 +10,15 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="_propagate_input_event" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="event" type="InputEvent" />
+ <description>
+ Virtual method to be implemented by the user. If it returns [code]true[/code], the [param event] is propagated to [SubViewport] children. Propagation doesn't happen if it returns [code]false[/code]. If the function is not implemented, all events are propagated to SubViewports.
+ </description>
+ </method>
+ </methods>
<members>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="1" />
<member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index b03ef3ab4e..5f6b1960b7 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -593,6 +593,9 @@
<member name="initial_position" type="int" setter="set_initial_position" getter="get_initial_position" enum="Window.WindowInitialPosition" default="0">
Specifies the initial type of position for the [Window]. See [enum WindowInitialPosition] constants.
</member>
+ <member name="keep_title_visible" type="bool" setter="set_keep_title_visible" getter="get_keep_title_visible" default="false">
+ If [code]true[/code], the [Window] width is expanded to keep the title bar text fully visible.
+ </member>
<member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i(0, 0)">
If non-zero, the [Window] can't be resized to be bigger than this size.
[b]Note:[/b] This property will be ignored if the value is lower than [member min_size].
@@ -785,13 +788,19 @@
Maximized window mode, i.e. [Window] will occupy whole screen area except task bar and still display its borders. Normally happens when the maximize button is pressed.
</constant>
<constant name="MODE_FULLSCREEN" value="3" enum="Mode">
- Full screen window mode. Note that this is not [i]exclusive[/i] full screen. On Windows and Linux, a borderless window is used to emulate full screen. On macOS, a new desktop is used to display the running project.
- Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
+ Full screen mode with full multi-window support.
+ Full screen window covers the entire display area of a screen and has no decorations. The display's video mode is not changed.
+ [b]On Windows:[/b] Multi-window full-screen mode has a 1px border of the [member ProjectSettings.rendering/environment/defaults/default_clear_color] color.
+ [b]On macOS:[/b] A new desktop is used to display the running project.
+ [b]Note:[/b] Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
</constant>
<constant name="MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="Mode">
- Exclusive full screen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant MODE_FULLSCREEN].
- Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
- Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
+ A single window full screen mode. This mode has less overhead, but only one window can be open on a given screen at a time (opening a child window or application switching will trigger a full screen transition).
+ Full screen window covers the entire display area of a screen and has no border or decorations. The display's video mode is not changed.
+ [b]On Windows:[/b] Depending on video driver, full screen transition might cause screens to go black for a moment.
+ [b]On macOS:[/b] A new desktop is used to display the running project. Exclusive full screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
+ [b]On Linux (X11):[/b] Exclusive full screen mode bypasses compositor.
+ [b]Note:[/b] Regardless of the platform, enabling full screen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling full screen mode.
</constant>
<constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags">
The window can't be resized by dragging its resize grip. It's still possible to resize the window using [member size]. This flag is ignored for full screen windows. Set with [member unresizable].
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 7105ff280a..e2852d5a31 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -3249,6 +3249,22 @@ void AnimationTrackEditGroup::_notification(int p_what) {
}
}
+void AnimationTrackEditGroup::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ Point2 pos = mb->get_position();
+ Rect2 node_name_rect = Rect2(0, 0, timeline->get_name_limit(), get_size().height);
+
+ if (node_name_rect.has_point(pos)) {
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ editor_selection->clear();
+ editor_selection->add_node(root->get_node(node));
+ }
+ }
+}
+
void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, const String &p_name, const NodePath &p_node) {
icon = p_type;
node_name = p_name;
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 5327099517..5592d43ffe 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -349,6 +349,8 @@ class AnimationTrackEditGroup : public Control {
protected:
void _notification(int p_what);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
public:
void set_type_and_name(const Ref<Texture2D> &p_type, const String &p_name, const NodePath &p_node);
virtual Size2 get_minimum_size() const override;
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 6c41e34e51..c492589e63 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -859,16 +859,20 @@ Vector<String> EditorExportPlatform::get_forced_export_files() {
bool use_data = GLOBAL_GET("internationalization/locale/include_text_server_data");
if (use_data) {
// Try using user provided data file.
- String ts_data = "res://" + TS->get_support_data_filename();
- if (FileAccess::exists(ts_data)) {
- files.push_back(ts_data);
- } else {
- // Use default text server data.
- String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data");
- ERR_FAIL_COND_V(!TS->save_support_data(icu_data_file), files);
- files.push_back(icu_data_file);
- // Remove the file later.
- MessageQueue::get_singleton()->push_callable(callable_mp_static(DirAccess::remove_absolute), icu_data_file);
+ if (!TS->get_support_data_filename().is_empty()) {
+ String ts_data = "res://" + TS->get_support_data_filename();
+ if (FileAccess::exists(ts_data)) {
+ files.push_back(ts_data);
+ } else {
+ // Use default text server data.
+ String abs_path = ProjectSettings::get_singleton()->globalize_path(ts_data);
+ ERR_FAIL_COND_V(!TS->save_support_data(abs_path), files);
+ if (FileAccess::exists(abs_path)) {
+ files.push_back(ts_data);
+ // Remove the file later.
+ MessageQueue::get_singleton()->push_callable(callable_mp_static(DirAccess::remove_absolute), abs_path);
+ }
+ }
}
}
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 36f712dde8..be06a3932c 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -216,7 +216,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_icon(0, get_editor_theme_icon(SNAME("Folder")));
subdirectory_item->set_selectable(0, true);
subdirectory_item->set_metadata(0, lpath);
- if (!p_select_in_favorites && (current_path == lpath || ((display_mode == DISPLAY_MODE_SPLIT) && current_path.get_base_dir() == lpath))) {
+ if (!p_select_in_favorites && (current_path == lpath || ((display_mode != DISPLAY_MODE_TREE_ONLY) && current_path.get_base_dir() == lpath))) {
subdirectory_item->select(0);
// Keep select an item when re-created a tree
// To prevent crashing when nothing is selected.
@@ -302,7 +302,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
udata.push_back(file_item);
EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, this, "_tree_thumbnail_done", udata);
}
- } else if (display_mode == DISPLAY_MODE_SPLIT) {
+ } else {
if (lpath.get_base_dir() == current_path.get_base_dir()) {
subdirectory_item->select(0);
subdirectory_item->set_as_cursor(0);
@@ -455,22 +455,29 @@ void FileSystemDock::set_display_mode(DisplayMode p_display_mode) {
void FileSystemDock::_update_display_mode(bool p_force) {
// Compute the new display mode.
if (p_force || old_display_mode != display_mode) {
- button_toggle_display_mode->set_pressed(display_mode == DISPLAY_MODE_SPLIT);
switch (display_mode) {
case DISPLAY_MODE_TREE_ONLY:
+ button_toggle_display_mode->set_icon(get_editor_theme_icon(SNAME("Panels1")));
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- if (display_mode == DISPLAY_MODE_TREE_ONLY) {
- toolbar2_hbc->show();
- } else {
- toolbar2_hbc->hide();
- }
+ toolbar2_hbc->show();
_update_tree(get_uncollapsed_paths());
file_list_vb->hide();
break;
- case DISPLAY_MODE_SPLIT:
+ case DISPLAY_MODE_HSPLIT:
+ case DISPLAY_MODE_VSPLIT:
+ const bool is_vertical = display_mode == DISPLAY_MODE_VSPLIT;
+ const int split_offset = split_box->get_split_offset();
+ is_vertical ? split_box_offset_h = split_offset : split_box_offset_v = split_offset;
+ split_box->set_vertical(is_vertical);
+
+ const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h;
+ split_box->set_split_offset(actual_offset);
+ const StringName icon = is_vertical ? SNAME("Panels2") : SNAME("Panels2Alt");
+ button_toggle_display_mode->set_icon(get_editor_theme_icon(icon));
+
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
tree->ensure_cursor_is_visible();
@@ -500,7 +507,6 @@ void FileSystemDock::_notification(int p_what) {
EditorResourcePreview::get_singleton()->connect("preview_invalidated", callable_mp(this, &FileSystemDock::_preview_invalidated));
button_reload->set_icon(get_editor_theme_icon(SNAME("Reload")));
- button_toggle_display_mode->set_icon(get_editor_theme_icon(SNAME("Panels2")));
button_file_list_display_mode->connect("pressed", callable_mp(this, &FileSystemDock::_toggle_file_display));
files->connect("item_activated", callable_mp(this, &FileSystemDock::_file_list_activate_file));
@@ -587,7 +593,15 @@ void FileSystemDock::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update icons.
button_reload->set_icon(get_editor_theme_icon(SNAME("Reload")));
- button_toggle_display_mode->set_icon(get_editor_theme_icon(SNAME("Panels2")));
+
+ StringName mode_icon = "Panels1";
+ if (display_mode == DISPLAY_MODE_VSPLIT) {
+ mode_icon = "Panels2";
+ } else if (display_mode == DISPLAY_MODE_HSPLIT) {
+ mode_icon = "Panels2Alt";
+ }
+ button_toggle_display_mode->set_icon(get_editor_theme_icon(mode_icon));
+
if (is_layout_rtl()) {
button_hist_next->set_icon(get_editor_theme_icon(SNAME("Back")));
button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Forward")));
@@ -665,7 +679,7 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
_push_to_history();
// Update the file list.
- if (!updating_tree && display_mode == DISPLAY_MODE_SPLIT) {
+ if (!updating_tree && display_mode != DISPLAY_MODE_TREE_ONLY) {
_update_file_list(false);
}
}
@@ -717,7 +731,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
_push_to_history();
_update_tree(get_uncollapsed_paths(), false, p_select_in_favorites, true);
- if (display_mode == DISPLAY_MODE_SPLIT) {
+ if (display_mode != DISPLAY_MODE_TREE_ONLY) {
_update_file_list(false);
files->get_v_scroll_bar()->set_value(0);
}
@@ -2411,7 +2425,8 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
case DISPLAY_MODE_TREE_ONLY: {
_update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
} break;
- case DISPLAY_MODE_SPLIT: {
+ case DISPLAY_MODE_HSPLIT:
+ case DISPLAY_MODE_VSPLIT: {
_update_file_list(false);
_update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
} break;
@@ -2423,8 +2438,15 @@ void FileSystemDock::_rescan() {
EditorFileSystem::get_singleton()->scan();
}
-void FileSystemDock::_toggle_split_mode(bool p_active) {
- set_display_mode(p_active ? DISPLAY_MODE_SPLIT : DISPLAY_MODE_TREE_ONLY);
+void FileSystemDock::_change_split_mode() {
+ DisplayMode next_mode = DISPLAY_MODE_TREE_ONLY;
+ if (display_mode == DISPLAY_MODE_VSPLIT) {
+ next_mode = DISPLAY_MODE_HSPLIT;
+ } else if (display_mode == DISPLAY_MODE_TREE_ONLY) {
+ next_mode = DISPLAY_MODE_VSPLIT;
+ }
+
+ set_display_mode(next_mode);
emit_signal(SNAME("display_mode_changed"));
}
@@ -2436,7 +2458,7 @@ void FileSystemDock::focus_on_filter() {
LineEdit *current_search_box = nullptr;
if (display_mode == DISPLAY_MODE_TREE_ONLY) {
current_search_box = tree_search_box;
- } else if (display_mode == DISPLAY_MODE_SPLIT) {
+ } else {
current_search_box = file_list_search_box;
}
@@ -2677,7 +2699,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
EditorSettings::get_singleton()->set_favorites(dirs);
_update_tree(get_uncollapsed_paths());
- if (display_mode == DISPLAY_MODE_SPLIT && current_path == "Favorites") {
+ if (display_mode != DISPLAY_MODE_TREE_ONLY && current_path == "Favorites") {
_update_file_list(true);
}
return;
@@ -3152,7 +3174,7 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
String fpath = files->get_item_metadata(current);
if (!fpath.ends_with("/")) {
current_path = fpath;
- if (display_mode == DISPLAY_MODE_SPLIT) {
+ if (display_mode != DISPLAY_MODE_TREE_ONLY) {
_update_tree(get_uncollapsed_paths());
}
}
@@ -3225,7 +3247,7 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
}
item->select(0);
- if (display_mode == DisplayMode::DISPLAY_MODE_SPLIT) {
+ if (display_mode != DisplayMode::DISPLAY_MODE_TREE_ONLY) {
files->deselect_all();
// Try to select the corresponding file list item.
const int files_item_idx = files->find_metadata(fpath);
@@ -3559,10 +3581,9 @@ FileSystemDock::FileSystemDock() {
toolbar_hbc->add_child(button_reload);
button_toggle_display_mode = memnew(Button);
- button_toggle_display_mode->set_toggle_mode(true);
- button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode));
+ button_toggle_display_mode->connect("pressed", callable_mp(this, &FileSystemDock::_change_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
- button_toggle_display_mode->set_tooltip_text(TTR("Toggle Split Mode"));
+ button_toggle_display_mode->set_tooltip_text(TTR("Change Split Mode"));
button_toggle_display_mode->set_flat(true);
toolbar_hbc->add_child(button_toggle_display_mode);
@@ -3587,7 +3608,7 @@ FileSystemDock::FileSystemDock() {
add_child(tree_popup);
- split_box = memnew(VSplitContainer);
+ split_box = memnew(SplitContainer);
split_box->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(split_box);
@@ -3597,7 +3618,7 @@ FileSystemDock::FileSystemDock() {
SET_DRAG_FORWARDING_GCD(tree, FileSystemDock);
tree->set_allow_rmb_select(true);
tree->set_select_mode(Tree::SELECT_MULTI);
- tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
+ tree->set_custom_minimum_size(Size2(40 * EDSCALE, 15 * EDSCALE));
tree->set_column_clip_content(0, true);
split_box->add_child(tree);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 818b91bdb9..1e04b6a4ff 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -88,7 +88,8 @@ public:
enum DisplayMode {
DISPLAY_MODE_TREE_ONLY,
- DISPLAY_MODE_SPLIT,
+ DISPLAY_MODE_VSPLIT,
+ DISPLAY_MODE_HSPLIT,
};
enum FileSortOption {
@@ -144,9 +145,12 @@ private:
VBoxContainer *scanning_vb = nullptr;
ProgressBar *scanning_progress = nullptr;
- VSplitContainer *split_box = nullptr;
+ SplitContainer *split_box = nullptr;
VBoxContainer *file_list_vb = nullptr;
+ int split_box_offset_h = 0;
+ int split_box_offset_v = 0;
+
HashSet<String> favorites;
Button *button_toggle_display_mode = nullptr;
@@ -299,7 +303,7 @@ private:
void _set_scanning_mode();
void _rescan();
- void _toggle_split_mode(bool p_active);
+ void _change_split_mode();
void _search_changed(const String &p_text, const Control *p_from);
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 4185460126..9d66e606b0 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -274,6 +274,7 @@ void Path3DGizmo::redraw() {
Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this);
Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this);
+ Ref<StandardMaterial3D> path_tilt_material = gizmo_plugin->get_material("path_tilt_material", this);
Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles");
Ref<StandardMaterial3D> sec_handles_material = gizmo_plugin->get_material("sec_handles");
@@ -339,6 +340,7 @@ void Path3DGizmo::redraw() {
// 2. Draw handles when selected.
if (Path3DEditorPlugin::singleton->get_edited_path() == path) {
PackedVector3Array handle_lines;
+ PackedVector3Array tilt_handle_lines;
PackedVector3Array primary_handle_points;
PackedVector3Array secondary_handle_points;
PackedInt32Array collected_secondary_handle_ids; // Avoid shadowing member on Node3DEditorGizmo.
@@ -367,7 +369,7 @@ void Path3DGizmo::redraw() {
}
// Collect out-handles except for the last point.
- if (idx < c->get_point_count()) {
+ if (idx < c->get_point_count() - 1) {
info.type = HandleType::HANDLE_TYPE_OUT;
const int handle_idx = idx * 3 + 1;
collected_secondary_handle_ids.append(handle_idx);
@@ -389,9 +391,9 @@ void Path3DGizmo::redraw() {
const Basis posture = c->get_point_baked_posture(idx, true);
const Vector3 up = posture.get_column(1);
- secondary_handle_points.append(pos + up);
- handle_lines.append(pos);
- handle_lines.append(pos + up);
+ secondary_handle_points.append(pos + up * disk_size);
+ tilt_handle_lines.append(pos);
+ tilt_handle_lines.append(pos + up * disk_size);
}
// Tilt disk.
@@ -403,13 +405,13 @@ void Path3DGizmo::redraw() {
PackedVector3Array disk;
disk.append(pos);
- const int n = 24;
+ const int n = 36;
for (int i = 0; i <= n; i++) {
const float a = Math_TAU * i / n;
const Vector3 edge = sin(a) * side + cos(a) * up;
- disk.append(pos + edge);
+ disk.append(pos + edge * disk_size);
}
- add_vertices(disk, path_material, Mesh::PRIMITIVE_LINE_STRIP);
+ add_vertices(disk, path_tilt_material, Mesh::PRIMITIVE_LINE_STRIP);
}
}
}
@@ -417,6 +419,11 @@ void Path3DGizmo::redraw() {
if (handle_lines.size() > 1) {
add_lines(handle_lines, path_thin_material);
}
+
+ if (tilt_handle_lines.size() > 1) {
+ add_lines(tilt_handle_lines, path_tilt_material);
+ }
+
if (primary_handle_points.size()) {
add_handles(primary_handle_points, handles_material);
}
@@ -426,8 +433,9 @@ void Path3DGizmo::redraw() {
}
}
-Path3DGizmo::Path3DGizmo(Path3D *p_path) {
+Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
path = p_path;
+ disk_size = p_disk_size;
set_node_3d(p_path);
orig_in_length = 0;
orig_out_length = 0;
@@ -555,7 +563,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos);
real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos);
real_t dist_to_p_in = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_in(i))).distance_to(mbpos);
- real_t dist_to_p_up = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_baked_posture(i, true).get_column(1))).distance_to(mbpos);
+ real_t dist_to_p_up = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_baked_posture(i, true).get_column(1) * disk_size)).distance_to(mbpos);
// Find the offset and point index of the place to break up.
// Also check for the control points.
@@ -721,8 +729,9 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
mirror_handle_angle = true;
mirror_handle_length = true;
- Ref<Path3DGizmoPlugin> gizmo_plugin;
- gizmo_plugin.instantiate();
+ disk_size = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8);
+
+ Ref<Path3DGizmoPlugin> gizmo_plugin = memnew(Path3DGizmoPlugin(disk_size));
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
topmenu_bar = memnew(HBoxContainer);
@@ -789,7 +798,7 @@ Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
Path3D *path = Object::cast_to<Path3D>(p_spatial);
if (path) {
- ref = Ref<Path3DGizmo>(memnew(Path3DGizmo(path)));
+ ref = Ref<Path3DGizmo>(memnew(Path3DGizmo(path, disk_size)));
}
return ref;
@@ -803,10 +812,14 @@ int Path3DGizmoPlugin::get_priority() const {
return -1;
}
-Path3DGizmoPlugin::Path3DGizmoPlugin() {
- Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
+Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) {
+ Color path_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.9));
+ Color path_tilt_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/path_tilt", Color(1.0, 1.0, 0.4, 0.9));
+ disk_size = p_disk_size;
+
create_material("path_material", path_color);
- create_material("path_thin_material", Color(0.5, 0.5, 0.5));
+ create_material("path_thin_material", Color(0.6, 0.6, 0.6));
+ create_material("path_tilt_material", path_tilt_color);
create_handle_material("handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("sec_handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorCurveHandle"), EditorStringName(EditorIcons)));
}
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 871e6a1563..5a5f76b015 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -58,6 +58,7 @@ class Path3DGizmo : public EditorNode3DGizmo {
mutable Vector3 original;
mutable float orig_in_length;
mutable float orig_out_length;
+ mutable float disk_size = 0.8;
// Cache information of secondary handles.
Vector<HandleInfo> _secondary_handles_info;
@@ -69,19 +70,21 @@ public:
virtual void commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
virtual void redraw() override;
- Path3DGizmo(Path3D *p_path = nullptr);
+ Path3DGizmo(Path3D *p_path = nullptr, float p_disk_size = 0.8);
};
class Path3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Path3DGizmoPlugin, EditorNode3DGizmoPlugin);
+ float disk_size = 0.8;
+
protected:
Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial) override;
public:
String get_gizmo_name() const override;
int get_priority() const override;
- Path3DGizmoPlugin();
+ Path3DGizmoPlugin(float p_disk_size);
};
class Path3DEditorPlugin : public EditorPlugin {
@@ -95,6 +98,8 @@ class Path3DEditorPlugin : public EditorPlugin {
Button *curve_close = nullptr;
MenuButton *handle_menu = nullptr;
+ float disk_size = 0.8;
+
enum Mode {
MODE_CREATE,
MODE_EDIT,
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a83dedad6d..e7727aec4b 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1683,6 +1683,32 @@ bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_var
}
} break;
+ case Variant::OBJECT: {
+ Resource *resource = Object::cast_to<Resource>(r_variant);
+ if (!resource) {
+ break;
+ }
+
+ List<PropertyInfo> properties;
+ resource->get_property_list(&properties);
+
+ for (const PropertyInfo &E : properties) {
+ if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
+ continue;
+ }
+ String propertyname = E.name;
+ Variant old_variant = resource->get(propertyname);
+ Variant updated_variant = old_variant;
+ if (_check_node_path_recursive(p_root_node, updated_variant, p_renames)) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->add_do_property(resource, propertyname, updated_variant);
+ undo_redo->add_undo_property(resource, propertyname, old_variant);
+ resource->set(propertyname, updated_variant);
+ }
+ }
+ break;
+ };
+
default: {
}
}
diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd
index fb20817117..781843b8e2 100644
--- a/modules/gdscript/tests/scripts/utils.notest.gd
+++ b/modules/gdscript/tests/scripts/utils.notest.gd
@@ -17,7 +17,7 @@ static func get_type(property: Dictionary, is_return: bool = false) -> String:
TYPE_OBJECT:
if not str(property.class_name).is_empty():
return property.class_name
- return variant_get_type_name(property.type)
+ return type_string(property.type)
static func get_property_signature(property: Dictionary, is_static: bool = false) -> String:
@@ -66,88 +66,6 @@ static func get_method_signature(method: Dictionary, is_signal: bool = false) ->
return result
-static func variant_get_type_name(type: Variant.Type) -> String:
- match type:
- TYPE_NIL:
- return "Nil" # `Nil` in core, `null` in GDScript.
- TYPE_BOOL:
- return "bool"
- TYPE_INT:
- return "int"
- TYPE_FLOAT:
- return "float"
- TYPE_STRING:
- return "String"
- TYPE_VECTOR2:
- return "Vector2"
- TYPE_VECTOR2I:
- return "Vector2i"
- TYPE_RECT2:
- return "Rect2"
- TYPE_RECT2I:
- return "Rect2i"
- TYPE_VECTOR3:
- return "Vector3"
- TYPE_VECTOR3I:
- return "Vector3i"
- TYPE_TRANSFORM2D:
- return "Transform2D"
- TYPE_VECTOR4:
- return "Vector4"
- TYPE_VECTOR4I:
- return "Vector4i"
- TYPE_PLANE:
- return "Plane"
- TYPE_QUATERNION:
- return "Quaternion"
- TYPE_AABB:
- return "AABB"
- TYPE_BASIS:
- return "Basis"
- TYPE_TRANSFORM3D:
- return "Transform3D"
- TYPE_PROJECTION:
- return "Projection"
- TYPE_COLOR:
- return "Color"
- TYPE_STRING_NAME:
- return "StringName"
- TYPE_NODE_PATH:
- return "NodePath"
- TYPE_RID:
- return "RID"
- TYPE_OBJECT:
- return "Object"
- TYPE_CALLABLE:
- return "Callable"
- TYPE_SIGNAL:
- return "Signal"
- TYPE_DICTIONARY:
- return "Dictionary"
- TYPE_ARRAY:
- return "Array"
- TYPE_PACKED_BYTE_ARRAY:
- return "PackedByteArray"
- TYPE_PACKED_INT32_ARRAY:
- return "PackedInt32Array"
- TYPE_PACKED_INT64_ARRAY:
- return "PackedInt64Array"
- TYPE_PACKED_FLOAT32_ARRAY:
- return "PackedFloat32Array"
- TYPE_PACKED_FLOAT64_ARRAY:
- return "PackedFloat64Array"
- TYPE_PACKED_STRING_ARRAY:
- return "PackedStringArray"
- TYPE_PACKED_VECTOR2_ARRAY:
- return "PackedVector2Array"
- TYPE_PACKED_VECTOR3_ARRAY:
- return "PackedVector3Array"
- TYPE_PACKED_COLOR_ARRAY:
- return "PackedColorArray"
- push_error("Argument `type` is invalid. Use `TYPE_*` constants.")
- return "<invalid type>"
-
-
static func get_property_hint_name(hint: PropertyHint) -> String:
match hint:
PROPERTY_HINT_NONE:
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index b86a8b3cb1..467bedc4b2 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -223,6 +223,16 @@ void test(TestType p_type) {
// Initialize the language for the test routine.
init_language(fa->get_path_absolute().get_base_dir());
+ // Load global classes.
+ TypedArray<Dictionary> script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
+ continue;
+ }
+ ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"]);
+ }
+
Vector<uint8_t> buf;
uint64_t flen = fa->get_length();
buf.resize(flen + 1);
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index 91c14e0e91..e9f55faf7f 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -266,7 +266,7 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it
return true;
}
-Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
if (unsupported) {
return FAILED;
}
@@ -277,6 +277,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(const String &p_xid, const Stri
// Open connection and add signal handler.
FileDialogData fd;
fd.callback = p_callback;
+ fd.prev_focus = p_window_id;
CryptoCore::RandomGenerator rng;
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
@@ -416,6 +417,9 @@ void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) {
Variant *v_args[2] = { &v_status, &v_files };
fd.callback.call_deferredp((const Variant **)&v_args, 2);
}
+ if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus);
+ }
}
dbus_message_unref(msg);
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h
index a9b83b3844..6ffb3e7b04 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.h
+++ b/platform/linuxbsd/freedesktop_portal_desktop.h
@@ -56,6 +56,7 @@ private:
struct FileDialogData {
DBusConnection *connection = nullptr;
+ DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID;
Callable callback;
String path;
};
@@ -73,7 +74,7 @@ public:
bool is_supported() { return !unsupported; }
- Error file_dialog_show(const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);
+ Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);
// Retrieve the system's preferred color scheme.
// 0: No preference or unknown.
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 897a6438d2..678ec340c0 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -364,14 +364,14 @@ bool DisplayServerX11::is_dark_mode() const {
}
Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
- WindowID window_id = _get_focused_window_or_popup();
+ WindowID window_id = last_focused_window;
if (!windows.has(window_id)) {
window_id = MAIN_WINDOW_ID;
}
String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
- return portal_desktop->file_dialog_show(xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback);
+ return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback);
}
#endif
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index c03b4765f8..d89511927e 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -368,6 +368,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Size2i window_get_title_size(const String &p_title, WindowID p_window) const override;
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override;
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 56cb4938ec..f984fd9dc5 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -1887,6 +1887,8 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
}
}
+ WindowID prev_focus = last_focused_window;
+
Callable callback = p_callback; // Make a copy for async completion handler.
switch (p_mode) {
case FILE_DIALOG_MODE_SAVE_FILE: {
@@ -1954,6 +1956,9 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
callback.callp((const Variant **)&v_args, 2, ret, ce);
}
}
+ if (prev_focus != INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
+ }
}];
} break;
case FILE_DIALOG_MODE_OPEN_ANY:
@@ -2033,6 +2038,9 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
callback.callp((const Variant **)&v_args, 2, ret, ce);
}
}
+ if (prev_focus != INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
+ }
}];
} break;
}
@@ -2626,6 +2634,47 @@ void DisplayServerMacOS::window_set_title(const String &p_title, WindowID p_wind
[wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
}
+Size2i DisplayServerMacOS::window_get_title_size(const String &p_title, WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ Size2i size;
+ ERR_FAIL_COND_V(!windows.has(p_window), size);
+
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen || wd.borderless) {
+ return size;
+ }
+ if ([wd.window_object respondsToSelector:@selector(isMiniaturized)]) {
+ if ([wd.window_object isMiniaturized]) {
+ return size;
+ }
+ }
+
+ float scale = screen_get_max_scale();
+
+ if (wd.window_button_view) {
+ size.x = ([wd.window_button_view getOffset].x + [wd.window_button_view frame].size.width);
+ size.y = ([wd.window_button_view getOffset].y + [wd.window_button_view frame].size.height);
+ } else {
+ NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton];
+ NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton];
+ float cb_frame = NSMinX([cb frame]);
+ float mb_frame = NSMinX([mb frame]);
+ bool is_rtl = ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft);
+
+ float window_buttons_spacing = (is_rtl) ? (cb_frame - mb_frame) : (mb_frame - cb_frame);
+ size.x = window_buttons_spacing * 4;
+ size.y = [cb frame].origin.y + [cb frame].size.height;
+ }
+
+ NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont titleBarFontOfSize:0], NSFontAttributeName, nil];
+ NSSize text_size = [[[NSAttributedString alloc] initWithString:[NSString stringWithUTF8String:p_title.utf8().get_data()] attributes:attributes] size];
+ size.x += text_size.width;
+ size.y = MAX(size.y, text_size.height);
+
+ return size * scale;
+}
+
void DisplayServerMacOS::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -3176,7 +3225,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
} break;
case WINDOW_FLAG_BORDERLESS: {
// OrderOut prevents a lose focus bug with the window.
+ bool was_visible = false;
if ([wd.window_object isVisible]) {
+ was_visible = true;
[wd.window_object orderOut:nil];
}
wd.borderless = p_enabled;
@@ -3191,7 +3242,7 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
[wd.window_object setFrame:frameRect display:NO];
}
_update_window_style(wd);
- if ([wd.window_object isVisible]) {
+ if (was_visible || [wd.window_object isVisible]) {
if ([wd.window_object isMiniaturized]) {
return;
} else if (wd.no_focus) {
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 639a7699ee..804028053d 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -1047,6 +1047,8 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
args.push_back("--p12-password");
args.push_back(certificate_pass);
}
+ args.push_back("--code-signature-flags");
+ args.push_back("runtime");
args.push_back("-v"); /* provide some more feedback */
@@ -1139,7 +1141,6 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
const String &p_ent_path, bool p_should_error_on_non_code) {
-#ifdef MACOS_ENABLED
static Vector<String> extensions_to_sign;
if (extensions_to_sign.is_empty()) {
@@ -1186,7 +1187,6 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
current_file = dir_access->get_next();
}
-#endif
return OK;
}
@@ -1225,7 +1225,7 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
}
- if (is_executable(p_in_app_path)) {
+ if (dir_access->file_exists(p_in_app_path) && is_executable(p_in_app_path)) {
// chmod with 0755 if the file is executable.
FileAccess::set_unix_permissions(p_in_app_path, 0755);
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index c7b7f6a65d..ed52c5eb92 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -240,6 +240,8 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
filters.push_back({ (LPCWSTR)filter_names[i].ptr(), (LPCWSTR)filter_exts[i].ptr() });
}
+ WindowID prev_focus = last_focused_window;
+
HRESULT hr = S_OK;
IFileDialog *pfd = nullptr;
if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) {
@@ -340,6 +342,9 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
}
}
pfd->Release();
+ if (prev_focus != INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
+ }
return OK;
} else {
@@ -1191,6 +1196,51 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
}
+Size2i DisplayServerWindows::window_get_title_size(const String &p_title, WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ Size2i size;
+ ERR_FAIL_COND_V(!windows.has(p_window), size);
+
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen || wd.minimized || wd.borderless) {
+ return size;
+ }
+
+ HDC hdc = GetDCEx(wd.hWnd, NULL, DCX_WINDOW);
+ if (hdc) {
+ Char16String s = p_title.utf16();
+ SIZE text_size;
+ if (GetTextExtentPoint32W(hdc, (LPCWSTR)(s.get_data()), s.length(), &text_size)) {
+ size.x = text_size.cx;
+ size.y = text_size.cy;
+ }
+
+ ReleaseDC(wd.hWnd, hdc);
+ }
+ RECT rect;
+ if (DwmGetWindowAttribute(wd.hWnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rect, sizeof(RECT)) == S_OK) {
+ if (rect.right - rect.left > 0) {
+ ClientToScreen(wd.hWnd, (POINT *)&rect.left);
+ ClientToScreen(wd.hWnd, (POINT *)&rect.right);
+
+ if (win81p_PhysicalToLogicalPointForPerMonitorDPI) {
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.left);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.right);
+ }
+
+ size.x += (rect.right - rect.left);
+ size.y = MAX(size.y, rect.bottom - rect.top);
+ }
+ }
+ if (icon.is_valid()) {
+ size.x += 32;
+ } else {
+ size.x += 16;
+ }
+ return size;
+}
+
void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -4385,6 +4435,7 @@ bool DisplayServerWindows::winink_available = false;
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr;
+PhysicalToLogicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_PhysicalToLogicalPointForPerMonitorDPI = nullptr;
typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_DPI_UNAWARE = 0,
@@ -4522,6 +4573,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
win81p_LogicalToPhysicalPointForPerMonitorDPI = (LogicalToPhysicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "LogicalToPhysicalPointForPerMonitorDPI");
+ win81p_PhysicalToLogicalPointForPerMonitorDPI = (PhysicalToLogicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "PhysicalToLogicalPointForPerMonitorDPI");
winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 28f2f7e6ff..48c8c20280 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -262,6 +262,7 @@ typedef struct tagPOINTER_PEN_INFO {
typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
typedef BOOL(WINAPI *LogicalToPhysicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint);
+typedef BOOL(WINAPI *PhysicalToLogicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint);
typedef struct {
BYTE bWidth; // Width, in pixels, of the image
@@ -309,6 +310,7 @@ class DisplayServerWindows : public DisplayServer {
// DPI conversion API
static LogicalToPhysicalPointForPerMonitorDPIPtr win81p_LogicalToPhysicalPointForPerMonitorDPI;
+ static PhysicalToLogicalPointForPerMonitorDPIPtr win81p_PhysicalToLogicalPointForPerMonitorDPI;
void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver);
String tablet_driver;
@@ -569,6 +571,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Size2i window_get_title_size(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) const override;
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override;
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index b522a75a9c..51652fa814 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -5,14 +5,24 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
import os
from detect import get_mingw_bin_prefix
+from detect import try_cmd
from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
- os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
- os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ else:
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ else:
+ os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ else:
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
if __name__ == "__main__":
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 3ba81dba88..0a5f696992 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -424,14 +424,17 @@ Point2 Node2D::to_global(Point2 p_local) const {
}
void Node2D::_notification(int p_notification) {
- ERR_THREAD_GUARD;
switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
+ ERR_MAIN_THREAD_GUARD;
+
if (get_viewport()) {
get_parent()->connect(SNAME("child_order_changed"), callable_mp(get_viewport(), &Viewport::gui_set_root_order_dirty), CONNECT_REFERENCE_COUNTED);
}
} break;
case NOTIFICATION_EXIT_TREE: {
+ ERR_MAIN_THREAD_GUARD;
+
if (get_viewport()) {
get_parent()->disconnect(SNAME("child_order_changed"), callable_mp(get_viewport(), &Viewport::gui_set_root_order_dirty));
}
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 07d84eebde..cb8279d534 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -131,10 +131,9 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
}
void Node3D::_notification(int p_what) {
- ERR_THREAD_GUARD;
-
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ ERR_MAIN_THREAD_GUARD;
ERR_FAIL_NULL(get_tree());
Node *p = get_parent();
@@ -163,6 +162,8 @@ void Node3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
+ ERR_MAIN_THREAD_GUARD;
+
notification(NOTIFICATION_EXIT_WORLD, true);
if (xform_change.in_list()) {
get_tree()->xform_change_list.remove(&xform_change);
@@ -176,6 +177,8 @@ void Node3D::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_WORLD: {
+ ERR_MAIN_THREAD_GUARD;
+
data.inside_world = true;
data.viewport = nullptr;
Node *parent = get_parent();
@@ -198,6 +201,8 @@ void Node3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_WORLD: {
+ ERR_MAIN_THREAD_GUARD;
+
#ifdef TOOLS_ENABLED
clear_gizmos();
#endif
@@ -211,6 +216,8 @@ void Node3D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
+ ERR_THREAD_GUARD;
+
#ifdef TOOLS_ENABLED
for (int i = 0; i < data.gizmos.size(); i++) {
data.gizmos.write[i]->transform();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index e7a2a26a29..20fcf9cba7 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -3223,7 +3223,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
int line_height = get_line_height();
if (GDVIRTUAL_IS_OVERRIDDEN(_filter_code_completion_candidates)) {
- code_completion_options.clear();
+ Vector<ScriptLanguage::CodeCompletionOption> code_completion_options_new;
code_completion_base = "";
/* Build options argument. */
@@ -3273,11 +3273,15 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
- code_completion_options.push_back(option);
+ code_completion_options_new.push_back(option);
}
+ if (_should_reset_selected_option_for_new_options(code_completion_options_new)) {
+ code_completion_current_selected = 0;
+ }
+ code_completion_options = code_completion_options_new;
+
code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
- code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
@@ -3352,7 +3356,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
/* For now handle only traditional quoted strings. */
bool single_quote = in_string != -1 && first_quote_col > 0 && delimiters[in_string].start_key == "'";
- code_completion_options.clear();
+ Vector<ScriptLanguage::CodeCompletionOption> code_completion_options_new;
code_completion_base = string_to_complete;
/* Don't autocomplete setting numerical values. */
@@ -3384,7 +3388,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (string_to_complete.length() == 0) {
option.get_option_characteristics(string_to_complete);
- code_completion_options.push_back(option);
+ code_completion_options_new.push_back(option);
+
if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
@@ -3459,7 +3464,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
}
}
- code_completion_options.push_back(option);
+ code_completion_options_new.push_back(option);
if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
@@ -3467,26 +3472,46 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
}
/* No options to complete, cancel. */
- if (code_completion_options.size() == 0) {
+ if (code_completion_options_new.size() == 0) {
cancel_code_completion();
return;
}
/* A perfect match, stop completion. */
- if (code_completion_options.size() == 1 && string_to_complete == code_completion_options[0].display) {
+ if (code_completion_options_new.size() == 1 && string_to_complete == code_completion_options_new[0].display) {
cancel_code_completion();
return;
}
- code_completion_options.sort_custom<CodeCompletionOptionCompare>();
+ code_completion_options_new.sort_custom<CodeCompletionOptionCompare>();
+ if (_should_reset_selected_option_for_new_options(code_completion_options_new)) {
+ code_completion_current_selected = 0;
+ }
+ code_completion_options = code_completion_options_new;
code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
- code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
}
+// Assumes both the new_options and the code_completion_options are sorted.
+bool CodeEdit::_should_reset_selected_option_for_new_options(const Vector<ScriptLanguage::CodeCompletionOption> &p_new_options) {
+ if (code_completion_current_selected >= p_new_options.size()) {
+ return true;
+ }
+
+ for (int i = 0; i < code_completion_options.size() && i < p_new_options.size(); i++) {
+ if (i > code_completion_current_selected) {
+ return false;
+ }
+ if (code_completion_options[i].display != p_new_options[i].display) {
+ return true;
+ }
+ }
+ return false;
+}
+
void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
_update_delimiter_cache(p_from_line, p_to_line);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 97c435b52d..4b0629d29d 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -222,6 +222,7 @@ private:
void _update_scroll_selected_line(float p_mouse_y);
void _filter_code_completion_candidates_impl();
+ bool _should_reset_selected_option_for_new_options(const Vector<ScriptLanguage::CodeCompletionOption> &p_new_options);
/* Line length guidelines */
TypedArray<int> line_length_guideline_columns;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index aff0ed6f06..957a8f276e 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -405,6 +405,7 @@ AcceptDialog::AcceptDialog() {
set_transient(true);
set_exclusive(true);
set_clamp_to_embedder(true);
+ set_keep_title_visible(true);
bg_panel = memnew(Panel);
add_child(bg_panel, false, INTERNAL_MODE_FRONT);
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 851a94b32f..0d33774e20 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -190,6 +190,13 @@ void SubViewportContainer::_propagate_nonpositional_event(const Ref<InputEvent>
return;
}
+ bool send;
+ if (GDVIRTUAL_CALL(_propagate_input_event, p_event, send)) {
+ if (!send) {
+ return;
+ }
+ }
+
_send_event_to_viewports(p_event);
}
@@ -204,6 +211,13 @@ void SubViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
+ bool send;
+ if (GDVIRTUAL_CALL(_propagate_input_event, p_event, send)) {
+ if (!send) {
+ return;
+ }
+ }
+
if (stretch && shrink > 1) {
Transform2D xform;
xform.scale(Vector2(1, 1) / shrink);
@@ -275,6 +289,8 @@ void SubViewportContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink");
+
+ GDVIRTUAL_BIND(_propagate_input_event, "event");
}
SubViewportContainer::SubViewportContainer() {
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 3c6cd09d66..06420de730 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -50,6 +50,8 @@ protected:
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
+ GDVIRTUAL1RC(bool, _propagate_input_event, Ref<InputEvent>);
+
public:
void set_stretch(bool p_enable);
bool is_stretch_enabled() const;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 06acdd0237..8f38a6f6c8 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -273,10 +273,9 @@ void CanvasItem::_exit_canvas() {
}
void CanvasItem::_notification(int p_what) {
- ERR_MAIN_THREAD_GUARD;
-
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ ERR_MAIN_THREAD_GUARD;
ERR_FAIL_COND(!is_inside_tree());
Node *parent = get_parent();
@@ -336,6 +335,8 @@ void CanvasItem::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
+ ERR_MAIN_THREAD_GUARD;
+
if (xform_change.in_list()) {
get_tree()->xform_change_list.remove(&xform_change);
}
@@ -357,14 +358,20 @@ void CanvasItem::_notification(int p_what) {
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
+ ERR_MAIN_THREAD_GUARD;
+
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
} break;
case NOTIFICATION_WORLD_2D_CHANGED: {
+ ERR_MAIN_THREAD_GUARD;
+
_exit_canvas();
_enter_canvas();
} break;
case NOTIFICATION_PARENTED: {
// The node is not inside the tree during this notification.
+ ERR_MAIN_THREAD_GUARD;
+
_notify_transform();
} break;
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index f5468b29c5..71ec9b29c5 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -270,20 +270,21 @@ void Window::set_title(const String &p_title) {
ERR_MAIN_THREAD_GUARD;
title = p_title;
+ tr_title = atr(p_title);
+#ifdef DEBUG_ENABLED
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+ // Append a suffix to the window title to denote that the project is running
+ // from a debug build (including the editor). Since this results in lower performance,
+ // this should be clearly presented to the user.
+ tr_title = vformat("%s (DEBUG)", tr_title);
+ }
+#endif
if (embedder) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
- String tr_title = atr(p_title);
-#ifdef DEBUG_ENABLED
- if (window_id == DisplayServer::MAIN_WINDOW_ID) {
- // Append a suffix to the window title to denote that the project is running
- // from a debug build (including the editor). Since this results in lower performance,
- // this should be clearly presented to the user.
- tr_title = vformat("%s (DEBUG)", tr_title);
- }
-#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
+ _update_window_size();
}
}
@@ -586,15 +587,6 @@ void Window::_make_window() {
DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id);
- String tr_title = atr(title);
-#ifdef DEBUG_ENABLED
- if (window_id == DisplayServer::MAIN_WINDOW_ID) {
- // Append a suffix to the window title to denote that the project is running
- // from a debug build (including the editor). Since this results in lower performance,
- // this should be clearly presented to the user.
- tr_title = vformat("%s (DEBUG)", tr_title);
- }
-#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
@@ -994,6 +986,12 @@ void Window::_update_window_size() {
}
DisplayServer::get_singleton()->window_set_max_size(max_size_used, window_id);
+
+ if (keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ size_limit = size_limit.max(title_size);
+ }
+
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
DisplayServer::get_singleton()->window_set_size(size, window_id);
}
@@ -1281,17 +1279,19 @@ void Window::_notification(int p_what) {
_invalidate_theme_cache();
_update_theme_item_cache();
- if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
- String tr_title = atr(title);
+ tr_title = atr(title);
#ifdef DEBUG_ENABLED
- if (window_id == DisplayServer::MAIN_WINDOW_ID) {
- // Append a suffix to the window title to denote that the project is running
- // from a debug build (including the editor). Since this results in lower performance,
- // this should be clearly presented to the user.
- tr_title = vformat("%s (DEBUG)", tr_title);
- }
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+ // Append a suffix to the window title to denote that the project is running
+ // from a debug build (including the editor). Since this results in lower performance,
+ // this should be clearly presented to the user.
+ tr_title = vformat("%s (DEBUG)", tr_title);
+ }
#endif
+
+ if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
+ _update_window_size();
}
} break;
@@ -1384,6 +1384,20 @@ Window::ContentScaleStretch Window::get_content_scale_stretch() const {
return content_scale_stretch;
}
+void Window::set_keep_title_visible(bool p_title_visible) {
+ if (keep_title_visible == p_title_visible) {
+ return;
+ }
+ keep_title_visible = p_title_visible;
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ _update_window_size();
+ }
+}
+
+bool Window::get_keep_title_visible() const {
+ return keep_title_visible;
+}
+
void Window::set_content_scale_factor(real_t p_factor) {
ERR_MAIN_THREAD_GUARD;
ERR_FAIL_COND(p_factor <= 0);
@@ -2713,6 +2727,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_content_scale_stretch", "stretch"), &Window::set_content_scale_stretch);
ClassDB::bind_method(D_METHOD("get_content_scale_stretch"), &Window::get_content_scale_stretch);
+ ClassDB::bind_method(D_METHOD("set_keep_title_visible", "title_visible"), &Window::set_keep_title_visible);
+ ClassDB::bind_method(D_METHOD("get_keep_title_visible"), &Window::get_keep_title_visible);
+
ClassDB::bind_method(D_METHOD("set_content_scale_factor", "factor"), &Window::set_content_scale_factor);
ClassDB::bind_method(D_METHOD("get_content_scale_factor"), &Window::get_content_scale_factor);
@@ -2826,6 +2843,7 @@ void Window::_bind_methods() {
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size", PROPERTY_HINT_NONE, "suffix:px"), "set_max_size", "get_max_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_title_visible"), "set_keep_title_visible", "get_keep_title_visible");
ADD_GROUP("Content Scale", "content_scale_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size");
diff --git a/scene/main/window.h b/scene/main/window.h
index db739cc304..8a54b6c7d3 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -111,6 +111,7 @@ private:
bool initialized = false;
String title;
+ String tr_title;
mutable int current_screen = 0;
mutable Vector2i position;
mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
@@ -131,6 +132,7 @@ private:
bool updating_embedded_window = false;
bool clamp_to_embedder = false;
bool unparent_when_invisible = false;
+ bool keep_title_visible = false;
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
@@ -336,6 +338,9 @@ public:
void set_content_scale_stretch(ContentScaleStretch p_stretch);
ContentScaleStretch get_content_scale_stretch() const;
+ void set_keep_title_visible(bool p_title_visible);
+ bool get_keep_title_visible() const;
+
void set_content_scale_factor(real_t p_factor);
real_t get_content_scale_factor() const;
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index f41238b075..c8516a0966 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -696,6 +696,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_get_popup_safe_rect", "window"), &DisplayServer::window_get_popup_safe_rect);
ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_get_title_size", "title", "window_id"), &DisplayServer::window_get_title_size, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_set_mouse_passthrough", "region", "window_id"), &DisplayServer::window_set_mouse_passthrough, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_current_screen", "window_id"), &DisplayServer::window_get_current_screen, DEFVAL(MAIN_WINDOW_ID));
diff --git a/servers/display_server.h b/servers/display_server.h
index 85f9270696..71bfd7b607 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -390,6 +390,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual Size2i window_get_title_size(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) const { return Size2i(); }
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 671134fb06..71f821205e 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -303,8 +303,8 @@ String ShaderCompiler::_get_sampler_name(ShaderLanguage::TextureFilter p_filter,
void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const HashMap<StringName, String> &p_func_code, String &r_to_add, HashSet<StringName> &added) {
int fidx = -1;
- for (int i = 0; i < p_node->functions.size(); i++) {
- if (p_node->functions[i].name == p_for_func) {
+ for (int i = 0; i < p_node->vfunctions.size(); i++) {
+ if (p_node->vfunctions[i].name == p_for_func) {
fidx = i;
break;
}
@@ -314,7 +314,7 @@ void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const Str
Vector<StringName> uses_functions;
- for (const StringName &E : p_node->functions[fidx].uses_function) {
+ for (const StringName &E : p_node->vfunctions[fidx].uses_function) {
uses_functions.push_back(E);
}
uses_functions.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
@@ -328,9 +328,9 @@ void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const Str
SL::FunctionNode *fnode = nullptr;
- for (int i = 0; i < p_node->functions.size(); i++) {
- if (p_node->functions[i].name == uses_functions[k]) {
- fnode = p_node->functions[i].function;
+ for (int i = 0; i < p_node->vfunctions.size(); i++) {
+ if (p_node->vfunctions[i].name == uses_functions[k]) {
+ fnode = p_node->vfunctions[i].function;
break;
}
}
@@ -765,8 +765,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
HashMap<StringName, String> function_code;
//code for functions
- for (int i = 0; i < pnode->functions.size(); i++) {
- SL::FunctionNode *fnode = pnode->functions[i].function;
+ for (int i = 0; i < pnode->vfunctions.size(); i++) {
+ SL::FunctionNode *fnode = pnode->vfunctions[i].function;
function = fnode;
current_func_name = fnode->name;
function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
@@ -777,8 +777,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
HashSet<StringName> added_funcs_per_stage[STAGE_MAX];
- for (int i = 0; i < pnode->functions.size(); i++) {
- SL::FunctionNode *fnode = pnode->functions[i].function;
+ for (int i = 0; i < pnode->vfunctions.size(); i++) {
+ SL::FunctionNode *fnode = pnode->vfunctions[i].function;
function = fnode;
@@ -1150,9 +1150,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
const bool is_internal_func = internal_functions.has(vnode->name);
if (!is_internal_func) {
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == vnode->name) {
- func = shader->functions[i].function;
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (shader->vfunctions[i].name == vnode->name) {
+ func = shader->vfunctions[i].function;
break;
}
}
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 6f3280e6a1..34ffc1e90f 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -1455,17 +1455,17 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return true;
}
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable) {
continue;
}
- if (shader->functions[i].name == p_identifier) {
+ if (shader->vfunctions[i].name == p_identifier) {
if (r_data_type) {
- *r_data_type = shader->functions[i].function->return_type;
+ *r_data_type = shader->vfunctions[i].function->return_type;
}
if (r_array_size) {
- *r_array_size = shader->functions[i].function->return_array_size;
+ *r_array_size = shader->vfunctions[i].function->return_array_size;
}
if (r_type) {
*r_type = IDENTIFIER_FUNCTION;
@@ -3413,18 +3413,18 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
bool exists = false;
String arg_list = "";
- for (int i = 0; i < shader->functions.size(); i++) {
- if (name != shader->functions[i].name) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (name != shader->vfunctions[i].name) {
continue;
}
exists = true;
- if (!shader->functions[i].callable) {
+ if (!shader->vfunctions[i].callable) {
_set_error(vformat(RTR("Function '%s' can't be called from source code."), String(name)));
return false;
}
- FunctionNode *pfunc = shader->functions[i].function;
+ FunctionNode *pfunc = shader->vfunctions[i].function;
if (arg_list.is_empty()) {
for (int j = 0; j < pfunc->arguments.size(); j++) {
if (j > 0) {
@@ -4662,10 +4662,10 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi
}
bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == p_name) {
- ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
- FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (shader->vfunctions[i].name == p_name) {
+ ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->vfunctions[i].function->arguments.write[p_argument];
if (arg->tex_builtin_check) {
_set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name)));
return false;
@@ -4696,10 +4696,10 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam
}
bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == p_name) {
- ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
- FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (shader->vfunctions[i].name == p_name) {
+ ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->vfunctions[i].function->arguments.write[p_argument];
if (arg->tex_argument_check) {
_set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name)));
return false;
@@ -5229,11 +5229,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = func;
} else { //a function call
- if (p_block == nullptr) { // Non-constructor function call in global space is forbidden.
- if (is_const_decl) {
+
+ // Non-builtin function call is forbidden for constant declaration.
+ if (is_const_decl) {
+ if (shader->functions.has(identifier)) {
_set_error(RTR("Expected constant expression."));
+ return nullptr;
}
- return nullptr;
}
const StringName &name = identifier;
@@ -5260,12 +5262,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//test if function was parsed first
int function_index = -1;
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == name) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (shader->vfunctions[i].name == name) {
//add to current function as dependency
- for (int j = 0; j < shader->functions.size(); j++) {
- if (shader->functions[j].name == current_function) {
- shader->functions.write[j].uses_function.insert(name);
+ for (int j = 0; j < shader->vfunctions.size(); j++) {
+ if (shader->vfunctions[j].name == current_function) {
+ shader->vfunctions.write[j].uses_function.insert(name);
break;
}
}
@@ -5298,7 +5300,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//connect texture arguments, so we can cache in the
//argument what type of filter and repeat to use
- FunctionNode *call_function = shader->functions[function_index].function;
+ FunctionNode *call_function = shader->vfunctions[function_index].function;
if (call_function) {
func->return_cache = call_function->get_datatype();
func->struct_name = call_function->get_datatype_name();
@@ -9476,8 +9478,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable && shader->functions[i].name == name) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable && shader->vfunctions[i].name == name) {
_set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
@@ -9492,7 +9494,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
function.function = func_node;
- shader->functions.push_back(function);
+ shader->functions.insert(name, function);
+ shader->vfunctions.push_back(function);
func_node->name = name;
func_node->return_type = type;
@@ -10136,8 +10139,8 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
continue;
}
bool found = false;
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == E.key) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (shader->vfunctions[i].name == E.key) {
found = true;
break;
}
@@ -10257,11 +10260,11 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
}
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable || shader->functions[i].name == skip_function) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable || shader->vfunctions[i].name == skip_function) {
continue;
}
- matches.insert(String(shader->functions[i].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ matches.insert(String(shader->vfunctions[i].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
}
int idx = 0;
@@ -10319,26 +10322,26 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
block = block->parent_block;
}
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable) {
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable) {
continue;
}
- if (shader->functions[i].name == completion_function) {
+ if (shader->vfunctions[i].name == completion_function) {
String calltip;
- calltip += get_datatype_name(shader->functions[i].function->return_type);
+ calltip += get_datatype_name(shader->vfunctions[i].function->return_type);
- if (shader->functions[i].function->return_array_size > 0) {
+ if (shader->vfunctions[i].function->return_array_size > 0) {
calltip += "[";
- calltip += itos(shader->functions[i].function->return_array_size);
+ calltip += itos(shader->vfunctions[i].function->return_array_size);
calltip += "]";
}
calltip += " ";
- calltip += shader->functions[i].name;
+ calltip += shader->vfunctions[i].name;
calltip += "(";
- for (int j = 0; j < shader->functions[i].function->arguments.size(); j++) {
+ for (int j = 0; j < shader->vfunctions[i].function->arguments.size(); j++) {
if (j > 0) {
calltip += ", ";
} else {
@@ -10349,25 +10352,25 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
calltip += char32_t(0xFFFF);
}
- if (shader->functions[i].function->arguments[j].is_const) {
+ if (shader->vfunctions[i].function->arguments[j].is_const) {
calltip += "const ";
}
- if (shader->functions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
- if (shader->functions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
+ if (shader->vfunctions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
+ if (shader->vfunctions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
calltip += "out ";
} else { // ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT
calltip += "inout ";
}
}
- calltip += get_datatype_name(shader->functions[i].function->arguments[j].type);
+ calltip += get_datatype_name(shader->vfunctions[i].function->arguments[j].type);
calltip += " ";
- calltip += shader->functions[i].function->arguments[j].name;
+ calltip += shader->vfunctions[i].function->arguments[j].name;
- if (shader->functions[i].function->arguments[j].array_size > 0) {
+ if (shader->vfunctions[i].function->arguments[j].array_size > 0) {
calltip += "[";
- calltip += itos(shader->functions[i].function->arguments[j].array_size);
+ calltip += itos(shader->vfunctions[i].function->arguments[j].array_size);
calltip += "]";
}
@@ -10376,7 +10379,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
}
- if (shader->functions[i].function->arguments.size()) {
+ if (shader->vfunctions[i].function->arguments.size()) {
calltip += " ";
}
calltip += ")";
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 90fde72152..c707f6aad7 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -711,9 +711,10 @@ public:
HashMap<StringName, Varying> varyings;
HashMap<StringName, Uniform> uniforms;
HashMap<StringName, Struct> structs;
+ HashMap<StringName, Function> functions;
Vector<StringName> render_modes;
- Vector<Function> functions;
+ Vector<Function> vfunctions;
Vector<Constant> vconstants;
Vector<Struct> vstructs;
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index b44a47bf8a..27907b8bb5 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -3725,6 +3725,67 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_line(0) == "sstest");
}
+ SUBCASE("[CodeEdit] autocomplete currently selected option") {
+ code_edit->set_code_completion_enabled(true);
+ REQUIRE(code_edit->is_code_completion_enabled());
+
+ // Initially select item 0.
+ code_edit->insert_text_at_caret("te");
+ code_edit->set_caret_column(2);
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Initially selected item should be 0.");
+
+ // After adding later options shouldn't update selection.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4"); // Added te4.
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Adding later options shouldn't update selection.");
+
+ code_edit->set_code_completion_selected_index(2);
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te5", "te5"); // Added te5.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6"); // Added te6.
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Adding later options shouldn't update selection.");
+
+ // Removing elements after selected element shouldn't update selection.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te5", "te5"); // Removed te6.
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Removing elements after selected element shouldn't update selection.");
+
+ // Changing elements after selected element shouldn't update selection.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6"); // Changed te5->te6.
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Changing elements after selected element shouldn't update selection.");
+
+ // Changing elements before selected element should reset selection.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te2", "te2"); // Changed te1->te2.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6");
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Changing elements before selected element should reset selection.");
+
+ // Removing elements before selected element should reset selection.
+ code_edit->set_code_completion_selected_index(2);
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3"); // Removed te2.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6");
+ code_edit->update_code_completion_options();
+ CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Removing elements before selected element should reset selection.");
+ }
+
memdelete(code_edit);
}