From 6cbf9d25234c8a12586d0b7a555513ee2333a5ea Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 08:40:58 +0200 Subject: [PATCH 01/16] 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 From 6f6b78d6615f8660611e3d03f7f02ac3ae846383 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 09:27:42 +0200 Subject: [PATCH 02/16] Copy and paste -> Copy a volume from an object and paste to another --- src/slic3r/GUI/GUI_ObjectList.cpp | 14 ++++++-------- src/slic3r/GUI/GUI_ObjectList.hpp | 2 -- src/slic3r/GUI/wxExtensions.cpp | 11 +++++------ src/slic3r/GUI/wxExtensions.hpp | 11 +++++------ 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index b0ccf6290..d53d0809e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -452,7 +452,7 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol 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); + volume->config.has("extruder") ? volume->config.option("extruder")->value : 0); 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)); @@ -1610,11 +1610,10 @@ void ObjectList::split() for (auto id = 0; id < model_object->volumes.size(); id++) { const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), - model_object->volumes[id]->is_modifier() ? - ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, - model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0, - false); + model_object->volumes[id]->is_modifier() ? + ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, + model_object->volumes[id]->config.has("extruder") ? + model_object->volumes[id]->config.option("extruder")->value : 0); // add settings to the part, if it has those auto opt_keys = model_object->volumes[id]->config.keys(); if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { @@ -1808,8 +1807,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) 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("extruder")->value, - false); + model_object->volumes[id]->config.option("extruder")->value); auto opt_keys = model_object->volumes[id]->config.keys(); if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { select_item(m_objects_model->AddSettingsChild(vol_item)); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index a30f76332..c5e097af8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -31,9 +31,7 @@ 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 { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 7f5b5ad9c..a6b879297 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -529,10 +529,9 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ext } wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, - const wxString &name, - const Slic3r::ModelVolumeType volume_type, - const int extruder/* = 0*/, - const bool create_frst_child/* = true*/) + const wxString &name, + const Slic3r::ModelVolumeType volume_type, + const int extruder/* = 0*/) { PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID(); if (!root) return wxDataViewItem(0); @@ -544,8 +543,8 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot) insert_position = -1; - if (create_frst_child && root->m_volumes_cnt == 0) - { + if (root->m_volumes_cnt == 0) + { const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 4a3482abc..19c4e7759 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -454,12 +454,11 @@ public: ~PrusaObjectDataViewModel(); wxDataViewItem Add(const wxString &name, const int extruder); - wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, - const wxString &name, - const Slic3r::ModelVolumeType volume_type, - const int extruder = 0, - const bool create_frst_child = true); - wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); + wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, + const wxString &name, + const Slic3r::ModelVolumeType volume_type, + const int extruder = 0); + wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem Delete(const wxDataViewItem &item); wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); From e61be7d260d40caf2b9d4edf128e086ca4d3144f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 11:20:09 +0200 Subject: [PATCH 03/16] Render picking pass renders volumes in the same order as the regular render pass --- src/slic3r/GUI/3DScene.cpp | 25 +++++++++-------- src/slic3r/GUI/3DScene.hpp | 4 +++ src/slic3r/GUI/GLCanvas3D.cpp | 51 +++++++++++++++++------------------ src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3dd680820..61920220e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -721,32 +721,31 @@ int GLVolumeCollection::load_wipe_tower_preview( return int(this->volumes.size() - 1); } -typedef std::pair GLVolumeWithZ; -typedef std::vector GLVolumesWithZList; -static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func) +GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func) { - GLVolumesWithZList list; + GLVolumeWithIdAndZList list; list.reserve(volumes.size()); - for (GLVolume* volume : volumes) + for (unsigned int i = 0; i < (unsigned int)volumes.size(); ++i) { + GLVolume* volume = volumes[i]; bool is_transparent = (volume->render_color[3] < 1.0f); if ((((type == GLVolumeCollection::Opaque) && !is_transparent) || ((type == GLVolumeCollection::Transparent) && is_transparent) || (type == GLVolumeCollection::All)) && (! filter_func || filter_func(*volume))) - list.emplace_back(std::make_pair(volume, 0.0)); + list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0))); } if ((type == GLVolumeCollection::Transparent) && (list.size() > 1)) { - for (GLVolumeWithZ& volume : list) + for (GLVolumeWithIdAndZ& volume : list) { - volume.second = volume.first->bounding_box.transformed(view_matrix * volume.first->world_matrix()).max(2); + volume.second.second = volume.first->bounding_box.transformed(view_matrix * volume.first->world_matrix()).max(2); } std::sort(list.begin(), list.end(), - [](const GLVolumeWithZ& v1, const GLVolumeWithZ& v2) -> bool { return v1.second < v2.second; } + [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.second.second < v2.second.second; } ); } @@ -784,8 +783,8 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool if (z_range_id != -1) glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range)); - GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); - for (GLVolumeWithZ& volume : to_render) { + GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); + for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); } @@ -814,8 +813,8 @@ void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); - for (GLVolumeWithZ& volume : to_render) + GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); + for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); volume.first->render_legacy(); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index ce7bf8e97..f8f29d270 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -412,6 +412,8 @@ public: }; typedef std::vector GLVolumePtrs; +typedef std::pair> GLVolumeWithIdAndZ; +typedef std::vector GLVolumeWithIdAndZList; class GLVolumeCollection { @@ -505,6 +507,8 @@ private: GLVolumeCollection& operator=(const GLVolumeCollection &); }; +GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func = nullptr); + class GLModel { protected: diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 29c64b9a5..ac802d217 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3490,7 +3490,7 @@ void GLCanvas3D::_picking_pass() const glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - _render_volumes(true); + _render_volumes_for_picking(); m_gizmos.render_current_gizmo_for_picking_pass(m_selection); if (m_multisample_allowed) @@ -3675,13 +3675,10 @@ void GLCanvas3D::_render_legend_texture() const m_legend_texture.render(*this); } -void GLCanvas3D::_render_volumes(bool fake_colors) const +void GLCanvas3D::_render_volumes_for_picking() const { static const GLfloat INV_255 = 1.0f / 255.0f; - if (!fake_colors) - glsafe(::glEnable(GL_LIGHTING)); - // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); @@ -3691,27 +3688,31 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - unsigned int volume_id = 0; - for (GLVolume* vol : m_volumes.volumes) + const Transform3d& view_matrix = m_camera.get_view_matrix(); + GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Opaque, view_matrix); + for (const GLVolumeWithIdAndZ& volume : to_render) { - if (fake_colors) - { - // Object picking mode. Render the object with a color encoding the object index. - unsigned int r = (volume_id & 0x000000FF) >> 0; - unsigned int g = (volume_id & 0x0000FF00) >> 8; - unsigned int b = (volume_id & 0x00FF0000) >> 16; - glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); - } - else - { - vol->set_render_color(); - glsafe(::glColor4fv(vol->render_color)); - } + // Object picking mode. Render the object with a color encoding the object index. + unsigned int r = (volume.second.first & 0x000000FF) >> 0; + unsigned int g = (volume.second.first & 0x0000FF00) >> 8; + unsigned int b = (volume.second.first & 0x00FF0000) >> 16; + glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); - if ((!fake_colors || !vol->disabled) && (vol->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) - vol->render(); + if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) + volume.first->render(); + } - ++volume_id; + to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Transparent, view_matrix); + for (const GLVolumeWithIdAndZ& volume : to_render) + { + // Object picking mode. Render the object with a color encoding the object index. + unsigned int r = (volume.second.first & 0x000000FF) >> 0; + unsigned int g = (volume.second.first & 0x0000FF00) >> 8; + unsigned int b = (volume.second.first & 0x00FF0000) >> 16; + glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); + + if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) + volume.first->render(); } glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); @@ -3719,9 +3720,6 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const glsafe(::glDisable(GL_BLEND)); glsafe(::glEnable(GL_CULL_FACE)); - - if (!fake_colors) - glsafe(::glDisable(GL_LIGHTING)); } void GLCanvas3D::_render_current_gizmo() const @@ -3999,7 +3997,6 @@ void GLCanvas3D::_update_volumes_hover_state() const return; GLVolume* volume = m_volumes.volumes[m_hover_volume_id]; - switch (m_selection.get_mode()) { case Selection::Volume: diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 53551a472..228e3ca89 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -605,7 +605,7 @@ private: #endif // ENABLE_RENDER_SELECTION_CENTER void _render_warning_texture() const; void _render_legend_texture() const; - void _render_volumes(bool fake_colors) const; + void _render_volumes_for_picking() const; void _render_current_gizmo() const; void _render_gizmos_overlay() const; void _render_toolbar() const; From a80978f84ac4f8a0909e0a88202560bae7ce2da7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 12:20:07 +0200 Subject: [PATCH 04/16] Do not show as hovered the entire instance when hovering on modifiers --- src/slic3r/GUI/GLCanvas3D.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fb064596f..1fc75a579 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4000,14 +4000,9 @@ void GLCanvas3D::_update_volumes_hover_state() const return; GLVolume* volume = m_volumes.volumes[m_hover_volume_id]; - switch (m_selection.get_mode()) - { - case Selection::Volume: - { + if (volume->is_modifier) volume->hover = true; - break; - } - case Selection::Instance: + else { int object_idx = volume->object_idx(); int instance_idx = volume->instance_idx(); @@ -4017,9 +4012,6 @@ void GLCanvas3D::_update_volumes_hover_state() const if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) v->hover = true; } - - break; - } } } From 7a1fab09d466d8d48eab7e33a8eac0ca981342ba Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 14:03:40 +0200 Subject: [PATCH 05/16] Copy and paste -> Clipboard refactored to accept more than one object --- src/slic3r/GUI/GUI_ObjectList.cpp | 1 + src/slic3r/GUI/Selection.cpp | 81 +++++++++++++------------------ src/slic3r/GUI/Selection.hpp | 17 ++----- 3 files changed, 38 insertions(+), 61 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d53d0809e..c36b8b288 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2167,6 +2167,7 @@ void ObjectList::update_selections_on_canvas() add_to_selection(item, selection, instance_idx, false); wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); + wxGetApp().plater()->canvas3D()->render(); } void ObjectList::select_item(const wxDataViewItem& item) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index e0a536561..9179fce42 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -47,23 +47,6 @@ 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) @@ -1046,33 +1029,36 @@ void Selection::copy_to_clipboard() m_clipboard.reset(); - for (unsigned int i : m_list) + for (const ObjectIdxsToInstanceIdxsMap::value_type& object : m_cache.content) { - const GLVolume* volume = (*m_volumes)[i]; - int obj_idx = volume->object_idx(); - if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size())) + ModelObject* src_object = m_model->objects[object.first]; + ModelObject* dst_object = m_clipboard.add_object(); + + for (int i : object.second) { - 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]); + dst_object->add_instance(*src_object->instances[i]); } + + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + if (volume->object_idx() == object.first) + { + ModelVolume* src_volume = src_object->volumes[i]; + ModelVolume* dst_volume = dst_object->add_volume(*src_volume); + dst_volume->set_new_unique_id(); + dst_volume->config = src_volume->config; + } + } + dst_object->config = src_object->config; } - 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()) + if (!m_valid || m_clipboard.is_empty()) return; if ((m_clipboard.get_mode() == Volume) && is_from_single_instance()) @@ -1767,26 +1753,25 @@ void Selection::paste_volumes_from_clipboard() 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) + ModelObject* src_object = m_clipboard.get_object(0); + if (src_object != nullptr) { - 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); + ModelObject* dst_object = m_model->objects[obj_idx]; + + ModelVolumePtrs volumes; + for (ModelVolume* src_volume : src_object->volumes) + { + ModelVolume* dst_volume = dst_object->add_volume(*src_volume); + dst_volume->config = src_volume->config; + dst_volume->set_new_unique_id(); + volumes.push_back(dst_volume); + } + wxGetApp().obj_list()->paste_volumes_into_list(obj_idx, volumes); } - 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 diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 3eb63486b..e04c37356 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -154,26 +154,17 @@ private: class Clipboard { Model m_model; - ModelObject* m_object; Selection::EMode m_mode; - Selection::EType m_type; public: - Clipboard(); + void reset() { m_model.clear_objects(); } + bool is_empty() const { return m_model.objects.empty(); } - 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(); } + ModelObject* add_object() { return m_model.add_object(); } + ModelObject* get_object(unsigned int id) { return (id < (unsigned int)m_model.objects.size()) ? m_model.objects[id] : nullptr; } 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. From 8b9568797a5b7015185bf451c0cb98cf254ab1d9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Apr 2019 15:55:32 +0200 Subject: [PATCH 06/16] Copy and paste -> prototype of copy and paste for objects --- src/slic3r/GUI/GUI_ObjectList.cpp | 19 ++++++++++++++++++- src/slic3r/GUI/GUI_ObjectList.hpp | 2 +- src/slic3r/GUI/Selection.cpp | 28 +++++++++++++++++++++------- src/slic3r/GUI/Selection.hpp | 4 +++- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index c36b8b288..4d205fa5f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -469,8 +469,25 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol #endif //no __WXOSX__ //__WXMSW__ } -void ObjectList::paste_object_into_list(const ModelObject& object) +void ObjectList::paste_objects_into_list(const std::vector& object_idxs) { + if (object_idxs.empty()) + return; + + wxDataViewItemArray items; + for (const size_t object : object_idxs) + { + add_object_to_list(object); + m_parts_changed = true; + parts_changed(object); + + items.Add(m_objects_model->GetItemById(object)); + } + + select_items(items); +#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME + selection_changed(); +#endif //no __WXOSX__ //__WXMSW__ } void ObjectList::OnChar(wxKeyEvent& event) diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index c5e097af8..a0343100a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -289,7 +289,7 @@ public: 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); + void paste_objects_into_list(const std::vector& object_idxs); private: void OnChar(wxKeyEvent& event); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 9179fce42..cb5add462 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1033,6 +1033,9 @@ void Selection::copy_to_clipboard() { ModelObject* src_object = m_model->objects[object.first]; ModelObject* dst_object = m_clipboard.add_object(); + dst_object->name = src_object->name; + dst_object->input_file = src_object->input_file; + dst_object->config = src_object->config; for (int i : object.second) { @@ -1044,13 +1047,16 @@ void Selection::copy_to_clipboard() const GLVolume* volume = (*m_volumes)[i]; if (volume->object_idx() == object.first) { - ModelVolume* src_volume = src_object->volumes[i]; - ModelVolume* dst_volume = dst_object->add_volume(*src_volume); - dst_volume->set_new_unique_id(); - dst_volume->config = src_volume->config; + int volume_idx = volume->volume_idx(); + if ((0 <= volume_idx) && (volume_idx < (int)src_object->volumes.size())) + { + ModelVolume* src_volume = src_object->volumes[volume->volume_idx()]; + ModelVolume* dst_volume = dst_object->add_volume(*src_volume); + dst_volume->set_new_unique_id(); + dst_volume->config = src_volume->config; + } } } - dst_object->config = src_object->config; } m_clipboard.set_mode(m_mode); @@ -1064,7 +1070,7 @@ void Selection::paste_from_clipboard() if ((m_clipboard.get_mode() == Volume) && is_from_single_instance()) paste_volumes_from_clipboard(); else - paste_object_from_clipboard(); + paste_objects_from_clipboard(); } bool Selection::is_clipboard_empty() @@ -1770,8 +1776,16 @@ void Selection::paste_volumes_from_clipboard() } } -void Selection::paste_object_from_clipboard() +void Selection::paste_objects_from_clipboard() { + std::vector object_idxs; + const ModelObjectPtrs& src_objects = m_clipboard.get_objects(); + for (const ModelObject* src_object : src_objects) + { + ModelObject* dst_object = m_model->add_object(*src_object); + object_idxs.push_back(m_model->objects.size() - 1); + } + wxGetApp().obj_list()->paste_objects_into_list(object_idxs); } } // namespace GUI diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index e04c37356..9fa9f1869 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -162,6 +162,7 @@ private: ModelObject* add_object() { return m_model.add_object(); } ModelObject* get_object(unsigned int id) { return (id < (unsigned int)m_model.objects.size()) ? m_model.objects[id] : nullptr; } + const ModelObjectPtrs& get_objects() const { return m_model.objects; } Selection::EMode get_mode() const { return m_mode; } void set_mode(Selection::EMode mode) { m_mode = mode; } @@ -322,8 +323,9 @@ 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(); + void paste_objects_from_clipboard(); }; } // namespace GUI From 4987e5a7d567d7cc1bbee3ade2bc9651e5f2886f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 08:36:00 +0200 Subject: [PATCH 07/16] Render selected objects first --- src/slic3r/GUI/3DScene.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 61920220e..1dd136517 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -748,6 +748,12 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.second.second < v2.second.second; } ); } + else if ((type == GLVolumeCollection::Opaque) && (list.size() > 1)) + { + std::sort(list.begin(), list.end(), + [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.first->selected && !v2.first->selected; } + ); + } return list; } From 99993170ebd1ea4fd1644972a2bbfd5708da966a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 11:09:32 +0200 Subject: [PATCH 08/16] Copy and paste -> Fixed copy of multiple instances and volumes insertion into objects list --- src/slic3r/GUI/GUI_ObjectList.cpp | 6 ++++-- src/slic3r/GUI/Selection.cpp | 4 ++-- src/slic3r/GUI/wxExtensions.cpp | 5 +++-- src/slic3r/GUI/wxExtensions.hpp | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4d205fa5f..fd2c43806 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1630,7 +1630,8 @@ void ObjectList::split() model_object->volumes[id]->is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0); + model_object->volumes[id]->config.option("extruder")->value : 0, + false); // add settings to the part, if it has those auto opt_keys = model_object->volumes[id]->config.keys(); if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { @@ -1824,7 +1825,8 @@ void ObjectList::add_object_to_list(size_t obj_idx) 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("extruder")->value); + model_object->volumes[id]->config.option("extruder")->value, + false); auto opt_keys = model_object->volumes[id]->config.keys(); if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { select_item(m_objects_model->AddSettingsChild(vol_item)); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index cb5add462..02149f275 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1045,12 +1045,12 @@ void Selection::copy_to_clipboard() for (unsigned int i : m_list) { const GLVolume* volume = (*m_volumes)[i]; - if (volume->object_idx() == object.first) + if ((volume->object_idx() == object.first) && (volume->instance_idx() == *object.second.begin())) { int volume_idx = volume->volume_idx(); if ((0 <= volume_idx) && (volume_idx < (int)src_object->volumes.size())) { - ModelVolume* src_volume = src_object->volumes[volume->volume_idx()]; + ModelVolume* src_volume = src_object->volumes[volume_idx]; ModelVolume* dst_volume = dst_object->add_volume(*src_volume); dst_volume->set_new_unique_id(); dst_volume->config = src_volume->config; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index a6b879297..356977b3a 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -531,7 +531,8 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ext wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, - const int extruder/* = 0*/) + const int extruder/* = 0*/, + const bool create_frst_child/* = true*/) { PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID(); if (!root) return wxDataViewItem(0); @@ -543,7 +544,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot) insert_position = -1; - if (root->m_volumes_cnt == 0) + if (create_frst_child && root->m_volumes_cnt == 0) { const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 19c4e7759..b935448d9 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -457,7 +457,8 @@ public: wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, - const int extruder = 0); + const int extruder = 0, + const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem Delete(const wxDataViewItem &item); From bd2ac8f1f8edd9d933bd1504d987f15e1ad67aed Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 11:27:15 +0200 Subject: [PATCH 09/16] Copy and paste -> Added offset to pasted objects/volumes --- src/slic3r/GUI/Selection.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 02149f275..705f02d33 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1770,6 +1770,7 @@ void Selection::paste_volumes_from_clipboard() ModelVolume* dst_volume = dst_object->add_volume(*src_volume); dst_volume->config = src_volume->config; dst_volume->set_new_unique_id(); + dst_volume->translate(10.0, 10.0, 0.0); volumes.push_back(dst_volume); } wxGetApp().obj_list()->paste_volumes_into_list(obj_idx, volumes); @@ -1783,6 +1784,7 @@ void Selection::paste_objects_from_clipboard() for (const ModelObject* src_object : src_objects) { ModelObject* dst_object = m_model->add_object(*src_object); + dst_object->translate(10.0, 10.0, 0.0); object_idxs.push_back(m_model->objects.size() - 1); } wxGetApp().obj_list()->paste_objects_into_list(object_idxs); From 4718c839f66dc6a0712e738390a08be3013143b7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 13:20:34 +0200 Subject: [PATCH 10/16] Copy and paste -> Added items for copy and paste on the toolbar --- resources/icons/copy.svg | 15 +++++++++++++++ resources/icons/paste.svg | 19 +++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.cpp | 35 ++++++++++++++++++++++++++++++----- src/slic3r/GUI/GLToolbar.cpp | 2 ++ src/slic3r/GUI/GLToolbar.hpp | 2 ++ src/slic3r/GUI/MainFrame.cpp | 14 ++------------ src/slic3r/GUI/MainFrame.hpp | 2 -- src/slic3r/GUI/Plater.cpp | 4 ++++ src/slic3r/GUI/Plater.hpp | 2 ++ 9 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 resources/icons/copy.svg create mode 100644 resources/icons/paste.svg diff --git a/resources/icons/copy.svg b/resources/icons/copy.svg new file mode 100644 index 000000000..fcb24122d --- /dev/null +++ b/resources/icons/copy.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/resources/icons/paste.svg b/resources/icons/paste.svg new file mode 100644 index 000000000..ba698e5b5 --- /dev/null +++ b/resources/icons/paste.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d1e5bbac6..f911dd171 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3232,12 +3232,37 @@ bool GLCanvas3D::_init_toolbar() if (!m_toolbar.add_separator()) return false; + item.name = "copy"; +#if ENABLE_SVG_ICONS + item.icon_filename = "copy.svg"; +#endif // ENABLE_SVG_ICONS + item.tooltip = GUI::L_str("Copy [Ctrl+C]"); + item.sprite_id = 4; + item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; + item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy(); }; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "paste"; +#if ENABLE_SVG_ICONS + item.icon_filename = "paste.svg"; +#endif // ENABLE_SVG_ICONS + item.tooltip = GUI::L_str("Paste [Ctrl+V]"); + item.sprite_id = 5; + item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; + item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste(); }; + if (!m_toolbar.add_item(item)) + return false; + + if (!m_toolbar.add_separator()) + return false; + item.name = "more"; #if ENABLE_SVG_ICONS item.icon_filename = "instance_add.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Add instance [+]"); - item.sprite_id = 4; + item.sprite_id = 6; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); }; @@ -3249,7 +3274,7 @@ bool GLCanvas3D::_init_toolbar() item.icon_filename = "instance_remove.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Remove instance [-]"); - item.sprite_id = 5; + item.sprite_id = 7; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); }; @@ -3264,7 +3289,7 @@ bool GLCanvas3D::_init_toolbar() item.icon_filename = "split_objects.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Split to objects"); - item.sprite_id = 6; + item.sprite_id = 8; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); }; @@ -3276,7 +3301,7 @@ bool GLCanvas3D::_init_toolbar() item.icon_filename = "split_parts.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Split to parts"); - item.sprite_id = 7; + item.sprite_id = 9; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); }; @@ -3291,7 +3316,7 @@ bool GLCanvas3D::_init_toolbar() item.icon_filename = "layers.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Layers editing"); - item.sprite_id = 8; + item.sprite_id = 10; item.is_toggable = true; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; item.visibility_callback = [this]()->bool { return m_process->current_printer_technology() == ptFFF; }; diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 144d02476..842700aef 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -21,6 +21,8 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); +wxDEFINE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 0f8b17e04..24314d60f 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -20,6 +20,8 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); +wxDECLARE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index a6c014899..d24d41a48 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -256,16 +256,6 @@ 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 @@ -399,8 +389,8 @@ void MainFrame::init_menubar() 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()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater->can_copy()); }, item_copy->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater->can_paste()); }, item_paste->GetId()); } // Window menu diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 16116ec43..625e70b83 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -68,8 +68,6 @@ 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 daab7818e..ebe7e2c75 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1406,6 +1406,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { reset(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { arrange(); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_COPY, [q](SimpleEvent&) { q->copy_selection_to_clipboard(); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_PASTE, [q](SimpleEvent&) { q->paste_from_clipboard(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_MORE, [q](SimpleEvent&) { q->increase_instances(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease_instances(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this); @@ -3723,5 +3725,7 @@ bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); } bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); } bool Plater::can_arrange() const { return p->can_arrange(); } bool Plater::can_layers_editing() const { return p->can_layers_editing(); } +bool Plater::can_copy() const { return !is_selection_empty(); } +bool Plater::can_paste() const { return !is_selection_clipboard_empty(); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 3d3ba8b3e..a70656c58 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -194,6 +194,8 @@ public: bool can_split_to_volumes() const; bool can_arrange() const; bool can_layers_editing() const; + bool can_copy() const; + bool can_paste() const; private: struct priv; From 4046d517c9f9564e414a3309fbd5401c72a319b4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 14:21:08 +0200 Subject: [PATCH 11/16] Copy and paste -> Disabled paste of volumes when nothing is selected and fixed enabling/disabling of paste item in toolbar and edit menu --- src/slic3r/GUI/Plater.cpp | 10 ++++++---- src/slic3r/GUI/Plater.hpp | 2 +- src/slic3r/GUI/Selection.cpp | 22 ++++++++++++++-------- src/slic3r/GUI/Selection.hpp | 29 +++++++++++++++-------------- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ebe7e2c75..a34562d85 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3711,10 +3711,12 @@ void Plater::paste_from_clipboard() { p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } - -bool Plater::is_selection_clipboard_empty() const +bool Plater::can_paste_from_clipboard() const { - return p->view3D->get_canvas3d()->get_selection().is_clipboard_empty(); + const Selection& selection = p->view3D->get_canvas3d()->get_selection(); + const Selection::Clipboard& clipboard = selection.get_clipboard(); + Selection::EMode mode = clipboard.get_mode(); + return !clipboard.is_empty() && ((mode == Selection::Instance) || selection.is_from_single_instance()); } bool Plater::can_delete() const { return p->can_delete(); } @@ -3726,6 +3728,6 @@ bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); } bool Plater::can_arrange() const { return p->can_arrange(); } bool Plater::can_layers_editing() const { return p->can_layers_editing(); } bool Plater::can_copy() const { return !is_selection_empty(); } -bool Plater::can_paste() const { return !is_selection_clipboard_empty(); } +bool Plater::can_paste() const { return can_paste_from_clipboard(); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index a70656c58..708c07f39 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -184,7 +184,7 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); - bool is_selection_clipboard_empty() const; + bool can_paste_from_clipboard() const; bool can_delete() const; bool can_delete_all() const; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 705f02d33..41313d5ed 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1067,15 +1067,21 @@ void Selection::paste_from_clipboard() if (!m_valid || m_clipboard.is_empty()) return; - if ((m_clipboard.get_mode() == Volume) && is_from_single_instance()) - paste_volumes_from_clipboard(); - else - paste_objects_from_clipboard(); -} + switch (m_clipboard.get_mode()) + { + case Volume: + { + if (is_from_single_instance()) + paste_volumes_from_clipboard(); -bool Selection::is_clipboard_empty() -{ - return m_clipboard.is_empty(); + break; + } + case Instance: + { + paste_objects_from_clipboard(); + break; + } + } } void Selection::update_valid() diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 9fa9f1869..a8b0c06dc 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -138,19 +138,6 @@ public: typedef std::set InstanceIdxsList; typedef std::map ObjectIdxsToInstanceIdxsMap; -private: - struct Cache - { - // Cache of GLVolume derived transformation matrices, valid during mouse dragging. - VolumesCache volumes_data; - // Center of the dragged selection, valid during mouse dragging. - Vec3d dragging_center; - // Map from indices of ModelObject instances in Model::objects - // to a set of indices of ModelVolume instances in ModelObject::instances - // Here the index means a position inside the respective std::vector, not ModelID. - ObjectIdxsToInstanceIdxsMap content; - }; - class Clipboard { Model m_model; @@ -168,6 +155,19 @@ private: void set_mode(Selection::EMode mode) { m_mode = mode; } }; +private: + struct Cache + { + // Cache of GLVolume derived transformation matrices, valid during mouse dragging. + VolumesCache volumes_data; + // Center of the dragged selection, valid during mouse dragging. + Vec3d dragging_center; + // Map from indices of ModelObject instances in Model::objects + // to a set of indices of ModelVolume instances in ModelObject::instances + // Here the index means a position inside the respective std::vector, not ModelID. + ObjectIdxsToInstanceIdxsMap content; + }; + // Volumes owned by GLCanvas3D. GLVolumePtrs* m_volumes; // Model, not owned. @@ -287,7 +287,8 @@ public: void copy_to_clipboard(); void paste_from_clipboard(); - bool is_clipboard_empty(); + + const Clipboard& get_clipboard() const { return m_clipboard; } private: void update_valid(); From a8fd1ceca074e05dc6190ff8b6440f37f62fb325 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 11 Apr 2019 15:51:12 +0200 Subject: [PATCH 12/16] New icons for copy and paste toolbar items --- resources/icons/copy.svg | 44 +++++++++++++++++++++++++++++---------- resources/icons/paste.svg | 40 +++++++++++++++++++++-------------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/resources/icons/copy.svg b/resources/icons/copy.svg index fcb24122d..9b8430dd7 100644 --- a/resources/icons/copy.svg +++ b/resources/icons/copy.svg @@ -1,15 +1,37 @@ - - - - + + + + - - + + + + + + + + + + + + diff --git a/resources/icons/paste.svg b/resources/icons/paste.svg index ba698e5b5..028ffb8ea 100644 --- a/resources/icons/paste.svg +++ b/resources/icons/paste.svg @@ -1,19 +1,27 @@ - - - - + + + + + - - + + + + + + From 6ff12111a60f4cef51d03033dd3b3da224424703 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Apr 2019 08:49:24 +0200 Subject: [PATCH 13/16] Copy and paste -> Disabled paste of instances when selection is in Volume mode --- src/slic3r/GUI/Plater.cpp | 12 +++++++++++- src/slic3r/GUI/Selection.cpp | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 027db69f5..c18091e4b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3717,7 +3717,17 @@ bool Plater::can_paste_from_clipboard() const const Selection& selection = p->view3D->get_canvas3d()->get_selection(); const Selection::Clipboard& clipboard = selection.get_clipboard(); Selection::EMode mode = clipboard.get_mode(); - return !clipboard.is_empty() && ((mode == Selection::Instance) || selection.is_from_single_instance()); + + if (clipboard.is_empty()) + return false; + + if ((mode == Selection::Volume) && !selection.is_from_single_instance()) + return false; + + if ((mode == Selection::Instance) && (selection.get_mode() != Selection::Instance)) + return false; + + return true; } bool Plater::can_delete() const { return p->can_delete(); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 315aa487a..22df9ed19 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1078,7 +1078,8 @@ void Selection::paste_from_clipboard() } case Instance: { - paste_objects_from_clipboard(); + if (m_mode == Instance) + paste_objects_from_clipboard(); break; } From 5a1b9cd3826b653bfaca8fdec20e7cb353337f83 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Apr 2019 08:57:53 +0200 Subject: [PATCH 14/16] Copy and paste -> Fixed tooltips for copy and paste toolbar items on Mac --- src/slic3r/GUI/GLCanvas3D.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 44181ffcb..19ce28bed 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3236,7 +3236,7 @@ bool GLCanvas3D::_init_toolbar() #if ENABLE_SVG_ICONS item.icon_filename = "copy.svg"; #endif // ENABLE_SVG_ICONS - item.tooltip = GUI::L_str("Copy [Ctrl+C]"); + item.tooltip = GUI::L_str("Copy") + " [" + GUI::shortkey_ctrl_prefix() + "C]"; item.sprite_id = 4; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy(); }; @@ -3247,7 +3247,7 @@ bool GLCanvas3D::_init_toolbar() #if ENABLE_SVG_ICONS item.icon_filename = "paste.svg"; #endif // ENABLE_SVG_ICONS - item.tooltip = GUI::L_str("Paste [Ctrl+V]"); + item.tooltip = GUI::L_str("Paste") + " [" + GUI::shortkey_ctrl_prefix() + "V]"; item.sprite_id = 5; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste(); }; From defcd26b4ac03843611c5ec42938e8c232d1cb60 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Apr 2019 11:28:24 +0200 Subject: [PATCH 15/16] Copy and paste -> Fixed paste for multivolumes copies --- src/slic3r/GUI/GUI_ObjectList.cpp | 6 ++++++ src/slic3r/GUI/Selection.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index fd2c43806..b65b78043 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -463,6 +463,12 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol m_parts_changed = true; parts_changed(obj_idx); + if (items.size() > 1) + { + m_selection_mode = smVolume; + m_last_selected_item = wxDataViewItem(0); + } + select_items(items); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 22df9ed19..8ee449a21 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1795,6 +1795,7 @@ void Selection::paste_objects_from_clipboard() dst_object->translate(10.0, 10.0, 0.0); object_idxs.push_back(m_model->objects.size() - 1); } + wxGetApp().obj_list()->paste_objects_into_list(object_idxs); } From edab2a056e26cddf877b83f1f0c7b8effe671952 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 12 Apr 2019 11:50:14 +0200 Subject: [PATCH 16/16] Added icons for Edit menu items: Delete selected, Delete all, Copy, Paste --- resources/icons/copy_menu.svg | 37 ++++++++++++++++++++++++ resources/icons/delete_all_menu.svg | 31 ++++++++++++++++++++ resources/icons/paste_menu.svg | 27 ++++++++++++++++++ resources/icons/remove_menu.svg | 44 +++++++++++++++++++++++++++++ src/slic3r/GUI/MainFrame.cpp | 8 +++--- 5 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 resources/icons/copy_menu.svg create mode 100644 resources/icons/delete_all_menu.svg create mode 100644 resources/icons/paste_menu.svg create mode 100644 resources/icons/remove_menu.svg diff --git a/resources/icons/copy_menu.svg b/resources/icons/copy_menu.svg new file mode 100644 index 000000000..0d1af6a0a --- /dev/null +++ b/resources/icons/copy_menu.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/delete_all_menu.svg b/resources/icons/delete_all_menu.svg new file mode 100644 index 000000000..5ee6d6ea6 --- /dev/null +++ b/resources/icons/delete_all_menu.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/paste_menu.svg b/resources/icons/paste_menu.svg new file mode 100644 index 000000000..74dbbf8ee --- /dev/null +++ b/resources/icons/paste_menu.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/remove_menu.svg b/resources/icons/remove_menu.svg new file mode 100644 index 000000000..a25ae965b --- /dev/null +++ b/resources/icons/remove_menu.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d24d41a48..56c7ec0ed 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -375,16 +375,16 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { m_plater->select_all(); }, ""); editMenu->AppendSeparator(); wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete, _(L("Deletes the current selection")), - [this](wxCommandEvent&) { m_plater->remove_selected(); }, ""); + [this](wxCommandEvent&) { m_plater->remove_selected(); }, "remove_menu"); 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(); }, ""); + [this](wxCommandEvent&) { m_plater->reset(); }, "delete_all_menu"); 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(); }, ""); + [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, "copy_menu"); wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + "\tCtrl+V", _(L("Paste clipboard")), - [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, ""); + [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "paste_menu"); 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());