diff options
Diffstat (limited to 'src/slic3r/GUI/GUI_ObjectList.cpp')
-rw-r--r-- | src/slic3r/GUI/GUI_ObjectList.cpp | 371 |
1 files changed, 318 insertions, 53 deletions
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dffaf7afc..62c00d02d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -21,6 +21,25 @@ namespace GUI wxDEFINE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); +typedef std::map<std::string, std::vector<std::string>> FreqSettingsBundle; + +// pt_FFF +FreqSettingsBundle FREQ_SETTINGS_BUNDLE_FFF = +{ + { L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } }, + { L("Infill") , { "fill_density", "fill_pattern" } }, + { L("Support material") , { "support_material", "support_material_auto", "support_material_threshold", + "support_material_pattern", "support_material_buildplate_only", + "support_material_spacing" } }, + { L("Extruders") , { "wipe_into_infill", "wipe_into_objects" } } +}; + +// pt_SLA +FreqSettingsBundle FREQ_SETTINGS_BUNDLE_SLA = +{ + { L("Pad and Support") , { "supports_enable", "pad_enable" } } +}; + ObjectList::ObjectList(wxWindow* parent) : wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE), m_parent(parent) @@ -51,6 +70,7 @@ ObjectList::ObjectList(wxWindow* parent) : create_object_popupmenu(&m_menu_object); create_part_popupmenu(&m_menu_part); create_sla_object_popupmenu(&m_menu_sla_object); + create_instance_popupmenu(&m_menu_instance); // describe control behavior Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { @@ -97,7 +117,7 @@ void ObjectList::create_objects_ctrl() // temporary workaround for the correct behavior of the Scrolled sidebar panel: // 1. set a height of the list to some big value // 2. change it to the normal min value (200) after first whole App updating/layouting - SetMinSize(wxSize(-1, 1500)); // #ys_FIXME + SetMinSize(wxSize(-1, 3000)); // #ys_FIXME m_sizer = new wxBoxSizer(wxVERTICAL); m_sizer->Add(this, 1, wxGROW | wxLEFT, 20); @@ -400,15 +420,28 @@ void ObjectList::OnContextMenu(wxDataViewEvent&) void ObjectList::show_context_menu() { + if (multiple_selection() && selected_instances_of_same_object()) + { + wxGetApp().plater()->PopupMenu(&m_menu_instance); + + wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { + evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId()); + return; + } + const auto item = GetSelection(); if (item) { - if (!(m_objects_model->GetItemType(item) & (itObject | itVolume))) + const ItemType type = m_objects_model->GetItemType(item); + if (!(type & (itObject | itVolume | itInstance))) return; - wxMenu* menu = m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part : + + wxMenu* menu = type & itInstance ? &m_menu_instance : + m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part : wxGetApp().plater()->printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object; - append_menu_item_settings(menu); + if (!(type & itInstance)) + append_menu_item_settings(menu); wxGetApp().plater()->PopupMenu(menu); @@ -443,15 +476,35 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) { const wxDataViewItem item(event.GetItem()); - // only allow drags for item, not containers - if (multiple_selection() || GetSelection()!=item || - m_objects_model->GetParent(item) == wxDataViewItem(0) || - m_objects_model->GetItemType(item) != itVolume ) { + const bool mult_sel = multiple_selection(); + + if (mult_sel && !selected_instances_of_same_object() || + !mult_sel && (GetSelection() != item || + m_objects_model->GetParent(item) == wxDataViewItem(0) ) ) { + event.Veto(); + return; + } + + const ItemType& type = m_objects_model->GetItemType(item); + if (!(type & (itVolume | itInstance))) { event.Veto(); return; } - m_dragged_data.init(m_objects_model->GetObjectIdByItem(item), m_objects_model->GetVolumeIdByItem(item)); + if (mult_sel) + { + m_dragged_data.init(m_objects_model->GetObjectIdByItem(item),type); + std::set<int>& sub_obj_idxs = m_dragged_data.inst_idxs(); + wxDataViewItemArray sels; + GetSelections(sels); + for (auto sel : sels ) + sub_obj_idxs.insert(m_objects_model->GetInstanceIdByItem(sel)); + } + else + m_dragged_data.init(m_objects_model->GetObjectIdByItem(item), + type&itVolume ? m_objects_model->GetVolumeIdByItem(item) : + m_objects_model->GetInstanceIdByItem(item), + type); /* Under MSW or OSX, DnD moves an item to the place of another selected item * But under GTK, DnD moves an item between another two items. @@ -470,31 +523,41 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move; } +bool ObjectList::can_drop(const wxDataViewItem& item) const +{ + return m_dragged_data.type() == itInstance && !item.IsOk() || + m_dragged_data.type() == itVolume && item.IsOk() && + m_objects_model->GetItemType(item) == itVolume && + m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item); +} + void ObjectList::OnDropPossible(wxDataViewEvent &event) { - wxDataViewItem item(event.GetItem()); + const wxDataViewItem& item = event.GetItem(); - // only allow drags for item or background, not containers - if (!item.IsOk() || - m_objects_model->GetParent(item) == wxDataViewItem(0) || - m_objects_model->GetItemType(item) != itVolume || - m_dragged_data.obj_idx() != m_objects_model->GetObjectIdByItem(item)) + if (!can_drop(item)) event.Veto(); } void ObjectList::OnDrop(wxDataViewEvent &event) { - wxDataViewItem item(event.GetItem()); + const wxDataViewItem& item = event.GetItem(); - if (!item.IsOk() || m_objects_model->GetParent(item) == wxDataViewItem(0) || - m_objects_model->GetItemType(item) != itVolume || - m_dragged_data.obj_idx() != m_objects_model->GetObjectIdByItem(item)) { + if (!can_drop(item)) + { event.Veto(); m_dragged_data.clear(); return; } - const int from_volume_id = m_dragged_data.vol_idx(); + if (m_dragged_data.type() == itInstance) + { + instances_to_separated_object(m_dragged_data.obj_idx(), m_dragged_data.inst_idxs()); + m_dragged_data.clear(); + return; + } + + const int from_volume_id = m_dragged_data.sub_obj_idx(); int to_volume_id = m_objects_model->GetVolumeIdByItem(item); // It looks like a fixed in current version of the wxWidgets @@ -506,7 +569,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event) // if (to_volume_id > from_volume_id) to_volume_id--; // #endif // __WXGTK__ - auto& volumes = (*m_objects)[/*m_selected_object_id*/m_dragged_data.obj_idx()]->volumes; + auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes; auto delta = to_volume_id < from_volume_id ? -1 : 1; int cnt = 0; for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++) @@ -516,7 +579,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event) m_objects_model->GetParent(item))); m_parts_changed = true; - parts_changed(/*m_selected_object_id*/m_dragged_data.obj_idx()); + parts_changed(m_dragged_data.obj_idx()); m_dragged_data.clear(); } @@ -547,6 +610,19 @@ std::vector<std::string> get_options(const bool is_part) { return get_options(is_part, wxGetApp().plater()->printer_technology() == ptSLA); } + +const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_name) +{ + const FreqSettingsBundle& bundle = wxGetApp().plater()->printer_technology() == ptSLA ? + FREQ_SETTINGS_BUNDLE_SLA : FREQ_SETTINGS_BUNDLE_FFF; + + for (auto& it : bundle) + { + if (bundle_name == _(it.first)) + return it.second; + } + return std::vector<std::string> {}; +} // category -> vector ( option ; label ) typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy; @@ -633,16 +709,39 @@ void ObjectList::get_settings_choice(const wxString& category_name) // Add settings item for object - const auto item = GetSelection(); + update_settings_item(); +} + +void ObjectList::get_freq_settings_choice(const wxString& bundle_name) +{ + const std::vector<std::string>& options = get_options_for_bundle(bundle_name); + + auto opt_keys = m_config->keys(); + + for (auto& opt_key : options) + { + if ( find(opt_keys.begin(), opt_keys.end(), opt_key) == opt_keys.end() ) + m_config->set_key_value(opt_key, m_default_config->option(opt_key)->clone()); + } + + // Add settings item for object + update_settings_item(); +} + +void ObjectList::update_settings_item() +{ + auto item = GetSelection(); if (item) { - const auto settings_item = m_objects_model->GetSettingsItem(item); + if (m_objects_model->GetItemType(item) == itInstance) + item = m_objects_model->GetTopParent(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)); } else { auto panel = wxGetApp().sidebar().scrolled_panel(); panel->Freeze(); - wxGetApp().obj_settings()->UpdateAndShow(true);//obj_manipul()->update_settings_list(); + wxGetApp().obj_settings()->UpdateAndShow(true); panel->Thaw(); } } @@ -650,9 +749,11 @@ void ObjectList::get_settings_choice(const wxString& category_name) void ObjectList::append_menu_item_add_generic(wxMenuItem* menu, const int type) { auto sub_menu = new wxMenu; + if (wxGetApp().get_mode() == comExpert) { append_menu_item(sub_menu, wxID_ANY, _(L("Load")) + " " + dots, "", [this, type](wxCommandEvent&) { load_subobject(type); }, "", menu->GetMenu()); sub_menu->AppendSeparator(); + } std::vector<std::string> menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }; for (auto& item : menu_items) { @@ -678,21 +779,25 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu) menu->Destroy(settings_id); } - if (wxGetApp().get_view_mode() == ConfigMenuModeSimple) + const ConfigOptionMode mode = wxGetApp().get_mode(); + + if (mode < comExpert) { append_menu_item(menu, wxID_ANY, _(L("Add part")), "", [this](wxCommandEvent&) { load_subobject(ModelVolume::MODEL_PART); }, *m_bmp_vector[ModelVolume::MODEL_PART]); + } + if (mode == comSimple) { append_menu_item(menu, wxID_ANY, _(L("Add support enforcer")), "", - [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_ENFORCER); }, + [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_ENFORCER); }, *m_bmp_vector[ModelVolume::SUPPORT_ENFORCER]); append_menu_item(menu, wxID_ANY, _(L("Add support blocker")), "", - [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_BLOCKER); }, + [this](wxCommandEvent&) { load_generic_subobject(_(L("Box")).ToUTF8().data(), ModelVolume::SUPPORT_BLOCKER); }, *m_bmp_vector[ModelVolume::SUPPORT_BLOCKER]); return; } - - for (int type = 0; type < menu_object_types_items.size(); type++) + + for (int type = mode == comExpert ? 0 : 1 ; type < menu_object_types_items.size(); type++) { auto& item = menu_object_types_items[type]; @@ -710,23 +815,57 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu) [this](wxCommandEvent&) { split(); }, m_bmp_split, menu); } -wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu) +wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) { - // Update (delete old & create new) settings popupmenu - const auto settings_id = menu->FindItem(_("Add settings")); + PrusaMenu* menu = dynamic_cast<PrusaMenu*>(menu_); + // Delete old items from settings popupmenu + auto settings_id = menu->FindItem(_("Add settings")); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); - if (wxGetApp().get_view_mode() == ConfigMenuModeSimple) + for (auto& it : FREQ_SETTINGS_BUNDLE_FFF) + { + settings_id = menu->FindItem(_(it.first)); + if (settings_id != wxNOT_FOUND) + menu->Destroy(settings_id); + } + for (auto& it : FREQ_SETTINGS_BUNDLE_SLA) + { + settings_id = menu->FindItem(_(it.first)); + if (settings_id != wxNOT_FOUND) + menu->Destroy(settings_id); + } + + menu->DestroySeparators(); // delete old separators + + const auto sel_vol = get_selected_model_volume(); + if (sel_vol && sel_vol->type() >= ModelVolume::SUPPORT_ENFORCER) + return nullptr; + + const ConfigOptionMode mode = wxGetApp().get_mode(); + if (mode == comSimple) return nullptr; + // Create new items for settings popupmenu + + menu->m_separator_frst = menu->AppendSeparator(); + + // Add frequently settings + create_freq_settings_popupmenu(menu); + + if (mode == comAdvanced) + return nullptr; + + menu->m_separator_scnd = menu->AppendSeparator(); + + // Add full settings list auto menu_item = new wxMenuItem(menu, wxID_ANY, _(L("Add settings"))); menu_item->SetBitmap(m_bmp_cog); - const auto sel_vol = get_selected_model_volume(); - if (sel_vol && sel_vol->type() >= ModelVolume::SUPPORT_ENFORCER) - menu_item->Enable(false); - else +// const auto sel_vol = get_selected_model_volume(); +// if (sel_vol && sel_vol->type() >= ModelVolume::SUPPORT_ENFORCER) +// menu_item->Enable(false); +// else menu_item->SetSubMenu(create_settings_popupmenu(menu)); return menu->Append(menu_item); @@ -739,20 +878,27 @@ wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu) } -void ObjectList::create_object_popupmenu(wxMenu *menu) +wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu) { - append_menu_items_add_volume(menu); + return append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")), "", + [this](wxCommandEvent&) { split_instances(); }, "", menu); +} +void ObjectList::create_object_popupmenu(wxMenu *menu) +{ // Split object to parts - menu->AppendSeparator(); m_menu_item_split = append_menu_item_split(menu); - - // Settings menu->AppendSeparator(); + + // rest of a object_menu will be added later in: + // - append_menu_items_add_volume() -> for "Add (volumes)" + // - append_menu_item_settings() -> for "Add (settings)" } void ObjectList::create_sla_object_popupmenu(wxMenu *menu) { + // rest of a object_sla_menu will be added later in: + // - append_menu_item_settings() -> for "Add (settings)" } void ObjectList::create_part_popupmenu(wxMenu *menu) @@ -763,8 +909,13 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) menu->AppendSeparator(); append_menu_item_change_type(menu); - // Append settings popupmenu - menu->AppendSeparator(); + // rest of a object_sla_menu will be added later in: + // - append_menu_item_settings() -> for "Add (settings)" +} + +void ObjectList::create_instance_popupmenu(wxMenu*menu) +{ + m_menu_item_split_instances = append_menu_item_instance_to_object(menu); } wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu) @@ -784,6 +935,24 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu) return menu; } +void ObjectList::create_freq_settings_popupmenu(wxMenu *menu) +{ + const FreqSettingsBundle& bundle = wxGetApp().plater()->printer_technology() == ptFFF ? + FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA; + + auto extruders_cnt = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA ? 1 : + wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size(); + + for (auto& it : bundle) { + if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1) + continue; + + append_menu_item(menu, wxID_ANY, _(it.first), "", + [menu, this](wxCommandEvent& event) { get_freq_settings_choice(menu->GetLabel(event.GetId())); }, + CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu); + } +} + void ObjectList::update_opt_keys(t_config_option_keys& opt_keys) { auto full_current_opts = get_options(false); @@ -843,13 +1012,15 @@ void ObjectList::load_part( ModelObject* model_object, delta = model_object->origin_translation - object->origin_translation; } for (auto volume : object->volumes) { +#if !ENABLE_VOLUMES_CENTERING_FIXES volume->center_geometry(); +#endif // !ENABLE_VOLUMES_CENTERING_FIXES volume->translate(delta); auto new_volume = model_object->add_volume(*volume); new_volume->set_type(static_cast<ModelVolume::Type>(type)); new_volume->name = boost::filesystem::path(input_file).filename().string(); - part_names.Add(new_volume->name); + part_names.Add(from_u8(new_volume->name)); // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); @@ -893,8 +1064,30 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh); new_volume->set_type(static_cast<ModelVolume::Type>(type)); +#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2))); +#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT +#if !ENABLE_VOLUMES_CENTERING_FIXES new_volume->center_geometry(); +#endif // !ENABLE_VOLUMES_CENTERING_FIXES + +#if ENABLE_GENERIC_SUBPARTS_PLACEMENT + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + int instance_idx = selection.get_instance_idx(); + if (instance_idx != -1) + { + const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const Transform3d& inst_m = v->get_instance_transformation().get_matrix(true); + TriangleMesh vol_mesh(mesh); + vol_mesh.transform(inst_m); + Vec3d vol_shift = -vol_mesh.bounding_box().center(); + vol_mesh.translate((float)vol_shift(0), (float)vol_shift(1), (float)vol_shift(2)); + Vec3d world_mesh_bb_size = vol_mesh.bounding_box().size(); + BoundingBoxf3 inst_bb = (*m_objects)[obj_idx]->instance_bounding_box(instance_idx); + Vec3d world_target = Vec3d(inst_bb.max(0), inst_bb.min(1), inst_bb.min(2)) + 0.5 * world_mesh_bb_size; + new_volume->set_offset(inst_m.inverse() * (world_target - v->get_instance_offset())); + } +#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT new_volume->name = name; // set a default extruder value, since user can't add it manually @@ -903,7 +1096,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int m_parts_changed = true; parts_changed(obj_idx); - select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type)); + const auto object_item = m_objects_model->GetTopParent(GetSelection()); + select_item(m_objects_model->AddVolumeChild(object_item, from_u8(name), type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -1031,7 +1225,7 @@ void ObjectList::split() parent = 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, + const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? @@ -1082,13 +1276,38 @@ bool ObjectList::is_splittable() if (!get_volume_by_item(item, volume) || !volume) return false; + if (volume->is_splittable() != -1) // if is_splittable value is already known + return volume->is_splittable() == 0 ? false : true; + TriangleMeshPtrs meshptrs = volume->mesh.split(); bool splittable = meshptrs.size() > 1; for (TriangleMesh* m : meshptrs) { delete m; } + volume->set_splittable(splittable ? 1 : 0); return splittable; } +bool ObjectList::selected_instances_of_same_object() +{ + wxDataViewItemArray sels; + GetSelections(sels); + + const int obj_idx = m_objects_model->GetObjectIdByItem(sels.front()); + + for (auto item : sels) { + if (! (m_objects_model->GetItemType(item) & itInstance) || + obj_idx != m_objects_model->GetObjectIdByItem(item)) + return false; + } + return true; +} + +bool ObjectList::can_split_instances() +{ + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + return selection.is_multiple_full_instance() || selection.is_single_full_instance(); +} + void ObjectList::part_settings_changed() { m_part_settings_changed = true; @@ -1156,6 +1375,10 @@ void ObjectList::part_selection_changed() else if (m_objects_model->GetItemType(item) == itInstance) { og_name = _(L("Instance manipulation")); update_and_show_manipulations = true; + + // fill m_config by object's values + const int obj_idx_ = m_objects_model->GetObjectIdByItem(item); + m_config = &(*m_objects)[obj_idx_]->config; } } @@ -1188,7 +1411,7 @@ 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 = model_object->name; + 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); @@ -1207,8 +1430,8 @@ void ObjectList::add_object_to_list(size_t obj_idx) if (model_object->volumes.size() > 1) { for (auto id = 0; id < model_object->volumes.size(); id++) { auto vol_item = m_objects_model->AddVolumeChild(item, - model_object->volumes[id]->name, - model_object->volumes[id]->type()/*ModelVolume::MODEL_PART*/, + 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, false); @@ -1388,7 +1611,7 @@ bool ObjectList::multiple_selection() const void ObjectList::update_selections() { - auto& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); wxDataViewItemArray sels; // We doesn't update selection if SettingsItem for the current object/part is selected @@ -1474,7 +1697,7 @@ void ObjectList::update_selections() void ObjectList::update_selections_on_canvas() { - auto& selection = wxGetApp().plater()->canvas3D()->get_selection(); + GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); const int sel_cnt = GetSelectedItemsCount(); if (sel_cnt == 0) { @@ -1698,6 +1921,48 @@ void ObjectList::update_settings_items() UnselectAll(); } +void ObjectList::update_object_menu() +{ + append_menu_items_add_volume(&m_menu_object); +} + +void ObjectList::instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idxs) +{ + // create new object from selected instance + ModelObject* model_object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]); + for (int inst_idx = model_object->instances.size() - 1; inst_idx >= 0; inst_idx--) + { + if (find(inst_idxs.begin(), inst_idxs.end(), inst_idx) != inst_idxs.end()) + continue; + model_object->delete_instance(inst_idx); + } + + // Add new object to the object_list + add_object_to_list(m_objects->size() - 1); + + for (std::set<int>::const_reverse_iterator it = inst_idxs.rbegin(); it != inst_idxs.rend(); ++it) + { + // delete selected instance from the object + del_subobject_from_object(obj_idx, *it, itInstance); + delete_instance_from_list(obj_idx, *it); + } +} + +void ObjectList::split_instances() +{ + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const int obj_idx = selection.get_object_idx(); + if (obj_idx == -1) + return; + + const int inst_idx = selection.get_instance_idx(); + const std::set<int> inst_idxs = inst_idx < 0 ? + selection.get_instance_idxs() : + std::set<int>{ inst_idx }; + + instances_to_separated_object(obj_idx, inst_idxs); +} + void ObjectList::ItemValueChanged(wxDataViewEvent &event) { if (event.GetColumn() == 0) |