diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 306a546c57..106ea2d160 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -71,6 +71,8 @@ ObjectList::ObjectList(wxWindow* parent) : Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, [this](wxDataViewEvent& e) {on_begin_drag(e); }); Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, [this](wxDataViewEvent& e) {on_drop_possible(e); }); Bind(wxEVT_DATAVIEW_ITEM_DROP, [this](wxDataViewEvent& e) {on_drop(e); }); + + Bind(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED,[this](wxCommandEvent& e) {last_volume_is_deleted(e.GetInt()); }); } ObjectList::~ObjectList() @@ -88,6 +90,7 @@ void ObjectList::create_objects_ctrl() m_objects_model = new PrusaObjectDataViewModel; AssociateModel(m_objects_model); + m_objects_model->SetAssociatedControl(this); #if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE EnableDragSource(wxDF_UNICODETEXT); EnableDropTarget(wxDF_UNICODETEXT); @@ -96,7 +99,7 @@ void ObjectList::create_objects_ctrl() // column 0(Icon+Text) of the view control: // And Icon can be consisting of several bitmaps AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(), - 0, 250, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); + 0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); // column 1 of the view control: AppendColumn(create_objects_list_extruder_column(4)); @@ -1434,5 +1437,19 @@ void ObjectList::change_part_type() } } +void ObjectList::last_volume_is_deleted(const int obj_idx) +{ + + if (obj_idx < 0 || (*m_objects).empty() || (*m_objects)[obj_idx]->volumes.empty()) + return; + auto volume = (*m_objects)[obj_idx]->volumes[0]; + + // clear volume's config values + volume->config.clear(); + + // set a default extruder value, since user can't add it manually + volume->config.set_key_value("extruder", new ConfigOptionInt(0)); +} + } //namespace GUI } //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index d5f4848adb..dd0b27bd7a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -149,6 +149,8 @@ public: ModelVolume* get_selected_model_volume(); void change_part_type(); + + void last_volume_is_deleted(const int obj_idx); }; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index bf3857870a..6d68d4f02f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -12,6 +12,7 @@ #include "Model.hpp" wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); +wxDEFINE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const std::string& icon, wxEvtHandler* event_handler) @@ -564,12 +565,22 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_ // thus removing the node from it doesn't result in freeing it if (node_parent) { + if (node->m_type == itInstanceRoot) + { + for (int i = node->GetChildCount() - 1; i > 0; i--) + Delete(wxDataViewItem(node->GetNthChild(i))); + return parent; + } + auto id = node_parent->GetChildren().Index(node); auto idx = node->GetIdx(); - node_parent->GetChildren().Remove(node); - if (node->m_type == itVolume) + + if (node->m_type == itVolume) { node_parent->m_volumes_cnt--; + DeleteSettings(item); + } + node_parent->GetChildren().Remove(node); if (id > 0) { if(id == node_parent->GetChildCount()) id--; @@ -600,21 +611,69 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) obj_node->GetChildren().Remove(node_parent); delete node_parent; ret_item = wxDataViewItem(obj_node); - ItemDeleted(ret_item, wxDataViewItem(node_parent)); #ifndef __WXGTK__ if (obj_node->GetChildCount() == 0) obj_node->m_container = false; #endif //__WXGTK__ + ItemDeleted(ret_item, wxDataViewItem(node_parent)); return ret_item; } + + // if there is last volume item after deleting, delete this last volume too + if (node_parent->GetChildCount() <= 3) + { + int vol_cnt = 0; + int vol_idx = 0; + for (int i = 0; i < node_parent->GetChildCount(); ++i) { + if (node_parent->GetNthChild(i)->GetType() == itVolume) { + vol_idx = i; + vol_cnt++; + } + if (vol_cnt > 1) + break; + } + + if (vol_cnt == 1) { + delete node; + ItemDeleted(parent, item); + + PrusaObjectDataViewModelNode *last_child_node = node_parent->GetNthChild(vol_idx); + DeleteSettings(wxDataViewItem(last_child_node)); + node_parent->GetChildren().Remove(last_child_node); + delete last_child_node; + +#ifndef __WXGTK__ + if (node_parent->GetChildCount() == 0) + node_parent->m_container = false; +#endif //__WXGTK__ + ItemDeleted(parent, wxDataViewItem(last_child_node)); + + wxCommandEvent event(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED); + auto it = find(m_objects.begin(), m_objects.end(), node_parent); + event.SetInt(it == m_objects.end() ? -1 : it - m_objects.begin()); + wxPostEvent(m_ctrl, event); + + ret_item = parent; + + return ret_item; + } + } } else { auto it = find(m_objects.begin(), m_objects.end(), node); auto id = it - m_objects.begin(); if (it != m_objects.end()) + { + // Delete all sub-items + int i = m_objects[id]->GetChildCount() - 1; + while (i >= 0) { + Delete(wxDataViewItem(m_objects[id]->GetNthChild(i))); + i = m_objects[id]->GetChildCount() - 1; + } m_objects.erase(it); + } if (id > 0) { if(id == m_objects.size()) id--; ret_item = wxDataViewItem(m_objects[id]); @@ -733,8 +792,8 @@ void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) continue; auto item = wxDataViewItem(node); + DeleteSettings(item); children.RemoveAt(id); - root->m_volumes_cnt--; // free the node delete node; @@ -742,6 +801,7 @@ void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) // notify control ItemDeleted(parent, item); } + root->m_volumes_cnt = 0; // set m_containet to FALSE if parent has no child #ifndef __WXGTK__ @@ -749,6 +809,21 @@ void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) #endif //__WXGTK__ } +void PrusaObjectDataViewModel::DeleteSettings(const wxDataViewItem& parent) +{ + PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent.GetID(); + if (!node) return; + + // if volume has a "settings"item, than delete it before volume deleting + if (node->GetChildCount() > 0 && node->GetNthChild(0)->GetType() == itSettings) { + auto settings_node = node->GetNthChild(0); + auto settings_item = wxDataViewItem(settings_node); + node->GetChildren().RemoveAt(0); + delete settings_node; + ItemDeleted(parent, settings_item); + } +} + wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx) { if (obj_idx >= m_objects.size()) @@ -841,7 +916,7 @@ void PrusaObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type = itUndef; PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); - if (!node || node->GetIdx() < 0 && !(node->GetType() & (itObject|itSettings|itInstanceRoot))) + if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot))) return; idx = node->GetIdx(); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index e5e4600da7..d9f996b27c 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -422,11 +422,16 @@ private: // PrusaObjectDataViewModel // ---------------------------------------------------------------------------- +// custom message the model sends to associated control to notify a last volume deleted from the object: +wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); + class PrusaObjectDataViewModel :public wxDataViewModel { std::vector m_objects; std::vector m_volume_bmps; + wxDataViewCtrl* m_ctrl{ nullptr }; + public: PrusaObjectDataViewModel(); ~PrusaObjectDataViewModel(); @@ -444,6 +449,7 @@ public: void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); void DeleteVolumeChildren(wxDataViewItem& parent); + void DeleteSettings(const wxDataViewItem& parent); wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); @@ -500,6 +506,8 @@ public: void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } void SetVolumeType(const wxDataViewItem &item, const int type); + + void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } }; // ----------------------------------------------------------------------------