diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index e474ca642a..8e82e21862 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -173,6 +173,9 @@ void AppConfig::set_defaults() if (get("use_free_camera").empty()) set_bool("use_free_camera", false); + if (get("camera_navigation_style").empty()) + set("camera_navigation_style", "0"); + #ifdef SUPPORT_REVERSE_MOUSE_ZOOM if (get("reverse_mouse_wheel_zoom").empty()) set_bool("reverse_mouse_wheel_zoom", false); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 227c93d15a..5bf629ccde 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1137,6 +1137,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_multisample_allowed(false) , m_moving(false) , m_tab_down(false) + , m_camera_movement(false) , m_cursor_type(Standard) , m_color_by("volume") , m_reload_delayed(false) @@ -3853,7 +3854,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.ignore_left_up = true; m_tooltip.set_in_imgui(false); if (imgui->update_mouse_data(evt)) { - if (evt.LeftDown() && m_canvas != nullptr) + if ((evt.LeftDown() || (evt.Moving() && (evt.AltDown() || evt.ShiftDown()))) && m_canvas != nullptr) m_canvas->SetFocus(); m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast(); m_tooltip.set_in_imgui(true); @@ -4172,7 +4173,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } - else if (evt.Dragging()) { + else if (evt.Dragging() || is_camera_rotate(evt) || is_camera_pan(evt)) { m_mouse.dragging = true; if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) { @@ -4182,7 +4183,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } // do not process the dragging if the left mouse was set down in another canvas - else if (evt.LeftIsDown()) { + else if (is_camera_rotate(evt)) { // Orca: Sphere rotation for painting view // if dragging over blank area with left button, rotate if ((any_gizmo_active || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) { @@ -4244,9 +4245,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } + m_camera_movement = true; m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); } - else if (evt.MiddleIsDown() || evt.RightIsDown()) { + else if (is_camera_pan(evt)) { // If dragging over blank area with right button, pan. if (m_mouse.is_start_position_2D_defined()) { // get point in model space at Z = 0 @@ -4268,10 +4270,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.ignore_right_up = true; } + m_camera_movement = true; m_mouse.drag.start_position_2D = pos; } } - else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) { + else if ((evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) || + (m_camera_movement && !is_camera_rotate(evt) && !is_camera_pan(evt))) { m_mouse.position = pos.cast(); if (evt.LeftUp()) { @@ -4450,6 +4454,25 @@ void GLCanvas3D::on_set_focus(wxFocusEvent& evt) } _refresh_if_shown_on_screen(); m_tooltip_enabled = true; + m_is_touchpad_navigation = wxGetApp().app_config->get_bool("camera_navigation_style"); +} + +bool GLCanvas3D::is_camera_rotate(const wxMouseEvent& evt) const +{ + if (m_is_touchpad_navigation) { + return evt.Moving() && evt.AltDown() && !evt.ShiftDown(); + } else { + return evt.Dragging() && evt.LeftIsDown(); + } +} + +bool GLCanvas3D::is_camera_pan(const wxMouseEvent& evt) const +{ + if (m_is_touchpad_navigation) { + return evt.Moving() && evt.ShiftDown() && !evt.AltDown(); + } else { + return evt.Dragging() && (evt.MiddleIsDown() || evt.RightIsDown()); + } } Size GLCanvas3D::get_canvas_size() const @@ -5052,6 +5075,7 @@ void GLCanvas3D::export_toolpaths_to_obj(const char* filename) const void GLCanvas3D::mouse_up_cleanup() { m_moving = false; + m_camera_movement = false; m_mouse.drag.move_volume_idx = -1; m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 6f9de7c9ad..bed5ac3ae1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -551,6 +551,8 @@ private: std::array m_old_size{ 0, 0 }; + bool m_is_touchpad_navigation{ false }; + // Screen is only refreshed from the OnIdle handler if it is dirty. bool m_dirty; bool m_initialized; @@ -564,6 +566,7 @@ private: bool m_multisample_allowed; bool m_moving; bool m_tab_down; + bool m_camera_movement; //BBS: add toolpath outside bool m_toolpath_outside{ false }; ECursorType m_cursor_type; @@ -963,6 +966,9 @@ public: void on_set_focus(wxFocusEvent& evt); void force_set_focus(); + bool is_camera_rotate(const wxMouseEvent& evt) const; + bool is_camera_pan(const wxMouseEvent& evt) const; + Size get_canvas_size() const; Vec2d get_local_mouse_position() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1894e1d35c..5284595e0b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5275,6 +5275,7 @@ void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_ // so we put it into an inner scope PreferencesDialog dlg(mainframe, open_on_tab, highlight_option); dlg.ShowModal(); + this->plater_->get_current_canvas3D()->force_set_focus(); // BBS //app_layout_changed = dlg.settings_layout_changed(); #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 7e06f6e17d..c25b14d7e1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -589,6 +589,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ { PreferencesDialog dlg(this); dlg.ShowModal(); + plater()->get_current_canvas3D()->force_set_focus(); #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed()) #else @@ -2703,6 +2704,7 @@ void MainFrame::init_menubar_as_editor() [this](wxCommandEvent &) { PreferencesDialog dlg(this); dlg.ShowModal(); + plater()->get_current_canvas3D()->force_set_focus(); #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed()) #else @@ -2729,6 +2731,7 @@ void MainFrame::init_menubar_as_editor() [this](wxCommandEvent &) { PreferencesDialog dlg(this); dlg.ShowModal(); + plater()->get_current_canvas3D()->force_set_focus(); #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed()) #else diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index d5dd87da15..f54fe37cda 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1019,6 +1019,9 @@ wxWindow* PreferencesDialog::create_general_page() std::vector DefaultPage = {_L("Home"), _L("Prepare")}; auto item_default_page = create_item_combobox(_L("Default Page"), page, _L("Set the page opened on startup."), "default_page", DefaultPage); + std::vector CameraNavStyle = {_L("Default"), _L("Touchpad")}; + auto item_camera_navigation_style = create_item_combobox(_L("Camera style"), page, _L("Select camera navigation style.\nDefault: LMB+move for rotation, RMB/MMB+move for panning.\nTouchpad: Alt+move for rotation, Shift+move for panning."), "camera_navigation_style", CameraNavStyle); + auto item_mouse_zoom_settings = create_item_checkbox(_L("Zoom to mouse position"), page, _L("Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center."), 50, "zoom_to_mouse"); auto item_use_free_camera_settings = create_item_checkbox(_L("Use free camera"), page, _L("If enabled, use free camera. If not enabled, use constrained camera."), 50, "use_free_camera"); @@ -1083,6 +1086,7 @@ wxWindow* PreferencesDialog::create_general_page() sizer_page->Add(item_region, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_currency, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_default_page, 0, wxTOP, FromDIP(3)); + sizer_page->Add(item_camera_navigation_style, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_mouse_zoom_settings, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_use_free_camera_settings, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_show_splash_screen, 0, wxTOP, FromDIP(3));