Merge remote-tracking branch 'remotes/origin/master' into vb_wold_object_manipulation

This commit is contained in:
bubnikv 2019-05-03 19:13:47 +02:00
commit a8241ad7f7
10 changed files with 421 additions and 153 deletions

View File

@ -1516,6 +1516,50 @@ std::string ModelObject::get_export_filename() const
return ret;
}
stl_stats ModelObject::get_object_stl_stats() const
{
if (this->volumes.size() == 1)
return this->volumes[0]->mesh.stl.stats;
stl_stats full_stats = this->volumes[0]->mesh.stl.stats;
// fill full_stats from all objet's meshes
for (ModelVolume* volume : this->volumes)
{
if (volume->id() == this->volumes[0]->id())
continue;
const stl_stats& stats = volume->mesh.stl.stats;
// initialize full_stats (for repaired errors)
full_stats.degenerate_facets += stats.degenerate_facets;
full_stats.edges_fixed += stats.edges_fixed;
full_stats.facets_removed += stats.facets_removed;
full_stats.facets_added += stats.facets_added;
full_stats.facets_reversed += stats.facets_reversed;
full_stats.backwards_edges += stats.backwards_edges;
// another used satistics value
if (volume->is_model_part()) {
full_stats.volume += stats.volume;
full_stats.number_of_parts += stats.number_of_parts;
}
}
return full_stats;
}
int ModelObject::get_mesh_errors_count(const int vol_idx /*= -1*/) const
{
if (vol_idx >= 0)
return this->volumes[vol_idx]->get_mesh_errors_count();
const stl_stats& stats = get_object_stl_stats();
return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
}
void ModelVolume::set_material_id(t_model_material_id material_id)
{
m_material_id = material_id;
@ -1581,6 +1625,14 @@ void ModelVolume::calculate_convex_hull()
m_convex_hull = mesh.convex_hull_3d();
}
int ModelVolume::get_mesh_errors_count() const
{
const stl_stats& stats = this->mesh.stl.stats;
return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
}
const TriangleMesh& ModelVolume::get_convex_hull() const
{
return m_convex_hull;

View File

@ -289,6 +289,11 @@ public:
std::string get_export_filename() const;
// Get full stl statistics for all object's meshes
stl_stats get_object_stl_stats() const;
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
int get_mesh_errors_count(const int vol_idx = -1) const;
protected:
friend class Print;
friend class SLAPrint;
@ -382,6 +387,8 @@ public:
void calculate_convex_hull();
const TriangleMesh& get_convex_hull() const;
// Get count of errors in the mesh
int get_mesh_errors_count() const;
// Helpers for loading / storing into AMF / 3MF files.
static ModelVolumeType type_from_string(const std::string &s);

View File

@ -303,13 +303,13 @@ bool GUI_App::dark_mode_menus()
void GUI_App::init_label_colours()
{
if (dark_mode()) {
m_color_label_modified = wxColour(252, 77, 1);
m_color_label_sys = wxColour(26, 132, 57);
}
else {
m_color_label_modified = wxColour(253, 111, 40);
m_color_label_sys = wxColour(115, 220, 103);
}
else {
m_color_label_modified = wxColour(252, 77, 1);
m_color_label_sys = wxColour(26, 132, 57);
}
m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
}

View File

@ -211,6 +211,76 @@ void ObjectList::create_popup_menus()
create_instance_popupmenu(&m_menu_instance);
}
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(0)*/)
{
const wxDataViewItem item = input_item == wxDataViewItem(0) ? GetSelection() : input_item;
if (!item)
{
obj_idx = vol_idx = -1;
return;
}
const ItemType type = m_objects_model->GetItemType(item);
obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
type & itVolume ? m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)) : -1;
vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
}
int ObjectList::get_mesh_errors_count(const int obj_idx, const int vol_idx /*= -1*/) const
{
if (obj_idx < 0)
return 0;
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
{
const int errors = get_mesh_errors_count(obj_idx, vol_idx);
if (errors == 0)
return ""; // hide tooltip
// Create tooltip string, if there are errors
wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors):\n")), errors);
const stl_stats& stats = vol_idx == -1 ?
(*m_objects)[obj_idx]->get_object_stl_stats() :
(*m_objects)[obj_idx]->volumes[vol_idx]->mesh.stl.stats;
std::map<std::string, int> error_msg = {
{ L("degenerate facets"), stats.degenerate_facets },
{ L("edges fixed"), stats.edges_fixed },
{ L("facets removed"), stats.facets_removed },
{ L("facets added"), stats.facets_added },
{ L("facets reversed"), stats.facets_reversed },
{ L("backwards edges"), stats.backwards_edges }
};
for (const auto& error : error_msg)
if (error.second > 0)
tooltip += wxString::Format("\t%d %s\n", error.second, _(error.first));
if (is_windows10())
tooltip += _(L("Right button click the icon to fix STL through Netfabb"));
return tooltip;
}
wxString ObjectList::get_mesh_errors_list()
{
if (!GetSelection())
return "";
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx);
return get_mesh_errors_list(obj_idx, vol_idx);
}
void ObjectList::set_tooltip_for_item(const wxPoint& pt)
{
wxDataViewItem item;
@ -218,40 +288,24 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt)
HitTest(pt, item, col);
if (!item) return;
/* GetMainWindow() return window, associated with wxDataViewCtrl.
* And for this window we should to set tooltips.
* Just this->SetToolTip(tooltip) => has no effect.
*/
if (col->GetTitle() == " " && GetSelectedItemsCount()<2)
GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings")));
else if (col->GetTitle() == _("Name") &&
m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.bmp().GetRefData()) {
int obj_idx = m_objects_model->GetIdByItem(item);
auto& stats = (*m_objects)[obj_idx]->volumes[0]->mesh.stl.stats;
int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors):\n")), errors);
std::map<std::string, int> error_msg;
error_msg[L("degenerate facets")] = stats.degenerate_facets;
error_msg[L("edges fixed")] = stats.edges_fixed;
error_msg[L("facets removed")] = stats.facets_removed;
error_msg[L("facets added")] = stats.facets_added;
error_msg[L("facets reversed")] = stats.facets_reversed;
error_msg[L("backwards edges")] = stats.backwards_edges;
for (auto error : error_msg)
else if (col->GetTitle() == _("Name"))
{
if (error.second > 0)
tooltip += wxString::Format(_("\t%d %s\n"), error.second, error.first);
#ifdef __WXMSW__
if (pt.x < 2 * wxGetApp().em_unit() || pt.x > 4 * wxGetApp().em_unit()) {
GetMainWindow()->SetToolTip(""); // hide tooltip
return;
}
// OR
// tooltip += wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, "
// "%d facets added, %d facets reversed, %d backwards edges")),
// stats.degenerate_facets, stats.edges_fixed, stats.facets_removed,
// stats.facets_added, stats.facets_reversed, stats.backwards_edges);
if (is_windows10())
tooltip += _(L("Right button click the icon to fix STL through Netfabb"));
GetMainWindow()->SetToolTip(tooltip);
#endif //__WXMSW__
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
GetMainWindow()->SetToolTip(get_mesh_errors_list(obj_idx, vol_idx));
}
else
GetMainWindow()->SetToolTip(""); // hide tooltip
@ -413,8 +467,8 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
void ObjectList::init_icons()
{
m_bmp_modifiermesh = ScalableBitmap(nullptr, "add_modifier"); // Add part
m_bmp_solidmesh = ScalableBitmap(nullptr, "add_part"); // Add modifier
m_bmp_solidmesh = ScalableBitmap(nullptr, "add_part"); // Add part
m_bmp_modifiermesh = ScalableBitmap(nullptr, "add_modifier"); // Add modifier
m_bmp_support_enforcer = ScalableBitmap(nullptr, "support_enforcer");// Add support enforcer
m_bmp_support_blocker = ScalableBitmap(nullptr, "support_blocker"); // Add support blocker
@ -430,6 +484,8 @@ void ObjectList::init_icons()
// init icon for manifold warning
m_bmp_manifold_warning = ScalableBitmap(nullptr, "exclamation");
// Set warning bitmap for the model
m_objects_model->SetWarningBitmap(&m_bmp_manifold_warning.bmp());
// init bitmap for "Split to sub-objects" context menu
m_bmp_split = ScalableBitmap(nullptr, "split_parts_SMALL");
@ -443,8 +499,8 @@ void ObjectList::rescale_icons()
m_bmp_vector.clear();
m_bmp_vector.reserve(4); // bitmaps for different types of parts
for (ScalableBitmap* bitmap : std::vector<ScalableBitmap*> {
&m_bmp_modifiermesh, // Add part
&m_bmp_solidmesh, // Add modifier
&m_bmp_solidmesh, // Add part
&m_bmp_modifiermesh, // Add modifier
&m_bmp_support_enforcer, // Add support enforcer
&m_bmp_support_blocker }) // Add support blocker
{
@ -455,6 +511,9 @@ void ObjectList::rescale_icons()
m_objects_model->SetVolumeBitmaps(m_bmp_vector);
m_bmp_manifold_warning.msw_rescale();
// Set warning bitmap for the model
m_objects_model->SetWarningBitmap(&m_bmp_manifold_warning.bmp());
m_bmp_split.msw_rescale();
m_bmp_cog.msw_rescale();
@ -516,7 +575,8 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
for (const ModelVolume* volume : volumes)
{
auto vol_item = m_objects_model->AddVolumeChild(object_item, volume->name, volume->type(),
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(object_item, volume->name, volume->type(),
volume->get_mesh_errors_count()>0 ,
volume->config.has("extruder") ? volume->config.option<ConfigOptionInt>("extruder")->value : 0);
auto opt_keys = volume->config.keys();
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
@ -592,10 +652,13 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
if (title == " ")
show_context_menu();
else if (title == _("Name") && pt.x >15 &&
m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.bmp().GetRefData())
else if (title == _("Name"))
{
if (is_windows10())
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
if (is_windows10() && get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
fix_through_netfabb();
}
@ -955,6 +1018,7 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
{
const std::vector<std::string>& options = get_options_for_bundle(bundle_name);
assert(m_config);
auto opt_keys = m_config->keys();
const DynamicPrintConfig& from_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
@ -984,6 +1048,10 @@ void ObjectList::update_settings_item()
const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item);
select_item(settings_item ? settings_item :
m_objects_model->AddSettingsChild(item));
// update object selection on Plater
if (!m_prevent_canvas_selection_update)
update_selections_on_canvas();
}
else {
auto panel = wxGetApp().sidebar().scrolled_panel();
@ -1153,13 +1221,15 @@ void ObjectList::append_menu_items_osx(wxMenu* menu)
menu->AppendSeparator();
}
void ObjectList::append_menu_item_fix_through_netfabb(wxMenu* menu)
wxMenuItem* ObjectList::append_menu_item_fix_through_netfabb(wxMenu* menu)
{
if (!is_windows10())
return;
append_menu_item(menu, wxID_ANY, _(L("Fix through the Netfabb")), "",
return nullptr;
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _(L("Fix through the Netfabb")), "",
[this](wxCommandEvent&) { fix_through_netfabb(); }, "", menu);
menu->AppendSeparator();
return menu_item;
}
void ObjectList::append_menu_item_export_stl(wxMenu* menu) const
@ -1345,21 +1415,23 @@ void ObjectList::load_subobject(ModelVolumeType type)
int obj_idx = m_objects_model->GetIdByItem(item);
if (obj_idx < 0) return;
wxArrayString part_names;
load_part((*m_objects)[obj_idx], part_names, type);
std::vector<std::pair<wxString, bool>> volumes_info;
load_part((*m_objects)[obj_idx], volumes_info, type);
changed_object(obj_idx);
for (int i = 0; i < part_names.size(); ++i) {
const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), type);
wxDataViewItem sel_item;
for (const auto& volume : volumes_info )
sel_item = m_objects_model->AddVolumeChild(item, volume.first, type, volume.second);
if (i == part_names.size() - 1)
if (sel_item)
select_item(sel_item);
}
}
void ObjectList::load_part( ModelObject* model_object,
wxArrayString& part_names,
std::vector<std::pair<wxString, bool>> &volumes_info,
ModelVolumeType type)
{
wxWindow* parent = wxGetApp().tab_panel()->GetPage(0);
@ -1395,7 +1467,7 @@ void ObjectList::load_part( ModelObject* model_object,
new_volume->set_type(type);
new_volume->name = boost::filesystem::path(input_file).filename().string();
part_names.Add(from_u8(new_volume->name));
volumes_info.push_back(std::make_pair(from_u8(new_volume->name), new_volume->get_mesh_errors_count()>0));
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -1544,7 +1616,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
changed_object(obj_idx);
const auto object_item = m_objects_model->GetTopParent(GetSelection());
select_item(m_objects_model->AddVolumeChild(object_item, name, type));
select_item(m_objects_model->AddVolumeChild(object_item, name, type,
new_volume->get_mesh_errors_count()>0));
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
@ -1576,6 +1649,10 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
else if (!del_subobject_from_object(obj_idx, idx, type))
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(m_objects_model->GetParent(item));
m_objects_model->Delete(item);
}
@ -1682,18 +1759,18 @@ void ObjectList::split()
else
parent = item;
for (auto id = 0; id < model_object->volumes.size(); id++) {
const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name),
model_object->volumes[id]->is_modifier() ?
ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART,
model_object->volumes[id]->config.has("extruder") ?
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
for (const ModelVolume* volume : model_object->volumes) {
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name),
volume->is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART,
volume->get_mesh_errors_count()>0,
volume->config.has("extruder") ?
volume->config.option<ConfigOptionInt>("extruder")->value : 0,
false);
// add settings to the part, if it has those
auto opt_keys = model_object->volumes[id]->config.keys();
auto opt_keys = volume->config.keys();
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
select_item(m_objects_model->AddSettingsChild(vol_item));
/*Collapse*/Expand(vol_item);
Expand(vol_item);
}
}
@ -1766,6 +1843,7 @@ void ObjectList::changed_object(const int obj_idx/* = -1*/) const
void ObjectList::part_selection_changed()
{
int obj_idx = -1;
int volume_id = -1;
m_config = nullptr;
wxString og_name = wxEmptyString;
@ -1812,7 +1890,7 @@ void ObjectList::part_selection_changed()
}
else if (m_objects_model->GetItemType(item) == itVolume) {
og_name = _(L("Part manipulation"));
const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
volume_id = m_objects_model->GetVolumeIdByItem(item);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
update_and_show_manipulations = true;
}
@ -1832,7 +1910,11 @@ void ObjectList::part_selection_changed()
if (update_and_show_manipulations) {
wxGetApp().obj_manipul()->get_og()->set_name(" " + og_name + " ");
wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(GetSelection()));
if (item) {
wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item));
wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors_list(obj_idx, volume_id));
}
}
if (update_and_show_settings)
@ -1852,34 +1934,26 @@ void ObjectList::part_selection_changed()
void ObjectList::add_object_to_list(size_t obj_idx)
{
auto model_object = (*m_objects)[obj_idx];
wxString item_name = from_u8(model_object->name);
const wxString& item_name = from_u8(model_object->name);
const auto item = m_objects_model->Add(item_name,
!model_object->config.has("extruder") ? 0 :
model_object->config.option<ConfigOptionInt>("extruder")->value);
// Add error icon if detected auto-repaire
auto stats = model_object->volumes[0]->mesh.stl.stats;
int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
if (errors > 0) {
wxVariant variant;
variant << DataViewBitmapText(item_name, m_bmp_manifold_warning.bmp());
m_objects_model->SetValue(variant, item, 0);
}
model_object->config.option<ConfigOptionInt>("extruder")->value,
get_mesh_errors_count(obj_idx) > 0);
// add volumes to the object
if (model_object->volumes.size() > 1) {
for (auto id = 0; id < model_object->volumes.size(); id++) {
auto vol_item = m_objects_model->AddVolumeChild(item,
from_u8(model_object->volumes[id]->name),
model_object->volumes[id]->type(),
!model_object->volumes[id]->config.has("extruder") ? 0 :
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value,
for (const ModelVolume* volume : model_object->volumes) {
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(item,
from_u8(volume->name),
volume->type(),
volume->get_mesh_errors_count()>0,
!volume->config.has("extruder") ? 0 :
volume->config.option<ConfigOptionInt>("extruder")->value,
false);
auto opt_keys = model_object->volumes[id]->config.keys();
auto opt_keys = volume->config.keys();
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
select_item(m_objects_model->AddSettingsChild(vol_item));
/*Collapse*/Expand(vol_item);
Expand(vol_item);
}
}
Expand(item);
@ -1893,7 +1967,7 @@ void ObjectList::add_object_to_list(size_t obj_idx)
auto opt_keys = model_object->config.keys();
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
select_item(m_objects_model->AddSettingsChild(item));
/*Collapse*/Expand(item);
Expand(item);
}
#ifndef __WXOSX__
@ -2087,6 +2161,11 @@ void ObjectList::update_selections()
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return;
}
// but if there is selected only one of several instances by context menu,
// then select this instance in ObjectList
if (selection.is_single_full_instance())
sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), selection.get_instance_idx()));
}
else if (selection.is_single_full_object() || selection.is_multiple_full_object())
{
@ -2677,18 +2756,10 @@ void ObjectList::rename_item()
update_name_in_model(item);
}
void ObjectList::fix_through_netfabb() const
void ObjectList::fix_through_netfabb()
{
const wxDataViewItem item = GetSelection();
if (!item)
return;
const ItemType type = m_objects_model->GetItemType(item);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
type & itVolume ? m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)) : -1;
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx);
wxGetApp().plater()->fix_through_netfabb(obj_idx, vol_idx);
@ -2702,28 +2773,27 @@ void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) co
if (!item)
return;
auto model_object = (*m_objects)[obj_idx];
const stl_stats& stats = model_object->volumes[vol_idx<0 ? 0 : vol_idx]->mesh.stl.stats;
const int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
if (errors == 0) {
// delete Error_icon if all errors are fixed
wxVariant variant;
variant << DataViewBitmapText(from_u8(model_object->name), wxNullBitmap);
m_objects_model->SetValue(variant, item, 0);
if (get_mesh_errors_count(obj_idx, vol_idx) == 0)
{
// if whole object has no errors more,
if (get_mesh_errors_count(obj_idx) == 0)
// unmark all items in the object
m_objects_model->DeleteWarningIcon(vol_idx >= 0 ? m_objects_model->GetParent(item) : item, true);
else
// unmark fixed item only
m_objects_model->DeleteWarningIcon(item);
}
}
void ObjectList::msw_rescale()
{
const int em = wxGetApp().em_unit();
// update min size !!! A width of control shouldn't be a wxDefaultCoord
SetMinSize(wxSize(1, 15 * wxGetApp().em_unit()));
SetMinSize(wxSize(1, 15 * em));
GetColumn(0)->SetWidth(19 * wxGetApp().em_unit());
GetColumn(1)->SetWidth(8 * wxGetApp().em_unit());
GetColumn(2)->SetWidth(int(2 * wxGetApp().em_unit()));
GetColumn(0)->SetWidth(19 * em);
GetColumn(1)->SetWidth( 8 * em);
GetColumn(2)->SetWidth( 2 * em);
// rescale all icons, used by ObjectList
rescale_icons();

View File

@ -175,6 +175,16 @@ public:
void init_icons();
void rescale_icons();
// Get obj_idx and vol_idx values for the selected (by default) or an adjusted item
void get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& item = wxDataViewItem(0));
// 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();
void set_tooltip_for_item(const wxPoint& pt);
void selection_changed();
@ -192,7 +202,7 @@ public:
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
void append_menu_items_osx(wxMenu* menu);
void append_menu_item_fix_through_netfabb(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const ;
void append_menu_item_change_extruder(wxMenu* menu) const;
void append_menu_item_delete(wxMenu* menu);
@ -206,7 +216,7 @@ public:
void update_opt_keys(t_config_option_keys& t_optopt_keys);
void load_subobject(ModelVolumeType type);
void load_part(ModelObject* model_object, wxArrayString& part_names, ModelVolumeType type);
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
void del_object(const int obj_idx);
void del_subobject_item(wxDataViewItem& item);
@ -280,7 +290,7 @@ public:
void instances_to_separated_objects(const int obj_idx);
void split_instances();
void rename_item();
void fix_through_netfabb() const;
void fix_through_netfabb();
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);

