diff options
-rw-r--r-- | core/extension/gdextension_interface.cpp | 9 | ||||
-rw-r--r-- | core/extension/gdextension_interface.h | 15 | ||||
-rw-r--r-- | core/io/resource.cpp | 33 | ||||
-rw-r--r-- | core/io/resource.h | 1 | ||||
-rw-r--r-- | core/io/resource_format_binary.cpp | 2 | ||||
-rw-r--r-- | doc/classes/EditorInterface.xml | 8 | ||||
-rw-r--r-- | doc/classes/LineEdit.xml | 15 | ||||
-rw-r--r-- | drivers/SCsub | 8 | ||||
-rw-r--r-- | drivers/metal/rendering_device_driver_metal.mm | 6 | ||||
-rw-r--r-- | editor/code_editor.cpp | 2 | ||||
-rw-r--r-- | editor/editor_interface.cpp | 26 | ||||
-rw-r--r-- | editor/editor_interface.h | 2 | ||||
-rw-r--r-- | modules/basis_universal/SCsub | 20 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 28 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 4 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 16 | ||||
-rw-r--r-- | scene/gui/line_edit.cpp | 56 | ||||
-rw-r--r-- | scene/gui/line_edit.h | 5 | ||||
-rw-r--r-- | scene/resources/resource_format_text.cpp | 2 |
19 files changed, 206 insertions, 52 deletions
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index ddf90f6130..66b0161160 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -507,6 +507,14 @@ static GDExtensionBool gdextension_variant_has_key(GDExtensionConstVariantPtr p_ return ret; } +static GDObjectInstanceID gdextension_variant_get_object_instance_id(GDExtensionConstVariantPtr p_self) { + const Variant *self = (const Variant *)p_self; + if (likely(self->get_type() == Variant::OBJECT)) { + return self->operator ObjectID(); + } + return 0; +} + static void gdextension_variant_get_type_name(GDExtensionVariantType p_type, GDExtensionUninitializedVariantPtr r_ret) { String name = Variant::get_type_name((Variant::Type)p_type); memnew_placement(r_ret, String(name)); @@ -1610,6 +1618,7 @@ void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(variant_has_method); REGISTER_INTERFACE_FUNC(variant_has_member); REGISTER_INTERFACE_FUNC(variant_has_key); + REGISTER_INTERFACE_FUNC(variant_get_object_instance_id); REGISTER_INTERFACE_FUNC(variant_get_type_name); REGISTER_INTERFACE_FUNC(variant_can_convert); REGISTER_INTERFACE_FUNC(variant_can_convert_strict); diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 9e3ce25698..374dbfd071 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -1308,6 +1308,21 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid); /** + * @name variant_get_object_instance_id + * @since 4.4 + * + * Gets the object instance ID from a variant of type GDEXTENSION_VARIANT_TYPE_OBJECT. + * + * If the variant isn't of type GDEXTENSION_VARIANT_TYPE_OBJECT, then zero will be returned. + * The instance ID will be returned even if the object is no longer valid - use `object_get_instance_by_id()` to check if the object is still valid. + * + * @param p_self A pointer to the Variant. + * + * @return The instance ID for the contained object. + */ +typedef GDObjectInstanceID (*GDExtensionInterfaceVariantGetObjectInstanceId)(GDExtensionConstVariantPtr p_self); + +/** * @name variant_get_type_name * @since 4.1 * diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 5f8a4b85a4..0ff4fbe490 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -99,31 +99,42 @@ void Resource::set_path_cache(const String &p_path) { GDVIRTUAL_CALL(_set_path_cache, p_path); } +static thread_local RandomPCG unique_id_gen(0, RandomPCG::DEFAULT_INC); + +void Resource::seed_scene_unique_id(uint32_t p_seed) { + unique_id_gen.seed(p_seed); +} + String Resource::generate_scene_unique_id() { // Generate a unique enough hash, but still user-readable. // If it's not unique it does not matter because the saver will try again. - OS::DateTime dt = OS::get_singleton()->get_datetime(); - uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec()); - hash = hash_murmur3_one_32(dt.year, hash); - hash = hash_murmur3_one_32(dt.month, hash); - hash = hash_murmur3_one_32(dt.day, hash); - hash = hash_murmur3_one_32(dt.hour, hash); - hash = hash_murmur3_one_32(dt.minute, hash); - hash = hash_murmur3_one_32(dt.second, hash); - hash = hash_murmur3_one_32(Math::rand(), hash); + if (unique_id_gen.get_seed() == 0) { + OS::DateTime dt = OS::get_singleton()->get_datetime(); + uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec()); + hash = hash_murmur3_one_32(dt.year, hash); + hash = hash_murmur3_one_32(dt.month, hash); + hash = hash_murmur3_one_32(dt.day, hash); + hash = hash_murmur3_one_32(dt.hour, hash); + hash = hash_murmur3_one_32(dt.minute, hash); + hash = hash_murmur3_one_32(dt.second, hash); + hash = hash_murmur3_one_32(Math::rand(), hash); + unique_id_gen.seed(hash); + } + + uint32_t random_num = unique_id_gen.rand(); static constexpr uint32_t characters = 5; static constexpr uint32_t char_count = ('z' - 'a'); static constexpr uint32_t base = char_count + ('9' - '0'); String id; for (uint32_t i = 0; i < characters; i++) { - uint32_t c = hash % base; + uint32_t c = random_num % base; if (c < char_count) { id += String::chr('a' + c); } else { id += String::chr('0' + (c - char_count)); } - hash /= base; + random_num /= base; } return id; diff --git a/core/io/resource.h b/core/io/resource.h index 8966c0233c..015f7ad197 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -114,6 +114,7 @@ public: virtual void set_path_cache(const String &p_path); // Set raw path without involving resource cache. _FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); } + static void seed_scene_unique_id(uint32_t p_seed); static String generate_scene_unique_id(); void set_scene_unique_id(const String &p_id); String get_scene_unique_id() const; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index b4826c356e..3bfa022382 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -2136,6 +2136,8 @@ static String _resource_get_class(Ref<Resource> p_resource) { } Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { + Resource::seed_scene_unique_id(p_path.hash()); + Error err; Ref<FileAccess> f; if (p_flags & ResourceSaver::FLAG_COMPRESS) { diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 795c5c1c2f..43059db8b2 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -343,6 +343,14 @@ [/codeblock] </description> </method> + <method name="popup_quick_open"> + <return type="void" /> + <param index="0" name="callback" type="Callable" /> + <param index="1" name="base_types" type="StringName[]" default="[]" /> + <description> + Pops up an editor dialog for quick selecting a resource file. The [param callback] must take a single argument of type [String] which will contain the path of the selected resource or be empty if the dialog is canceled. If [param base_types] is provided, the dialog will only show resources that match these types. Only types deriving from [Resource] are supported. + </description> + </method> <method name="reload_scene_from_path"> <return type="void" /> <param index="0" name="scene_filepath" type="String" /> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 41f42392de..3e0c328dcb 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -8,7 +8,7 @@ - When the [LineEdit] control is focused using the keyboard arrow keys, it will only gain focus and not enter edit mode. - To enter edit mode, click on the control with the mouse or press the [code]ui_text_submit[/code] action (by default [kbd]Enter[/kbd] or [kbd]Kp Enter[/kbd]). - To exit edit mode, press [code]ui_text_submit[/code] or [code]ui_cancel[/code] (by default [kbd]Escape[/kbd]) actions. - - Check [method is_editing] and [signal editing_toggled] for more information. + - Check [method edit], [method unedit], [method is_editing], and [signal editing_toggled] for more information. [b]Important:[/b] - Focusing the [LineEdit] with [code]ui_focus_next[/code] (by default [kbd]Tab[/kbd]) or [code]ui_focus_prev[/code] (by default [kbd]Shift + Tab[/kbd]) or [method Control.grab_focus] still enters edit mode (for compatibility). [LineEdit] features many built-in shortcuts that are always available ([kbd]Ctrl[/kbd] here maps to [kbd]Cmd[/kbd] on macOS): @@ -75,6 +75,13 @@ Clears the current selection. </description> </method> + <method name="edit"> + <return type="void" /> + <description> + Allows entering edit mode whether the [LineEdit] is focused or not. + Use [method Callable.call_deferred] if you want to enter edit mode on [signal text_submitted]. + </description> + </method> <method name="get_menu" qualifiers="const"> <return type="PopupMenu" /> <description> @@ -223,6 +230,12 @@ Selects the whole [String]. </description> </method> + <method name="unedit"> + <return type="void" /> + <description> + Allows exiting edit mode while preserving focus. + </description> + </method> </methods> <members> <member name="alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0"> diff --git a/drivers/SCsub b/drivers/SCsub index 219c4451ee..e0bfa138f5 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -1,6 +1,8 @@ #!/usr/bin/env python from misc.utility.scons_hints import * +from methods import print_error + Import("env") env.drivers_sources = [] @@ -20,7 +22,7 @@ if env["platform"] == "windows": SConscript("backtrace/SCsub") if env["xaudio2"]: if "xaudio2" not in supported: - print("Target platform '{}' does not support the XAudio2 audio driver. Aborting.".format(env["platform"])) + print_error("Target platform '{}' does not support the XAudio2 audio driver".format(env["platform"])) Exit(255) SConscript("xaudio2/SCsub") @@ -34,7 +36,7 @@ if env["vulkan"]: SConscript("vulkan/SCsub") if env["d3d12"]: if "d3d12" not in supported: - print("Target platform '{}' does not support the D3D12 rendering driver. Aborting.".format(env["platform"])) + print_error("Target platform '{}' does not support the D3D12 rendering driver".format(env["platform"])) Exit(255) SConscript("d3d12/SCsub") if env["opengl3"]: @@ -43,7 +45,7 @@ if env["opengl3"]: SConscript("egl/SCsub") if env["metal"]: if "metal" not in supported: - print("Target platform '{}' does not support the Metal rendering driver. Aborting.".format(env["platform"])) + print_error("Target platform '{}' does not support the Metal rendering driver".format(env["platform"])) Exit(255) SConscript("metal/SCsub") diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index 9d691a0d23..0f7faaddf0 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -358,7 +358,11 @@ RDD::TextureID RenderingDeviceDriverMetal::texture_create(const TextureFormat &p } RDD::TextureID RenderingDeviceDriverMetal::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) { - ERR_FAIL_V_MSG(RDD::TextureID(), "not implemented"); + id<MTLTexture> obj = (__bridge id<MTLTexture>)(void *)(uintptr_t)p_native_texture; + + // We only need to create a RDD::TextureID for an existing, natively-provided texture. + + return rid::make(obj); } RDD::TextureID RenderingDeviceDriverMetal::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 07547fee8a..88a32b1a6d 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -644,6 +644,8 @@ void FindReplaceBar::_search_text_submitted(const String &p_text) { } else { search_next(); } + + callable_mp(search_text, &LineEdit::edit).call_deferred(); } void FindReplaceBar::_replace_text_submitted(const String &p_text) { diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp index fa6198f695..264c80dcbf 100644 --- a/editor/editor_interface.cpp +++ b/editor/editor_interface.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" +#include "editor/gui/editor_quick_open_dialog.h" #include "editor/gui/editor_run_bar.h" #include "editor/gui/editor_scene_tabs.h" #include "editor/gui/scene_tree_editor.h" @@ -336,6 +337,24 @@ void EditorInterface::popup_property_selector(Object *p_object, const Callable & property_selector->connect(SNAME("canceled"), canceled_callback, CONNECT_DEFERRED); } +void EditorInterface::popup_quick_open(const Callable &p_callback, const TypedArray<StringName> &p_base_types) { + StringName required_type = SNAME("Resource"); + Vector<StringName> base_types; + if (p_base_types.is_empty()) { + base_types.append(required_type); + } else { + for (int i = 0; i < p_base_types.size(); i++) { + StringName type = p_base_types[i]; + ERR_FAIL_COND_MSG(!(ClassDB::is_parent_class(type, required_type) || EditorNode::get_editor_data().script_class_is_parent(type, required_type)), "Only types deriving from Resource are supported in the quick open dialog."); + base_types.append(type); + } + } + + EditorQuickOpenDialog *quick_open = EditorNode::get_singleton()->get_quick_open_dialog(); + quick_open->connect(SNAME("canceled"), callable_mp(this, &EditorInterface::_quick_open).bind(String(), p_callback)); + quick_open->popup_dialog(base_types, callable_mp(this, &EditorInterface::_quick_open).bind(p_callback)); +} + void EditorInterface::_node_selected(const NodePath &p_node_path, const Callable &p_callback) { const NodePath path = get_edited_scene_root()->get_path().rel_path_to(p_node_path); _call_dialog_callback(p_callback, path, "node selected"); @@ -353,6 +372,12 @@ void EditorInterface::_property_selection_canceled(const Callable &p_callback) { _call_dialog_callback(p_callback, NodePath(), "property selection canceled"); } +void EditorInterface::_quick_open(const String &p_file_path, const Callable &p_callback) { + EditorQuickOpenDialog *quick_open = EditorNode::get_singleton()->get_quick_open_dialog(); + quick_open->disconnect(SNAME("canceled"), callable_mp(this, &EditorInterface::_quick_open)); + _call_dialog_callback(p_callback, p_file_path, "quick open"); +} + void EditorInterface::_call_dialog_callback(const Callable &p_callback, const Variant &p_selected, const String &p_context) { Callable::CallError ce; Variant ret; @@ -568,6 +593,7 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_node_selector", "callback", "valid_types", "current_value"), &EditorInterface::popup_node_selector, DEFVAL(TypedArray<StringName>()), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("popup_property_selector", "object", "callback", "type_filter", "current_value"), &EditorInterface::popup_property_selector, DEFVAL(PackedInt32Array()), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("popup_quick_open", "callback", "base_types"), &EditorInterface::popup_quick_open, DEFVAL(TypedArray<StringName>())); // Editor docks. diff --git a/editor/editor_interface.h b/editor/editor_interface.h index 20d66d71f5..4877444dac 100644 --- a/editor/editor_interface.h +++ b/editor/editor_interface.h @@ -72,6 +72,7 @@ class EditorInterface : public Object { void _node_selection_canceled(const Callable &p_callback); void _property_selected(const String &p_property_name, const Callable &p_callback); void _property_selection_canceled(const Callable &p_callback); + void _quick_open(const String &p_file_path, const Callable &p_callback); void _call_dialog_callback(const Callable &p_callback, const Variant &p_selected, const String &p_context); // Editor tools. @@ -138,6 +139,7 @@ public: void popup_node_selector(const Callable &p_callback, const TypedArray<StringName> &p_valid_types = TypedArray<StringName>(), Node *p_current_value = nullptr); // Must use Vector<int> because exposing Vector<Variant::Type> is not supported. void popup_property_selector(Object *p_object, const Callable &p_callback, const PackedInt32Array &p_type_filter = PackedInt32Array(), const String &p_current_value = String()); + void popup_quick_open(const Callable &p_callback, const TypedArray<StringName> &p_base_types = TypedArray<StringName>()); // Editor docks. diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub index 0142317e1e..9bea0a0ca9 100644 --- a/modules/basis_universal/SCsub +++ b/modules/basis_universal/SCsub @@ -50,6 +50,26 @@ if env.dev_build: env_thirdparty = env_basisu.Clone() env_thirdparty.disable_warnings() + +# Disable unneeded features to reduce binary size. +# <https://github.com/BinomialLLC/basis_universal/wiki/How-to-Use-and-Configure-the-Transcoder> +env_thirdparty.Append( + CPPDEFINES=[ + # Storage formats. + # Godot only implements `.basis` support through basis_universal. + # Support for `.ktx` files are implemented with a direct libktx implementation. + # Building the encoder requires `BASISD_SUPPORT_KTX2` to be enabled, + # so we can only disable Zstandard compression for `.ktx` files + # (this is not used in `.basis` files). + ("BASISD_SUPPORT_KTX2_ZSTD", 0), + # GPU compression formats. + ("BASISD_SUPPORT_ATC", 0), # Proprietary Adreno format not supported by Godot. + ("BASISD_SUPPORT_FXT1", 0), # Legacy format not supported by Godot. + ("BASISD_SUPPORT_PVRTC1", 0), # Legacy format not supported by Godot. + ("BASISD_SUPPORT_PVRTC2", 0), # Legacy format not supported by Godot. + ] +) + if env.editor_build: env_thirdparty.Append(CPPDEFINES=["BASISU_NO_IMG_LOADERS"]) env_thirdparty.add_source_files(thirdparty_obj, encoder_sources) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 5d8e89938c..ffa3840181 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1520,6 +1520,7 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod rendering_device->screen_create(window_id); } #endif + wd.initialized = true; return window_id; } @@ -2065,7 +2066,7 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window) return Size2(); } -void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) { +void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) { // Windows docs for window styles: // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles @@ -2074,12 +2075,16 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style_ex = WS_EX_WINDOWEDGE; if (p_main_window) { r_style_ex |= WS_EX_APPWINDOW; - r_style |= WS_VISIBLE; + if (p_initialized) { + r_style |= WS_VISIBLE; + } } if (p_fullscreen || p_borderless) { r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past. - if (p_maximized) { + if (p_minimized) { + r_style |= WS_MINIMIZE; + } else if (p_maximized) { r_style |= WS_MAXIMIZE; } if (!p_fullscreen) { @@ -2094,13 +2099,19 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre } } else { if (p_resizable) { - if (p_maximized) { + if (p_minimized) { + r_style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE; + } else if (p_maximized) { r_style = WS_OVERLAPPEDWINDOW | WS_MAXIMIZE; } else { r_style = WS_OVERLAPPEDWINDOW; } } else { - r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + if (p_minimized) { + r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MINIMIZE; + } else { + r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + } } } @@ -2108,7 +2119,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE; } - if (!p_borderless && !p_no_activate_focus) { + if (!p_borderless && !p_no_activate_focus && p_initialized) { r_style |= WS_VISIBLE; } @@ -2125,7 +2136,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain DWORD style = 0; DWORD style_ex = 0; - _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex); + _get_window_style(p_window == MAIN_WINDOW_ID, wd.initialized, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.minimized, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex); SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); @@ -5536,7 +5547,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); + _get_window_style(window_id_counter == MAIN_WINDOW_ID, false, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MINIMIZED, p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); RECT WindowRect; @@ -6368,6 +6379,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } + windows[MAIN_WINDOW_ID].initialized = true; show_window(MAIN_WINDOW_ID); #if defined(RD_ENABLED) diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 54e1c9681d..7d6a3e96a6 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -524,6 +524,8 @@ class DisplayServerWindows : public DisplayServer { bool is_popup = false; Rect2i parent_safe_rect; + + bool initialized = false; }; JoypadWindows *joypad = nullptr; @@ -591,7 +593,7 @@ class DisplayServerWindows : public DisplayServer { HashMap<int64_t, Vector2> pointer_last_pos; void _send_window_event(const WindowData &wd, WindowEvent p_event); - void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); + void _get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); MouseMode mouse_mode; int restore_mouse_trails = 0; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 002a738b83..fe4c91cb56 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -245,7 +245,21 @@ void ColorPicker::finish_shaders() { } void ColorPicker::set_focus_on_line_edit() { - callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(); + bool has_hardware_keyboard = true; +#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED) + has_hardware_keyboard = DisplayServer::get_singleton()->has_hardware_keyboard(); +#endif // ANDROID_ENABLED || IOS_ENABLED + if (has_hardware_keyboard) { + callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(); + } else { + // A hack to avoid showing the virtual keyboard when the ColorPicker window popups and + // no hardware keyboard is detected on Android and IOS. + // This will only focus the LineEdit without editing, the virtual keyboard will only be visible when + // we touch the LineEdit to enter edit mode. + callable_mp(c_text, &LineEdit::set_editable).call_deferred(false); + callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(); + callable_mp(c_text, &LineEdit::set_editable).call_deferred(true); + } } void ColorPicker::_update_controls() { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 6e5b555cdf..9967805134 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -45,28 +45,37 @@ #include "editor/editor_settings.h" #endif -void LineEdit::_edit() { +void LineEdit::edit() { if (!is_inside_tree()) { return; } if (!has_focus()) { grab_focus(); + return; } if (!editable || editing) { return; } + if (select_all_on_focus) { + if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { + // Select all when the mouse button is up. + pending_select_all_on_focus = true; + } else { + select_all(); + } + } + editing = true; _validate_caret_can_draw(); show_virtual_keyboard(); queue_redraw(); - emit_signal(SNAME("editing_toggled"), true); } -void LineEdit::_unedit() { +void LineEdit::unedit() { if (!editing) { return; } @@ -84,8 +93,6 @@ void LineEdit::_unedit() { if (deselect_on_focus_loss_enabled && !selection.drag_attempt) { deselect(); } - - emit_signal(SNAME("editing_toggled"), false); } bool LineEdit::is_editing() const { @@ -390,7 +397,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } if (editable && !editing) { - _edit(); + edit(); + emit_signal(SNAME("editing_toggled"), true); } accept_event(); @@ -406,7 +414,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { set_caret_at_pixel_pos(b->get_position().x); if (!editing) { - _edit(); + edit(); + emit_signal(SNAME("editing_toggled"), true); } if (!paste_buffer.is_empty()) { @@ -506,7 +515,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } if (editable && !editing) { - _edit(); + edit(); + emit_signal(SNAME("editing_toggled"), true); return; } queue_redraw(); @@ -599,7 +609,9 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } if (editable && !editing && k->is_action_pressed("ui_text_submit", false)) { - _edit(); + edit(); + emit_signal(SNAME("editing_toggled"), true); + accept_event(); return; } @@ -734,7 +746,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } if (editing) { - _unedit(); + unedit(); + emit_signal(SNAME("editing_toggled"), false); } accept_event(); @@ -743,7 +756,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { if (k->is_action("ui_cancel")) { if (editing) { - _unedit(); + unedit(); + emit_signal(SNAME("editing_toggled"), false); } accept_event(); @@ -1332,24 +1346,17 @@ void LineEdit::_notification(int p_what) { } break; case NOTIFICATION_FOCUS_ENTER: { - if (select_all_on_focus) { - if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { - // Select all when the mouse button is up. - pending_select_all_on_focus = true; - } else { - select_all(); - } - } - // Only allow editing if the LineEdit is not focused with arrow keys. if (!(Input::get_singleton()->is_action_pressed("ui_up") || Input::get_singleton()->is_action_pressed("ui_down") || Input::get_singleton()->is_action_pressed("ui_left") || Input::get_singleton()->is_action_pressed("ui_right"))) { - _edit(); + edit(); + emit_signal(SNAME("editing_toggled"), true); } } break; case NOTIFICATION_FOCUS_EXIT: { if (editing) { - _unedit(); + unedit(); + emit_signal(SNAME("editing_toggled"), false); } } break; @@ -2138,7 +2145,8 @@ void LineEdit::set_editable(bool p_editable) { editable = p_editable; if (!editable && editing) { - _unedit(); + unedit(); + emit_signal(SNAME("editing_toggled"), false); } _validate_caret_can_draw(); @@ -2759,6 +2767,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment); ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment); + ClassDB::bind_method(D_METHOD("edit"), &LineEdit::edit); + ClassDB::bind_method(D_METHOD("unedit"), &LineEdit::unedit); ClassDB::bind_method(D_METHOD("is_editing"), &LineEdit::is_editing); ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear); ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index ac7436646b..9253dd8711 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -207,9 +207,6 @@ private: float base_scale = 1.0; } theme_cache; - void _edit(); - void _unedit(); - void _close_ime_window(); void _update_ime_window_position(); @@ -265,6 +262,8 @@ protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; public: + void edit(); + void unedit(); bool is_editing() const; bool has_ime_text() const; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index d531eea311..5aa6bf718c 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1708,6 +1708,8 @@ static String _resource_get_class(Ref<Resource> p_resource) { } Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { + Resource::seed_scene_unique_id(p_path.hash()); // Seeding for save path should make it deterministic for importers. + if (p_path.ends_with(".tscn")) { packed_scene = p_resource; } |