diff --git a/resources/icons/exclamation_manifold.svg b/resources/icons/exclamation_manifold.svg new file mode 100644 index 000000000..cd8ba5954 --- /dev/null +++ b/resources/icons/exclamation_manifold.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/exclamation_manifold.svg b/resources/icons/white/exclamation_manifold.svg new file mode 100644 index 000000000..a18590167 --- /dev/null +++ b/resources/icons/white/exclamation_manifold.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8337ab384..b42dfb6a4 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1615,6 +1615,7 @@ TriangleMeshStats ModelObject::get_object_stl_stats() const const TriangleMeshStats& stats = volume->mesh().stats(); // initialize full_stats (for repaired errors) + full_stats.open_edges += stats.open_edges; full_stats.degenerate_facets += stats.degenerate_facets; full_stats.edges_fixed += stats.edges_fixed; full_stats.facets_removed += stats.facets_removed; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 23ce889df..8689f43cd 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1403,9 +1403,8 @@ void GUI_App::force_colors_update() void GUI_App::update_ui_from_settings() { update_label_colours(); - mainframe->update_ui_from_settings(); - #ifdef _WIN32 + // Upadte UU colors before Update UI from settings if (m_force_colors_update) { m_force_colors_update = false; mainframe->force_color_changed(); @@ -1414,6 +1413,7 @@ void GUI_App::update_ui_from_settings() m_wizard->force_color_changed(); } #endif + mainframe->update_ui_from_settings(); } void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_maximized) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 35e5bb83e..7c019337e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -382,12 +382,17 @@ int ObjectList::get_mesh_errors_count(const int obj_idx, const int vol_idx /*= - return (*m_objects)[obj_idx]->get_mesh_errors_count(vol_idx); } -wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx /*= -1*/) const +static std::string get_warning_icon_name(const TriangleMeshStats& stats) +{ + return stats.repaired() ? (stats.manifold() ? "exclamation_manifold" : "exclamation") : ""; +} + +std::pair ObjectList::get_mesh_errors(const int obj_idx, const int vol_idx /*= -1*/, bool from_plater /*= false*/) const { const int errors = get_mesh_errors_count(obj_idx, vol_idx); if (errors == 0) - return ""; // hide tooltip + return { "", "" }; // hide tooltip // Create tooltip string, if there are errors wxString tooltip = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors) + ":\n"; @@ -407,21 +412,26 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx / if (stats.backwards_edges > 0) tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", stats.backwards_edges), stats.backwards_edges) + "\n"; - if (is_windows10()) - tooltip += _L("Right button click the icon to fix STL through Netfabb"); + if (!stats.manifold()) { + tooltip += _L("Remaning errors") + ":\n"; + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d open edge", "%1$d open edges", stats.open_edges), stats.open_edges) + "\n"; + } - return tooltip; + if (is_windows10() && !from_plater) + tooltip += "\n" + _L("Right button click the icon to fix STL through Netfabb"); + + return { tooltip, get_warning_icon_name(stats) }; } -wxString ObjectList::get_mesh_errors_list() +std::pair ObjectList::get_mesh_errors(bool from_plater /*= false*/) { if (!GetSelection()) - return ""; + return { "", "" }; int obj_idx, vol_idx; get_selected_item_indexes(obj_idx, vol_idx); - return get_mesh_errors_list(obj_idx, vol_idx); + return get_mesh_errors(obj_idx, vol_idx, from_plater); } void ObjectList::set_tooltip_for_item(const wxPoint& pt) @@ -459,7 +469,7 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt) { int obj_idx, vol_idx; get_selected_item_indexes(obj_idx, vol_idx, item); - tooltip = get_mesh_errors_list(obj_idx, vol_idx); + tooltip = get_mesh_errors(obj_idx, vol_idx).first; } GetMainWindow()->SetToolTip(tooltip); @@ -1775,8 +1785,12 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) return; // If last volume item with warning was deleted, unmark object item - if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0) - m_objects_model->DeleteWarningIcon(parent); + if (type & itVolume) { + if (auto obj = object(obj_idx); obj->get_mesh_errors_count() == 0) + m_objects_model->DeleteWarningIcon(parent); + else + m_objects_model->AddWarningIcon(parent, get_warning_icon_name(obj->mesh().stats())); + } m_objects_model->Delete(item); update_info_items(obj_idx); @@ -1985,7 +1999,7 @@ void ObjectList::split() for (const ModelVolume* volume : model_object->volumes) { const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name), volume->type(),// is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, - volume->get_mesh_errors_count()>0, + get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); // add settings to the part, if it has those @@ -2484,7 +2498,7 @@ void ObjectList::part_selection_changed() if (item) { // wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item)); wxGetApp().obj_manipul()->update_item_name(m_objects_model->GetName(item)); - wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors_list(obj_idx, volume_id)); + wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors(obj_idx, volume_id)); } } @@ -2627,7 +2641,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) const wxString& item_name = from_u8(model_object->name); const auto item = m_objects_model->Add(item_name, model_object->config.has("extruder") ? model_object->config.extruder() : 0, - get_mesh_errors_count(obj_idx) > 0); + get_warning_icon_name(model_object->mesh().stats())); update_info_items(obj_idx, nullptr, call_selection_changed); @@ -2637,7 +2651,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(item, from_u8(volume->name), volume->type(), - volume->get_mesh_errors_count()>0, + get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); add_settings_item(vol_item, &volume->config.get()); @@ -2746,6 +2760,8 @@ void ObjectList::delete_from_model_and_list(const std::vector& it // If last volume item with warning was deleted, unmark object item if (obj->get_mesh_errors_count() == 0) m_objects_model->DeleteWarningIcon(parent); + else + m_objects_model->AddWarningIcon(parent, get_warning_icon_name(obj->mesh().stats())); } wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx, printer_technology() != ptSLA); } @@ -4162,8 +4178,10 @@ void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) co // unmark fixed item only m_objects_model->DeleteWarningIcon(item); } - else - m_objects_model->AddWarningIcon(item); + else { + auto obj = object(obj_idx); + m_objects_model->AddWarningIcon(item, get_warning_icon_name(vol_idx < 0 ? obj->mesh().stats() : obj->volumes[vol_idx]->mesh().stats())); + } } void ObjectList::msw_rescale() @@ -4294,7 +4312,7 @@ wxDataViewItemArray ObjectList::reorder_volumes_and_get_selection(int obj_idx, s for (const ModelVolume* volume : object->volumes) { wxDataViewItem vol_item = m_objects_model->AddVolumeChild(object_item, from_u8(volume->name), volume->type(), - volume->get_mesh_errors_count() > 0, + get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); // add settings to the part, if it has those diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 0fbad1919..491bd2684 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -210,12 +210,12 @@ public: void get_selection_indexes(std::vector& obj_idxs, std::vector& vol_idxs); // Get count of errors in the mesh int get_mesh_errors_count(const int obj_idx, const int vol_idx = -1) const; - /* Get list of errors in the mesh. Return value is a string, used for the tooltip - * Function without parameters is for a call from Manipulation panel, - * when we don't know parameters of selected item - */ - wxString get_mesh_errors_list(const int obj_idx, const int vol_idx = -1) const; - wxString get_mesh_errors_list(); + // Get list of errors in the mesh and name of the warning icon + // Return value is a pair , used for the tooltip and related warning icon + // Function without parameters is for a call from Manipulation panel, + // when we don't know parameters of selected item + std::pair get_mesh_errors(const int obj_idx, const int vol_idx = -1, bool from_plater = false) const; + std::pair get_mesh_errors(bool from_plater = false); void set_tooltip_for_item(const wxPoint& pt); void selection_changed(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index d35def196..6eaa6316d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -132,7 +132,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : return; wxGetApp().obj_list()->fix_through_netfabb(); - update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list()); + update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors()); }); sizer->Add(m_fix_throught_netfab_bitmap); @@ -776,8 +776,12 @@ void ObjectManipulation::update_item_name(const wxString& item_name) m_item_name->SetLabel(item_name); } -void ObjectManipulation::update_warning_icon_state(const wxString& tooltip) -{ +void ObjectManipulation::update_warning_icon_state(const std::pair& warning) +{ + if (const std::string& warning_icon_name = warning.second; + !warning_icon_name.empty()) + m_manifold_warning_bmp = ScalableBitmap(m_parent, warning_icon_name); + const wxString& tooltip = warning.first; m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp()); m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize()); m_fix_throught_netfab_bitmap->SetToolTip(tooltip); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 92ba01775..9b77591be 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -194,7 +194,7 @@ public: #endif // __APPLE__ void update_item_name(const wxString &item_name); - void update_warning_icon_state(const wxString& tooltip); + void update_warning_icon_state(const std::pair& warning); void msw_rescale(); void sys_color_changed(); void on_change(const std::string& opt_key, int axis, double new_value); diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 8ceb3cc23..746a99a2f 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -37,6 +37,7 @@ void ObjectDataViewModelNode::init_container() static constexpr char LayerRootIcon[] = "edit_layers_all"; static constexpr char LayerIcon[] = "edit_layers_some"; static constexpr char WarningIcon[] = "exclamation"; +static constexpr char WarningManifoldIcon[] = "exclamation_manifold"; struct InfoItemAtributes { std::string name; @@ -57,13 +58,15 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* pare Slic3r::ModelVolumeType type, const wxBitmap& bmp, const wxString& extruder, - const int idx/* = -1*/) : + const int idx/* = -1*/, + const std::string& warning_icon_name /*= std::string*/) : m_parent(parent), m_name(sub_obj_name), m_type(itVolume), m_volume_type(type), m_idx(idx), - m_extruder(type == Slic3r::ModelVolumeType::MODEL_PART || type == Slic3r::ModelVolumeType::PARAMETER_MODIFIER ? extruder : "") + m_extruder(type == Slic3r::ModelVolumeType::MODEL_PART || type == Slic3r::ModelVolumeType::PARAMETER_MODIFIER ? extruder : ""), + m_warning_icon_name(warning_icon_name) { m_bmp = bmp; set_action_and_extruder_icons(); @@ -170,6 +173,13 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); } +void ObjectDataViewModelNode::set_warning_icon(const std::string& warning_icon_name) +{ + m_warning_icon_name = warning_icon_name; + if (warning_icon_name.empty()) + m_bmp = m_empty_bmp; +} + void ObjectDataViewModelNode::update_settings_digest_bitmaps() { m_bmp = m_empty_bmp; @@ -316,6 +326,8 @@ ObjectDataViewModel::ObjectDataViewModel() m_volume_bmps = MenuFactory::get_volume_bitmaps(); m_warning_bmp = create_scaled_bitmap(WarningIcon); + m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); + for (auto item : INFO_ITEMS) m_info_bmps[item.first] = create_scaled_bitmap(item.second.bmp_name); } @@ -328,15 +340,19 @@ ObjectDataViewModel::~ObjectDataViewModel() m_bitmap_cache = nullptr; } +wxBitmap& ObjectDataViewModel::GetWarningBitmap(const std::string& warning_icon_name) +{ + return warning_icon_name.empty() ? m_empty_bmp : warning_icon_name == WarningIcon ? m_warning_bmp : m_warning_manifold_bmp; +} + wxDataViewItem ObjectDataViewModel::Add(const wxString &name, const int extruder, - const bool has_errors/* = false*/) + const std::string& warning_icon_name/* = std::string()*/ ) { - const wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); + const wxString extruder_str = extruder == 0 ? _L("default") : wxString::Format("%d", extruder); auto root = new ObjectDataViewModelNode(name, extruder_str); - // Add error icon if detected auto-repaire - if (has_errors) - root->m_bmp = m_warning_bmp; + // Add warning icon if detected auto-repaire + root->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); m_objects.push_back(root); // notify control @@ -350,7 +366,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name, wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, - const bool has_errors/* = false*/, + const std::string& warning_icon_name/* = std::string()*/, const int extruder/* = 0*/, const bool create_frst_child/* = true*/) { @@ -364,12 +380,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent if (insert_position < 0) insert_position = get_root_idx(root, itInstanceRoot); - const bool obj_errors = root->m_bmp.IsOk(); - if (create_frst_child && root->m_volumes_cnt == 0) { const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART; - const auto node = new ObjectDataViewModelNode(root, root->m_name, type, GetVolumeIcon(type, obj_errors), extruder_str, 0); + const auto node = new ObjectDataViewModelNode(root, root->m_name, type, GetVolumeIcon(type, root->m_warning_icon_name), extruder_str, 0, root->m_warning_icon_name); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control @@ -380,12 +394,13 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent if (insert_position >= 0) insert_position++; } - const auto node = new ObjectDataViewModelNode(root, name, volume_type, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt); + const auto node = new ObjectDataViewModelNode(root, name, volume_type, GetVolumeIcon(volume_type, warning_icon_name), extruder_str, root->m_volumes_cnt, warning_icon_name); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // if part with errors is added, but object wasn't marked, then mark it - if (!obj_errors && has_errors) - root->SetBitmap(m_warning_bmp); + if (!warning_icon_name.empty() && warning_icon_name != root->m_warning_icon_name && + (root->m_warning_icon_name.empty() || root->m_warning_icon_name == WarningManifoldIcon) ) + root->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); // notify control const wxDataViewItem child((void*)node); @@ -1665,6 +1680,7 @@ void ObjectDataViewModel::Rescale() { m_volume_bmps = MenuFactory::get_volume_bitmaps(); m_warning_bmp = create_scaled_bitmap(WarningIcon); + m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); wxDataViewItemArray all_items; GetAllChildren(wxDataViewItem(0), all_items); @@ -1680,10 +1696,10 @@ void ObjectDataViewModel::Rescale() switch (node->m_type) { case itObject: - if (node->m_bmp.IsOk()) node->m_bmp = m_warning_bmp; + if (node->m_bmp.IsOk()) node->m_bmp = GetWarningBitmap(node->m_warning_icon_name); break; case itVolume: - node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight()); + node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_warning_icon_name); break; case itLayerRoot: node->m_bmp = create_scaled_bitmap(LayerRootIcon); @@ -1697,19 +1713,19 @@ void ObjectDataViewModel::Rescale() } } -wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/) +wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const std::string& warning_icon_name/* = std::string()*/) { - if (!is_marked) + if (warning_icon_name.empty()) return m_volume_bmps[static_cast(vol_type)]; - std::string scaled_bitmap_name = "warning" + std::to_string(static_cast(vol_type)); - scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit()); + std::string scaled_bitmap_name = warning_icon_name + std::to_string(static_cast(vol_type)); + scaled_bitmap_name += "-em" + std::to_string(wxGetApp().em_unit()) + (wxGetApp().dark_mode() ? "-dm" : "-lm"); wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name); if (bmp == nullptr) { std::vector bmps; - bmps.emplace_back(m_warning_bmp); + bmps.emplace_back(GetWarningBitmap(warning_icon_name)); bmps.emplace_back(m_volume_bmps[static_cast(vol_type)]); bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps); @@ -1718,20 +1734,20 @@ wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_ty return *bmp; } -void ObjectDataViewModel::AddWarningIcon(const wxDataViewItem& item) +void ObjectDataViewModel::AddWarningIcon(const wxDataViewItem& item, const std::string& warning_icon_name) { if (!item.IsOk()) return; ObjectDataViewModelNode *node = static_cast(item.GetID()); if (node->GetType() & itObject) { - node->SetBitmap(m_warning_bmp); + node->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); return; } if (node->GetType() & itVolume) { - node->SetBitmap(GetVolumeIcon(node->GetVolumeType(), true)); - node->GetParent()->SetBitmap(m_warning_bmp); + node->SetWarningBitmap(GetVolumeIcon(node->GetVolumeType(), warning_icon_name), warning_icon_name); + node->GetParent()->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); return; } } @@ -1747,11 +1763,11 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo return; if (node->GetType() & itVolume) { - node->SetBitmap(m_volume_bmps[static_cast(node->volume_type())]); + node->SetWarningBitmap(m_volume_bmps[static_cast(node->volume_type())], ""); return; } - node->SetBitmap(wxNullBitmap); + node->SetWarningBitmap(wxNullBitmap, ""); if (unmark_object) { wxDataViewItemArray children; diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index f65f829f4..95e53babd 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -78,6 +78,7 @@ class ObjectDataViewModelNode wxBitmap m_action_icon; PrintIndicator m_printable {piUndef}; wxBitmap m_printable_icon; + std::string m_warning_icon_name{ "" }; std::string m_action_icon_name = ""; ModelVolumeType m_volume_type; @@ -100,7 +101,8 @@ public: Slic3r::ModelVolumeType type, const wxBitmap& bmp, const wxString& extruder, - const int idx = -1); + const int idx = -1, + const std::string& warning_icon_name = std::string()); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const t_layer_height_range& layer_range, @@ -179,6 +181,7 @@ public: void SetVolumeType(ModelVolumeType type) { m_volume_type = type; } void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } void SetExtruder(const wxString &extruder) { m_extruder = extruder; } + void SetWarningBitmap(const wxBitmap& icon, const std::string& warning_icon_name) { m_bmp = icon; m_warning_icon_name = warning_icon_name; } const wxBitmap& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } @@ -225,6 +228,8 @@ public: void set_extruder_icon(); // Set printable icon for node void set_printable_icon(PrintIndicator printable); + // Set warning icon for node + void set_warning_icon(const std::string& warning_icon); void update_settings_digest_bitmaps(); bool update_settings_digest(const std::vector& categories); @@ -253,7 +258,9 @@ class ObjectDataViewModel :public wxDataViewModel std::vector m_objects; std::vector m_volume_bmps; std::map m_info_bmps; + wxBitmap m_empty_bmp; wxBitmap m_warning_bmp; + wxBitmap m_warning_manifold_bmp; wxDataViewCtrl* m_ctrl { nullptr }; @@ -263,11 +270,11 @@ public: wxDataViewItem Add( const wxString &name, const int extruder, - const bool has_errors = false); + const std::string& warning_icon_name = std::string()); wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, - const bool has_errors = false, + const std::string& warning_icon_name = std::string(), const int extruder = 0, const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); @@ -378,8 +385,8 @@ public: void Rescale(); wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, - const bool is_marked = false); - void AddWarningIcon(const wxDataViewItem& item); + const std::string& warning_icon_name = std::string()); + void AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; @@ -392,6 +399,8 @@ private: wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type); wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); void AddAllChildren(const wxDataViewItem& parent); + + wxBitmap& GetWarningBitmap(const std::string& warning_icon_name); }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 89b30a47f..4ffa7dc13 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -125,6 +125,7 @@ wxDEFINE_EVENT(EVT_EXPORT_BEGAN, wxCommandEvent); class ObjectInfo : public wxStaticBoxSizer { + std::string m_warning_icon_name{ "exclamation" }; public: ObjectInfo(wxWindow *parent); @@ -142,6 +143,7 @@ public: bool showing_manifold_warning_icon; void show_sizer(bool show); void msw_rescale(); + void update_warning_icon(const std::string& warning_icon_name); }; ObjectInfo::ObjectInfo(wxWindow *parent) : @@ -175,7 +177,7 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : info_manifold_text->SetFont(wxGetApp().small_font()); info_manifold = new wxStaticText(parent, wxID_ANY, ""); info_manifold->SetFont(wxGetApp().small_font()); - manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap("exclamation")); + manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap(m_warning_icon_name)); auto *sizer_manifold = new wxBoxSizer(wxHORIZONTAL); sizer_manifold->Add(info_manifold_text, 0); sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2); @@ -194,7 +196,15 @@ void ObjectInfo::show_sizer(bool show) void ObjectInfo::msw_rescale() { - manifold_warning_icon->SetBitmap(create_scaled_bitmap("exclamation")); + manifold_warning_icon->SetBitmap(create_scaled_bitmap(m_warning_icon_name)); +} + +void ObjectInfo::update_warning_icon(const std::string& warning_icon_name) +{ + if (warning_icon_name.empty()) + return; + m_warning_icon_name = warning_icon_name; + manifold_warning_icon->SetBitmap(create_scaled_bitmap(m_warning_icon_name)); } enum SlicedInfoIdx @@ -1129,30 +1139,19 @@ void Sidebar::show_info_sizer() p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0)*koef, size(1)*koef, size(2)*koef)); p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast(model_object->materials_count()))); - const auto& stats = model_object->get_object_stl_stats();//model_object->volumes.front()->mesh.stl.stats; + const auto& stats = model_object->get_object_stl_stats(); p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume*pow(koef,3))); p->object_info->info_facets->SetLabel(format_wxstr(_L_PLURAL("%1% (%2$d shell)", "%1% (%2$d shells)", stats.number_of_parts), static_cast(model_object->facets_count()), stats.number_of_parts)); - int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + - stats.facets_reversed + stats.backwards_edges; - if (errors > 0) { - wxString tooltip = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors); - p->object_info->info_manifold->SetLabel(tooltip); + if (stats.repaired()) { + int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_reversed + stats.backwards_edges; + p->object_info->info_manifold->SetLabel(format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors)); - tooltip += ":\n"; - if (stats.degenerate_facets > 0) - tooltip += format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", stats.degenerate_facets), stats.degenerate_facets) + ", "; - if (stats.edges_fixed > 0) - tooltip += format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", stats.edges_fixed), stats.edges_fixed) + ", "; - if (stats.facets_removed > 0) - tooltip += format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", stats.facets_removed), stats.facets_removed) + ", "; - if (stats.facets_reversed > 0) - tooltip += format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", stats.facets_reversed), stats.facets_reversed) + ", "; - if (stats.backwards_edges > 0) - tooltip += format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", stats.backwards_edges), stats.backwards_edges) + ", "; - tooltip.RemoveLast(2);//remove last coma + auto mesh_errors = obj_list()->get_mesh_errors(true); + wxString tooltip = mesh_errors.first; + p->object_info->update_warning_icon(mesh_errors.second); p->object_info->showing_manifold_warning_icon = true; p->object_info->info_manifold->SetToolTip(tooltip); p->object_info->manifold_warning_icon->SetToolTip(tooltip);