From cbe4fa478e0c0db851d71cc9e4281f1fc3836caf Mon Sep 17 00:00:00 2001 From: vovodroid Date: Wed, 24 Jul 2024 12:16:41 +0300 Subject: [PATCH] Add instances --- resources/images/instance_add.svg | 68 +++++++++++++++++++++++ resources/images/instance_add_dark.svg | 68 +++++++++++++++++++++++ resources/images/instance_remove.svg | 58 +++++++++++++++++++ resources/images/instance_remove_dark.svg | 58 +++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.cpp | 58 ++++++++++++++----- src/slic3r/GUI/GUI_Factories.cpp | 25 ++++++++- src/slic3r/GUI/GUI_Factories.hpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 12 ++-- src/slic3r/GUI/Jobs/FillBedJob.cpp | 35 ++++++++++-- src/slic3r/GUI/Jobs/FillBedJob.hpp | 4 +- src/slic3r/GUI/Plater.cpp | 25 ++++++--- src/slic3r/GUI/Plater.hpp | 1 + 12 files changed, 377 insertions(+), 37 deletions(-) create mode 100644 resources/images/instance_add.svg create mode 100644 resources/images/instance_add_dark.svg create mode 100644 resources/images/instance_remove.svg create mode 100644 resources/images/instance_remove_dark.svg diff --git a/resources/images/instance_add.svg b/resources/images/instance_add.svg new file mode 100644 index 00000000000..8c9ce6a2d1a --- /dev/null +++ b/resources/images/instance_add.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/instance_add_dark.svg b/resources/images/instance_add_dark.svg new file mode 100644 index 00000000000..e3f31a8bab5 --- /dev/null +++ b/resources/images/instance_add_dark.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/instance_remove.svg b/resources/images/instance_remove.svg new file mode 100644 index 00000000000..7f851bc023d --- /dev/null +++ b/resources/images/instance_remove.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + diff --git a/resources/images/instance_remove_dark.svg b/resources/images/instance_remove_dark.svg new file mode 100644 index 00000000000..b6335df6c60 --- /dev/null +++ b/resources/images/instance_remove_dark.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9fc70c62451..0170fdd78f3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3267,20 +3267,20 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } - //case '+': { - // if (dynamic_cast(m_canvas->GetParent()) != nullptr) - // post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt)); - // else - // post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); - // break; - //} - //case '-': { - // if (dynamic_cast(m_canvas->GetParent()) != nullptr) - // post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt)); - // else - // post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); - // break; - //} + case '+': { + if (dynamic_cast(m_canvas->GetParent()) != nullptr) + post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt)); + else + post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); + break; + } + case '-': { + if (dynamic_cast(m_canvas->GetParent()) != nullptr) + post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt)); + else + post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); + break; + } case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; } case 'A': case 'a': @@ -6249,6 +6249,12 @@ void GLCanvas3D::_switch_toolbars_icon_filename() item = m_main_toolbar.get_item("arrange"); item->set_icon_filename(m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg"); + item = m_main_toolbar.get_item("more"); + item->set_icon_filename(m_is_dark ? "instance_add_dark.svg" : "instance_add.svg"); + + item = m_main_toolbar.get_item("fewer"); + item->set_icon_filename(m_is_dark ? "instance_remove_dark.svg" : "instance_remove.svg"); + item = m_main_toolbar.get_item("splitobjects"); item->set_icon_filename(m_is_dark ? "split_objects_dark.svg" : "split_objects.svg"); @@ -6398,6 +6404,30 @@ bool GLCanvas3D::_init_main_toolbar() if (!m_main_toolbar.add_separator()) return false; + item.name = "more"; + item.icon_filename = m_is_dark ? "instance_add_dark.svg" : "instance_add.svg"; + item.tooltip = _utf8(L("Add instance")) + " [+]"; + item.sprite_id++; + item.left.render_callback = nullptr; + item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; + item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; + item.left.toggable = false; + item.enabling_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); }; + if (!m_main_toolbar.add_item(item)) + return false; + + item.name = "fewer"; + item.icon_filename = m_is_dark ? "instance_remove_dark.svg" : "instance_remove.svg"; + item.tooltip = _utf8(L("Remove instance")) + " [-]"; + item.sprite_id++; + item.left.render_callback = nullptr; + item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; + item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; + item.left.toggable = false; + item.enabling_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); }; + if (!m_main_toolbar.add_item(item)) + return false; + item.name = "splitobjects"; item.icon_filename = m_is_dark ? "split_objects_dark.svg" : "split_objects.svg"; item.tooltip = _utf8(L("Split to objects")); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index cb0748f2a50..4f905428b72 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -776,7 +776,7 @@ void MenuFactory::append_menu_item_fill_bed(wxMenu *menu) { append_menu_item( menu, wxID_ANY, _L("Fill bed with copies"), _L("Fill the remaining area of bed with copies of the selected object"), - [](wxCommandEvent &) { plater()->fill_bed_with_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent); + [](wxCommandEvent &) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent); } wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu) @@ -1254,7 +1254,7 @@ void MenuFactory::create_common_object_menu(wxMenu* menu) { append_menu_item_rename(menu); // BBS - //append_menu_items_instance_manipulation(menu); + append_menu_items_instance_manipulation(menu); // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake. append_menu_item_delete(menu); //append_menu_item_instance_to_object(menu); @@ -1296,6 +1296,9 @@ void MenuFactory::create_object_menu() void MenuFactory::create_extra_object_menu() { + // Object instances + append_menu_items_instance_manipulation(&m_object_menu); + m_object_menu.AppendSeparator(); append_menu_item_fill_bed(&m_object_menu); // Object Clone append_menu_item_clone(&m_object_menu); @@ -1738,6 +1741,24 @@ wxMenu* MenuFactory::assemble_multi_selection_menu() return menu; } +//PS +void MenuFactory::append_menu_items_instance_manipulation(wxMenu* menu) +{ + MenuType type = menu == &m_object_menu ? mtObjectFFF : mtObjectSLA; + + items_increase[type] = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), + [](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); + items_decrease[type] = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), + [](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr, + []() { return plater()->can_decrease_instances(); }, m_parent); + items_set_number_of_copies[type] = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), + [](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); + append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"), + [](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr, + []() { return plater()->can_increase_instances(); }, m_parent); +} //BBS: add partplate related logic wxMenu* MenuFactory::plate_menu() diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 7c73e0facf0..4bed65aafa2 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -151,7 +151,7 @@ class MenuFactory void append_menu_item_edit_text(wxMenu *menu); void append_menu_item_edit_svg(wxMenu *menu); - //void append_menu_items_instance_manipulation(wxMenu *menu); + void append_menu_items_instance_manipulation(wxMenu *menu); //void update_menu_items_instance_manipulation(MenuType type); //BBS add bbl menu item void append_menu_item_clone(wxMenu* menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index e2175f09d21..4d7ca139652 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1509,12 +1509,12 @@ void ObjectList::key_event(wxKeyEvent& event) cut(); else if (wxGetKeyState(wxKeyCode('K')) && wxGetKeyState(WXK_CONTROL)) clone(); - //else if (event.GetUnicodeKey() == '+') - // increase_instances(); - //else if (event.GetUnicodeKey() == '-') - // decrease_instances(); - //else if (event.GetUnicodeKey() == 'p') - // toggle_printable_state(); + else if (event.GetUnicodeKey() == '+') + increase_instances(); + else if (event.GetUnicodeKey() == '-') + decrease_instances(); + else if (event.GetUnicodeKey() == 'p') + toggle_printable_state(); else if (filaments_count() > 1) { std::vector numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; wxChar key_char = event.GetUnicodeKey(); diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index e594f98ae1e..d02c45b65e2 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -169,17 +169,36 @@ void FillBedJob::prepare() ModelInstance *mi = model_object->instances[sel_id]; ArrangePolygon template_ap = get_instance_arrange_poly(mi, global_config); - for (int i = 0; i < needed_items; ++i) { + int obj_idx; + double offset_base, offset; + bool was_one_instance; + if (m_instances) { + obj_idx = m_plater->get_selected_object_idx(); + offset_base = m_plater->canvas3D()->get_size_proportional_to_max_bed_size(0.05); + offset = offset_base; + was_one_instance = model_object->instances.size()==1; + } + + for (int i = 0; i < needed_items; ++i, offset += offset_base) { ArrangePolygon ap = template_ap; ap.poly = m_selected.front().poly; ap.bed_idx = PartPlateList::MAX_PLATES_COUNT; ap.height = 1; ap.itemid = -1; - ap.setter = [this, mi](const ArrangePolygon &p) { + ap.setter = [this, mi, offset](const ArrangePolygon &p) { ModelObject *mo = m_plater->model().objects[m_object_idx]; - ModelObject* newObj = m_plater->model().add_object(*mo); - newObj->name = mo->name +" "+ std::to_string(p.itemid); - for (ModelInstance *newInst : newObj->instances) { newInst->apply_arrange_result(p.translation.cast(), p.rotation); } + ModelObject *obj; + if (m_instances) { + ModelInstance* model_instance = mo->instances.back(); + Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0); + mo->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation(), model_instance->get_mirror()); + obj = mo; + } else { + ModelObject* newObj = m_plater->model().add_object(*mo); + newObj->name = mo->name +" "+ std::to_string(p.itemid); + obj = newObj; + } + for (ModelInstance *newInst : obj->instances) { newInst->apply_arrange_result(p.translation.cast(), p.rotation); } //m_plater->sidebar().obj_list()->paste_objects_into_list({m_plater->model().objects.size()-1}); }; m_selected.emplace_back(ap); @@ -257,7 +276,7 @@ void FillBedJob::process(Ctl &ctl) _u8L("Bed filling done.")); } -FillBedJob::FillBedJob() : m_plater{wxGetApp().plater()} {} +FillBedJob::FillBedJob(bool instances) : m_plater{wxGetApp().plater()}, m_instances{instances} {} void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr) { @@ -324,6 +343,10 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr) //model_object->ensure_on_bed(); //BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": model_object->ensure_on_bed()"; + if (m_instances && wxGetApp().app_config->get("auto_arrange") == "true") { + m_plater->set_prepare_state(Job::PREPARE_STATE_MENU); + m_plater->arrange(); + } m_plater->update(); } } diff --git a/src/slic3r/GUI/Jobs/FillBedJob.hpp b/src/slic3r/GUI/Jobs/FillBedJob.hpp index 20672e0f378..28950aeac8b 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.hpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.hpp @@ -26,12 +26,14 @@ class FillBedJob : public Job int m_status_range = 0; Plater *m_plater; + bool m_instances; + public: void prepare(); void process(Ctl &ctl) override; - FillBedJob(); + FillBedJob(bool instances = false); int status_range() const { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b51937e43cb..e75dd334a0d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -11199,8 +11199,6 @@ void Plater::remove_selected() void Plater::increase_instances(size_t num) { - // BBS -#if 0 if (! can_increase_instances()) { return; } Plater::TakeSnapshot snapshot(this, "Increase Instances"); @@ -11233,13 +11231,14 @@ void Plater::increase_instances(size_t num) p->selection_changed(); this->p->schedule_background_process(); -#endif + if (wxGetApp().app_config->get("auto_arrange") == "true") { + this->set_prepare_state(Job::PREPARE_STATE_MENU); + this->arrange(); + } } void Plater::decrease_instances(size_t num) { - // BBS -#if 0 if (! can_decrease_instances()) { return; } Plater::TakeSnapshot snapshot(this, "Decrease Instances"); @@ -11263,7 +11262,10 @@ void Plater::decrease_instances(size_t num) p->selection_changed(); this->p->schedule_background_process(); -#endif + if (wxGetApp().app_config->get("auto_arrange") == "true") { + this->set_prepare_state(Job::PREPARE_STATE_MENU); + this->arrange(); + } } static long GetNumberFromUser( const wxString& msg, @@ -11308,7 +11310,7 @@ void Plater::set_number_of_copies(/*size_t num*/) decrease_instances(-diff); } -void Plater::fill_bed_with_instances() +void Plater::fill_bed_with_copies() { auto &w = get_ui_job_worker(); if (w.is_idle()) { @@ -11317,6 +11319,15 @@ void Plater::fill_bed_with_instances() } } +void Plater::fill_bed_with_instances() +{ + auto &w = get_ui_job_worker(); + if (w.is_idle()) { + p->take_snapshot(_u8L("Arrange")); + replace_job(w, std::make_unique(true)); + } +} + bool Plater::is_selection_empty() const { return p->get_selection().is_empty() || p->get_selection().is_wipe_tower(); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 4086a157715..0a78c001f8d 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -383,6 +383,7 @@ class Plater: public wxPanel void increase_instances(size_t num = 1); void decrease_instances(size_t num = 1); void set_number_of_copies(/*size_t num*/); + void fill_bed_with_copies(); void fill_bed_with_instances(); bool is_selection_empty() const; void scale_selection_to_fit_print_volume();