summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/extension/gdextension_interface.cpp9
-rw-r--r--core/extension/gdextension_interface.h15
-rw-r--r--core/io/resource.cpp33
-rw-r--r--core/io/resource.h1
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--doc/classes/EditorInterface.xml8
-rw-r--r--doc/classes/LineEdit.xml15
-rw-r--r--drivers/SCsub8
-rw-r--r--drivers/metal/rendering_device_driver_metal.mm6
-rw-r--r--editor/code_editor.cpp2
-rw-r--r--editor/editor_interface.cpp26
-rw-r--r--editor/editor_interface.h2
-rw-r--r--modules/basis_universal/SCsub20
-rw-r--r--platform/windows/display_server_windows.cpp28
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--scene/gui/color_picker.cpp16
-rw-r--r--scene/gui/line_edit.cpp56
-rw-r--r--scene/gui/line_edit.h5
-rw-r--r--scene/resources/resource_format_text.cpp2
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;
}