diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 698cc836cd9..29aa609aa78 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1671,6 +1671,33 @@ void Node3DEditorViewport::_list_select(Ref b) { } } +// Helper function to redirect mouse events to the active freelook viewport +static bool _redirect_freelook_input(const Ref &p_event, Node3DEditorViewport *p_exclude_viewport = nullptr) { + if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED) { + return false; + } + + Node3DEditor *editor = Node3DEditor::get_singleton(); + if (!editor->get_freelook_viewport()) { + return false; + } + + Node3DEditorViewport *freelook_vp = editor->get_freelook_viewport(); + if (freelook_vp == p_exclude_viewport) { + return false; + } + + Ref mouse_event = p_event; + if (!mouse_event.is_valid()) { + return false; + } + + Control *target_surface = freelook_vp->get_surface(); + + target_surface->emit_signal(SceneStringName(gui_input), p_event); + return true; +} + // This is only active during instant transforms, // to capture and wrap mouse events outside the control. void Node3DEditorViewport::input(const Ref &p_event) { @@ -1688,6 +1715,10 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { return; //do NONE } + if (_redirect_freelook_input(p_event, this)) { + return; + } + EditorPlugin::AfterGUIInput after = EditorPlugin::AFTER_GUI_INPUT_PASS; { EditorNode *en = EditorNode::get_singleton(); @@ -2702,6 +2733,8 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) { previous_mouse_position = get_local_mouse_position(); + spatial_editor->set_freelook_viewport(this); + // Hide mouse like in an FPS (warping doesn't work) Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); @@ -2709,6 +2742,8 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) { // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential cursor = camera_cursor; + spatial_editor->set_freelook_viewport(nullptr); + // Restore mouse Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); @@ -5990,6 +6025,10 @@ Node3DEditorViewport::~Node3DEditorViewport() { void Node3DEditorViewportContainer::gui_input(const Ref &p_event) { ERR_FAIL_COND(p_event.is_null()); + if (_redirect_freelook_input(p_event)) { + return; + } + Ref mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { @@ -6084,7 +6123,7 @@ void Node3DEditorViewportContainer::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - if (mouseover) { + if (mouseover && Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED) { Ref h_grabber = get_theme_icon(SNAME("grabber"), SNAME("HSplitContainer")); Ref v_grabber = get_theme_icon(SNAME("grabber"), SNAME("VSplitContainer")); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 5a8d54c9f4b..ac8d43293c9 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -560,6 +560,7 @@ public: SubViewport *get_viewport_node() { return viewport; } Camera3D *get_camera_3d() { return camera; } // return the default camera object. + Control *get_surface() { return surface; } Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p_index); ~Node3DEditorViewport(); @@ -825,6 +826,8 @@ private: Node3D *selected = nullptr; + Node3DEditorViewport *freelook_viewport = nullptr; + void _request_gizmo(Object *p_obj); void _request_gizmo_for_id(ObjectID p_id); void _set_subgizmo_selection(Object *p_obj, Ref p_gizmo, int p_id, Transform3D p_transform = Transform3D()); @@ -1025,6 +1028,9 @@ public: } Node3DEditorViewport *get_last_used_viewport(); + void set_freelook_viewport(Node3DEditorViewport *p_viewport) { freelook_viewport = p_viewport; } + Node3DEditorViewport *get_freelook_viewport() const { return freelook_viewport; } + void add_gizmo_plugin(Ref p_plugin); void remove_gizmo_plugin(Ref p_plugin);