diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 441f30816..b8f596e6b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -695,33 +695,41 @@ void ObjectList::selection_changed() part_selection_changed(); } -void ObjectList::fill_layer_config_ranges_cache() +void ObjectList::copy_layers_to_clipboard() { wxDataViewItemArray sel_layers; GetSelections(sel_layers); - const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]); + const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers.front()); if (obj_idx < 0 || (int)m_objects->size() <= obj_idx) return; const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges; - m_layer_config_ranges_cache.clear(); + t_layer_config_ranges& cache_ranges = m_clipboard.get_ranges_cache(); + + if (sel_layers.Count() == 1 && m_objects_model->GetItemType(sel_layers.front()) & itLayerRoot) + { + cache_ranges.clear(); + cache_ranges = ranges; + return; + } for (const auto layer_item : sel_layers) if (m_objects_model->GetItemType(layer_item) & itLayer) { auto range = m_objects_model->GetLayerRangeByItem(layer_item); auto it = ranges.find(range); if (it != ranges.end()) - m_layer_config_ranges_cache[it->first] = it->second; + cache_ranges[it->first] = it->second; } } void ObjectList::paste_layers_into_list() { const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection()); + t_layer_config_ranges& cache_ranges = m_clipboard.get_ranges_cache(); if (obj_idx < 0 || (int)m_objects->size() <= obj_idx || - m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA) + cache_ranges.empty() || printer_technology() == ptSLA) return; const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx); @@ -732,7 +740,7 @@ void ObjectList::paste_layers_into_list() t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges; // and create Layer item(s) according to the layer_config_ranges - for (const auto range : m_layer_config_ranges_cache) + for (const auto range : cache_ranges) ranges.emplace(range); layers_item = add_layer_root_item(object_item); @@ -745,6 +753,48 @@ void ObjectList::paste_layers_into_list() #endif //no __WXOSX__ } +void ObjectList::copy_settings_to_clipboard() +{ + wxDataViewItem item = GetSelection(); + assert(item.IsOk()); + if (m_objects_model->GetItemType(item) & itSettings) + item = m_objects_model->GetParent(item); + + DynamicPrintConfig& config_cache = m_clipboard.get_config_cache(); + config_cache = get_item_config(item); +} + +void ObjectList::paste_settings_into_list() +{ + wxDataViewItem item = GetSelection(); + assert(item.IsOk()); + if (m_objects_model->GetItemType(item) & itSettings) + item = m_objects_model->GetParent(item); + + ItemType item_type = m_objects_model->GetItemType(item); + if(!(item_type & (itObject | itVolume |itLayer))) + return; + + DynamicPrintConfig& config_cache = m_clipboard.get_config_cache(); + assert(!config_cache.empty()); + + auto keys = config_cache.keys(); + auto part_options = get_options(true); + + for (const std::string& opt_key: keys) { + if (item_type & (itVolume | itLayer) && + std::find(part_options.begin(), part_options.end(), opt_key) == part_options.end()) + continue; // we can't to add object specific options for the part's(itVolume | itLayer) config + + const ConfigOption* option = config_cache.option(opt_key); + if (option) + m_config->set_key_value(opt_key, option->clone()); + } + + // Add settings item for object/sub-object and show them + show_settings(add_settings_item(item, m_config)); +} + void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes) { if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx)) @@ -984,20 +1034,46 @@ void ObjectList::extruder_editing() void ObjectList::copy() { - // if (m_selection_mode & smLayer) - // fill_layer_config_ranges_cache(); - // else { - // m_layer_config_ranges_cache.clear(); - wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); - // } + wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); } void ObjectList::paste() { - // if (!m_layer_config_ranges_cache.empty()) - // paste_layers_into_list(); - // else - wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); + wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); +} + +bool ObjectList::copy_to_clipboard() +{ + wxDataViewItemArray sels; + GetSelections(sels); + ItemType type = m_objects_model->GetItemType(sels.front()); + if (!(type & (itSettings | itLayer | itLayerRoot))) { + m_clipboard.reset(); + return false; + } + + if (type & itSettings) + copy_settings_to_clipboard(); + if (type & (itLayer | itLayerRoot)) + copy_layers_to_clipboard(); + + m_clipboard.set_type(type); + return true; +} + +bool ObjectList::paste_from_clipboard() +{ + if (!(m_clipboard.get_type() & (itSettings | itLayer | itLayerRoot))) { + m_clipboard.reset(); + return false; + } + + if (m_clipboard.get_type() & itSettings) + paste_settings_into_list(); + if (m_clipboard.get_type() & (itLayer | itLayerRoot)) + paste_layers_into_list(); + + return true; } void ObjectList::undo() diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 4490ec5e9..ad222a4a8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -81,10 +81,32 @@ public: smLayerRoot = 16, // used for undo/redo }; + struct Clipboard + { + void reset() { + m_type = itUndef; + m_layer_config_ranges_cache .clear(); + m_config_cache.clear(); + } + bool empty() const { return m_type == itUndef; } + ItemType get_type() const { return m_type; } + void set_type(ItemType type) { m_type = type; } + + t_layer_config_ranges& get_ranges_cache() { return m_layer_config_ranges_cache; } + DynamicPrintConfig& get_config_cache() { return m_config_cache; } + + private: + ItemType m_type {itUndef}; + t_layer_config_ranges m_layer_config_ranges_cache; + DynamicPrintConfig m_config_cache; + }; + private: SELECTION_MODE m_selection_mode {smUndef}; int m_selected_layers_range_idx; + Clipboard m_clipboard; + struct dragged_item_data { void init(const int obj_idx, const int subobj_idx, const ItemType type) { @@ -148,8 +170,6 @@ private: std::vector<wxBitmap*> m_bmp_vector; - t_layer_config_ranges m_layer_config_ranges_cache; - int m_selected_object_id = -1; bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select() // happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler @@ -230,6 +250,8 @@ public: void copy(); void paste(); + bool copy_to_clipboard(); + bool paste_from_clipboard(); void undo(); void redo(); @@ -385,8 +407,11 @@ public: void fix_through_netfabb(); void update_item_error_icon(const int obj_idx, int vol_idx) const ; - void fill_layer_config_ranges_cache(); + void copy_layers_to_clipboard(); void paste_layers_into_list(); + void copy_settings_to_clipboard(); + void paste_settings_into_list(); + bool clipboard_is_empty() const { return m_clipboard.empty(); } void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes); void paste_objects_into_list(const std::vector<size_t>& object_idxs); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 03bbab796..34b151a93 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5456,7 +5456,10 @@ void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_acti void Plater::copy_selection_to_clipboard() { - if (can_copy_to_clipboard()) + // At first try to copy selected values to the ObjectList's clipboard + // to check if Settings or Layers are selected in the list + // and then copy to 3DCanvas's clipboard if not + if (can_copy_to_clipboard() && !p->sidebar->obj_list()->copy_to_clipboard()) p->view3D->get_canvas3d()->get_selection().copy_to_clipboard(); } @@ -5466,7 +5469,12 @@ void Plater::paste_from_clipboard() return; Plater::TakeSnapshot snapshot(this, _L("Paste From Clipboard")); - p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); + + // At first try to paste values from the ObjectList's clipboard + // to check if Settings or Layers were copied + // and then paste from the 3DCanvas's clipboard if not + if (!p->sidebar->obj_list()->paste_from_clipboard()) + p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } void Plater::search(bool plater_is_active) @@ -5591,7 +5599,7 @@ bool Plater::can_paste_from_clipboard() const const Selection& selection = p->view3D->get_canvas3d()->get_selection(); const Selection::Clipboard& clipboard = selection.get_clipboard(); - if (clipboard.is_empty()) + if (clipboard.is_empty() && p->sidebar->obj_list()->clipboard_is_empty()) return false; if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) && !clipboard.is_sla_compliant())