diff --git a/resources/icons/info.png b/resources/icons/info.png new file mode 100644 index 0000000000..9eeee9b3cd Binary files /dev/null and b/resources/icons/info.png differ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7bbdc72b11..2149f21e7c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -508,6 +508,7 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas) m_layer_height_profile.clear(); m_layers_texture.valid = false; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); } void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor) @@ -517,6 +518,7 @@ void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); m_layers_texture.valid = false; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); } void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params) @@ -526,6 +528,7 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); m_layers_texture.valid = false; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); } void GLCanvas3D::LayersEditing::generate_layer_height_texture() @@ -565,6 +568,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas) wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Manual edit"))); const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); } } m_layer_height_profile_modified = false; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 58560c8bd7..15c4578d82 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1525,14 +1525,20 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) if (type == itUndef) return; + wxDataViewItem parent = m_objects_model->GetParent(item); + if (type & itSettings) - del_settings_from_config(m_objects_model->GetParent(item)); + del_settings_from_config(parent); else if (type & itInstanceRoot && obj_idx != -1) del_instances_from_object(obj_idx); else if (type & itLayerRoot && obj_idx != -1) del_layers_from_object(obj_idx); else if (type & itLayer && obj_idx != -1) del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item)); + else if (type & itInfo && obj_idx != -1) { + Unselect(item); + Select(parent); + } else if (idx == -1) return; else if (!del_subobject_from_object(obj_idx, idx, type)) @@ -1540,9 +1546,10 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) // If last volume item with warning was deleted, unmark object item if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0) - m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item)); + m_objects_model->DeleteWarningIcon(parent); m_objects_model->Delete(item); + update_info_items(obj_idx); } void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item) @@ -2118,20 +2125,32 @@ void ObjectList::part_selection_changed() { if (item) { - if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr)) { - obj_idx = m_objects_model->GetIdByItem(item); + const ItemType type = m_objects_model->GetItemType(item); + const wxDataViewItem parent = m_objects_model->GetParent(item); + const ItemType parent_type = m_objects_model->GetItemType(parent); + obj_idx = m_objects_model->GetObjectIdByItem(item); + + if (parent == wxDataViewItem(nullptr) + || type == itInfo) { og_name = _(L("Object manipulation")); m_config = &(*m_objects)[obj_idx]->config; update_and_show_manipulations = true; + + if (type == itInfo) { + InfoItemType info_type = m_objects_model->GetInfoItemType(item); + if (info_type != InfoItemType::VariableLayerHeight) { + GLGizmosManager::EType gizmo_type = + info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports + : GLGizmosManager::EType::Seam; + GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); + if (gizmos_mgr.get_current_type() != gizmo_type) + gizmos_mgr.open_gizmo(gizmo_type); + } else + wxGetApp().plater()->toggle_layers_editing(true); + } } else { - obj_idx = m_objects_model->GetObjectIdByItem(item); - - const ItemType type = m_objects_model->GetItemType(item); if (type & itSettings) { - const auto parent = m_objects_model->GetParent(item); - const ItemType parent_type = m_objects_model->GetItemType(parent); - if (parent_type & itObject) { og_name = _(L("Object Settings to modify")); m_config = &(*m_objects)[obj_idx]->config; @@ -2243,6 +2262,52 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D return ret; } + +void ObjectList::update_info_items(size_t obj_idx) +{ + const ModelObject* model_object = (*m_objects)[obj_idx]; + wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx); + assert(item_obj.IsOk()); + + for (InfoItemType type : {InfoItemType::CustomSupports, + InfoItemType::CustomSeam, + InfoItemType::VariableLayerHeight}) { + wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type); + bool shows = item.IsOk(); + bool should_show = false; + + switch (type) { + case InfoItemType::CustomSupports : + case InfoItemType::CustomSeam : + should_show = printer_technology() == ptFFF + && std::any_of(model_object->volumes.begin(), model_object->volumes.end(), + [type](const ModelVolume* mv) { + return ! (type == InfoItemType::CustomSupports + ? mv->supported_facets.empty() + : mv->seam_facets.empty()); + }); + break; + + case InfoItemType::VariableLayerHeight : + should_show = printer_technology() == ptFFF + && ! model_object->layer_height_profile.empty(); + break; + } + + if (! shows && should_show) { + m_objects_model->AddInfoChild(item_obj, type); + Expand(item_obj); + } + else if (shows && ! should_show) { + Unselect(item); + m_objects_model->Delete(item); + Select(item_obj); + } + } +} + + + void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) { auto model_object = (*m_objects)[obj_idx]; @@ -2251,6 +2316,8 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) model_object->config.has("extruder") ? model_object->config.extruder() : 0, get_mesh_errors_count(obj_idx) > 0); + update_info_items(obj_idx); + // add volumes to the object if (model_object->volumes.size() > 1) { for (const ModelVolume* volume : model_object->volumes) { @@ -3029,7 +3096,7 @@ void ObjectList::update_selections_on_canvas() if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); - if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer)) + if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer | itInfo)) add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode); else add_to_selection(item, selection, instance_idx, mode); @@ -3442,6 +3509,9 @@ void ObjectList::update_object_list_by_printer_technology() m_objects_model->GetChildren(wxDataViewItem(nullptr), object_items); for (auto& object_item : object_items) { + // update custom supports info + update_info_items(m_objects_model->GetObjectIdByItem(object_item)); + // Update Settings Item for object update_settings_item_and_selection(object_item, sel); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index d70c53849d..5812e26f75 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -18,7 +18,6 @@ class wxBoxSizer; class wxBitmapComboBox; class wxMenuItem; -class ObjectDataViewModel; class MenuWithSeparators; namespace Slic3r { @@ -347,6 +346,7 @@ public: void update_and_show_object_settings_item(); void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections); void update_object_list_by_printer_technology(); + void update_info_items(size_t obj_idx); void instances_to_separated_object(const int obj_idx, const std::set& inst_idx); void instances_to_separated_objects(const int obj_idx); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index f3f87cc33e..d870687129 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -7,6 +7,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_ObjectList.hpp" #include @@ -316,8 +317,12 @@ void GLGizmoFdmSupports::update_model_object() const updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get()); } - if (updated) + if (updated) { + const ModelObjectPtrs& mos = wxGetApp().model().objects; + wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 6c3a8ddd3a..9724767550 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -7,7 +7,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/Plater.hpp" - +#include "slic3r/GUI/GUI_ObjectList.hpp" #include @@ -222,8 +222,12 @@ void GLGizmoSeam::update_model_object() const updated |= mv->seam_facets.set(*m_triangle_selectors[idx].get()); } - if (updated) + if (updated) { + const ModelObjectPtrs& mos = wxGetApp().model().objects; + wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 9dc785b3fa..2f1396d634 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -163,6 +163,17 @@ void GLGizmosManager::reset_all_states() m_hover = Undefined; } +bool GLGizmosManager::open_gizmo(EType type) +{ + int idx = int(type); + if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) { + activate_gizmo(m_current == idx ? Undefined : (EType)idx); + update_data(); + return true; + } + return false; +} + void GLGizmosManager::set_hover_id(int id) { if (!m_enabled || m_current == Undefined) @@ -266,24 +277,21 @@ bool GLGizmosManager::is_running() const bool GLGizmosManager::handle_shortcut(int key) { - if (!m_enabled) + if (!m_enabled || m_parent.get_selection().is_empty()) return false; - if (m_parent.get_selection().is_empty()) + auto it = std::find_if(m_gizmos.begin(), m_gizmos.end(), + [key](const std::unique_ptr& gizmo) { + int gizmo_key = gizmo->get_shortcut_key(); + return gizmo->is_selectable() + && ((gizmo_key == key - 64) || (gizmo_key == key - 96)); + }); + + if (it == m_gizmos.end()) return false; - bool handled = false; - - for (size_t idx : get_selectable_idxs()) { - int it_key = m_gizmos[idx]->get_shortcut_key(); - - if (m_gizmos[idx]->is_activable() && ((it_key == key - 64) || (it_key == key - 96))) { - activate_gizmo(m_current == idx ? Undefined : (EType)idx); - handled = true; - } - } - - return handled; + EType gizmo_type = EType(it - m_gizmos.begin()); + return open_gizmo(gizmo_type); } bool GLGizmosManager::is_dragging() const @@ -814,10 +822,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) if (!processed && !evt.HasModifiers()) { if (handle_shortcut(keyCode)) - { - update_data(); processed = true; - } } if (processed) @@ -1156,5 +1161,11 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const return true; } + +int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const +{ + return m_gizmos[type]->get_shortcut_key(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 917a5830c2..c8951966e6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -171,6 +171,7 @@ public: void refresh_on_off_state(); void reset_all_states(); bool is_serializing() const { return m_serializing; } + bool open_gizmo(EType type); void set_hover_id(int id); void enable_grabber(EType type, unsigned int id, bool enable); @@ -228,6 +229,7 @@ public: void update_after_undo_redo(const UndoRedo::Snapshot& snapshot); int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); } + int get_shortcut_key(GLGizmosManager::EType) const; private: void render_background(float left, float top, float right, float bottom, float border) const; diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index cf7b7b4796..49c75f9f2f 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -47,6 +47,19 @@ void ObjectDataViewModelNode::init_container() static constexpr char LayerRootIcon[] = "edit_layers_all"; static constexpr char LayerIcon[] = "edit_layers_some"; static constexpr char WarningIcon[] = "exclamation"; +static constexpr char InfoIcon[] = "info"; + +ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType info_type) : + m_parent(parent), + m_type(itInfo), + m_extruder(wxEmptyString) +{ + m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") + : info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") + : _L("Variable layer height"); + m_info_item_type = info_type; +} + ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) : m_parent(parent), @@ -69,6 +82,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_bmp = create_scaled_bitmap(LayerRootIcon); // FIXME: pass window ptr m_name = _(L("Layers")); } + else if (type == itInfo) + assert(false); if (type & (itInstanceRoot | itLayerRoot)) init_container(); @@ -250,6 +265,7 @@ ObjectDataViewModel::ObjectDataViewModel() m_volume_bmps = MenuFactory::get_volume_bitmaps(); m_warning_bmp = create_scaled_bitmap(WarningIcon); + m_info_bmp = create_scaled_bitmap(InfoIcon); } ObjectDataViewModel::~ObjectDataViewModel() @@ -330,12 +346,37 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent return child; } +wxDataViewItem ObjectDataViewModel::AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type) +{ + ObjectDataViewModelNode *root = static_cast(parent_item.GetID()); + if (!root) return wxDataViewItem(0); + + const auto node = new ObjectDataViewModelNode(root, info_type); + + // The new item should be added according to its order in InfoItemType. + // Find last info item with lower index and append after it. + const auto& children = root->GetChildren(); + int idx = -1; + for (int i=0; iGetType() == itInfo && int(children[i]->GetInfoItemType()) < int(info_type) ) + idx = i; + } + + root->Insert(node, idx+1); + node->SetBitmap(m_info_bmp); + // notify control + const wxDataViewItem child((void*)node); + ItemAdded(parent_item, child); + return child; +} + wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item) { ObjectDataViewModelNode *root = static_cast(parent_item.GetID()); if (!root) return wxDataViewItem(0); const auto node = new ObjectDataViewModelNode(root, itSettings); + root->Insert(node, 0); // notify control const wxDataViewItem child((void*)node); @@ -1379,6 +1420,14 @@ ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const return node->m_type < 0 ? itUndef : node->m_type; } +InfoItemType ObjectDataViewModel::GetInfoItemType(const wxDataViewItem &item) const +{ + if (!item.IsOk()) + return InfoItemType::Undef; + ObjectDataViewModelNode *node = static_cast(item.GetID()); + return node->m_info_item_type; +} + wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const { if (!parent_item.IsOk()) @@ -1411,6 +1460,21 @@ wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) return GetItemByType(item, itLayerRoot); } +wxDataViewItem ObjectDataViewModel::GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const +{ + if (! parent_item.IsOk()) + return wxDataViewItem(0); + + ObjectDataViewModelNode *node = static_cast(parent_item.GetID()); + for (size_t i = 0; i < node->GetChildCount(); i++) { + const ObjectDataViewModelNode* child_node = node->GetNthChild(i); + if (child_node->m_type == itInfo && child_node->m_info_item_type == type) + return wxDataViewItem((void*)child_node); + } + + return wxDataViewItem(0); // not found +} + bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const { if (!item.IsOk()) diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index c23ec195bd..1dd41bb107 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -27,6 +27,7 @@ enum ItemType { itSettings = 16, itLayerRoot = 32, itLayer = 64, + itInfo = 128 }; enum ColumnNumber @@ -44,6 +45,14 @@ enum PrintIndicator piUnprintable , // unprintable }; +enum class InfoItemType +{ + Undef, + CustomSupports, + CustomSeam, + VariableLayerHeight +}; + class ObjectDataViewModelNode; WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); @@ -69,6 +78,7 @@ class ObjectDataViewModelNode std::string m_action_icon_name = ""; ModelVolumeType m_volume_type; + InfoItemType m_info_item_type {InfoItemType::Undef}; public: ObjectDataViewModelNode(const wxString& name, @@ -104,6 +114,7 @@ public: const wxString& extruder = wxEmptyString ); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type); + ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType type); ~ObjectDataViewModelNode() { @@ -176,6 +187,7 @@ public: const wxBitmap& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } + InfoItemType GetInfoItemType() const { return m_info_item_type; } void SetIdx(const int& idx); int GetIdx() const { return m_idx; } ModelVolumeType GetVolumeType() { return m_volume_type; } @@ -244,6 +256,7 @@ class ObjectDataViewModel :public wxDataViewModel std::vector m_objects; std::vector m_volume_bmps; wxBitmap m_warning_bmp; + wxBitmap m_info_bmp; wxDataViewCtrl* m_ctrl { nullptr }; @@ -261,6 +274,7 @@ public: const int extruder = 0, const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); + wxDataViewItem AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector& print_indicator); wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); @@ -335,12 +349,15 @@ public: // In our case it is an item with all columns bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } - ItemType GetItemType(const wxDataViewItem &item) const ; + ItemType GetItemType(const wxDataViewItem &item) const; + InfoItemType GetInfoItemType(const wxDataViewItem &item) const; wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const; + wxDataViewItem GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const; + bool IsSettingsItem(const wxDataViewItem &item) const; void UpdateSettingsDigest( const wxDataViewItem &item, const std::vector& categories); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 50adb89e41..5db983f43a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4967,6 +4967,12 @@ void Plater::convert_unit(ConversionType conv_type) } } +void Plater::toggle_layers_editing(bool enable) +{ + if (canvas3D()->is_layers_editing_enabled() != enable) + wxPostEvent(canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); +} + void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower) { wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 16590ed9b1..e99feee82f 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -191,6 +191,7 @@ public: bool is_selection_empty() const; void scale_selection_to_fit_print_volume(); void convert_unit(ConversionType conv_type); + void toggle_layers_editing(bool enable); void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);