diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index da5095bb6c..8721b4249f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -898,8 +898,10 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con void ObjectList::split(const bool split_part) { const auto item = GetSelection(); - if (!item || m_selected_object_id < 0) + const int obj_idx = get_selected_obj_idx(); + if (!item || obj_idx < 0) return; + ModelVolume* volume; if (!get_volume_by_item(split_part, item, volume)) return; DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config; @@ -909,52 +911,51 @@ void ObjectList::split(const bool split_part) return; } - auto model_object = (*m_objects)[m_selected_object_id]; + auto model_object = (*m_objects)[obj_idx]; - if (split_part) { - auto parent = m_objects_model->GetParent(item); - m_objects_model->DeleteChildren(parent); + auto parent = m_objects_model->GetTopParent(item); + if (parent) + m_objects_model->DeleteVolumeChildren(parent); + else + parent = item; - for (auto id = 0; id < model_object->volumes.size(); id++) - m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, - model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, - model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0, - false); - - Expand(parent); - } - else { - for (auto id = 0; id < model_object->volumes.size(); id++) - m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name, - ModelVolume::MODEL_PART, - model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0, - false); - Expand(item); + for (auto id = 0; id < model_object->volumes.size(); id++) { + const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, + model_object->volumes[id]->is_modifier() ? + ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, + model_object->volumes[id]->config.has("extruder") ? + model_object->volumes[id]->config.option("extruder")->value : 0, + false); + // add settings to the part, if it has those + auto opt_keys = model_object->volumes[id]->config.keys(); + if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { + select_item(m_objects_model->AddSettingsChild(vol_item)); + Collapse(vol_item); + } } m_parts_changed = true; - parts_changed(m_selected_object_id); - - // restores selection -// _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id); + parts_changed(obj_idx); } bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume) { - if (!item || m_selected_object_id < 0) + auto obj_idx = get_selected_obj_idx(); + if (!item || obj_idx < 0) return false; const auto volume_id = m_objects_model->GetVolumeIdByItem(item); + + // object is selected if (volume_id < 0) { - if (split_part) return false; - volume = (*m_objects)[m_selected_object_id]->volumes[0]; + if ( split_part || (*m_objects)[obj_idx]->volumes.size() > 1 ) + return false; + volume = (*m_objects)[obj_idx]->volumes[0]; } + // volume is selected else - volume = (*m_objects)[m_selected_object_id]->volumes[volume_id]; - if (volume) - return true; - return false; + volume = (*m_objects)[obj_idx]->volumes[volume_id]; + + return true; } bool ObjectList::is_splittable_object(const bool split_part) @@ -962,20 +963,14 @@ bool ObjectList::is_splittable_object(const bool split_part) const wxDataViewItem item = GetSelection(); if (!item) return false; - wxDataViewItemArray children; - if (!split_part && m_objects_model->GetChildren(item, children) > 0) - return false; - ModelVolume* volume; if (!get_volume_by_item(split_part, item, volume) || !volume) return false; TriangleMeshPtrs meshptrs = volume->mesh.split(); bool splittable = meshptrs.size() > 1; - for (TriangleMesh* m : meshptrs) - { - delete m; - } + for (TriangleMesh* m : meshptrs) { delete m; } + return splittable; } @@ -1076,6 +1071,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) m_objects_model->SetValue(variant, item, 0); } + // add volumes to the object if (model_object->volumes.size() > 1) { for (auto id = 0; id < model_object->volumes.size(); id++) m_objects_model->AddVolumeChild(item, @@ -1086,9 +1082,17 @@ void ObjectList::add_object_to_list(size_t obj_idx) Expand(item); } + // add instances to the object, if it has those if (model_object->instances.size()>1) increase_object_instances(obj_idx, model_object->instances.size()); + // add settings to the object, if it has those + auto opt_keys = model_object->config.keys(); + if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { + select_item(m_objects_model->AddSettingsChild(item)); + Collapse(item); + } + #ifndef __WXOSX__ selection_changed(); #endif //__WXMSW__ @@ -1198,11 +1202,18 @@ void ObjectList::update_selections() auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection(); wxDataViewItemArray sels; - for (auto idx: selection.get_volume_idxs()) - { - const auto gl_vol = selection.get_volume(idx); - sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); + if (selection.is_single_full_object()) { + for (auto idx : selection.get_volume_idxs()) { + const auto gl_vol = selection.get_volume(idx); + sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); + } } + else if (selection.is_single_full_instance()) { + for (auto idx : selection.get_instance_idxs()) { + sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), idx)); + } + } + select_items(sels); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8d6a0408e5..c5743c3cee 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -714,6 +714,39 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent) #endif //__WXGTK__ } +void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) +{ + PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent.GetID(); + if (!root) // happens if item.IsOk()==false + return; + + // first remove the node from the parent's array of children; + // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_ + // thus removing the node from it doesn't result in freeing it + auto& children = root->GetChildren(); + for (int id = root->GetChildCount() - 1; id >= 0; --id) + { + auto node = children[id]; + if (node->m_type != itVolume) + continue; + + auto item = wxDataViewItem(node); + children.RemoveAt(id); + root->m_volumes_cnt--; + + // free the node + delete node; + + // notify control + ItemDeleted(parent, item); + } + + // set m_containet to FALSE if parent has no child +#ifndef __WXGTK__ + root->m_container = false; +#endif //__WXGTK__ +} + wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx) { if (obj_idx >= m_objects.size()) @@ -727,7 +760,7 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx) wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx) { - if (obj_idx >= m_objects.size()) { + if (obj_idx >= m_objects.size() || obj_idx < 0) { printf("Error! Out of objects range.\n"); return wxDataViewItem(0); } @@ -749,6 +782,25 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu return wxDataViewItem(0); } +wxDataViewItem PrusaObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx) +{ + if (obj_idx >= m_objects.size() || obj_idx < 0) { + printf("Error! Out of objects range.\n"); + return wxDataViewItem(0); + } + + auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx])); + if (!instances_item) + return wxDataViewItem(0); + + auto parent = (PrusaObjectDataViewModelNode*)instances_item.GetID();; + for (size_t i = 0; i < parent->GetChildCount(); i++) + if (parent->GetNthChild(i)->m_idx == inst_idx) + return wxDataViewItem(parent->GetNthChild(i)); + + return wxDataViewItem(0); +} + int PrusaObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) { wxASSERT(item.IsOk()); @@ -1024,21 +1076,33 @@ ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const return node->m_type; } -wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const +wxDataViewItem PrusaObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const { - if (!item.IsOk()) + if (!parent_item.IsOk()) return wxDataViewItem(0); - PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); + PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent_item.GetID(); if (node->GetChildCount() == 0) return wxDataViewItem(0); - if (node->GetNthChild(0)->m_type == itSettings) - return wxDataViewItem((void*)node->GetNthChild(0)); + for (int i = 0; i < node->GetChildCount(); i++) { + if (node->GetNthChild(i)->m_type == type) + return wxDataViewItem((void*)node->GetNthChild(i)); + } return wxDataViewItem(0); } +wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const +{ + return GetItemByType(item, itSettings); +} + +wxDataViewItem PrusaObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const +{ + return GetItemByType(item, itInstanceRoot); +} + bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const { if (!item.IsOk()) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 3c91592335..6293fb9628 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -443,8 +443,10 @@ public: wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); + void DeleteVolumeChildren(wxDataViewItem& parent); wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); + wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); int GetIdByItem(const wxDataViewItem& item); int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; @@ -490,7 +492,9 @@ public: virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } ItemType GetItemType(const wxDataViewItem &item) const ; + wxDataViewItem GetItemByType(const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; + wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector& categories);