diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 154947e2db..e1b77e5f00 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -39,6 +39,9 @@ public: int get_thumbnail_bed_idx() const { return m_bed_for_thumbnails_generation; } bool is_glvolume_on_thumbnail_bed(const Model& model, int obj_idx, int instance_idx) const; + void set_last_hovered_bed(int i) { m_last_hovered_bed = i; } + int get_last_hovered_bed() const { return m_last_hovered_bed; } + private: @@ -52,7 +55,7 @@ private: bool m_show_next_bed = false; std::map m_inst_to_bed; std::map m_printbase_to_texture; - + int m_last_hovered_bed = -1; }; extern MultipleBeds s_multiple_beds; diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 2c825b0235..0d556d0f5f 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -110,7 +110,7 @@ void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Tra { bool is_thumbnail = s_multiple_beds.get_thumbnail_bed_idx() != -1; bool is_preview = wxGetApp().plater()->is_preview_shown(); - int bed_to_highlight = -1; + int bed_to_highlight = s_multiple_beds.get_active_bed(); static std::vector beds_to_render; beds_to_render.clear(); @@ -121,14 +121,12 @@ void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Tra else { beds_to_render.resize(s_multiple_beds.get_number_of_beds() + int(s_multiple_beds.should_show_next_bed())); std::iota(beds_to_render.begin(), beds_to_render.end(), 0); - if (s_multiple_beds.get_number_of_beds() != 1) - bed_to_highlight = s_multiple_beds.get_active_bed(); } for (int i : beds_to_render) { Transform3d mat = view_matrix; mat.translate(s_multiple_beds.get_bed_translation(i)); - render_internal(canvas, mat, projection_matrix, bottom, scale_factor, show_texture, false, i == bed_to_highlight); + render_internal(canvas, mat, projection_matrix, bottom, scale_factor, show_texture, false, is_thumbnail || i == bed_to_highlight); } } @@ -150,9 +148,9 @@ void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, switch (m_type) { - case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom, show_texture); break; } + case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom, show_texture, active); break; } default: - case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom, show_texture, picking); break; } + case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom, show_texture, picking, active); break; } } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -335,18 +333,18 @@ void Bed3D::render_axes() m_axes.render(Transform3d::Identity(), 0.25f); } -void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture) +void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool is_active) { if (!bottom) render_model(view_matrix, projection_matrix); if (show_texture) - render_texture(bottom, canvas, view_matrix, projection_matrix); + render_texture(bottom, canvas, view_matrix, projection_matrix, is_active); else if (bottom) render_contour(view_matrix, projection_matrix); } -void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix) +void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool is_active) { if (m_texture_filename.empty()) { m_texture.reset(); @@ -414,7 +412,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& v shader->start_using(); shader->set_uniform("view_model_matrix", view_matrix); shader->set_uniform("projection_matrix", projection_matrix); - shader->set_uniform("transparent_background", bottom); + shader->set_uniform("transparent_background", bottom || ! is_active); shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg")); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -489,7 +487,7 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj } } -void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking) +void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking, bool is_active) { if (m_texture_filename.empty() && m_model_filename.empty()) { render_default(bottom, picking, show_texture, view_matrix, projection_matrix); @@ -500,7 +498,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, co render_model(view_matrix, projection_matrix); if (show_texture) - render_texture(bottom, canvas, view_matrix, projection_matrix); + render_texture(bottom, canvas, view_matrix, projection_matrix, is_active); else if (bottom) render_contour(view_matrix, projection_matrix); } diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 08f65eca35..27e6714712 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -87,10 +87,10 @@ private: static std::tuple detect_type(const Pointfs& shape); void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture, bool picking, bool active); - void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture); - void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix); + void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool is_active); + void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool is_active); void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix); - void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking); + void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture, bool picking, bool is_active); void render_default(bool bottom, bool picking, bool show_texture, const Transform3d& view_matrix, const Transform3d& projection_matrix); void render_contour(const Transform3d& view_matrix, const Transform3d& projection_matrix); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 47f66b6933..42a05135bf 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -102,6 +102,24 @@ static bool show_imgui_demo_window = false; namespace Slic3r { namespace GUI { +static void select_bed(int i) +{ + int old_bed = s_multiple_beds.get_active_bed(); + if (i == old_bed || i == -1) + return; + + s_multiple_beds.set_active_bed(i); + if (wxGetApp().plater()->is_preview_shown()) { + s_reload_preview_after_switching_beds = true; + wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); + wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); + } + wxGetApp().plater()->sidebar().update_sliced_info_sizer(); +} + + + + #ifdef __WXGTK3__ // wxGTK3 seems to simulate OSX behavior in regard to HiDPI scaling support. RetinaHelper::RetinaHelper(wxWindow* window) : m_window(window), m_self(nullptr) {} @@ -1460,7 +1478,6 @@ bool GLCanvas3D::check_volumes_outside_state(GLVolumeCollection& volumes, ModelI bool contained_min_one = false; const Slic3r::BuildVolume& build_volume = m_bed.build_volume(); - s_multiple_beds.request_next_bed(false); const std::vector volumes_idxs = volumes_to_process_idxs(); for (unsigned int vol_idx : volumes_idxs) { @@ -1834,22 +1851,14 @@ void GLCanvas3D::render() { - if (s_multiple_beds.get_number_of_beds() != 1) { + if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) { ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize); for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) { bool inactive = i != s_multiple_beds.get_active_bed(); if (inactive) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5)); - if (ImGui::ImageButton((void*)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0))) { - int old_bed = s_multiple_beds.get_active_bed(); - s_multiple_beds.set_active_bed(i); - if (wxGetApp().plater()->is_preview_shown()) { - s_reload_preview_after_switching_beds = true; - wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); - camera.translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); - } - wxGetApp().plater()->sidebar().update_sliced_info_sizer(); - } + if (ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0))) + select_bed(i); if (inactive) ImGui::PopStyleColor(); } @@ -3281,10 +3290,11 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) void GLCanvas3D::on_render_timer(wxTimerEvent& evt) { + m_dirty = true; + // no need to wake up idle // right after this event, idle event is fired - // m_dirty = true; - // wxWakeUpIdle(); + //wxWakeUpIdle(); } @@ -3376,6 +3386,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) Point pos(evt.GetX(), evt.GetY()); + static wxTimer s_virtual_bed_timer; + s_virtual_bed_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) { s_multiple_beds.request_next_bed(true); schedule_extra_frame(100); }); + ImGuiWrapper* imgui = wxGetApp().imgui(); if (m_tooltip.is_in_imgui() && evt.LeftUp()) // ignore left up events coming from imgui windows and not processed by them @@ -3613,6 +3626,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); m_dirty = true; } + } else if (evt.LeftDown()) { + select_bed(s_multiple_beds.get_last_hovered_bed()); } } @@ -3640,6 +3655,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Dragging() && evt.LeftIsDown() && !evt.CmdDown() && m_layers_editing.state == LayersEditing::Unknown && m_mouse.drag.move_volume_idx != -1 && m_mouse.is_start_position_3D_defined()) { if (!m_mouse.drag.move_requires_threshold) { + static bool was_dragging = false; + was_dragging = m_mouse.dragging; m_mouse.dragging = true; Vec3d cur_pos = m_mouse.drag.start_position_3D; // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag @@ -3682,6 +3699,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) update_sequential_clearance(false); wxGetApp().obj_manipul()->set_dirty(); m_dirty = true; + + const Selection::IndicesList& list = m_selection.get_volume_idxs(); + static bool was_outside = true; + bool is_outside = std::any_of(list.begin(), list.end(), [this](unsigned int i) { return m_volumes.volumes[i]->is_outside; }); + if (is_outside && (! was_dragging || ! was_outside)) + s_virtual_bed_timer.Start(1000, true); + was_outside = is_outside; } } else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) { @@ -3754,6 +3778,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_layers_editing.accept_changes(*this); } else if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) { + s_multiple_beds.request_next_bed(false); + s_virtual_bed_timer.Stop(); do_move(L("Move Object")); wxGetApp().obj_manipul()->set_dirty(); m_sequential_print_clearance.stop_dragging(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f600c67434..e485302d09 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2052,8 +2052,8 @@ void Plater::priv::scale_selection_to_fit_print_volume() void Plater::priv::schedule_background_process() { delayed_error_message.clear(); - // Trigger the timer event after 0.5s - this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); + // Trigger the timer event after 0.1s + this->background_process_timer.Start(100, wxTIMER_ONE_SHOT); // Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff. this->view3D->get_canvas3d()->set_config(this->config); } @@ -3277,7 +3277,8 @@ void Plater::priv::on_right_click(RBtnEvent& evt) if (evt.data.second) { // right button was clicked on empty space if (!get_selection().is_empty()) // several objects are selected in 3DScene return; - menu = menus.default_menu(); + if (s_multiple_beds.get_last_hovered_bed() != -1) + menu = menus.default_menu(); } else menu = menus.multi_selection_menu(); diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 96be46de29..aeb65c826f 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -10,6 +10,8 @@ #include "Selection.hpp" #include "Plater.hpp" +#include "libslic3r/MultipleBeds.hpp" + namespace Slic3r { namespace GUI { @@ -164,9 +166,27 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (!item->is_active()) continue; + bool sth_hit = false; + current_hit.raycaster_id = item->get_id(); - const Transform3d& trafo = item->get_transform(); - if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) { + const Transform3d& trafo_orig = item->get_transform(); + Transform3d trafo = trafo_orig; + if (type == EType::Bed) { + int bed_idx_hit = -1; + for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) { + trafo = trafo_orig; + trafo.translate(s_multiple_beds.get_bed_translation(i)); + sth_hit = item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane); + if (sth_hit) { + bed_idx_hit = i; + break; + } + } + s_multiple_beds.set_last_hovered_bed(bed_idx_hit); + } else + sth_hit = item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane); + + if (sth_hit) { current_hit.position = (trafo * current_hit.position.cast()).cast(); current_hit.normal = (trafo.matrix().block(0, 0, 3, 3).inverse().transpose() * current_hit.normal.cast()).normalized().cast(); if (item->use_back_faces() || current_hit.normal.dot(camera_forward) < 0.0f) {