summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/HTTPRequest.xml2
-rw-r--r--editor/editor_node.cpp55
-rw-r--r--editor/editor_node.h3
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp16
-rw-r--r--editor/project_manager.cpp8
-rw-r--r--editor/scene_tree_editor.cpp8
-rw-r--r--platform/javascript/export/export_plugin.cpp9
-rw-r--r--platform/uwp/export/export_plugin.cpp8
-rw-r--r--scene/animation/tween.cpp12
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/main/http_request.cpp6
-rw-r--r--scene/main/http_request.h6
-rw-r--r--scene/main/viewport.cpp64
14 files changed, 142 insertions, 58 deletions
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 42047a68c8..641d73e333 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -247,7 +247,7 @@
<member name="max_redirects" type="int" setter="set_max_redirects" getter="get_max_redirects" default="8">
Maximum number of allowed redirects.
</member>
- <member name="timeout" type="int" setter="set_timeout" getter="get_timeout" default="0">
+ <member name="timeout" type="float" setter="set_timeout" getter="get_timeout" default="0.0">
</member>
<member name="use_threads" type="bool" setter="set_use_threads" getter="is_using_threads" default="false">
If [code]true[/code], multithreading is used to improve performance.
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index bf118b8e16..305fe5f6ff 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1885,6 +1885,7 @@ void EditorNode::_dialog_action(String p_file) {
case FILE_CLOSE:
case FILE_CLOSE_ALL_AND_QUIT:
case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
+ case FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT:
case SCENE_TAB_CLOSE:
case FILE_SAVE_SCENE:
case FILE_SAVE_AS_SCENE: {
@@ -2524,17 +2525,23 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
_scene_tab_closed(editor_data.get_edited_scene());
} break;
case FILE_CLOSE_ALL_AND_QUIT:
- case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: {
+ case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
+ case FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
tab_closing = _next_unsaved_scene(false);
_scene_tab_changed(tab_closing);
- if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
+ if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER || p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
Node *scene_root = editor_data.get_edited_scene_root(tab_closing);
if (scene_root) {
String scene_filename = scene_root->get_scene_file_path();
- save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ if (p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Reload"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before reloading?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ } else {
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Quit"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ }
save_confirmation->popup_centered();
break;
}
@@ -2820,11 +2827,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android"));
} break;
- case RUN_RELOAD_CURRENT_PROJECT: {
- restart_editor();
- } break;
case FILE_QUIT:
- case RUN_PROJECT_MANAGER: {
+ case RUN_PROJECT_MANAGER:
+ case RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
if (_next_unsaved_scene(!save_each) == -1) {
@@ -2832,7 +2837,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
break;
} else {
if (save_each) {
- _menu_option_confirm(p_option == FILE_QUIT ? FILE_CLOSE_ALL_AND_QUIT : FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER, false);
+ if (p_option == RELOAD_CURRENT_PROJECT) {
+ _menu_option_confirm(FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT, false);
+ } else if (p_option == FILE_QUIT) {
+ _menu_option_confirm(FILE_CLOSE_ALL_AND_QUIT, false);
+ } else {
+ _menu_option_confirm(FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER, false);
+ }
} else {
String unsaved_scenes;
int i = _next_unsaved_scene(true, 0);
@@ -2840,9 +2851,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
unsaved_scenes += "\n " + editor_data.get_edited_scene_root(i)->get_scene_file_path();
i = _next_unsaved_scene(true, ++i);
}
-
- save_confirmation->get_ok_button()->set_text(TTR("Save & Quit"));
- save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes to the following scene(s) before opening Project Manager?")) + unsaved_scenes);
+ if (p_option == RELOAD_CURRENT_PROJECT) {
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Reload"));
+ save_confirmation->set_text(TTR("Save changes to the following scene(s) before reloading?") + unsaved_scenes);
+ } else {
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Quit"));
+ save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes to the following scene(s) before opening Project Manager?")) + unsaved_scenes);
+ }
save_confirmation->popup_centered();
}
}
@@ -3039,6 +3054,7 @@ void EditorNode::_discard_changes(const String &p_str) {
switch (current_option) {
case FILE_CLOSE_ALL_AND_QUIT:
case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
+ case FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT:
case FILE_CLOSE:
case FILE_CLOSE_OTHERS:
case FILE_CLOSE_RIGHT:
@@ -3055,13 +3071,19 @@ void EditorNode::_discard_changes(const String &p_str) {
_remove_scene(tab_closing);
_update_scene_tabs();
- if (current_option == FILE_CLOSE_ALL_AND_QUIT || current_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
+ if (current_option == FILE_CLOSE_ALL_AND_QUIT || current_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER || current_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
// If restore tabs is enabled, reopen the scene that has just been closed, so it's remembered properly.
if (bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) {
_menu_option_confirm(FILE_OPEN_PREV, true);
}
if (_next_unsaved_scene(false) == -1) {
- current_option = current_option == FILE_CLOSE_ALL_AND_QUIT ? FILE_QUIT : RUN_PROJECT_MANAGER;
+ if (current_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
+ current_option = RELOAD_CURRENT_PROJECT;
+ } else if (current_option == FILE_CLOSE_ALL_AND_QUIT) {
+ current_option = FILE_QUIT;
+ } else {
+ current_option = RUN_PROJECT_MANAGER;
+ }
_discard_changes();
} else {
_menu_option_confirm(current_option, false);
@@ -3098,6 +3120,9 @@ void EditorNode::_discard_changes(const String &p_str) {
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
} break;
+ case RELOAD_CURRENT_PROJECT: {
+ restart_editor();
+ } break;
}
}
@@ -6463,7 +6488,7 @@ EditorNode::EditorNode() {
tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RUN_RELOAD_CURRENT_PROJECT);
+ p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT);
ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::Q);
ED_SHORTCUT_OVERRIDE("editor/quit_to_project_list", "macos", KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::Q);
p->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 0b6dbaec49..0c9df16b2e 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -153,6 +153,7 @@ private:
FILE_CLOSE_ALL,
FILE_CLOSE_ALL_AND_QUIT,
FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER,
+ FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT,
FILE_QUIT,
FILE_EXTERNAL_OPEN_SCENE,
EDIT_UNDO,
@@ -169,7 +170,7 @@ private:
RUN_PLAY_CUSTOM_SCENE,
RUN_SETTINGS,
RUN_USER_DATA_FOLDER,
- RUN_RELOAD_CURRENT_PROJECT,
+ RELOAD_CURRENT_PROJECT,
RUN_PROJECT_MANAGER,
RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5057fc7531..1364f7891e 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -711,7 +711,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")
// SSL
- EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem")
+ EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
// Profiler
_initial_set("debugger/profiler_frame_history_size", 600);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index d713e70251..764f467192 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4324,8 +4324,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case UNLOCK_SELECTED: {
@@ -4346,8 +4346,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case GROUP_SELECTED: {
@@ -4368,8 +4368,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case UNGROUP_SELECTED: {
@@ -4390,8 +4390,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 0879d0dd18..cd95f97286 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -2873,10 +2873,16 @@ ProjectManager::ProjectManager() {
Vector2i window_size = DisplayServer::get_singleton()->window_get_size();
Vector2i screen_size = DisplayServer::get_singleton()->screen_get_size();
Vector2i screen_position = DisplayServer::get_singleton()->screen_get_position();
- window_size *= scale_factor;
+
+ // Consider the editor display scale.
+ window_size.x = round((float)window_size.x * scale_factor);
+ window_size.y = round((float)window_size.y * scale_factor);
+
+ // Make the window centered on the screen.
Vector2i window_position;
window_position.x = screen_position.x + (screen_size.x - window_size.x) / 2;
window_position.y = screen_position.y + (screen_size.y - window_size.y) / 2;
+
DisplayServer::get_singleton()->window_set_size(window_size);
DisplayServer::get_singleton()->window_set_position(window_position);
}
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 3b8c540592..44eb5c670d 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -96,8 +96,8 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
if (n->is_class("CanvasItem") || n->is_class("Node3D")) {
undo_redo->add_do_method(n, "remove_meta", "_edit_lock_");
undo_redo->add_undo_method(n, "set_meta", "_edit_lock_", true);
- undo_redo->add_do_method(this, "_update_tree", Variant());
- undo_redo->add_undo_method(this, "_update_tree", Variant());
+ undo_redo->add_do_method(this, "_update_tree");
+ undo_redo->add_undo_method(this, "_update_tree");
undo_redo->add_do_method(this, "emit_signal", "node_changed");
undo_redo->add_undo_method(this, "emit_signal", "node_changed");
}
@@ -114,8 +114,8 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
if (n->is_class("CanvasItem") || n->is_class("Node3D")) {
undo_redo->add_do_method(n, "remove_meta", "_edit_group_");
undo_redo->add_undo_method(n, "set_meta", "_edit_group_", true);
- undo_redo->add_do_method(this, "_update_tree", Variant());
- undo_redo->add_undo_method(this, "_update_tree", Variant());
+ undo_redo->add_do_method(this, "_update_tree");
+ undo_redo->add_undo_method(this, "_update_tree");
undo_redo->add_do_method(this, "emit_signal", "node_changed");
undo_redo->add_undo_method(this, "emit_signal", "node_changed");
}
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 4448acccc2..84694461cf 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -360,6 +360,15 @@ Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
}
bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the HTML5 platform currently as there
+ // is no suitable renderer to use with them. So we forbid exporting and tell
+ // users why. This is skipped in DEV_ENABLED so that contributors can still test
+ // the pipeline once we start having WebGL or WebGPU support.
+ r_error = "The HTML5 platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
+ return false;
+#endif
+
String err;
bool valid = false;
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 230e5c749c..88343d6f85 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -131,6 +131,14 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
}
bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the UWP platform currently as it
+ // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
+ // contributors can still test the pipeline if/when we can build it again.
+ r_error = "The UWP platform is currently not supported in Godot 4.0.\n";
+ return false;
+#endif
+
String err;
bool valid = false;
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index a2fed718be..c8eb270a0a 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -741,12 +741,12 @@ bool PropertyTweener::step(float &r_delta) {
}
float time = MIN(elapsed_time - delay, duration);
- target_instance->set_indexed(property, tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type));
-
if (time < duration) {
+ target_instance->set_indexed(property, tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type));
r_delta = 0;
return true;
} else {
+ target_instance->set_indexed(property, final_val);
finished = true;
r_delta = elapsed_time - delay - duration;
emit_signal(SNAME("finished"));
@@ -895,8 +895,13 @@ bool MethodTweener::step(float &r_delta) {
return true;
}
+ Variant current_val;
float time = MIN(elapsed_time - delay, duration);
- Variant current_val = tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type);
+ if (time < duration) {
+ current_val = tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type);
+ } else {
+ current_val = final_val;
+ }
const Variant **argptr = (const Variant **)alloca(sizeof(Variant *));
argptr[0] = &current_val;
@@ -938,6 +943,7 @@ MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to,
callback = p_callback;
initial_val = p_from;
delta_val = tween->calculate_delta_value(p_from, p_to);
+ final_val = p_to;
duration = p_duration;
}
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 5b0745b2b3..62c357dfb4 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -274,6 +274,7 @@ private:
Ref<Tween> tween;
Variant initial_val;
Variant delta_val;
+ Variant final_val;
Callable callback;
};
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 700ba761f6..ac10c2bad8 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -558,12 +558,12 @@ void HTTPRequest::set_https_proxy(const String &p_host, int p_port) {
client->set_https_proxy(p_host, p_port);
}
-void HTTPRequest::set_timeout(int p_timeout) {
+void HTTPRequest::set_timeout(double p_timeout) {
ERR_FAIL_COND(p_timeout < 0);
timeout = p_timeout;
}
-int HTTPRequest::get_timeout() {
+double HTTPRequest::get_timeout() {
return timeout;
}
@@ -615,7 +615,7 @@ void HTTPRequest::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "accept_gzip"), "set_accept_gzip", "is_accepting_gzip");
ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "timeout", PROPERTY_HINT_RANGE, "0,86400"), "set_timeout", "get_timeout");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "timeout", PROPERTY_HINT_RANGE, "0,3600,0.1,or_greater"), "set_timeout", "get_timeout");
ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "result"), PropertyInfo(Variant::INT, "response_code"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "headers"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "body")));
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 62880fa282..26d648458f 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -96,7 +96,7 @@ private:
int max_redirects = 8;
- int timeout = 0;
+ double timeout = 0;
void _redirect_request(const String &p_new_url);
@@ -146,8 +146,8 @@ public:
Timer *timer;
- void set_timeout(int p_timeout);
- int get_timeout();
+ void set_timeout(double p_timeout);
+ double get_timeout();
void _timeout();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index ec33e5752e..4525696071 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2001,30 +2001,58 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (from && p_event->is_pressed()) {
Control *next = nullptr;
- if (p_event->is_action_pressed("ui_focus_next", true, true)) {
- next = from->find_next_valid_focus();
- }
+ Ref<InputEventJoypadMotion> joypadmotion_event = p_event;
+ if (joypadmotion_event.is_valid()) {
+ Input *input = Input::get_singleton();
- if (p_event->is_action_pressed("ui_focus_prev", true, true)) {
- next = from->find_prev_valid_focus();
- }
+ if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
+ next = from->find_next_valid_focus();
+ }
- if (p_event->is_action_pressed("ui_up", true, true)) {
- next = from->_get_focus_neighbor(SIDE_TOP);
- }
+ if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
+ next = from->find_prev_valid_focus();
+ }
- if (p_event->is_action_pressed("ui_left", true, true)) {
- next = from->_get_focus_neighbor(SIDE_LEFT);
- }
+ if (p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
+ next = from->_get_focus_neighbor(SIDE_TOP);
+ }
- if (p_event->is_action_pressed("ui_right", true, true)) {
- next = from->_get_focus_neighbor(SIDE_RIGHT);
- }
+ if (p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
+ next = from->_get_focus_neighbor(SIDE_LEFT);
+ }
- if (p_event->is_action_pressed("ui_down", true, true)) {
- next = from->_get_focus_neighbor(SIDE_BOTTOM);
- }
+ if (p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
+ next = from->_get_focus_neighbor(SIDE_RIGHT);
+ }
+ if (p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
+ next = from->_get_focus_neighbor(SIDE_BOTTOM);
+ }
+ } else {
+ if (p_event->is_action_pressed("ui_focus_next", true, true)) {
+ next = from->find_next_valid_focus();
+ }
+
+ if (p_event->is_action_pressed("ui_focus_prev", true, true)) {
+ next = from->find_prev_valid_focus();
+ }
+
+ if (p_event->is_action_pressed("ui_up", true, true)) {
+ next = from->_get_focus_neighbor(SIDE_TOP);
+ }
+
+ if (p_event->is_action_pressed("ui_left", true, true)) {
+ next = from->_get_focus_neighbor(SIDE_LEFT);
+ }
+
+ if (p_event->is_action_pressed("ui_right", true, true)) {
+ next = from->_get_focus_neighbor(SIDE_RIGHT);
+ }
+
+ if (p_event->is_action_pressed("ui_down", true, true)) {
+ next = from->_get_focus_neighbor(SIDE_BOTTOM);
+ }
+ }
if (next) {
next->grab_focus();
set_input_as_handled();