diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 882636f1c..5bd2f2654 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1741,7 +1741,7 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) ItemType type; m_objects_model->GetItemInfo(item, type, obj_idx, idx); - if (type & itUndef) + if (type == itUndef) return; if (type & itSettings) @@ -2633,12 +2633,26 @@ bool ObjectList::is_selected(const ItemType type) const return false; } +int ObjectList::get_selected_layers_range_idx() const +{ + const wxDataViewItem& item = GetSelection(); + if (!item) + return -1; + + const ItemType type = m_objects_model->GetItemType(item); + if (type & itSettings && m_objects_model->GetItemType(m_objects_model->GetParent(item)) != itLayer) + return -1; + + return m_objects_model->GetLayerIdByItem(type & itLayer ? item : m_objects_model->GetParent(item)); +} + void ObjectList::update_selections() { const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); wxDataViewItemArray sels; - m_selection_mode = smInstance; + if ( ( m_selection_mode & (smSettings|smLayer|smLayerRoot) ) == 0) + m_selection_mode = smInstance; // We doesn't update selection if SettingsItem for the current object/part is selected // if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings ) @@ -2664,6 +2678,23 @@ void ObjectList::update_selections() else if (selection.is_single_full_object() || selection.is_multiple_full_object()) { const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content(); + if (m_selection_mode & (smSettings | smLayer | smLayerRoot)) + { + auto obj_idx = objects_content.begin()->first; + wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx); + if (m_selection_mode & smSettings) + { + if (m_selected_layers_range_idx < 0) + sels.Add(m_objects_model->GetSettingsItem(obj_item)); + else + sels.Add(m_objects_model->GetSettingsItem(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx))); + } + else if (m_selection_mode & smLayerRoot) + sels.Add(m_objects_model->GetLayerRootItem(obj_item)); + else if (m_selection_mode & smLayer) + sels.Add(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx)); + } + else { for (const auto& object : objects_content) { if (object.second.size() == 1) // object with 1 instance sels.Add(m_objects_model->GetItemById(object.first)); @@ -2688,10 +2719,23 @@ void ObjectList::update_selections() for (const auto& inst : instances) sels.Add(m_objects_model->GetItemByInstanceId(object.first, inst)); } - } + } } } else if (selection.is_any_volume() || selection.is_any_modifier()) { + if (m_selection_mode & smSettings) + { + const auto idx = *selection.get_volume_idxs().begin(); + const auto gl_vol = selection.get_volume(idx); + if (gl_vol->volume_idx() >= 0) { + // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids + // are not associated with ModelVolumes, but they are temporarily generated by the backend + // (for example, SLA supports or SLA pad). + wxDataViewItem vol_item = m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()); + sels.Add(m_objects_model->GetSettingsItem(vol_item)); + } + } + else { for (auto idx : selection.get_volume_idxs()) { const auto gl_vol = selection.get_volume(idx); if (gl_vol->volume_idx() >= 0) @@ -2700,7 +2744,7 @@ void ObjectList::update_selections() // (for example, SLA supports or SLA pad). sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); } - m_selection_mode = smVolume; + m_selection_mode = smVolume; } } else if (selection.is_single_full_instance() || selection.is_multiple_full_instance()) { @@ -2744,7 +2788,7 @@ void ObjectList::update_selections() } } - if (sels.size() == 0) + if (sels.size() == 0 || m_selection_mode & smSettings) m_selection_mode = smUndef; select_items(sels); @@ -3177,7 +3221,7 @@ void ObjectList::change_part_type() void ObjectList::last_volume_is_deleted(const int obj_idx) { - if (obj_idx < 0 || obj_idx >= m_objects->size() || (*m_objects)[obj_idx]->volumes.empty()) + if (obj_idx < 0 || obj_idx >= m_objects->size() || (*m_objects)[obj_idx]->volumes.size() != 1) return; auto volume = (*m_objects)[obj_idx]->volumes.front(); @@ -3618,13 +3662,12 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const void ObjectList::update_after_undo_redo() { - m_prevent_list_events = true; m_prevent_canvas_selection_update = true; Plater::SuppressSnapshots suppress(wxGetApp().plater()); // Unselect all objects before deleting them, so that no change of selection is emitted during deletion. - this->UnselectAll(); + unselect_objects();//this->UnselectAll(); m_objects_model->DeleteAll(); size_t obj_idx = 0; @@ -3634,13 +3677,12 @@ void ObjectList::update_after_undo_redo() } #ifndef __WXOSX__ - selection_changed(); +// selection_changed(); #endif /* __WXOSX__ */ update_selections(); m_prevent_canvas_selection_update = false; - m_prevent_list_events = false; } ModelObject* ObjectList::object(const int obj_idx) const diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 5f5d5d625..5c971c40f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -66,13 +66,20 @@ struct ItemForDelete class ObjectList : public wxDataViewCtrl { +public: enum SELECTION_MODE { smUndef = 0, smVolume = 1, smInstance = 2, - smLayer = 4 - } m_selection_mode {smUndef}; + smLayer = 4, + smSettings = 8, // used for undo/redo + smLayerRoot = 16, // used for undo/redo + }; + +private: + SELECTION_MODE m_selection_mode {smUndef}; + int m_selected_layers_range_idx; struct dragged_item_data { @@ -302,6 +309,9 @@ public: void init_objects(); bool multiple_selection() const ; bool is_selected(const ItemType type) const; + int get_selected_layers_range_idx() const; + void set_selected_layers_range_idx(const int range_idx) { m_selected_layers_range_idx = range_idx; } + void set_selection_mode(SELECTION_MODE mode) { m_selection_mode = mode; } void update_selections(); void update_selections_on_canvas(); void select_item(const wxDataViewItem& item); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b98faaa3c..067d13b8a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3729,6 +3729,16 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name) snapshot_data.printer_technology = this->printer_technology; if (this->view3D->is_layers_editing_enabled()) snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE; + if (this->sidebar->obj_list()->is_selected(itSettings)) { + snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR; + snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx(); + } + else if (this->sidebar->obj_list()->is_selected(itLayer)) { + snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR; + snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx(); + } + else if (this->sidebar->obj_list()->is_selected(itLayerRoot)) + snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR; //FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config. // This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config. if (this->printer_technology == ptFFF) { @@ -3795,7 +3805,21 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator top_snapshot_data.printer_technology = this->printer_technology; if (this->view3D->is_layers_editing_enabled()) top_snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE; + if (this->sidebar->obj_list()->is_selected(itSettings)) { + top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR; + top_snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx(); + } + else if (this->sidebar->obj_list()->is_selected(itLayer)) { + top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR; + top_snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx(); + } + else if (this->sidebar->obj_list()->is_selected(itLayerRoot)) + top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR; bool new_variable_layer_editing_active = (new_flags & UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE) != 0; + bool new_selected_settings_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR) != 0; + bool new_selected_layer_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR) != 0; + bool new_selected_layerroot_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR) != 0; + // Disable layer editing before the Undo / Redo jump. if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled()) view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); @@ -3828,6 +3852,14 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator tab_print->update_dirty(); } } + // set selection mode for ObjectList on sidebar + this->sidebar->obj_list()->set_selection_mode(new_selected_settings_on_sidebar ? ObjectList::SELECTION_MODE::smSettings : + new_selected_layer_on_sidebar ? ObjectList::SELECTION_MODE::smLayer : + new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot : + ObjectList::SELECTION_MODE::smUndef); + if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar) + this->sidebar->obj_list()->set_selected_layers_range_idx(it_snapshot->snapshot_data.layer_range_idx); + this->update_after_undo_redo(temp_snapshot_was_taken); // Enable layer editing after the Undo / Redo jump. if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 6300ada31..3fc404864 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1508,7 +1508,7 @@ ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const if (!item.IsOk()) return itUndef; ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); - return node->m_type; + return node->m_type < 0 ? itUndef : node->m_type; } wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index eba839ffb..daf6752b7 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -36,7 +36,7 @@ namespace Slic3r { namespace UndoRedo { -SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0) +SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range_idx(-1) { } diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp index c17802560..37cc5a049 100644 --- a/src/slic3r/Utils/UndoRedo.hpp +++ b/src/slic3r/Utils/UndoRedo.hpp @@ -9,6 +9,9 @@ #include +typedef double coordf_t; +typedef std::pair t_layer_height_range; + namespace Slic3r { class Model; @@ -34,10 +37,14 @@ struct SnapshotData PrinterTechnology printer_technology; // Bitmap of Flags (see the Flags enum). unsigned int flags; + int layer_range_idx; // Bitmask of various binary flags to be stored with the snapshot. enum Flags { VARIABLE_LAYER_EDITING_ACTIVE = 1, + SELECTED_SETTINGS_ON_SIDEBAR = 2, + SELECTED_LAYERROOT_ON_SIDEBAR = 4, + SELECTED_LAYER_ON_SIDEBAR = 8, }; };