From 126f0e50734ce69b9961e6c0549a98bf2f308dcb Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 22 Oct 2018 11:45:03 +0200 Subject: [PATCH 1/8] Added mirroring factors to .amf import/export --- src/libslic3r/Format/AMF.cpp | 87 ++++++++++++++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.cpp | 14 ++---- src/slic3r/GUI/GUI_Utils.cpp | 1 + src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 21 +++++++-- 5 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 00ed0d937..be0261634 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -32,6 +32,9 @@ // 2 : Added z component of offset // Added x and y components of rotation // Added x, y and z components of scale +#if ENABLE_MIRROR +// Added x, y and z components of mirror +#endif // ENABLE_MIRROR const unsigned int VERSION_AMF = 2; const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; @@ -126,14 +129,27 @@ struct AMFParserContext NODE_TYPE_RY, // amf/constellation/instance/ry NODE_TYPE_RZ, // amf/constellation/instance/rz NODE_TYPE_SCALE, // amf/constellation/instance/scale - NODE_TYPE_SCALEX, // amf/constellation/instance/scalex - NODE_TYPE_SCALEY, // amf/constellation/instance/scaley - NODE_TYPE_SCALEZ, // amf/constellation/instance/scalez + NODE_TYPE_SCALEX, // amf/constellation/instance/scalex + NODE_TYPE_SCALEY, // amf/constellation/instance/scaley + NODE_TYPE_SCALEZ, // amf/constellation/instance/scalez +#if ENABLE_MIRROR + NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx + NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory + NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz +#endif // ENABLE_MIRROR NODE_TYPE_METADATA, // anywhere under amf/*/metadata }; struct Instance { +#if ENABLE_MIRROR + Instance() + : deltax_set(false), deltay_set(false), deltaz_set(false) + , rx_set(false), ry_set(false), rz_set(false) + , scalex_set(false), scaley_set(false), scalez_set(false) + , mirrorx_set(false), mirrory_set(false), mirrorz_set(false) {} +#else Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rx_set(false), ry_set(false), rz_set(false), scalex_set(false), scaley_set(false), scalez_set(false) {} +#endif // ENABLE_MIRROR // Shift in the X axis. float deltax; bool deltax_set; @@ -159,6 +175,15 @@ struct AMFParserContext bool scaley_set; float scalez; bool scalez_set; +#if ENABLE_MIRROR + // Mirroring factors + float mirrorx; + bool mirrorx_set; + float mirrory; + bool mirrory_set; + float mirrorz; + bool mirrorz_set; +#endif // ENABLE_MIRROR }; struct Object { @@ -289,6 +314,14 @@ void AMFParserContext::startElement(const char *name, const char **atts) node_type_new = NODE_TYPE_SCALEZ; else if (strcmp(name, "scale") == 0) node_type_new = NODE_TYPE_SCALE; +#if ENABLE_MIRROR + else if (strcmp(name, "mirrorx") == 0) + node_type_new = NODE_TYPE_MIRRORX; + else if (strcmp(name, "mirrory") == 0) + node_type_new = NODE_TYPE_MIRRORY; + else if (strcmp(name, "mirrorz") == 0) + node_type_new = NODE_TYPE_MIRRORZ; +#endif // ENABLE_MIRROR } break; case 4: @@ -345,16 +378,23 @@ void AMFParserContext::characters(const XML_Char *s, int len) { switch (m_path.size()) { case 4: - if (m_path.back() == NODE_TYPE_DELTAX || - m_path.back() == NODE_TYPE_DELTAY || - m_path.back() == NODE_TYPE_DELTAZ || + if (m_path.back() == NODE_TYPE_DELTAX || + m_path.back() == NODE_TYPE_DELTAY || + m_path.back() == NODE_TYPE_DELTAZ || m_path.back() == NODE_TYPE_RX || m_path.back() == NODE_TYPE_RY || m_path.back() == NODE_TYPE_RZ || m_path.back() == NODE_TYPE_SCALEX || m_path.back() == NODE_TYPE_SCALEY || m_path.back() == NODE_TYPE_SCALEZ || +#if ENABLE_MIRROR + m_path.back() == NODE_TYPE_SCALE || + m_path.back() == NODE_TYPE_MIRRORX || + m_path.back() == NODE_TYPE_MIRRORY || + m_path.back() == NODE_TYPE_MIRRORZ) +#else m_path.back() == NODE_TYPE_SCALE) +#endif // ENABLE_MIRROR m_value[0].append(s, len); break; case 6: @@ -446,6 +486,26 @@ void AMFParserContext::endElement(const char * /* name */) m_instance->scalez_set = true; m_value[0].clear(); break; +#if ENABLE_MIRROR + case NODE_TYPE_MIRRORX: + assert(m_instance); + m_instance->mirrorx = float(atof(m_value[0].c_str())); + m_instance->mirrorx_set = true; + m_value[0].clear(); + break; + case NODE_TYPE_MIRRORY: + assert(m_instance); + m_instance->mirrory = float(atof(m_value[0].c_str())); + m_instance->mirrory_set = true; + m_value[0].clear(); + break; + case NODE_TYPE_MIRRORZ: + assert(m_instance); + m_instance->mirrorz = float(atof(m_value[0].c_str())); + m_instance->mirrorz_set = true; + m_value[0].clear(); + break; +#endif // ENABLE_MIRROR // Object vertices: case NODE_TYPE_VERTEX: @@ -585,6 +645,9 @@ void AMFParserContext::endDocument() mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0)); +#if ENABLE_MIRROR + mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0)); +#endif // ENABLE_MIRROR } } } @@ -891,6 +954,11 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c " <scalex>%lf</scalex>\n" " <scaley>%lf</scaley>\n" " <scalez>%lf</scalez>\n" +#if ENABLE_MIRROR + " <mirrorx>%lf</mirrorx>\n" + " <mirrory>%lf</mirrory>\n" + " <mirrorz>%lf</mirrorz>\n" +#endif // ENABLE_MIRROR " </instance>\n", object_id, instance->get_offset(X), @@ -901,7 +969,14 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c instance->get_rotation(Z), instance->get_scaling_factor(X), instance->get_scaling_factor(Y), +#if ENABLE_MIRROR + instance->get_scaling_factor(Z), + instance->get_mirror(X), + instance->get_mirror(Y), + instance->get_mirror(Z)); +#else instance->get_scaling_factor(Z)); +#endif // ENABLE_MIRROR //FIXME missing instance->scaling_factor instances.append(buf); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4bb0f499f..7d47ff8f6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3432,7 +3432,6 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const #if ENABLE_EXTENDED_SELECTION void GLCanvas3D::mirror_selection(Axis axis) { - m_regenerate_volumes = false; m_selection.mirror(axis); _on_mirror(); wxGetApp().obj_manipul()->update_settings_value(m_selection); @@ -3457,7 +3456,12 @@ void GLCanvas3D::reload_scene(bool force) #if ENABLE_EXTENDED_SELECTION if (m_regenerate_volumes) + { reset_volumes(); + + // to update the toolbar + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + } #endif // ENABLE_EXTENDED_SELECTION set_bed_shape(dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"))->values); @@ -3477,9 +3481,6 @@ void GLCanvas3D::reload_scene(bool force) { load_object(*m_model, obj_idx); } - - // to update the toolbar - post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); } update_gizmos_data(); @@ -3858,7 +3859,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Scale: { #if ENABLE_EXTENDED_SELECTION - m_regenerate_volumes = false; m_selection.scale(m_gizmos.get_scale()); _on_scale(); #else @@ -3875,7 +3875,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { #if ENABLE_EXTENDED_SELECTION - m_regenerate_volumes = false; m_selection.rotate(m_gizmos.get_rotation()); _on_rotate(); #else @@ -3958,7 +3957,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_gizmos.get_current_type() == Gizmos::Flatten) { // Rotate the object so the normal points downward: #if ENABLE_EXTENDED_SELECTION - m_regenerate_volumes = false; m_selection.rotate(m_gizmos.get_flattening_rotation()); _on_flatten(); wxGetApp().obj_manipul()->update_settings_value(m_selection); @@ -4397,7 +4395,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Scale: { #if ENABLE_EXTENDED_SELECTION - m_regenerate_volumes = false; _on_scale(); #endif // ENABLE_EXTENDED_SELECTION break; @@ -4405,7 +4402,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { #if ENABLE_EXTENDED_SELECTION - m_regenerate_volumes = false; _on_rotate(); #else post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation())); diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index fb494ed23..5a7ece586 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -28,6 +28,7 @@ CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent) auto* sizer = new wxBoxSizer(wxHORIZONTAL); cbox = new wxCheckBox(this, wxID_ANY, checkbox_label); + cbox->SetValue(true); sizer->AddSpacer(5); sizer->Add(this->cbox, 0, wxEXPAND | wxALL, 5); SetSizer(sizer); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 6a202ad4c..f1e6595f7 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -300,7 +300,7 @@ void MainFrame::init_menubar() append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as STL...")), _(L("Export current plate as STL")), [this](wxCommandEvent&){ /*m_plater->export_stl(); */}, "brick_go.png"); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as AMF...")), _(L("Export current plate as AMF")), - [this](wxCommandEvent&){ /*m_plater->export_amf();*/ }, "brick_go.png"); + [this](wxCommandEvent&){ m_plater->export_amf(); }, "brick_go.png"); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as 3MF...")), _(L("Export current plate as 3MF")), [this](wxCommandEvent&){ m_plater->export_3mf(); }, "brick_go.png"); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b5cb21625..bef4d5a86 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -850,7 +850,9 @@ private: bool layers_height_allowed() const; bool can_delete_all() const; bool can_arrange() const; +#if ENABLE_MIRROR bool can_mirror() const; +#endif // ENABLE_MIRROR #endif // ENABLE_EXTENDED_SELECTION }; @@ -1256,14 +1258,17 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType wxString wildcard; switch (file_type) { case FT_STL: - case FT_AMF: - case FT_3MF: wildcard = file_wildcards[FT_STL]; - break; - + break; + case FT_AMF: + wildcard = file_wildcards[FT_AMF]; + break; + case FT_3MF: + wildcard = file_wildcards[FT_3MF]; + break; default: wildcard = file_wildcards[FT_MODEL]; - break; + break; } fs::path output_file(print.output_filepath(std::string())); @@ -1899,6 +1904,7 @@ bool Plater::priv::init_object_menu() object_menu.AppendSeparator(); +#if ENABLE_MIRROR wxMenu* mirror_menu = new wxMenu(); if (mirror_menu == nullptr) return false; @@ -1911,6 +1917,7 @@ bool Plater::priv::init_object_menu() [this](wxCommandEvent&){ mirror(Z); }, "bullet_blue.png", &object_menu); wxMenuItem* item_mirror = append_submenu(&object_menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object"))); +#endif // ENABLE_MIRROR wxMenuItem* item_split = append_menu_item(&object_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual parts")), [this](wxCommandEvent&){ split_object(); }, "shape_ungroup.png"); @@ -1919,7 +1926,9 @@ bool Plater::priv::init_object_menu() // ui updates needs to be binded to the parent panel if (q != nullptr) { +#if ENABLE_MIRROR q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_mirror()); }, item_mirror->GetId()); +#endif // ENABLE_MIRROR q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_object()); }, item_delete->GetId()); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_increase->GetId()); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_decrease_instances()); }, item_decrease->GetId()); @@ -1976,10 +1985,12 @@ bool Plater::priv::can_arrange() const return !model.objects.empty(); } +#if ENABLE_MIRROR bool Plater::priv::can_mirror() const { return get_selection().is_from_single_instance(); } +#endif // ENABLE_MIRROR #endif // ENABLE_EXTENDED_SELECTION // Plater / Public From 974e2056fbc85cf19265523adfd2992277081003 Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Mon, 22 Oct 2018 11:52:13 +0200 Subject: [PATCH 2/8] Plater: Fix file patterns --- src/slic3r/GUI/Plater.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bef4d5a86..8fd13cfe2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -700,7 +700,7 @@ private: static const std::regex pattern_drop; }; -const std::regex PlaterDropTarget::pattern_drop("[.](stl|obj|amf|3mf|prusa)$", std::regex::icase); +const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)", std::regex::icase); bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames) { @@ -856,9 +856,9 @@ private: #endif // ENABLE_EXTENDED_SELECTION }; -const std::regex Plater::priv::pattern_bundle("[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)$", std::regex::icase); -const std::regex Plater::priv::pattern_3mf("[.]3mf$", std::regex::icase); -const std::regex Plater::priv::pattern_zip_amf("[.]zip[.]amf$", std::regex::icase); +const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); +const std::regex Plater::priv::pattern_3mf(".*3mf", std::regex::icase); +const std::regex Plater::priv::pattern_zip_amf(".*[.]zip[.]amf", std::regex::icase); Plater::priv::priv(Plater *q, MainFrame *main_frame) : q(q), From 37e165d82d89767dfd18b63592a2bab8c5dea11f Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Mon, 22 Oct 2018 11:50:05 +0200 Subject: [PATCH 3/8] Build: Fix resources symlink --- src/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 330134c3b..332649cf9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -119,28 +119,28 @@ if (MSVC) foreach (CONF ${CMAKE_CONFIGURATION_TYPES}) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}" WIN_CONF_OUTPUT_DIR) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}/resources" WIN_RESOURCES_SYMLINK) - add_custom_target("resources_symlink_${CONF}" ALL - DEPENDS slic3r + add_custom_command(TARGET slic3r POST_BUILD COMMAND if exist "${WIN_CONF_OUTPUT_DIR}" "(" if not exist "${WIN_RESOURCES_SYMLINK}" "(" mklink /J "${WIN_RESOURCES_SYMLINK}" "${SLIC3R_RESOURCES_DIR_WIN}" ")" ")" + COMMENT "Symlinking the resources directory into the build tree" VERBATIM ) endforeach () else () file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/resources" WIN_RESOURCES_SYMLINK) - add_custom_target(resources_symlink ALL - DEPENDS slic3r + add_custom_command(TARGET slic3r POST_BUILD COMMAND if not exist "${WIN_RESOURCES_SYMLINK}" "(" mklink /J "${WIN_RESOURCES_SYMLINK}" "${SLIC3R_RESOURCES_DIR_WIN}" ")" + COMMENT "Symlinking the resources directory into the build tree" VERBATIM ) endif () else () - add_custom_target(resources_symlink ALL - DEPENDS slic3r + add_custom_command(TARGET slic3r POST_BUILD COMMAND ln -sf "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources" + COMMENT "Symlinking the resources directory into the build tree" VERBATIM ) endif() From f6e6d9dc4ada0d8481884d8ad73c9bee2291f4c7 Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Fri, 19 Oct 2018 16:52:41 +0200 Subject: [PATCH 4/8] Fix Plater::priv::get_export_file() --- src/slic3r/GUI/MainFrame.cpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index f1e6595f7..5df19df80 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -296,9 +296,9 @@ void MainFrame::init_menubar() if (m_plater) { m_plater_menu = new wxMenu(); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export G-code...")), _(L("Export current plate as G-code")), - [this](wxCommandEvent&){ /*m_plater->export_gcode(); */}, "cog_go.png"); + [this](wxCommandEvent&){ m_plater->export_gcode(); }, "cog_go.png"); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as STL...")), _(L("Export current plate as STL")), - [this](wxCommandEvent&){ /*m_plater->export_stl(); */}, "brick_go.png"); + [this](wxCommandEvent&){ m_plater->export_stl(); }, "brick_go.png"); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as AMF...")), _(L("Export current plate as AMF")), [this](wxCommandEvent&){ m_plater->export_amf(); }, "brick_go.png"); append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as 3MF...")), _(L("Export current plate as 3MF")), diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8fd13cfe2..8bdc43a37 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1258,17 +1258,15 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType wxString wildcard; switch (file_type) { case FT_STL: - wildcard = file_wildcards[FT_STL]; - break; case FT_AMF: - wildcard = file_wildcards[FT_AMF]; - break; case FT_3MF: - wildcard = file_wildcards[FT_3MF]; - break; + case FT_GCODE: + wildcard = file_wildcards[file_type]; + break; + default: wildcard = file_wildcards[FT_MODEL]; - break; + break; } fs::path output_file(print.output_filepath(std::string())); From 84de664fb54fe87939c7072cc2f0932d82afb4a7 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 22 Oct 2018 12:07:40 +0200 Subject: [PATCH 5/8] Fixed TreeCtrl updating after mode change + Added another images for mode visualization --- resources/icons/mode_expert_.png | Bin 0 -> 1379 bytes resources/icons/mode_middle_.png | Bin 0 -> 1466 bytes resources/icons/mode_simple_.png | Bin 0 -> 1164 bytes src/slic3r/GUI/OptionsGroup.cpp | 2 ++ src/slic3r/GUI/Tab.cpp | 13 +++++++++---- 5 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 resources/icons/mode_expert_.png create mode 100644 resources/icons/mode_middle_.png create mode 100644 resources/icons/mode_simple_.png diff --git a/resources/icons/mode_expert_.png b/resources/icons/mode_expert_.png new file mode 100644 index 0000000000000000000000000000000000000000..4d78bcccf511511455f4de48fca473bb2d0aa677 GIT binary patch literal 1379 zcmV-p1)TbcP)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000EEdQ@0+Qek%> zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vrlIti8h5u_6vjhYPiRJLDnjOsY=is;#C!O&f zciL3^P%udPbTBmj`Fqk|IJ~G)#3|*J9FCY{_60ZQZpZD)E^g<eZ9PBPiR1o<hbiD1 zZjWi~{R`~!ctQ96T%YZvZ6C+>fxc$m2MlXwkDI-p?E?jWvwt~4d4I3OgX{Y*_sx07 zd#Bgus7OW^j2Arl5jZ%U)0!o~gJ7X78_qs>@Amr`63$`udzU-9rTKgE?sqS_b7i-O z=TwmU8YsQwXt%Sx&)t@xCu)zGpZ=Kj4*FZ}=Il1-xJ6fDLZ%Y!L4Ad?-JxSeD#P|# zLR0(%_qw%=W(cu?SO?9D)`&BEWOH)l&V?tB?b^7(#ps7uT)l5TY&Hw(vu_)exEfEd zA%{+2<U<3s0JFdQ!rQ!go3F89=FaHp8H4en`P%56@h9y*(44DunVsG8gtCBNe$_PG zSmf3jy#R#go>STKyEQu0jXQu1AShd!4FMKcZ$nh!M{R|Tb3i|Fk#0rrSo=NzQiQn$ z&Ts$$mpBL~cIv${Baa3?1)lp5eFXs)@ttXc4eB0n%&)oej`G&mi@%w%v;c%aA__D) z6u^p6P(K<CHB=->BoRrXVv?n#kYbXQlBTsr6%86yG^wg-)?&e;i6v7r%T}__0ZW+V zl$EmOoJ+x^1w$9SUC^VH>T9U6N=;R()m%$M`Lx)irKZhVZl(JkI^^F|SL)VtFM|h4 zX~ZET4IMV}C=<0d!;DjAnmTRfS?<($m+ccZej#^GjdyB`Sls&QgBr}LUqkR(PGm6y zF&`PkbrC>8`^C%|$LJTi#mr?7QHTdMmIbHtA_jtSu$Reqb`Nr=+(_ajZvMZ>(L(nd z<Y=MW$$jVchFUM%7bR?fmI_x+U6@$dW++9QOtsm4&T(2DKwt3XMCxFSC2LETOBD}s zJCMk83@fdc9<8n(O0yy)?^Ju_tU9r>wbj`a6EwIUYTce^(%HhyJtYXSH{oujE6-7# zc29+ojS*%~4o*N)C29(7mOk+@E#3;e%q9^ZDOYS1tfWpP##YK`fE|T_59`s$6Vk^} zu_Ot@&)Rfku~t*SqKisE2|Pkr5mY~JQGUf}#?&VYSUL(<YnX#)8#VYE$5;W4(DS;w zIaH9pSe4<iuhMju#+cnwN!2DzF*qfzr;MOy7!`?aD<UhXCl>F9t-{FIKVa!WeV2;w z1|mWQve~?mqE}QYEK)H&fqIAOg%T~tH&D-*{sie8Bl;nvZ;a>)q(><N)149u9h~R| z)Q;(okk+72l<3EpUMSIfOz-t{CMUY0r!zUxN2m^@=!%}s<V08WbS5YI0MrvFx}v8u zInfUxePcvFg!GLOUD4B-oal<4&g4Wt#`Gd5x}v8uInhU`4y5QKR0mRYMNemPqAPkj zlN0?2)Eha`6+NBFiGFDh5$KaW#8FOkMNemPqAPkjlM`Lh)0v#;lkMJ7PV^C~11b7s zyLXfmeX`v<%85SN?j1SNC)>TFoamG7-jNag(jFqvC)>RvC;DW&cceuB3lrw)**W?b z+PYSP@1brk00006VoOIv0RI600RN!9r;`8x010qNS#tmY5_A9n5_AFHW*>L}000Mc zNliru;tCcBE-rCcRgeGx05C~JK~yNuW8BWh_Fw1MF9t3d6^0K_?l7EXfB+^228K^O lJPb?>1i+|*Q3cdh002W22;H2eLIwZ;002ovPDHLkV1id3f^Pr- literal 0 HcmV?d00001 diff --git a/resources/icons/mode_middle_.png b/resources/icons/mode_middle_.png new file mode 100644 index 0000000000000000000000000000000000000000..d98d8f7091d0fcebd33a354a11feb8cd0a08f5bf GIT binary patch literal 1466 zcmV;r1x5OaP)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000FMdQ@0+Qek%> zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1Yww&N%a{MRaG2}VK)mc#R$-oY$?3hX>@uG@Wk zLSl>p0;-C#ssH<H&_DRFq>a2<3@L;SAD?{UjGMUapS^aQU)Sf@Y`?_G`Qr~pNKnh( z4E^Yz5!c56JNmow8Yinqo_Hj>&3q)3IWyzt=ogPf!h8I-5K70m?4Oo?{8C$s-`vsZ zz3mNPG(|pP;x0}$T*I72umXvaXAD;s=IyxmVz`Q=&)Crp^H=chcW>Bj`H0Ia6tvwE zg*S|jxYN(rErecJd(8auhm1SXU$7ga#WDK6yX*sy3UqAhwv}~<js;N48WvCtKgGSR zl29VHSix8Wn+2tkOOAo&aNaeS-Ee)?)m1Ffb7w=%Tv=8uigDt)Nb$3{!6r!>fg_d* z)&ya`uf?r-)0(fkh?$#1Pj*P=CY$etJ_UbL?uo{j(sgc&J5G=V*2PoPSjJ>-UeODL zxN%^r3*S}fNjKXQu>uBl!5p!{yp=sgQTNc6ES?4Zbn~=}esk821b_&0D;DDf3~a%P zy5KfrHs^q21V0%oXYpLXfK%n>Xn-4$0CFPFxiQAv>dVS|7}f$JR00l31Vb5Qd9Toq z`3MbV74@X5K~1A3%|U_>8bYuzJt~`+H??49(URpT(MOFTT8uHpoHz+AOjAfkDW;Ti z#-tgkGe&3h$hmNl;)|A0ti+N^u8>dlRcokLV@)+TZqji4TWCftw$yTW9a8GPYY*Le z?5XDgtqmD|=m^6`9BJe`YwkF<FRZyY=FVAj2WyitzxvsOHH6J>DcrOZot%L&_705O zWB`KZ$=Md2_dJ=KoNbA5D3rmP(@9QqlQA&pyJH>h&fSB#Q{G7ZAMwWDF-McS|ART2 z)E&%y<?RD&Ew3kvEQ01KoS4D}VQj;@oO-j-LK--Z7V`EKuuuj|25eb+3O2UFt!efH ziyR*7){vxA=h3*dT&4HgC1G*MpxD>|2|92MxiqfcDo$R*o=rzD-bN`nu72!II@%VS z7Ce(Ic<DH+Uhxe9|E$~XQTu@<V&u3b+M6^tgGg2$u{n_e_Cg1S)~b#SN^|jPn6sX= zx8Sf>a}{V~e6CF`7Y8>3M!AS8cF)pzi=nD7d8XGaqct#|Z3gbmQbTUTfl$U-0iGN) z7dT{`H!;u0|50P4?y2maYNE9_8z-v)iWv|?u?2O9vK#08L;|+FVfPX{#JQ(iXluNa z;ETi429JoqSwU`YZh*Ch(<JTIUd=8V#?)5Y0NIYSrgTs+-$0HU1F`Ac<dJBhvLXO9 zc@XG*9o+>jPhe|!uz=l0Yb{k1S9s9avCh@sS<o0qjEuvr+zVtGr!1FBZ_Put5NQEk zwbzIjtsC049t_~=ey^Vu{v!C9s`w>%o^q#;djGB5ZxlQPPv0p1j|EQ;#V>`w9f9kD zr*9PhS?+IQe^P&;k9z-J?r&nhtH04lz5h<`AH+@{)czx})2rI=>h{m_zan<}p!RXI zmfy+!Zp#SJ;{ZJA{j%I24o?q@f71I8<WAS^{aoyH-QLgLovz#axx3SKdp~z~x^D01 za;NL|elB>rZtv&rPS@@I+}-KAy`RgSuG{;$-08Z#p9`LT@;>v)-RZC2XAZg3b$dUT zJ6*T;bGg%Xdp{RD{q$Yt-Q8*Y&AZH#yVG@hKX-Tfq<0y3!%vX?fA%);>rHq<8UO$Q z24YJ`L;(K){{a7>y{D4^000SaNLh0L01|Wn01|Wo-ew<o00007bV*G`2jU7A2rnps zAi?AS001gUL_t(2&tv?5jOjmvupI*fr#=J2_lpb+Zx1mb111InU{t}V0_rLN0BO1g U?neBJ+yDRo07*qoM6N<$f@EOK;{X5v literal 0 HcmV?d00001 diff --git a/resources/icons/mode_simple_.png b/resources/icons/mode_simple_.png new file mode 100644 index 0000000000000000000000000000000000000000..aac2b61b042094981b9e8f37da32662fb48b8c5c GIT binary patch literal 1164 zcmV;71atd|P)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000BydQ@0+Qek%> zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vrlEfwqg#YUlIRX+0!EwMqRc?^ur?Hv0vx#Rj z)Y^=UCAq&gv(*3kbI>37h~q#(EyWz8!zbjBrC^fW@j1@y!hU>?&F?R9;;=3tt@Akh z<7@0|eL-9wH`rRw^)*hmtvqQZx>a5Y{j4mQtaWK6@^Zv)jZj|qmGIR1`pa!^-tk)W z{yiAPXo`GZNV;e5aE!BxM+ZLnGGjQ37jbJIyzTLLt{ojRe~NdXy=mvliu+e7$lVgf zH;q=D^<2AMp%-e8$}bnTbT9Ft-54#6(T}GqAwsE0>!EIsvd^%vLQ22i7BLKein;A0 zV<bG{24W2~E5=5gS)k_Nz>NzJ?)!P;4J`)gVmOOz;`dncCRw%}N|=L(n9sfu7>VCN z%_A)LUU;vY_j(&ARBnuw!brxG=KG+t;5Xx*XpCuHW|t0~U<>pm)6-~UlAA}Y0uUZc zQ{DC52R-@5J%RNgsJqMw4_I71QdH%KxBSl8W1YG{hv^+#TL~Z$YAc#y4+1W-SB~sV z#F(LD0-u7;#RsV%z^c-i2H1EX0Vm0<jeCsuwW4x_v9$n%`iPe#flvXg5ETBgkl>-B zUIVFWRMVtcOY|{BjWJrBdsH!R!PKIeCCgTlPa$cF$x=!=l`Pp~3)394QBFDMQc$!Y zb-~>QD@v(SeGOG>tX5OawQR7@7B=1DW?S0wR+=>5@cOsdj9O~BmChYj>Y;0o-FoV| zmjSO0Kf=%vhmADyD0gbSUfUOH{6_9)YP_gTVqsrr4{8XT-BR$}PINK@F$oOfHVMGc zGMTx=A;=^*nYk=@DO5m>b;4;piGg6~EIRnk?m_NHZlvK7H~A-WG|~MZ<Y=N><UYBb zP-|uXMe#eJ`4&!1ogdiP<}I5R8>RWtds8cwV;;SRF>2M3%U0w3fzW{81y@op*u0!Z zpoyd634F=KwfBr`$w_W);Jq%5@A=GTKAZWpS4$mRT9E`5us+S1TW546KlbCLC0DbG z>uHLZ@mtH9;DOZv_Uzde;ToE-m(s}m)?4cyJLOS(uHR=*=gM>|4%e<6kM07r`4?&K z%FvSLJ7J!5p-*A<-u|mJcV*~9nk&LQL7`vB@?seJl`v1b&~?Y08-}hs=G-v!wKQ*r zp<fB})EoU$n!91>x?|1_L)RU1ZW#Jnm^Z`Fcd~pMhORs2+%R<AG3SP%>y9}$3|)83 zxnbzKW6ljj*Bx_i7`pD5bHmVe$DA96t~=)3Fm&B9=Z2x{jyX3BU3bijVLblP$@DkZ z+afZyIfuyr000JJOGiWi{{a60|De66lK=n!32;bRa{vGmbN~PnbOGLGA9w%&00(qQ zO+^Rd3Kj@25=Sf;RsaA1DoI2^R4C75oO43_zpx}T0~;$d!>`|e8Qwns%YY1+7zlt- e1)~b6s{jD4<_My71_K=c0000<MNUMnLSTY7el2zY literal 0 HcmV?d00001 diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 8ee78cee6..b2f9cd272 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -388,6 +388,8 @@ void ConfigOptionsGroup::reload_config(){ } bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) { + if (m_options_mode.empty()) + return true; if (m_grid_sizer->GetEffectiveRowsCount() != m_options_mode.size() && m_options_mode.size() == 1) return m_options_mode[0] <= mode; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index bb7aa3e9b..698c46d23 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -483,7 +483,7 @@ void Tab::update_changed_tree_ui() auto title = m_treectrl->GetItemText(cur_item); for (auto page : m_pages) { - if (page->title() != title) + if (page->title() != title) continue; bool sys_page = true; bool modified_page = false; @@ -644,6 +644,11 @@ void Tab::update_visibility(ConfigOptionMode mode) Refresh(); Thaw(); + + // to update tree items color + wxTheApp->CallAfter([this]() { + update_changed_tree_ui(); + }); } Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const @@ -1782,7 +1787,7 @@ void TabPrinter::build_sla() auto page = add_options_page(_(L("General")), "printer_empty.png"); auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); - Line line{ _(L("Bed shape")), "" }; + Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" }; line.widget = [this](wxWindow* parent){ auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); // btn->SetFont(Slic3r::GUI::small_font); @@ -2762,8 +2767,8 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la bmp_name = "error.png"; else { auto mode = line.get_options()[0].opt.mode; //we assume that we have one option per line - bmp_name = mode == comExpert ? "mode_expert.png" : - mode == comMiddle ? "mode_middle.png" : "mode_simple.png"; + bmp_name = mode == comExpert ? "mode_expert_.png" : + mode == comMiddle ? "mode_middle_.png" : "mode_simple_.png"; } auto bmp = new wxStaticBitmap(parent, wxID_ANY, wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG)); return bmp; From 2a2d1d85f8e1dcc46f2d97d3e2970e49824997c5 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 22 Oct 2018 13:27:53 +0200 Subject: [PATCH 6/8] Added mirror factors to .3mf import and enabled import factors --- src/libslic3r/Format/3mf.cpp | 22 ++++++++++++++++++---- src/libslic3r/Model.cpp | 4 ++++ src/libslic3r/Technologies.hpp | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index bf94db6b1..085f55b9b 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1249,14 +1249,25 @@ namespace Slic3r { void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform) { - // slic3r ModelInstance cannot be transformed using a matrix - // we extract from the given matrix only the values currently used - // translation Vec3d offset = transform.matrix().block(0, 3, 3, 1); - // scale Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3); +#if ENABLE_MIRROR + // mirror + // it is impossible to reconstruct the original mirroring factors from a matrix, + // we can only detect if the matrix contains a left handed reference system + // in which case we reorient it back to right handed by mirroring the x axis + Vec3d mirror = Vec3d::Ones(); + if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) + { + mirror(0) = -1.0; + // remove mirror + m3x3.col(0) *= -1.0; + } + + // scale +#endif // ENABLE_MIRROR Vec3d scale(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm()); // invalid scale value, return @@ -1273,6 +1284,9 @@ namespace Slic3r { instance.set_offset(offset); instance.set_scaling_factor(scale); instance.set_rotation(rotation); +#if ENABLE_MIRROR + instance.set_mirror(mirror); +#endif // ENABLE_MIRROR } bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d001acedb..331d11833 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -711,9 +711,13 @@ void ModelObject::center_around_origin() if (!this->instances.empty()) { for (ModelInstance *i : this->instances) { +#if ENABLE_MIRROR + i->set_offset(i->get_offset() - shift); +#else // apply rotation and scaling to vector as well before translating instance, // in order to leave final position unaltered i->set_offset(i->get_offset() + i->transform_vector(-shift, true)); +#endif // ENABLE_MIRROR } this->invalidate_bounding_box(); } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3f8fd80f0..d80d6df0d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -11,7 +11,7 @@ // New selections #define ENABLE_EXTENDED_SELECTION (1 && ENABLE_1_42_0) // Add mirror components along the three axes in ModelInstance and GLVolume -#define ENABLE_MIRROR (0 && ENABLE_1_42_0) +#define ENABLE_MIRROR (1 && ENABLE_1_42_0) #endif // _technologies_h_ From 3ecb65d62c5f1509af8889de74fbe84452c26674 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 22 Oct 2018 15:18:05 +0200 Subject: [PATCH 7/8] Fixed mode updating under GTK --- src/slic3r/GUI/GUI_ObjectList.hpp | 1 + src/slic3r/GUI/OptionsGroup.cpp | 8 +++++++- src/slic3r/GUI/Tab.cpp | 2 +- src/slic3r/GUI/wxExtensions.hpp | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index c56e69670..56d01b7f5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -4,6 +4,7 @@ #include <wx/bitmap.h> #include <wx/dataview.h> #include <map> +#include <vector> class wxBoxSizer; class PrusaObjectDataViewModel; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index b2f9cd272..371747bc1 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -395,19 +395,25 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) { return m_options_mode[0] <= mode; sizer->ShowItems(true); +#ifdef __WXGTK__ + m_panel->Show(true); + m_grid_sizer->Show(true); +#endif /* __WXGTK__ */ int coef = 0; + int hidden_row_cnt = 0; const int cols = m_grid_sizer->GetCols(); for (auto opt_mode : m_options_mode) { const bool show = opt_mode <= mode; if (!show) { + hidden_row_cnt++; for (int i = 0; i < cols; ++i) m_grid_sizer->Show(coef + i, show); } coef+= cols; } - if (!sizer->IsShown(m_grid_sizer)) { + if (hidden_row_cnt == m_options_mode.size()) { sizer->ShowItems(false); return false; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 698c46d23..d4249ea23 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -476,7 +476,7 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool void Tab::update_changed_tree_ui() { auto cur_item = m_treectrl->GetFirstVisibleItem(); - if (!m_treectrl->IsVisible(cur_item)) + if (!cur_item || !m_treectrl->IsVisible(cur_item)) return; auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); while (cur_item){ diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 4ff73027c..80a564fd0 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -12,6 +12,7 @@ #include <vector> #include <set> +#include <functional> wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr); From 2f11df47ce28de70a4ae2c8919339356906ec608 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Mon, 22 Oct 2018 15:18:56 +0200 Subject: [PATCH 8/8] Layers editing --- src/slic3r/GUI/Plater.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8bdc43a37..ecf36595e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1365,7 +1365,7 @@ void Plater::priv::selection_changed() _3DScene::enable_toolbar_item(canvas3D, "split", have_sel); _3DScene::enable_toolbar_item(canvas3D, "cut", have_sel); _3DScene::enable_toolbar_item(canvas3D, "settings", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed); + _3DScene::enable_toolbar_item(canvas3D, "layersediting", have_sel && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D)); #endif // ENABLE_EXTENDED_SELECTION #if ENABLE_EXTENDED_SELECTION @@ -1477,6 +1477,9 @@ void Plater::priv::remove(size_t obj_idx) // Prevent toolpaths preview from rendering while we modify the Print object preview->set_enabled(false); + if (_3DScene::is_layers_editing_enabled(canvas3D)) + _3DScene::enable_layers_editing(canvas3D, false); + #if !ENABLE_EXTENDED_SELECTION objects.erase(objects.begin() + obj_idx); #endif // !ENABLE_EXTENDED_SELECTION @@ -1500,6 +1503,9 @@ void Plater::priv::reset() // Prevent toolpaths preview from rendering while we modify the Print object preview->set_enabled(false); + if (_3DScene::is_layers_editing_enabled(canvas3D)) + _3DScene::enable_layers_editing(canvas3D, false); + #if !ENABLE_EXTENDED_SELECTION objects.clear(); #endif // !ENABLE_EXTENDED_SELECTION @@ -1777,7 +1783,10 @@ void Plater::priv::on_action_settings(SimpleEvent&) void Plater::priv::on_action_layersediting(SimpleEvent&) { - // TODO + bool enable = !_3DScene::is_layers_editing_enabled(canvas3D); + _3DScene::enable_layers_editing(canvas3D, enable); + if (enable && !_3DScene::is_layers_editing_enabled(canvas3D)) + _3DScene::enable_toolbar_item(canvas3D, "layersediting", false); } #if !ENABLE_EXTENDED_SELECTION @@ -1970,7 +1979,8 @@ bool Plater::priv::can_cut_object() const bool Plater::priv::layers_height_allowed() const { - return config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D); + int obj_idx = get_selected_object_idx(); + return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D); } bool Plater::priv::can_delete_all() const