View File

@ -10,6 +10,7 @@
#include "Selection.hpp"
#include <boost/algorithm/string.hpp>
#include "slic3r/Utils/FixModelByWin10.hpp"
namespace Slic3r
{
@ -66,6 +67,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
, m_focused_option("")
#endif // __APPLE__
{
m_manifold_warning_bmp = ScalableBitmap(parent, "exclamation");
m_og->set_name(_(L("Object Manipulation")));
m_og->label_width = 12;//125;
m_og->set_grid_vgap(5);
@ -86,17 +88,51 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
ConfigOptionDef def;
// Objects(sub-objects) name
def.label = L("Name");
// def.label = L("Name");
// def.gui_type = "legend";
// def.tooltip = L("Object name");
// def.width = 21 * wxGetApp().em_unit();
// def.default_value = new ConfigOptionString{ " " };
// m_og->append_single_option_line(Option(def, "object_name"));
Line line = Line{ "Name", "Object name" };
auto manifold_warning_icon = [this](wxWindow* parent) {
m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap);
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_fix_throught_netfab_bitmap);
if (is_windows10())
m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e)
{
// if object/sub-object has no errors
if (m_fix_throught_netfab_bitmap->GetBitmap().GetRefData() == wxNullBitmap.GetRefData())
return;
wxGetApp().obj_list()->fix_through_netfabb();
update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list());
});
return sizer;
};
line.append_widget(manifold_warning_icon);
def.label = "";
def.gui_type = "legend";
def.tooltip = L("Object name");
#ifdef __APPLE__
def.width = 19;
#else
def.width = 21;
#endif
def.set_default_value(new ConfigOptionString{ " " });
m_og->append_single_option_line(Option(def, "object_name"));
line.append_option(Option(def, "object_name"));
m_og->append_line(line);
const int field_width = 5;
// Legend for object modification
auto line = Line{ "", "" };
line = Line{ "", "" };
def.label = "";
def.type = coString;
def.width = field_width/*50*/;
@ -353,6 +389,12 @@ void ObjectManipulation::emulate_kill_focus()
}
#endif // __APPLE__
void ObjectManipulation::update_warning_icon_state(const wxString& tooltip)
{
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
}
void ObjectManipulation::reset_settings_value()
{
m_new_position = Vec3d::Zero();
@ -568,5 +610,13 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
m_uniform_scale = new_value;
}
void ObjectManipulation::msw_rescale()
{
m_manifold_warning_bmp.msw_rescale();
m_fix_throught_netfab_bitmap->SetBitmap(m_manifold_warning_bmp.bmp());
get_og()->msw_rescale();
}
} //namespace GUI
} //namespace Slic3r

