diff options
-rw-r--r-- | core/io/http_client_tcp.cpp | 42 | ||||
-rw-r--r-- | core/io/http_client_tcp.h | 1 | ||||
-rw-r--r-- | doc/classes/Control.xml | 6 | ||||
-rw-r--r-- | doc/classes/Input.xml | 3 | ||||
-rw-r--r-- | doc/classes/StreamPeerBuffer.xml | 10 | ||||
-rw-r--r-- | doc/classes/Viewport.xml | 12 | ||||
-rw-r--r-- | editor/animation_track_editor.cpp | 2 | ||||
-rw-r--r-- | editor/code_editor.cpp | 4 | ||||
-rw-r--r-- | editor/editor_help.cpp | 2 | ||||
-rw-r--r-- | editor/editor_inspector.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/node_3d_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/theme_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/rename_dialog.cpp | 4 | ||||
-rw-r--r-- | editor/scene_tree_dock.cpp | 2 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 48 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 1 | ||||
-rw-r--r-- | scene/gui/base_button.cpp | 2 | ||||
-rw-r--r-- | scene/gui/control.cpp | 9 | ||||
-rw-r--r-- | scene/gui/control.h | 2 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 32 | ||||
-rw-r--r-- | scene/main/viewport.h | 6 |
22 files changed, 136 insertions, 60 deletions
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp index 24ec35fa3d..e61833ce7c 100644 --- a/core/io/http_client_tcp.cpp +++ b/core/io/http_client_tcp.cpp @@ -197,20 +197,12 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector< request += "\r\n"; CharString cs = request.utf8(); - Vector<uint8_t> data; - data.resize(cs.length() + p_body_size); - memcpy(data.ptrw(), cs.get_data(), cs.length()); + request_buffer->clear(); + request_buffer->put_data((const uint8_t *)cs.get_data(), cs.length()); if (p_body_size > 0) { - memcpy(data.ptrw() + cs.length(), p_body, p_body_size); - } - - err = connection->put_data(data.ptr(), data.size()); - - if (err) { - close(); - status = STATUS_CONNECTION_ERROR; - return err; + request_buffer->put_data(p_body, p_body_size); } + request_buffer->seek(0); status = STATUS_REQUESTING; head_request = p_method == METHOD_HEAD; @@ -261,6 +253,7 @@ void HTTPClientTCP::close() { ip_candidates.clear(); response_headers.clear(); response_str.clear(); + request_buffer->clear(); body_size = -1; body_left = 0; chunk_left = 0; @@ -436,6 +429,30 @@ Error HTTPClientTCP::poll() { return OK; } break; case STATUS_REQUESTING: { + if (request_buffer->get_available_bytes()) { + int avail = request_buffer->get_available_bytes(); + int pos = request_buffer->get_position(); + const Vector<uint8_t> data = request_buffer->get_data_array(); + int wrote = 0; + Error err; + if (blocking) { + err = connection->put_data(data.ptr() + pos, avail); + wrote += avail; + } else { + err = connection->put_partial_data(data.ptr() + pos, avail, wrote); + } + if (err != OK) { + close(); + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + pos += wrote; + request_buffer->seek(pos); + if (avail - wrote > 0) { + return OK; + } + request_buffer->clear(); + } while (true) { uint8_t byte; int rec = 0; @@ -763,6 +780,7 @@ void HTTPClientTCP::set_https_proxy(const String &p_host, int p_port) { HTTPClientTCP::HTTPClientTCP() { tcp_connection.instantiate(); + request_buffer.instantiate(); } HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func; diff --git a/core/io/http_client_tcp.h b/core/io/http_client_tcp.h index f5f4450f73..c10e0b1eca 100644 --- a/core/io/http_client_tcp.h +++ b/core/io/http_client_tcp.h @@ -62,6 +62,7 @@ private: int64_t body_left = 0; bool read_until_eof = false; + Ref<StreamPeerBuffer> request_buffer; Ref<StreamPeerTCP> tcp_connection; Ref<StreamPeer> connection; Ref<HTTPClientTCP> proxy_client; // Negotiate with proxy server. diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index d5551e1e04..b6c2dac33c 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -380,12 +380,6 @@ Returns the focus neighbor for the specified [enum Side]. A getter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top]. </description> </method> - <method name="get_focus_owner" qualifiers="const"> - <return type="Control" /> - <description> - Returns the control that has the keyboard focus or [code]null[/code] if none. - </description> - </method> <method name="get_global_rect" qualifiers="const"> <return type="Rect2" /> <description> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 423e58f5c6..60f8925ab3 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -383,7 +383,8 @@ <return type="void" /> <argument index="0" name="to" type="Vector2" /> <description> - Sets the mouse position to the specified vector. + Sets the mouse position to the specified vector, provided in pixels and relative to an origin at the upper left corner of the game window. + Mouse position is clipped to the limits of the screen resolution, or to the limits of the game window if [enum MouseMode] is set to [code]MOUSE_MODE_CONFINED[/code] or [code]MOUSE_MODE_CONFINED_HIDDEN[/code]. </description> </method> </methods> diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml index 989864760f..e335987ff5 100644 --- a/doc/classes/StreamPeerBuffer.xml +++ b/doc/classes/StreamPeerBuffer.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="StreamPeerBuffer" inherits="StreamPeer" version="4.0"> <brief_description> + Data buffer stream peer. </brief_description> <description> + Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [File] can be used directly. + A [StreamPeerBuffer] object keeps an internal cursor which is the offset in bytes to the start of the buffer. Get and put operations are performed at the cursor position and will move the cursor accordingly. </description> <tutorials> </tutorials> @@ -10,38 +13,45 @@ <method name="clear"> <return type="void" /> <description> + Clears the [member data_array] and resets the cursor. </description> </method> <method name="duplicate" qualifiers="const"> <return type="StreamPeerBuffer" /> <description> + Returns a new [StreamPeerBuffer] with the same [member data_array] content. </description> </method> <method name="get_position" qualifiers="const"> <return type="int" /> <description> + Returns the current cursor position. </description> </method> <method name="get_size" qualifiers="const"> <return type="int" /> <description> + Returns the size of [member data_array]. </description> </method> <method name="resize"> <return type="void" /> <argument index="0" name="size" type="int" /> <description> + Resizes the [member data_array]. This [i]doesn't[/i] update the cursor. </description> </method> <method name="seek"> <return type="void" /> <argument index="0" name="position" type="int" /> <description> + Moves the cursor to the specified position. [code]position[/code] must be a valid index of [member data_array]. </description> </method> </methods> <members> <member name="data_array" type="PackedByteArray" setter="set_data_array" getter="get_data_array" default="PackedByteArray()"> + The underlying data buffer. Setting this value resets the cursor. </member> </members> </class> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 4a11fbb489..1b37cab68e 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -107,6 +107,12 @@ Returns the drag data from the GUI, that was previously returned by [method Control._get_drag_data]. </description> </method> + <method name="gui_get_focus_owner"> + <return type="Control" /> + <description> + Returns the [Control] having the focus within this viewport. If no [Control] has the focus, returns null. + </description> + </method> <method name="gui_is_drag_successful" qualifiers="const"> <return type="bool" /> <description> @@ -119,6 +125,12 @@ Returns [code]true[/code] if the viewport is currently performing a drag operation. </description> </method> + <method name="gui_release_focus"> + <return type="void" /> + <description> + Removes the focus from the currently focussed [Control] within this viewport. If no [Control] has the focus, does nothing. + </description> + </method> <method name="is_embedding_subwindows" qualifiers="const"> <return type="bool" /> <description> diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 433866602b..e36d0b846b 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3481,7 +3481,7 @@ void AnimationTrackEditor::_track_remove_request(int p_track) { void AnimationTrackEditor::_track_grab_focus(int p_track) { // Don't steal focus if not working with the track editor. - if (Object::cast_to<AnimationTrackEdit>(get_focus_owner())) { + if (Object::cast_to<AnimationTrackEdit>(get_viewport()->gui_get_focus_owner())) { track_edits[p_track]->grab_focus(); } } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 0a269d960e..967f7e0d1f 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -122,7 +122,7 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) { return; } - Control *focus_owner = get_focus_owner(); + Control *focus_owner = get_viewport()->gui_get_focus_owner(); if (text_editor->has_focus() || (focus_owner && vbc_lineedit->is_ancestor_of(focus_owner))) { bool accepted = true; @@ -724,7 +724,7 @@ void CodeTextEditor::input(const Ref<InputEvent> &event) { } if (!text_editor->has_focus()) { - if ((find_replace_bar != nullptr && find_replace_bar->is_visible()) && (find_replace_bar->has_focus() || find_replace_bar->is_ancestor_of(get_focus_owner()))) { + if ((find_replace_bar != nullptr && find_replace_bar->is_visible()) && (find_replace_bar->has_focus() || find_replace_bar->is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { if (ED_IS_SHORTCUT("script_text_editor/find_next", key_event)) { find_replace_bar->search_next(); accept_event(); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 946fe6d893..bb76af8f9b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -2128,7 +2128,7 @@ void FindBar::unhandled_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { - if (k->is_pressed() && (rich_text_label->has_focus() || is_ancestor_of(get_focus_owner()))) { + if (k->is_pressed() && (rich_text_label->has_focus() || is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { bool accepted = true; switch (k->get_keycode()) { diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 0d68051125..6f7508b10b 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2299,7 +2299,7 @@ void EditorInspector::update_tree() { if (property_focusable != -1) { //check focusable is really focusable bool restore_focus = false; - Control *focused = get_focus_owner(); + Control *focused = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; if (focused) { Node *parent = focused->get_parent(); while (parent) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index dff01cbf05..d496804bf2 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2507,7 +2507,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { _update_cursor(); // Grab focus - if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { + if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) { viewport->call_deferred(SNAME("grab_focus")); } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 4610171d68..0c0188e8d1 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1203,7 +1203,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const } void Node3DEditorViewport::_surface_mouse_enter() { - if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { + if (!surface->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) { surface->grab_focus(); } } diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index bc2739bdac..aaa09237cf 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -2226,7 +2226,7 @@ void ThemeTypeEditor::_update_type_list() { } updating = true; - Control *focused = get_focus_owner(); + Control *focused = get_viewport()->gui_get_focus_owner(); if (focused) { if (focusables.has(focused)) { // If focus is currently on one of the internal property editors, don't update. diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 92dcd53830..c6a4c0d86a 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -337,7 +337,7 @@ void RenameDialog::_bind_methods() { } void RenameDialog::_update_substitute() { - LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(scene_tree_editor->get_focus_owner()); + LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner()); bool is_main_field = _is_main_field(focus_owner_line_edit); but_insert_name->set_disabled(!is_main_field); @@ -632,7 +632,7 @@ bool RenameDialog::_is_main_field(LineEdit *line_edit) { } void RenameDialog::_insert_text(String text) { - LineEdit *focus_owner = Object::cast_to<LineEdit>(scene_tree_editor->get_focus_owner()); + LineEdit *focus_owner = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner()); if (_is_main_field(focus_owner)) { focus_owner->selection_delete(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 30ea1bcbb9..9b18d3a491 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -78,7 +78,7 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) { void SceneTreeDock::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (get_focus_owner() && get_focus_owner()->is_text_field()) { + if (get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) { return; } diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 68762db3a9..d30d0afc5c 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -76,8 +76,8 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); @@ -89,6 +89,7 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); if (rcedit_path.is_empty()) { + WARN_PRINT("The rcedit tool is not configured in the Editor Settings (Export > Windows > Rcedit). No custom icon or app information data will be embedded in the exported executable."); return; } @@ -327,3 +328,46 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p return OK; } + +bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { + String err = ""; + bool valid = EditorExportPlatformPC::can_export(p_preset, err, r_missing_templates); + + String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); + if (rcedit_path.is_empty()) { + err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > Rcedit) to change the icon or app information data.") + "\n"; + } + + String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); + if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) { + err += TTR("Invalid icon path:") + " " + icon_path + "\n"; + } + + // Only non-negative integers can exist in the version string. + + String file_version = p_preset->get("application/file_version"); + if (!file_version.is_empty()) { + PackedStringArray version_array = file_version.split(".", false); + if (version_array.size() != 4 || !version_array[0].is_valid_int() || + !version_array[1].is_valid_int() || !version_array[2].is_valid_int() || + !version_array[3].is_valid_int() || file_version.find("-") > -1) { + err += TTR("Invalid file version:") + " " + file_version + "\n"; + } + } + + String product_version = p_preset->get("application/product_version"); + if (!product_version.is_empty()) { + PackedStringArray version_array = product_version.split(".", false); + if (version_array.size() != 4 || !version_array[0].is_valid_int() || + !version_array[1].is_valid_int() || !version_array[2].is_valid_int() || + !version_array[3].is_valid_int() || product_version.find("-") > -1) { + err += TTR("Invalid product version:") + " " + product_version + "\n"; + } + } + + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 351333aa42..89e5b1b635 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -47,6 +47,7 @@ public: virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override; virtual void get_export_options(List<ExportOption> *r_options) override; virtual bool get_export_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override; + virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; }; #endif diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ec451b07cf..da2ef6c5ec 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -403,7 +403,7 @@ bool BaseButton::_is_focus_owner_in_shorcut_context() const { } Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_focus_owner(); + Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 7ebc5c27f8..fdae8e2f1f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2196,8 +2196,7 @@ void Control::release_focus() { return; } - get_viewport()->_gui_remove_focus(); - update(); + get_viewport()->gui_release_focus(); } bool Control::is_top_level_control() const { @@ -2600,11 +2599,6 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } -Control *Control::get_focus_owner() const { - ERR_FAIL_COND_V(!is_inside_tree(), nullptr); - return get_viewport()->_gui_get_focus_owner(); -} - void Control::warp_mouse(const Point2 &p_to_pos) { ERR_FAIL_COND(!is_inside_tree()); get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos)); @@ -2894,7 +2888,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus); ClassDB::bind_method(D_METHOD("find_prev_valid_focus"), &Control::find_prev_valid_focus); ClassDB::bind_method(D_METHOD("find_next_valid_focus"), &Control::find_next_valid_focus); - ClassDB::bind_method(D_METHOD("get_focus_owner"), &Control::get_focus_owner); ClassDB::bind_method(D_METHOD("set_h_size_flags", "flags"), &Control::set_h_size_flags); ClassDB::bind_method(D_METHOD("get_h_size_flags"), &Control::get_h_size_flags); diff --git a/scene/gui/control.h b/scene/gui/control.h index bf79f790e7..962135280f 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -462,8 +462,6 @@ public: void set_focus_previous(const NodePath &p_prev); NodePath get_focus_previous() const; - Control *get_focus_owner() const; - void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index bde68f0b3d..09880ad6cf 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2092,7 +2092,7 @@ void Viewport::_gui_hide_control(Control *p_control) { } if (gui.key_focus == p_control) { - _gui_remove_focus(); + gui_release_focus(); } if (gui.mouse_over == p_control) { gui.mouse_over = nullptr; @@ -2142,15 +2142,7 @@ Window *Viewport::get_base_window() const { } void Viewport::_gui_remove_focus_for_window(Node *p_window) { if (get_base_window() == p_window) { - _gui_remove_focus(); - } -} - -void Viewport::_gui_remove_focus() { - if (gui.key_focus) { - Node *f = gui.key_focus; - gui.key_focus = nullptr; - f->notification(Control::NOTIFICATION_FOCUS_EXIT, true); + gui_release_focus(); } } @@ -2279,10 +2271,6 @@ void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paus } } -Control *Viewport::_gui_get_focus_owner() { - return gui.key_focus; -} - void Viewport::_gui_grab_click_focus(Control *p_control) { gui.mouse_click_grabber = p_control; call_deferred(SNAME("_post_gui_grab_click_focus")); @@ -2798,6 +2786,19 @@ int Viewport::gui_get_canvas_sort_index() { return gui.canvas_sort_index++; } +void Viewport::gui_release_focus() { + if (gui.key_focus) { + Control *f = gui.key_focus; + gui.key_focus = nullptr; + f->notification(Control::NOTIFICATION_FOCUS_EXIT, true); + f->update(); + } +} + +Control *Viewport::gui_get_focus_owner() { + return gui.key_focus; +} + void Viewport::set_msaa(MSAA p_msaa) { ERR_FAIL_INDEX(p_msaa, MSAA_MAX); if (msaa == p_msaa) { @@ -3591,6 +3592,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful); + ClassDB::bind_method(D_METHOD("gui_release_focus"), &Viewport::gui_release_focus); + ClassDB::bind_method(D_METHOD("gui_get_focus_owner"), &Viewport::gui_get_focus_owner); + ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 2541474cf3..3a71745f44 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -411,7 +411,6 @@ private: Control *_gui_get_drag_preview(); void _gui_remove_focus_for_window(Node *p_window); - void _gui_remove_focus(); void _gui_unfocus_control(Control *p_control); bool _gui_control_has_focus(const Control *p_control); void _gui_control_grab_focus(Control *p_control); @@ -419,8 +418,6 @@ private: void _post_gui_grab_click_focus(); void _gui_accept_event(); - Control *_gui_get_focus_owner(); - bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check); friend class AudioListener2D; @@ -559,6 +556,9 @@ public: void gui_reset_canvas_sort_index(); int gui_get_canvas_sort_index(); + void gui_release_focus(); + Control *gui_get_focus_owner(); + TypedArray<String> get_configuration_warnings() const override; void set_debug_draw(DebugDraw p_debug_draw); |