diff --git a/resources/icons/cog.svg b/resources/icons/cog.svg new file mode 100644 index 000000000..07adb6610 --- /dev/null +++ b/resources/icons/cog.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/resources/icons/cooling.svg b/resources/icons/cooling.svg new file mode 100644 index 000000000..b5d80e434 --- /dev/null +++ b/resources/icons/cooling.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/funnel.svg b/resources/icons/funnel.svg new file mode 100644 index 000000000..8877722e3 --- /dev/null +++ b/resources/icons/funnel.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/resources/icons/infill.svg b/resources/icons/infill.svg new file mode 100644 index 000000000..fcb1f99c9 --- /dev/null +++ b/resources/icons/infill.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/note.svg b/resources/icons/note.svg new file mode 100644 index 000000000..c14214201 --- /dev/null +++ b/resources/icons/note.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/output+page_white.svg b/resources/icons/output+page_white.svg new file mode 100644 index 000000000..ec1518f25 --- /dev/null +++ b/resources/icons/output+page_white.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/resources/icons/printer.svg b/resources/icons/printer.svg new file mode 100644 index 000000000..91e103ec7 --- /dev/null +++ b/resources/icons/printer.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/resources/icons/skirt+brim.svg b/resources/icons/skirt+brim.svg new file mode 100644 index 000000000..9242761b6 --- /dev/null +++ b/resources/icons/skirt+brim.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/resources/icons/spool.svg b/resources/icons/spool.svg new file mode 100644 index 000000000..840365938 --- /dev/null +++ b/resources/icons/spool.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/support.svg b/resources/icons/support.svg new file mode 100644 index 000000000..65c7592c8 --- /dev/null +++ b/resources/icons/support.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/time.svg b/resources/icons/time.svg new file mode 100644 index 000000000..5d8f23cfc --- /dev/null +++ b/resources/icons/time.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/wrench.svg b/resources/icons/wrench.svg new file mode 100644 index 000000000..7966da8d8 --- /dev/null +++ b/resources/icons/wrench.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index f00e908ce..4c6e542f4 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -120,7 +120,7 @@ Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input) { Polygon retval; for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.push_back(Point( (*pit).X, (*pit).Y )); + retval.points.emplace_back(pit->X, pit->Y); return retval; } @@ -128,7 +128,7 @@ Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input) { Polyline retval; for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.push_back(Point( (*pit).X, (*pit).Y )); + retval.points.emplace_back(pit->X, pit->Y); return retval; } @@ -137,7 +137,7 @@ Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input) Slic3r::Polygons retval; retval.reserve(input.size()); for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(ClipperPath_to_Slic3rPolygon(*it)); + retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it)); return retval; } @@ -146,7 +146,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input Slic3r::Polylines retval; retval.reserve(input.size()); for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(ClipperPath_to_Slic3rPolyline(*it)); + retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it)); return retval; } @@ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) { ClipperLib::Path retval; for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) - retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); + retval.emplace_back((*pit)(0), (*pit)(1)); return retval; } @@ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) ClipperLib::Path output; output.reserve(input.points.size()); for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit) - output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); + output.emplace_back((*pit)(0), (*pit)(1)); return output; } @@ -189,7 +189,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input) { ClipperLib::Paths retval; for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); return retval; } @@ -197,7 +197,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) { ClipperLib::Paths retval; for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); return retval; } @@ -226,7 +226,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) { ClipperLib::Paths paths; - paths.push_back(std::move(input)); + paths.emplace_back(std::move(input)); return _offset(std::move(paths), endType, delta, joinType, miterLimit); } @@ -585,7 +585,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co Polylines polylines; polylines.reserve(subject.size()); for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon) - polylines.push_back(*polygon); // implicit call to split_at_first_point() + polylines.emplace_back(polygon->operator Polyline()); // implicit call to split_at_first_point() // perform clipping Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_); @@ -643,7 +643,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons // convert Polylines to Lines Lines retval; for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) - retval.push_back(*polyline); + retval.emplace_back(polyline->operator Line()); return retval; } @@ -673,7 +673,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) ordering_points.reserve(nodes.size()); for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { Point p((*it)->Contour.front().X, (*it)->Contour.front().Y); - ordering_points.push_back(p); + ordering_points.emplace_back(p); } // perform the ordering @@ -684,7 +684,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) { // traverse the next depth traverse_pt((*it)->Childs, retval); - retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); + retval->emplace_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); if ((*it)->IsHole()) retval->back().reverse(); // ccw } } @@ -791,8 +791,8 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons) Polygons out; out.reserve(polytree.ChildCount()); for (int i = 0; i < polytree.ChildCount(); ++i) - out.push_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); + out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); return out; } -} \ No newline at end of file +} diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b5b9a008d..ba898d9d5 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1187,8 +1187,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b else { TriangleMesh upper_mesh, lower_mesh; - // Transform the mesh by the combined transformation matrix - volume->mesh.transform(instance_matrix * volume_matrix); + // Transform the mesh by the combined transformation matrix. + // Flip the triangles in case the composite transformation is left handed. + volume->mesh.transform(instance_matrix * volume_matrix, true); // Perform cut TriangleMeshSlicer tms(&volume->mesh); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 6c04c7781..42c6fbf75 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1790,15 +1790,16 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, if (! volumes.empty()) { // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh; - for (const ModelVolume *v : volumes) - { - TriangleMesh vol_mesh(v->mesh); - vol_mesh.transform(v->get_matrix()); + TriangleMesh mesh(volumes.front()->mesh); + mesh.transform(volumes.front()->get_matrix(), true); + for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { + const ModelVolume &model_volume = *volumes[idx_volume]; + TriangleMesh vol_mesh(model_volume.mesh); + vol_mesh.transform(model_volume.get_matrix(), true); mesh.merge(vol_mesh); } if (mesh.stl.stats.number_of_facets > 0) { - mesh.transform(m_trafo); + mesh.transform(m_trafo, true); // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing @@ -1819,9 +1820,9 @@ std::vector PrintObject::_slice_volume(const std::vector &z, // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. TriangleMesh mesh(volume.mesh); - mesh.transform(volume.get_matrix()); + mesh.transform(volume.get_matrix(), true); if (mesh.stl.stats.number_of_facets > 0) { - mesh.transform(m_trafo); + mesh.transform(m_trafo, true); // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7dc920517..809b32d90 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1041,31 +1041,37 @@ void SLAPrint::process() { ClipperPolygon poly; + // We need to reverse if flpXY OR is_lefthanded is true but + // not if both are true which is a logical inequality (XOR) + bool needreverse = flpXY != is_lefthanded; + // should be a move poly.Contour.reserve(polygon.contour.size() + 1); - for(auto& p : polygon.contour.points) - poly.Contour.emplace_back(p.x(), p.y()); - - auto pfirst = poly.Contour.front(); - poly.Contour.emplace_back(pfirst); + auto& cntr = polygon.contour.points; + if(needreverse) + for(auto it = cntr.rbegin(); it != cntr.rend(); ++it) + poly.Contour.emplace_back(it->x(), it->y()); + else + for(auto& p : cntr) + poly.Contour.emplace_back(p.x(), p.y()); for(auto& h : polygon.holes) { poly.Holes.emplace_back(); auto& hole = poly.Holes.back(); hole.reserve(h.points.size() + 1); - for(auto& p : h.points) hole.emplace_back(p.x(), p.y()); - auto pfirst = hole.front(); hole.emplace_back(pfirst); + if(needreverse) + for(auto& p : h.points) + hole.emplace_back(p.x(), p.y()); + else + for(auto it = h.points.rbegin(); it != h.points.rend(); ++it) + hole.emplace_back(it->x(), it->y()); } if(is_lefthanded) { for(auto& p : poly.Contour) p.X = -p.X; - std::reverse(poly.Contour.begin(), poly.Contour.end()); - for(auto& h : poly.Holes) { - for(auto& p : h) p.X = -p.X; - std::reverse(h.begin(), h.end()); - } + for(auto& h : poly.Holes) for(auto& p : h) p.X = -p.X; } sl::rotate(poly, double(instances[i].rotation)); @@ -1074,12 +1080,7 @@ void SLAPrint::process() if (flpXY) { for(auto& p : poly.Contour) std::swap(p.X, p.Y); - std::reverse(poly.Contour.begin(), poly.Contour.end()); - - for(auto& h : poly.Holes) { - for(auto& p : h) std::swap(p.X, p.Y); - std::reverse(h.begin(), h.end()); - } + for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y); } polygons.emplace_back(std::move(poly)); diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c145380c9..0d9a79978 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -314,10 +314,15 @@ void TriangleMesh::mirror(const Axis &axis) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::transform(const Transform3d& t) +void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) { stl_transform(&stl, t); stl_invalidate_shared_vertices(&stl); + if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { + // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. + this->repair(); + stl_reverse_all_facets(&stl); + } } void TriangleMesh::align_to_origin() diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index a65a4be75..527846f9d 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -49,7 +49,7 @@ public: void mirror_x() { this->mirror(X); } void mirror_y() { this->mirror(Y); } void mirror_z() { this->mirror(Z); } - void transform(const Transform3d& t); + void transform(const Transform3d& t, bool fix_left_handed = false); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 224bb802e..c0dcc659d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -507,7 +507,6 @@ void ObjectList::key_event(wxKeyEvent& event) || event.GetKeyCode() == WXK_BACK #endif //__WXOSX__ ) { - printf("WXK_BACK\n"); remove(); } else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 6c8fdcab7..61e98d542 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -179,7 +179,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) changed_box = true; } if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) - m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size; + m_new_size = (volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size).cwiseAbs(); } else // this should never happen @@ -209,7 +209,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = volume->get_volume_offset(); m_new_rotation = volume->get_volume_rotation(); m_new_scale = volume->get_volume_scaling_factor(); - m_new_size = volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size(); + m_new_size = (volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size()).cwiseAbs(); m_new_enabled = true; } else if (wxGetApp().obj_list()->multiple_selection()) diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 4c0879ad3..cd995bc09 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -85,7 +85,8 @@ void ObjectSettings::update_settings_list() #endif // __WXMSW__ btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { config->erase(opt_key); - wxTheApp->CallAfter([this]() { + wxGetApp().obj_list()->part_settings_changed(); + wxTheApp->CallAfter([this]() { wxWindowUpdateLocker noUpdates(m_parent); update_settings_list(); m_parent->Layout(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d0e0651be..cb52bccde 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -329,8 +329,12 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous m_canvas_width = m_parent.get_canvas_size().get_width(); m_canvas_height = m_parent.get_canvas_size().get_height(); } - else - select_point(m_hover_id); + else { + if (m_editing_mode_cache[m_hover_id].selected) + unselect_point(m_hover_id); + else + select_point(m_hover_id); + } return true; } @@ -562,12 +566,12 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f)); + const ImVec2 window_size(m_imgui->scaled(17.f, 18.f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); m_imgui->set_next_window_bg_alpha(0.5f); - m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); ImGui::PushItemWidth(100.0f); @@ -788,6 +792,19 @@ void GLGizmoSlaSupports::select_point(int i) } +void GLGizmoSlaSupports::unselect_point(int i) +{ + m_editing_mode_cache[i].selected = false; + m_selection_empty = true; + for (const CacheEntry& ce : m_editing_mode_cache) { + if (ce.selected) { + m_selection_empty = false; + break; + } + } +} + + void GLGizmoSlaSupports::editing_mode_discard_changes() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 95af05fd5..126aeab6e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -94,6 +94,7 @@ private: NoPoints, }; void select_point(int i); + void unselect_point(int i); void editing_mode_apply_changes(); void editing_mode_discard_changes(); void editing_mode_reload_cache(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 2eb6d985f..03c83cf51 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -341,13 +341,11 @@ bool ImGuiWrapper::want_any_input() const void ImGuiWrapper::init_font() { - const float font_size = m_font_size * m_style_scaling; - destroy_font(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size, nullptr, m_glyph_ranges); + ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), m_font_size, nullptr, m_glyph_ranges); if (font == nullptr) { font = io.Fonts->AddFontDefault(); if (font == nullptr) { diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index c1bf491e1..b593054c4 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -45,8 +45,8 @@ public: void new_frame(); void render(); - float scaled(float x) const { return x * m_font_size * m_style_scaling; } - ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + float scaled(float x) const { return x * m_font_size; } + ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); } ImVec2 calc_text_size(const wxString &text); void set_next_window_pos(float x, float y, int flag); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index bcf9bb61c..0ae6199e1 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -109,21 +109,26 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) if (is_wipe_tower() && volume->is_wipe_tower) return; + bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance()); + // resets the current list if needed bool needs_reset = as_single_selection; needs_reset |= volume->is_wipe_tower; needs_reset |= is_wipe_tower() && !volume->is_wipe_tower; - needs_reset |= !is_modifier() && volume->is_modifier; + needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier; needs_reset |= is_modifier() && !volume->is_modifier; if (needs_reset) clear(); if (!contains_volume(volume_idx)) - m_mode = volume->is_modifier ? Volume : Instance; + { + if (!keep_instance_mode) + m_mode = volume->is_modifier ? Volume : Instance; + } else - // keep current mode - return; + // keep current mode + return; switch (m_mode) { @@ -1143,16 +1148,12 @@ void Selection::update_type() } if (modifiers_count == 0) - { m_type = MultipleVolume; - requires_disable = true; - } else if (modifiers_count == (unsigned int)m_list.size()) - { m_type = MultipleModifier; - requires_disable = true; - } } + + requires_disable = true; } else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) {