diff --git a/resources/icons/mode_expert_.png b/resources/icons/mode_expert_.png new file mode 100644 index 000000000..4d78bcccf Binary files /dev/null and b/resources/icons/mode_expert_.png differ diff --git a/resources/icons/mode_middle_.png b/resources/icons/mode_middle_.png new file mode 100644 index 000000000..d98d8f709 Binary files /dev/null and b/resources/icons/mode_middle_.png differ diff --git a/resources/icons/mode_simple_.png b/resources/icons/mode_simple_.png new file mode 100644 index 000000000..aac2b61b0 Binary files /dev/null and b/resources/icons/mode_simple_.png differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b7d621a8..dbc4ecd21 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() 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/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/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_ 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_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/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..5df19df80 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -296,11 +296,11 @@ 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"); + [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/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 8ee78cee6..371747bc1 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -388,24 +388,32 @@ 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; 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/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b5cb21625..ecf36595e 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) { @@ -850,13 +850,15 @@ 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 }; -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), @@ -1258,7 +1260,8 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType case FT_STL: case FT_AMF: case FT_3MF: - wildcard = file_wildcards[FT_STL]; + case FT_GCODE: + wildcard = file_wildcards[file_type]; break; default: @@ -1362,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 @@ -1474,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 @@ -1497,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 @@ -1774,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 @@ -1899,6 +1911,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 +1924,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 +1933,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()); @@ -1963,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 @@ -1976,10 +1993,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 diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index bb7aa3e9b..d4249ea23 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -476,14 +476,14 @@ 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){ 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; 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);