From 6cbf9d25234c8a12586d0b7a555513ee2333a5ea Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 08:40:58 +0200 Subject: [PATCH] 1st installment of copy and paste -> prototype for volumes copy and paste --- src/slic3r/GUI/GUI_ObjectList.cpp | 37 +++++++++++++ src/slic3r/GUI/GUI_ObjectList.hpp | 8 +++ src/slic3r/GUI/MainFrame.cpp | 19 +++++++ src/slic3r/GUI/MainFrame.hpp | 2 + src/slic3r/GUI/Plater.cpp | 15 +++++ src/slic3r/GUI/Plater.hpp | 4 ++ src/slic3r/GUI/Selection.cpp | 92 +++++++++++++++++++++++++++++++ src/slic3r/GUI/Selection.hpp | 32 +++++++++++ 8 files changed, 209 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dc3909351..b0ccf6290 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -436,6 +436,43 @@ void ObjectList::selection_changed() part_selection_changed(); } +void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes) +{ + if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx)) + return; + + if (volumes.empty()) + return; + + ModelObject& model_object = *(*m_objects)[obj_idx]; + const auto object_item = m_objects_model->GetItemById(obj_idx); + + wxDataViewItemArray items; + + for (const ModelVolume* volume : volumes) + { + auto vol_item = m_objects_model->AddVolumeChild(object_item, volume->name, volume->type(), + volume->config.has("extruder") ? volume->config.option("extruder")->value : 0, false); + auto opt_keys = volume->config.keys(); + if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder"))) + select_item(m_objects_model->AddSettingsChild(vol_item)); + + items.Add(vol_item); + } + + m_parts_changed = true; + parts_changed(obj_idx); + + select_items(items); +#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME + selection_changed(); +#endif //no __WXOSX__ //__WXMSW__ +} + +void ObjectList::paste_object_into_list(const ModelObject& object) +{ +} + void ObjectList::OnChar(wxKeyEvent& event) { if (event.GetKeyCode() == WXK_BACK){ diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 2f465a4ab..a30f76332 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -31,6 +31,10 @@ typedef std::map> FreqSettingsBundle; // category -> vector ( option ; label ) typedef std::map< std::string, std::vector< std::pair > > settings_menu_hierarchy; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +typedef std::vector ModelVolumePtrs; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + namespace GUI { wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); @@ -285,6 +289,10 @@ public: void rename_item(); void fix_through_netfabb() const; void update_item_error_icon(const int obj_idx, int vol_idx) const ; + + void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes); + void paste_object_into_list(const ModelObject& object); + private: void OnChar(wxKeyEvent& event); void OnContextMenu(wxDataViewEvent &event); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index eac367669..13f1287a3 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -256,6 +256,16 @@ bool MainFrame::can_delete_all() const return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; } +bool MainFrame::can_copy() const +{ + return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false; +} + +bool MainFrame::can_paste() const +{ + return (m_plater != nullptr) ? !m_plater->is_selection_clipboard_empty() : false; +} + void MainFrame::on_dpi_changed(const wxRect &suggested_rect) { // TODO @@ -379,9 +389,18 @@ void MainFrame::init_menubar() wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete, _(L("Deletes all objects")), [this](wxCommandEvent&) { m_plater->reset(); }, ""); + editMenu->AppendSeparator(); + + wxMenuItem* item_copy = append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + "\tCtrl+C", _(L("Copy selection to clipboard")), + [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, ""); + wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + "\tCtrl+V", _(L("Paste clipboard")), + [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, ""); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_all()); }, item_delete_all->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_copy()); }, item_copy->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_paste()); }, item_paste->GetId()); } // Window menu diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 625e70b83..16116ec43 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -68,6 +68,8 @@ class MainFrame : public DPIFrame bool can_select() const; bool can_delete() const; bool can_delete_all() const; + bool can_copy() const; + bool can_paste() const; protected: virtual void on_dpi_changed(const wxRect &suggested_rect); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cffec2062..cedca34aa 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3704,6 +3704,21 @@ void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) void Plater::update_object_menu() { p->update_object_menu(); } +void Plater::copy_selection_to_clipboard() +{ + p->view3D->get_canvas3d()->get_selection().copy_to_clipboard(); +} + +void Plater::paste_from_clipboard() +{ + p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); +} + +bool Plater::is_selection_clipboard_empty() const +{ + return p->view3D->get_canvas3d()->get_selection().is_clipboard_empty(); +} + bool Plater::can_delete() const { return p->can_delete(); } bool Plater::can_delete_all() const { return p->can_delete_all(); } bool Plater::can_increase_instances() const { return p->can_increase_instances(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index f830edce3..3d3ba8b3e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -182,6 +182,10 @@ public: PrinterTechnology printer_technology() const; void set_printer_technology(PrinterTechnology printer_technology); + void copy_selection_to_clipboard(); + void paste_from_clipboard(); + bool is_selection_clipboard_empty() const; + bool can_delete() const; bool can_delete_all() const; bool can_increase_instances() const; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index dedf55a45..e0a536561 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -47,6 +47,23 @@ Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_trans { } +Selection::Clipboard::Clipboard() + : m_object(nullptr) +{ + m_object = m_model.add_object(); +} + +void Selection::Clipboard::add_volume(const ModelVolume& volume) +{ + ModelVolume* v = m_object->add_volume(volume); + v->config = volume.config; +} + +const ModelVolume* Selection::Clipboard::get_volume(unsigned int id) const +{ + return (id < (unsigned int)m_object->volumes.size()) ? m_object->volumes[id] : nullptr; +} + Selection::Selection() : m_volumes(nullptr) , m_model(nullptr) @@ -1022,6 +1039,53 @@ bool Selection::requires_local_axes() const return (m_mode == Volume) && is_from_single_instance(); } +void Selection::copy_to_clipboard() +{ + if (!m_valid) + return; + + m_clipboard.reset(); + + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + int obj_idx = volume->object_idx(); + if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size())) + { + const ModelObject* model_object = m_model->objects[obj_idx]; + int vol_idx = volume->volume_idx(); + if ((0 <= vol_idx) && (vol_idx < (int)model_object->volumes.size())) + m_clipboard.add_volume(*model_object->volumes[vol_idx]); + } + } + + int obj_idx = get_object_idx(); + if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size())) + m_clipboard.get_object()->config = m_model->objects[obj_idx]->config; + + m_clipboard.set_mode(m_mode); + m_clipboard.set_type(m_type); +} + +void Selection::paste_from_clipboard() +{ + if (!m_valid) + return; + + if (m_clipboard.is_empty()) + return; + + if ((m_clipboard.get_mode() == Volume) && is_from_single_instance()) + paste_volumes_from_clipboard(); + else + paste_object_from_clipboard(); +} + +bool Selection::is_clipboard_empty() +{ + return m_clipboard.is_empty(); +} + void Selection::update_valid() { m_valid = (m_volumes != nullptr) && (m_model != nullptr); @@ -1697,5 +1761,33 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const return count == (unsigned int)m_model->objects[object_idx]->volumes.size(); } +void Selection::paste_volumes_from_clipboard() +{ + int obj_idx = get_object_idx(); + if ((obj_idx < 0) || ((int)m_model->objects.size() <= obj_idx)) + return; + + ModelObject& model_object = *m_model->objects[obj_idx]; + unsigned int count = m_clipboard.get_volumes_count(); + ModelVolumePtrs volumes; + for (unsigned int i = 0; i < count; ++i) + { + const ModelVolume* volume = m_clipboard.get_volume(i); + ModelVolume* new_volume = model_object.add_volume(*volume); + new_volume->config = volume->config; + new_volume->set_new_unique_id(); + volumes.push_back(new_volume); + } + wxGetApp().obj_list()->paste_volumes_into_list(obj_idx, volumes); + int a = 0; +} + +void Selection::paste_object_from_clipboard() +{ + ModelObject* model_object = m_clipboard.get_object(); + if (model_object != nullptr) + wxGetApp().obj_list()->paste_object_into_list(*model_object); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index b03a8e89a..3eb63486b 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -151,6 +151,31 @@ private: ObjectIdxsToInstanceIdxsMap content; }; + class Clipboard + { + Model m_model; + ModelObject* m_object; + Selection::EMode m_mode; + Selection::EType m_type; + + public: + Clipboard(); + + void reset() { if (m_object != nullptr) m_object->clear_volumes(); } + void add_volume(const ModelVolume& volume); + const ModelVolume* get_volume(unsigned int id) const; + ModelObject* get_object() { return m_object; } + const ModelObject* get_object() const { return m_object; } + const unsigned int get_volumes_count() const { return (unsigned int)m_object->volumes.size(); } + + bool is_empty() const { return (m_object == nullptr) || m_object->volumes.empty(); } + + Selection::EMode get_mode() const { return m_mode; } + void set_mode(Selection::EMode mode) { m_mode = mode; } + Selection::EType get_type() const { return m_type; } + void set_type(Selection::EType type) { m_type = type; } + }; + // Volumes owned by GLCanvas3D. GLVolumePtrs* m_volumes; // Model, not owned. @@ -163,6 +188,7 @@ private: // set of indices to m_volumes IndicesList m_list; Cache m_cache; + Clipboard m_clipboard; mutable BoundingBoxf3 m_bounding_box; mutable bool m_bounding_box_dirty; @@ -267,6 +293,10 @@ public: bool requires_local_axes() const; + void copy_to_clipboard(); + void paste_from_clipboard(); + bool is_clipboard_empty(); + private: void update_valid(); void update_type(); @@ -301,6 +331,8 @@ private: void synchronize_unselected_volumes(); void ensure_on_bed(); bool is_from_fully_selected_instance(unsigned int volume_idx) const; + void paste_volumes_from_clipboard(); + void paste_object_from_clipboard(); }; } // namespace GUI