diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1011bfd5e..a1f06de31 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -59,6 +59,11 @@ static PrinterTechnology printer_technology() return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology(); } +static const Selection& scene_selection() +{ + return wxGetApp().plater()->canvas3D()->get_selection(); +} + // Config from current edited printer preset static DynamicPrintConfig& printer_config() { @@ -1312,7 +1317,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) void ObjectList::get_freq_settings_choice(const wxString& bundle_name) { std::vector<std::string> options = get_options_for_bundle(bundle_name); - wxDataViewItem item = GetSelection(); + const Selection& selection = scene_selection(); + wxDataViewItem item = GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? + m_objects_model->GetItemById(selection.get_object_idx()) : + GetSelection(); ItemType item_type = m_objects_model->GetItemType(item); @@ -1400,17 +1408,23 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu) const ConfigOptionMode mode = wxGetApp().get_mode(); + wxWindow* parent = wxGetApp().plater(); + if (mode == comAdvanced) { append_menu_item(menu, wxID_ANY, _(ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART)].first), "", - [this](wxCommandEvent&) { load_subobject(ModelVolumeType::MODEL_PART); }, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART)].second); + [this](wxCommandEvent&) { load_subobject(ModelVolumeType::MODEL_PART); }, + ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART)].second, nullptr, + [this]() { return is_instance_or_object_selected(); }, parent); } if (mode == comSimple) { append_menu_item(menu, wxID_ANY, _(ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER)].first), "", [this](wxCommandEvent&) { load_generic_subobject(L("Box"), ModelVolumeType::SUPPORT_ENFORCER); }, - ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER)].second); + ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER)].second, nullptr, + [this]() { return is_instance_or_object_selected(); }, parent); append_menu_item(menu, wxID_ANY, _(ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_BLOCKER)].first), "", [this](wxCommandEvent&) { load_generic_subobject(L("Box"), ModelVolumeType::SUPPORT_BLOCKER); }, - ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_BLOCKER)].second); + ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_BLOCKER)].second, nullptr, + [this]() { return is_instance_or_object_selected(); }, parent); return; } @@ -1420,7 +1434,8 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu) auto& item = ADD_VOLUME_MENU_ITEMS[type]; wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType(type)); - append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second); + append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second, + [this]() { return is_instance_or_object_selected(); }, parent); } } @@ -1431,10 +1446,17 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu) [this]() { return is_splittable(); }, wxGetApp().plater()); } -wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu) +bool ObjectList::is_instance_or_object_selected() +{ + const Selection& selection = scene_selection(); + return selection.is_single_full_instance() || selection.is_single_full_object(); +} + +wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent) { return append_menu_item(menu, wxID_ANY, _(L("Height range Modifier")), "", - [this](wxCommandEvent&) { layers_editing(); }, "edit_layers_all", menu); + [this](wxCommandEvent&) { layers_editing(); }, "edit_layers_all", menu, + [this]() { return is_instance_or_object_selected(); }, parent); } wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) @@ -1475,6 +1497,12 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) #endif menu->DestroySeparators(); // delete old separators + // If there are selected more then one instance but not all of them + // don't add settings menu items + const Selection& selection = scene_selection(); + if (selection.is_multiple_full_instance() && !selection.is_single_full_object()) + return nullptr; + const auto sel_vol = get_selected_model_volume(); if (sel_vol && sel_vol->type() >= ModelVolumeType::SUPPORT_ENFORCER) return nullptr; @@ -1490,7 +1518,8 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) menu->SetFirstSeparator(); // Add frequently settings - const bool is_object_settings = m_objects_model->GetItemType(GetSelection()) == itObject; + const ItemType item_type = m_objects_model->GetItemType(GetSelection()); + const bool is_object_settings = item_type & itObject || item_type & itInstance || selection.is_single_full_object(); create_freq_settings_popupmenu(menu, is_object_settings); if (mode == comAdvanced) @@ -1516,15 +1545,35 @@ wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu) wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent) { - return append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")), "", + wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")), "", [this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent); + + /* New behavior logic: + * 1. Split Object to several separated object, if ALL instances are selected + * 2. Separate selected instances from the initial object to the separated object, + * if some (not all) instances are selected + */ + parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { + evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ? + _(L("Set as a Separated Objects")) : _(L("Set as a Separated Object"))); + }, menu_item->GetId()); + + return menu_item; } wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* /*parent*/) { - return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [](wxCommandEvent&) { - wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state(); - }, menu); + return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) { + const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + wxDataViewItem item; + if (GetSelectedItemsCount() > 1 && selection.is_single_full_object()) + item = m_objects_model->GetItemById(selection.get_object_idx()); + else + item = GetSelection(); + + if (item) + toggle_printable_state(item); + }, menu); } void ObjectList::append_menu_items_osx(wxMenu* menu) @@ -1620,7 +1669,7 @@ void ObjectList::create_object_popupmenu(wxMenu *menu) menu->AppendSeparator(); // Layers Editing for object - append_menu_item_layers_editing(menu); + append_menu_item_layers_editing(menu, wxGetApp().plater()); menu->AppendSeparator(); // rest of a object_menu will be added later in: @@ -1664,17 +1713,6 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) void ObjectList::create_instance_popupmenu(wxMenu*menu) { m_menu_item_split_instances = append_menu_item_instance_to_object(menu, wxGetApp().plater()); - - /* New behavior logic: - * 1. Split Object to several separated object, if ALL instances are selected - * 2. Separate selected instances from the initial object to the separated object, - * if some (not all) instances are selected - */ - wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) { -// evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId()); - evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ? - _(L("Set as a Separated Objects")) : _(L("Set as a Separated Object"))); - }, m_menu_item_split_instances->GetId()); } void ObjectList::create_default_popupmenu(wxMenu*menu) @@ -1688,7 +1726,7 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu) wxMenu *menu = new wxMenu; settings_menu_hierarchy settings_menu; - const bool is_part = m_objects_model->GetParent(GetSelection()) != wxDataViewItem(nullptr); + const bool is_part = !(m_objects_model->GetItemType(GetSelection()) == itObject || scene_selection().is_single_full_object()); get_options_menu(settings_menu, is_part); for (auto cat : settings_menu) { @@ -1857,7 +1895,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode if (obj_idx < 0) return; - const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const Selection& selection = scene_selection(); assert(obj_idx == selection.get_object_idx()); /** Any changes of the Object's composition is duplicated for all Object's Instances @@ -2182,9 +2220,13 @@ void ObjectList::split() void ObjectList::layers_editing() { - const auto item = GetSelection(); - const int obj_idx = get_selected_obj_idx(); - if (!item || obj_idx < 0) + const Selection& selection = scene_selection(); + const int obj_idx = selection.get_object_idx(); + wxDataViewItem item = obj_idx >= 0 && GetSelectedItemsCount() > 1 && selection.is_single_full_object() ? + m_objects_model->GetItemById(obj_idx) : + GetSelection(); + + if (!item) return; const wxDataViewItem obj_item = m_objects_model->GetTopParent(item); @@ -2297,7 +2339,7 @@ bool ObjectList::selected_instances_of_same_object() bool ObjectList::can_split_instances() { - const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const Selection& selection = scene_selection(); return selection.is_multiple_full_instance() || selection.is_single_full_instance(); } @@ -2325,7 +2367,7 @@ void ObjectList::part_selection_changed() { og_name = _(L("Group manipulation")); - const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const Selection& selection = scene_selection(); // don't show manipulation panel for case of all Object's parts selection update_and_show_manipulations = !selection.is_single_full_instance(); } @@ -2933,7 +2975,7 @@ int ObjectList::get_selected_layers_range_idx() const void ObjectList::update_selections() { - const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const Selection& selection = scene_selection(); wxDataViewItemArray sels; if ( ( m_selection_mode & (smSettings|smLayer|smLayerRoot) ) == 0) @@ -3640,7 +3682,7 @@ void ObjectList::instances_to_separated_objects(const int obj_idx) void ObjectList::split_instances() { - const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + const Selection& selection = scene_selection(); const int obj_idx = selection.get_object_idx(); if (obj_idx == -1) return; diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 0874343b6..73b23453b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -226,11 +226,12 @@ public: void get_settings_choice(const wxString& category_name); void get_freq_settings_choice(const wxString& bundle_name); void show_settings(const wxDataViewItem settings_item); + bool is_instance_or_object_selected(); wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type); void append_menu_items_add_volume(wxMenu* menu); wxMenuItem* append_menu_item_split(wxMenu* menu); - wxMenuItem* append_menu_item_layers_editing(wxMenu* menu); + wxMenuItem* append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent); wxMenuItem* append_menu_item_settings(wxMenu* menu); wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5b97ce821..d0d58cb2b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3602,17 +3602,29 @@ void Plater::priv::on_right_click(RBtnEvent& evt) wxMenu* menu = nullptr; - if (obj_idx == -1) - menu = &default_menu; + if (obj_idx == -1) // no one or several object are selected + { + if (evt.data.second) // right button was clicked on empty space + menu = &default_menu; + else + return; + } else { // If in 3DScene is(are) selected volume(s), but right button was clicked on empty space if (evt.data.second) return; - menu = printer_technology == ptSLA ? &sla_object_menu : - get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject - &object_menu : &part_menu; + if (printer_technology == ptSLA) + menu = &sla_object_menu; + else + { + // show "Object menu" for each one or several FullInstance instead of FullObject + const bool is_some_full_instances = get_selection().is_single_full_instance() || + get_selection().is_single_full_object() || + get_selection().is_multiple_full_instance(); + menu = is_some_full_instances ? &object_menu : &part_menu; + } sidebar->obj_list()->append_menu_item_settings(menu); @@ -3805,14 +3817,18 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ [this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q); append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), - [this](wxCommandEvent&) { q->export_stl(false, true); }); + [this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr, + [this]() { + const Selection& selection = get_selection(); + return selection.is_single_full_instance() || selection.is_single_full_object(); + }, q); menu->AppendSeparator(); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { const Selection& selection = get_selection(); int instance_idx = selection.get_instance_idx(); - evt.Enable(instance_idx != -1); + evt.Enable(selection.is_single_full_instance() || selection.is_single_full_object()); if (instance_idx != -1) { evt.Check(model.objects[selection.get_object_idx()]->instances[instance_idx]->printable); @@ -3858,7 +3874,7 @@ bool Plater::priv::complit_init_object_menu() object_menu.AppendSeparator(); // Layers Editing for object - sidebar->obj_list()->append_menu_item_layers_editing(&object_menu); + sidebar->obj_list()->append_menu_item_layers_editing(&object_menu, q); object_menu.AppendSeparator(); // "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()