diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fac3daaf..8c7fc12df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -398,8 +398,10 @@ endif() # Resources install target, configure fhs.hpp on UNIX if (WIN32) install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources") -else () +elseif (SLIC3R_FHS) set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/PrusaSlicer") install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${SLIC3R_FHS_RESOURCES}") +else () + install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources") endif () configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index d4f72ffb3..0f89e6193 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -9,6 +9,7 @@ #include "3mf.hpp" #include +#include #include #include @@ -102,6 +103,13 @@ const char* INVALID_OBJECT_TYPES[] = "other" }; +class version_error : public std::runtime_error +{ +public: + version_error(const std::string& what_arg) : std::runtime_error(what_arg) {} + version_error(const char* what_arg) : std::runtime_error(what_arg) {} +}; + const char* get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key) { if ((attributes == nullptr) || (attributes_size == 0) || (attributes_size % 2 != 0) || (attribute_key == nullptr)) @@ -731,6 +739,11 @@ namespace Slic3r { return n; }, &data, 0); } + catch (const version_error& e) + { + // rethrow the exception + throw std::runtime_error(e.what()); + } catch (std::exception& e) { add_error(e.what()); @@ -1439,8 +1452,8 @@ namespace Slic3r { if (m_check_version && (m_version > VERSION_3MF)) { - std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.")); - throw std::runtime_error(msg.c_str()); + std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); + throw version_error(msg.c_str()); } } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index f43724cb6..92c958d8a 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -827,7 +827,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi if (check_version && (ctx.m_version > VERSION_AMF)) { - std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.")); + std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); throw std::runtime_error(msg.c_str()); } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index bb2dd34d9..454b4874f 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -138,7 +138,7 @@ bool Field::is_matched(const std::string& string, const std::string& pattern) static wxString na_value() { return _(L("N/A")); } -void Field::get_value_by_opt_type(wxString& str) +void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true*/) { switch (m_opt.type) { case coInt: @@ -150,7 +150,7 @@ void Field::get_value_by_opt_type(wxString& str) case coFloat:{ if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') str.RemoveLast(); - else if (!str.IsEmpty() && str.Last() == '%') { + else if (check_value && !str.IsEmpty() && str.Last() == '%') { wxString label = m_Label->GetLabel(); if (label.Last() == '\n') label.RemoveLast(); while (label.Last() == ' ') label.RemoveLast(); @@ -169,12 +169,12 @@ void Field::get_value_by_opt_type(wxString& str) { if (m_opt.nullable && str == na_value()) val = ConfigOptionFloatsNullable::nil_value(); - else if (!str.ToCDouble(&val)) + else if (check_value && !str.ToCDouble(&val)) { show_error(m_parent, _(L("Invalid numeric input."))); set_value(double_to_string(val), true); } - if (m_opt.min > val || val > m_opt.max) + if (check_value && (m_opt.min > val || val > m_opt.max)) { show_error(m_parent, _(L("Input value is out of range"))); if (m_opt.min > val) val = m_opt.min; @@ -192,12 +192,12 @@ void Field::get_value_by_opt_type(wxString& str) double val; // Replace the first occurence of comma in decimal number. str.Replace(",", ".", false); - if (!str.ToCDouble(&val)) + if (check_value && !str.ToCDouble(&val)) { show_error(m_parent, _(L("Invalid numeric input."))); set_value(double_to_string(val), true); } - else if ((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max || + else if (check_value && (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max || m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1) && (m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast(m_value))) { @@ -206,7 +206,7 @@ void Field::get_value_by_opt_type(wxString& str) const wxString msg_text = wxString::Format(_(L("Do you mean %s%% instead of %s %s?\n" "Select YES if you want to change this value to %s%%, \n" "or NO if you are sure that %s %s is a correct value.")), stVal, stVal, sidetext, stVal, stVal, sidetext); - wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")) + ": " + m_opt_id , wxICON_WARNING | wxYES | wxNO); if (dialog.ShowModal() == wxID_YES) { set_value(wxString::Format("%s%%", stVal), false/*true*/); str += "%%"; @@ -396,8 +396,9 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) if (!change_event) { wxString ret_str = static_cast(window)->GetValue(); - // update m_value to correct work of next value_was_changed() - get_value_by_opt_type(ret_str); + // update m_value to correct work of next value_was_changed(), + // but don't check/change inputed value and don't show a warning message + get_value_by_opt_type(ret_str, false); } } diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 11775a67c..b3cbf573f 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -152,7 +152,7 @@ public: virtual wxWindow* getWindow() { return nullptr; } bool is_matched(const std::string& string, const std::string& pattern); - void get_value_by_opt_type(wxString& str); + void get_value_by_opt_type(wxString& str, const bool check_value = true); /// Factory method for generating new derived classes. template diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7bfae3084..71bacd815 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2152,9 +2152,36 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const if (!m_volumes.empty()) { - // removes empty volumes - m_volumes.volumes.erase(std::remove_if(m_volumes.volumes.begin(), m_volumes.volumes.end(), - [](const GLVolume* volume) { return volume->print_zs.empty(); }), m_volumes.volumes.end()); + // Remove empty volumes from both m_volumes, update m_gcode_preview_volume_index. + { + size_t idx_volume_src = 0; + size_t idx_volume_dst = 0; + size_t idx_volume_index_src = 0; + size_t idx_volume_index_dst = 0; + size_t idx_volume_of_this_type_last = (idx_volume_index_src + 1 == m_gcode_preview_volume_index.first_volumes.size()) ? m_volumes.volumes.size() : m_gcode_preview_volume_index.first_volumes[idx_volume_index_src + 1].id; + size_t idx_volume_of_this_type_first_new = 0; + for (;;) { + if (idx_volume_src == idx_volume_of_this_type_last) { + if (idx_volume_of_this_type_first_new < idx_volume_dst) { + // There are some volumes of this type left, therefore their entry in the index has to be maintained. + if (idx_volume_index_dst < idx_volume_index_src) + m_gcode_preview_volume_index.first_volumes[idx_volume_index_dst] = m_gcode_preview_volume_index.first_volumes[idx_volume_index_src]; + m_gcode_preview_volume_index.first_volumes[idx_volume_index_dst].id = idx_volume_of_this_type_first_new; + ++ idx_volume_index_dst; + } + if (idx_volume_of_this_type_last == m_volumes.volumes.size()) + break; + ++ idx_volume_index_src; + idx_volume_of_this_type_last = (idx_volume_index_src + 1 == m_gcode_preview_volume_index.first_volumes.size()) ? m_volumes.volumes.size() : m_gcode_preview_volume_index.first_volumes[idx_volume_index_src + 1].id; + idx_volume_of_this_type_first_new = idx_volume_dst; + } + if (! m_volumes.volumes[idx_volume_src]->print_zs.empty()) + m_volumes.volumes[idx_volume_dst ++] = m_volumes.volumes[idx_volume_src]; + ++ idx_volume_src; + } + m_volumes.volumes.erase(m_volumes.volumes.begin() + idx_volume_dst, m_volumes.volumes.end()); + m_gcode_preview_volume_index.first_volumes.erase(m_gcode_preview_volume_index.first_volumes.begin() + idx_volume_index_dst, m_gcode_preview_volume_index.first_volumes.end()); + } _load_fff_shells(); } @@ -5097,7 +5124,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat unsigned int role = (unsigned int)(&filters - &roles_filters.front()); for (std::pair &filter : filters) if (filter.second->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { - if (m_gcode_preview_volume_index.first_volumes.back().id != role) + if (m_gcode_preview_volume_index.first_volumes.back().type != GCodePreviewVolumeIndex::Extrusion || m_gcode_preview_volume_index.first_volumes.back().flag != role) m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size()); GLVolume& vol = *filter.second; filter.second = m_volumes.new_toolpath_volume(vol.color); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index f40138408..c17569c11 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -589,13 +589,11 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config switch (opt->type) { case coFloatOrPercent:{ const auto &value = *config.option(opt_key); + + text_value = double_to_string(value.value); if (value.percent) - { - text_value = wxString::Format(_T("%i"), int(value.value)); text_value += "%"; - } - else - text_value = double_to_string(value.value); + ret = text_value; break; } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index af1298bfb..29f12a4d2 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -1532,7 +1532,9 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr } // Paint a lock at the system presets. bmps.emplace_back(m_bitmapCache->mkclear(space_icon_width, icon_height)); - bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmapLock : m_bitmapCache->mkclear(normal_icon_width, icon_height)); + // To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so + // for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth() + bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmapLock : m_bitmapCache->mkclear(m_bitmapLock->GetWidth(), icon_height)); // (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16)); bitmap = m_bitmapCache->insert(bitmap_key, bmps); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 127f7d743..79116dfc8 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -786,7 +786,12 @@ wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) { - const std::vector print_indicator(num, true); + std::vector print_indicator(num, true); + + // if InstanceRoot item isn't created for this moment + if (!GetInstanceRootItem(parent_item).IsOk()) + // use object's printable state to first instance + print_indicator[0] = IsPrintable(parent_item); return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator)); } @@ -799,21 +804,12 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& paren ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID(); - const bool just_created = inst_root_node->GetChildren().Count() == 0; - // Add instance nodes ObjectDataViewModelNode *instance_node = nullptr; size_t counter = 0; while (counter < print_indicator.size()) { instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance); -// // if InstanceRoot item is just created and start to adding Instances -// if (just_created && counter == 0) { -// ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID(); -// // use object's printable state to first instance -// instance_node->set_printable_icon(obj_node->IsPrintable()); -// } -// else instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable); inst_root_node->Append(instance_node);