mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-02 04:31:17 -07:00
Merge branch 'master' of https://github.com/prusa3d/Slic3r into et_canvas_gui_refactoring
This commit is contained in:
commit
6d9180ba92
26 changed files with 348 additions and 68 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1790,15 +1790,16 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &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<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||
// perform actual slicing
|
||||
|
|
@ -1819,9 +1820,9 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &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<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||
// perform actual slicing
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue