diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 49f0f6fa2..116f99eb8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -279,6 +279,7 @@ void ObjectList::create_popup_menus() create_part_popupmenu(&m_menu_part); create_sla_object_popupmenu(&m_menu_sla_object); create_instance_popupmenu(&m_menu_instance); + create_default_popupmenu(&m_menu_default); } void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(nullptr)*/) @@ -783,18 +784,23 @@ void ObjectList::OnChar(wxKeyEvent& event) void ObjectList::OnContextMenu(wxDataViewEvent&) { - list_manipulation(); + list_manipulation(true); } -void ObjectList::list_manipulation() +void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) { wxDataViewItem item; wxDataViewColumn* col = nullptr; const wxPoint pt = get_mouse_position_in_control(); HitTest(pt, item, col); - if (!item || col == nullptr) { - return; + if (!item) { + if (col == nullptr) + return; + if (evt_context_menu) { + show_context_menu(evt_context_menu); + return; + } } const wxString title = col->GetTitle(); @@ -802,7 +808,7 @@ void ObjectList::list_manipulation() if (title == " ") toggle_printable_state(item); else if (title == _("Editing")) - show_context_menu(); + show_context_menu(evt_context_menu); else if (title == _("Name")) { int obj_idx, vol_idx; @@ -818,7 +824,7 @@ void ObjectList::list_manipulation() #endif //__WXMSW__ } -void ObjectList::show_context_menu() +void ObjectList::show_context_menu(const bool evt_context_menu) { if (multiple_selection()) { @@ -831,22 +837,26 @@ void ObjectList::show_context_menu() } const auto item = GetSelection(); + wxMenu* menu {nullptr}; if (item) { const ItemType type = m_objects_model->GetItemType(item); if (!(type & (itObject | itVolume | itLayer | itInstance))) return; - wxMenu* menu = type & itInstance ? &m_menu_instance : + menu = type & itInstance ? &m_menu_instance : type & itLayer ? &m_menu_layer : m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? &m_menu_part : printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object; if (!(type & itInstance)) append_menu_item_settings(menu); - - wxGetApp().plater()->PopupMenu(menu); } + else if (evt_context_menu) + menu = &m_menu_default; + + if (menu) + wxGetApp().plater()->PopupMenu(menu); } void ObjectList::copy() @@ -1286,13 +1296,16 @@ void ObjectList::show_settings(const wxDataViewItem settings_item) wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) { auto sub_menu = new wxMenu; - if (wxGetApp().get_mode() == comExpert) { + if (wxGetApp().get_mode() == comExpert && type != ModelVolumeType::INVALID) { append_menu_item(sub_menu, wxID_ANY, _(L("Load")) + " " + dots, "", [this, type](wxCommandEvent&) { load_subobject(type); }, "", menu); sub_menu->AppendSeparator(); } - for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) { + for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) + { + if (type == ModelVolumeType::INVALID && item == "Slab") + continue; append_menu_item(sub_menu, wxID_ANY, _(item), "", [this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu); } @@ -1579,6 +1592,12 @@ void ObjectList::create_instance_popupmenu(wxMenu*menu) }, m_menu_item_split_instances->GetId()); } +void ObjectList::create_default_popupmenu(wxMenu*menu) +{ + wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType::INVALID); + append_submenu(menu, sub_menu, wxID_ANY, _(L("Add Shape")), "", "add_part"); +} + wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu) { wxMenu *menu = new wxMenu; @@ -1717,8 +1736,38 @@ void ObjectList::load_part( ModelObject* model_object, } +static TriangleMesh create_mesh(const std::string& type_name, const BoundingBoxf3& bb) +{ + TriangleMesh mesh; + + const double side = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.1); + + if (type_name == "Box") + // Sitting on the print bed, left front front corner at (0, 0). + mesh = make_cube(side, side, side); + else if (type_name == "Cylinder") + // Centered around 0, sitting on the print bed. + // The cylinder has the same volume as the box above. + mesh = make_cylinder(0.564 * side, side); + else if (type_name == "Sphere") + // Centered around 0, half the sphere below the print bed, half above. + // The sphere has the same volume as the box above. + mesh = make_sphere(0.62 * side, PI / 18); + else if (type_name == "Slab") + // Sitting on the print bed, left front front corner at (0, 0). + mesh = make_cube(bb.size().x() * 1.5, bb.size().y() * 1.5, bb.size().z() * 0.5); + mesh.repair(); + + return mesh; +} + void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type) { + if (type == ModelVolumeType::INVALID) { + load_shape_object(type_name); + return; + } + const int obj_idx = get_selected_obj_idx(); if (obj_idx < 0) return; @@ -1741,26 +1790,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode // Bounding box of the selected instance in world coordinate system including the translation, without modifiers. BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx); - const wxString name = _(L("Generic")) + "-" + _(type_name); - TriangleMesh mesh; - - double side = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.1); - - if (type_name == "Box") - // Sitting on the print bed, left front front corner at (0, 0). - mesh = make_cube(side, side, side); - else if (type_name == "Cylinder") - // Centered around 0, sitting on the print bed. - // The cylinder has the same volume as the box above. - mesh = make_cylinder(0.564 * side, side); - else if (type_name == "Sphere") - // Centered around 0, half the sphere below the print bed, half above. - // The sphere has the same volume as the box above. - mesh = make_sphere(0.62 * side, PI / 18); - else if (type_name == "Slab") - // Sitting on the print bed, left front front corner at (0, 0). - mesh = make_cube(instance_bb.size().x()*1.5, instance_bb.size().y()*1.5, instance_bb.size().z()*0.5); - mesh.repair(); + TriangleMesh mesh = create_mesh(type_name, instance_bb); // Mesh will be centered when loading. ModelVolume *new_volume = model_object.add_volume(std::move(mesh)); @@ -1782,6 +1812,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); } + const wxString name = _(L("Generic")) + "-" + _(type_name); new_volume->name = into_u8(name); // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); @@ -1799,6 +1830,57 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode #endif //no __WXOSX__ //__WXMSW__ } +void ObjectList::load_shape_object(const std::string& type_name) +{ + const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + assert(selection.get_object_idx() == -1); // Add nothing is something is selected on 3DScene + if (selection.get_object_idx() != -1) + return; + + const int obj_idx = m_objects->size(); + if (obj_idx < 0) + return; + + take_snapshot(_(L("Add Shape"))); + + // Create mesh + BoundingBoxf3 bb; + TriangleMesh mesh = create_mesh(type_name, bb); + + // Add mesh to model as a new object + Model& model = wxGetApp().plater()->model(); + const wxString name = _(L("Shape")) + "-" + _(type_name); + +#ifdef _DEBUG + check_model_ids_validity(model); +#endif /* _DEBUG */ + + std::vector object_idxs; + ModelObject* new_object = model.add_object(); + new_object->name = into_u8(name); + new_object->add_instance(); // each object should have at list one instance + + ModelVolume* new_volume = new_object->add_volume(mesh); + new_volume->name = into_u8(name); + // set a default extruder value, since user can't add it manually + new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); + new_object->invalidate_bounding_box(); + + const BoundingBoxf bed_shape = wxGetApp().plater()->bed_shape_bb(); + new_object->instances[0]->set_offset(Slic3r::to_3d(bed_shape.center().cast(), -new_object->origin_translation(2))); + + object_idxs.push_back(model.objects.size() - 1); +#ifdef _DEBUG + check_model_ids_validity(model); +#endif /* _DEBUG */ + + paste_objects_into_list(object_idxs); + +#ifdef _DEBUG + check_model_ids_validity(model); +#endif /* _DEBUG */ +} + void ObjectList::del_object(const int obj_idx) { wxGetApp().plater()->delete_object_from_model(obj_idx); @@ -3585,7 +3667,8 @@ void ObjectList::msw_rescale() &m_menu_part, &m_menu_sla_object, &m_menu_instance, - &m_menu_layer }) + &m_menu_layer, + &m_menu_default}) msw_rescale_menu(menu); Layout(); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 13d1106fc..4dd618a90 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -132,6 +132,7 @@ private: MenuWithSeparators m_menu_sla_object; MenuWithSeparators m_menu_instance; MenuWithSeparators m_menu_layer; + MenuWithSeparators m_menu_default; wxMenuItem* m_menu_item_settings { nullptr }; wxMenuItem* m_menu_item_split_instances { nullptr }; @@ -208,7 +209,7 @@ public: void set_tooltip_for_item(const wxPoint& pt); void selection_changed(); - void show_context_menu(); + void show_context_menu(const bool evt_context_menu); #ifndef __WXOSX__ void key_event(wxKeyEvent& event); #endif /* __WXOSX__ */ @@ -240,6 +241,7 @@ public: void create_sla_object_popupmenu(wxMenu*menu); void create_part_popupmenu(wxMenu*menu); void create_instance_popupmenu(wxMenu*menu); + void create_default_popupmenu(wxMenu *menu); wxMenu* create_settings_popupmenu(wxMenu *parent_menu); void create_freq_settings_popupmenu(wxMenu *parent_menu, const bool is_object_settings = true); @@ -248,6 +250,7 @@ public: void load_subobject(ModelVolumeType type); void load_part(ModelObject* model_object, std::vector> &volumes_info, ModelVolumeType type); void load_generic_subobject(const std::string& type_name, const ModelVolumeType type); + void load_shape_object(const std::string &type_name); void del_object(const int obj_idx); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(const wxDataViewItem& parent_item); @@ -362,7 +365,7 @@ private: // void OnChar(wxKeyEvent& event); #endif /* __WXOSX__ */ void OnContextMenu(wxDataViewEvent &event); - void list_manipulation(); + void list_manipulation(bool evt_context_menu = false); void OnBeginDrag(wxDataViewEvent &event); void OnDropPossible(wxDataViewEvent &event); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0dc7519e8..4ba54bc6c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4877,6 +4877,11 @@ GLCanvas3D* Plater::canvas3D() return p->view3D->get_canvas3d(); } +BoundingBoxf Plater::bed_shape_bb() const +{ + return p->bed_shape_bb(); +} + PrinterTechnology Plater::printer_technology() const { return p->printer_technology; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 0dc298566..26dcb5ac3 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -225,6 +225,7 @@ public: int get_selected_object_idx(); bool is_single_full_object_selection() const; GLCanvas3D* canvas3D(); + BoundingBoxf bed_shape_bb() const; PrinterTechnology printer_technology() const; void set_printer_technology(PrinterTechnology printer_technology);