View File

@ -9,6 +9,7 @@
class wxBitmapComboBox;
class wxStaticText;
class LockButton;
class wxStaticBitmap;
namespace Slic3r {
namespace GUI {
@ -69,6 +70,9 @@ class ObjectManipulation : public OG_Settings
LockButton* m_lock_bnt{ nullptr };
wxBitmapComboBox* m_word_local_combo = nullptr;
ScalableBitmap m_manifold_warning_bmp;
wxStaticBitmap* m_fix_throught_netfab_bitmap;
#ifndef __APPLE__
// Currently focused option name (empty if none)
std::string m_focused_option;
@ -100,6 +104,9 @@ public:
void emulate_kill_focus();
#endif // __APPLE__
void update_warning_icon_state(const wxString& tooltip);
void msw_rescale();
private:
void reset_settings_value();
void update_settings_value(const Selection& selection);

View File

@ -731,7 +731,7 @@ Sidebar::Sidebar(Plater *parent)
auto init_btn = [this](wxButton **btn, wxString label) {
*btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition,
wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
wxDefaultSize, wxBU_EXACTFIT);
(*btn)->SetFont(wxGetApp().bold_font());
};
@ -903,8 +903,7 @@ void Sidebar::msw_rescale()
p->frequently_changed_parameters->get_og(false)->msw_rescale();
p->object_list->msw_rescale();
p->object_manipulation->get_og()->msw_rescale();
p->object_manipulation->msw_rescale();
p->object_settings->msw_rescale();
p->object_info->msw_rescale();
@ -977,7 +976,7 @@ void Sidebar::show_info_sizer()
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2)));
p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count())));
auto& stats = model_object->volumes.front()->mesh.stl.stats;
const auto& stats = model_object->get_object_stl_stats();//model_object->volumes.front()->mesh.stl.stats;
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume));
p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast<int>(model_object->facets_count()), stats.number_of_parts));
@ -1335,6 +1334,7 @@ struct Plater::priv
bool can_split_to_volumes() const;
bool can_arrange() const;
bool can_layers_editing() const;
bool can_fix_through_netfabb() const;
private:
bool init_object_menu();
@ -2937,7 +2937,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
menu->AppendSeparator();
}
sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu);
wxMenuItem* item_fix_through_netfabb = sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu);
wxMenu* mirror_menu = new wxMenu();
if (mirror_menu == nullptr)
@ -2957,6 +2957,8 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
{
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_mirror()); }, item_mirror->GetId());
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete->GetId());
if (item_fix_through_netfabb)
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_fix_through_netfabb()); }, item_fix_through_netfabb->GetId());
}
return true;
@ -3126,6 +3128,15 @@ bool Plater::priv::can_delete_all() const
return !model.objects.empty();
}
bool Plater::priv::can_fix_through_netfabb() const
{
int obj_idx = get_selected_object_idx();
if (obj_idx < 0)
return false;
return model.objects[obj_idx]->get_mesh_errors_count() > 0;
}
bool Plater::priv::can_increase_instances() const
{
if (arranging || rotoptimizing) {

View File

@ -420,14 +420,21 @@ ObjectDataViewModel::~ObjectDataViewModel()
m_bitmap_cache = nullptr;
}
wxDataViewItem ObjectDataViewModel::Add(const wxString &name, const int extruder)
wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
const int extruder,
const bool has_errors/* = false*/)
{
const wxString extruder_str = extruder == 0 ? "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;
m_objects.push_back(root);
// notify control
wxDataViewItem child((void*)root);
wxDataViewItem parent((void*)NULL);
ItemAdded(parent, child);
return child;
}
@ -435,6 +442,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name, const int extruder
wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item,
const wxString &name,
const Slic3r::ModelVolumeType volume_type,
const bool has_errors/* = false*/,
const int extruder/* = 0*/,
const bool create_frst_child/* = true*/)
{
@ -448,9 +456,14 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
insert_position = -1;
const bool obj_errors = root->m_bmp.IsOk();
if (create_frst_child && root->m_volumes_cnt == 0)
{
const auto node = new ObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0);
const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART;
const auto node = new ObjectDataViewModelNode(root, root->m_name, GetVolumeIcon(type, obj_errors), extruder_str, 0);
node->m_volume_type = type;
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// notify control
const wxDataViewItem child((void*)node);
@ -458,12 +471,15 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
root->m_volumes_cnt++;
if (insert_position > 0) insert_position++;
node->m_volume_type = volume_type;
}
const auto node = new ObjectDataViewModelNode(root, name, *m_volume_bmps[int(volume_type)], extruder_str, root->m_volumes_cnt);
const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt);
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);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
@ -1228,15 +1244,61 @@ void ObjectDataViewModel::Rescale()
node->msw_rescale();
if (node->m_type & itVolume)
node->m_bmp = *m_volume_bmps[node->volume_type()];
node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
if (node->m_type & itObject && node->m_bmp.IsOk())
node->m_bmp = create_scaled_bitmap(nullptr, "exclamation");
node->m_bmp = *m_warning_bmp;
ItemChanged(item);
}
}
wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/)
{
if (!is_marked)
return *m_volume_bmps[static_cast<int>(vol_type)];
std::string scaled_bitmap_name = "warning" + std::to_string(static_cast<int>(vol_type));
scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
if (bmp == nullptr) {
std::vector<wxBitmap> bmps;
bmps.emplace_back(*m_warning_bmp);
bmps.emplace_back(*m_volume_bmps[static_cast<int>(vol_type)]);
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
}
return *bmp;
}
void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object/* = false*/)
{
if (!item.IsOk())
return;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node->GetBitmap().IsOk() || !(node->GetType() & (itVolume | itObject)))
return;
if (node->GetType() & itVolume) {
node->SetBitmap(*m_volume_bmps[static_cast<int>(node->volume_type())]);
return;
}
node->SetBitmap(wxNullBitmap);
if (unmark_object)
{
wxDataViewItemArray children;
GetChildren(item, children);
for (const wxDataViewItem& child : children)
DeleteWarningIcon(child);
}
}
//-----------------------------------------------------------------------------
// PrusaDataViewBitmapText
//-----------------------------------------------------------------------------
@ -2379,11 +2441,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
m_mode_btns.reserve(3);
for (const auto& button : buttons) {
// int x, y;
// parent->GetTextExtent(button.first, &x, &y, nullptr, nullptr, &Slic3r::GUI::wxGetApp().bold_font());
// const wxSize size = wxSize(x + button.second.GetWidth() + Slic3r::GUI::wxGetApp().em_unit(),
// y + Slic3r::GUI::wxGetApp().em_unit());
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first/*, size*/));
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));
}
for (auto btn : m_mode_btns)

View File

@ -323,14 +323,10 @@ public:
return false;
}
void SetBitmap(const wxBitmap &icon)
{
m_bmp = icon;
}
ItemType GetType() const {
return m_type;
}
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
void SetIdx(const int& idx) {
m_idx = idx;
@ -339,9 +335,7 @@ public:
m_name = wxString::Format("Instance_%d", m_idx + 1);
}
int GetIdx() const {
return m_idx;
}
int GetIdx() const { return m_idx; }
// use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node)
@ -393,6 +387,7 @@ class ObjectDataViewModel :public wxDataViewModel
{
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxBitmap* m_warning_bmp;
wxDataViewCtrl* m_ctrl{ nullptr };
@ -400,10 +395,13 @@ public:
ObjectDataViewModel();
~ObjectDataViewModel();
wxDataViewItem Add(const wxString &name, const int extruder);
wxDataViewItem Add( const wxString &name,
const int extruder,
const bool has_errors = false);
wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item,
const wxString &name,
const Slic3r::ModelVolumeType volume_type,
const bool has_errors = false,
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
@ -475,11 +473,16 @@ public:
const std::vector<std::string>& categories);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
// Rescale bitmaps for existing Items
void Rescale();
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
};
// ----------------------------------------------------------------------------