From 85af9b93f1e886ea0f80d890d97ac967da772cb9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 7 Oct 2022 16:26:19 +0200 Subject: [PATCH] Cut: Fixes and improvements for object's context menu * Disable or delete some menu items, which are inappropriate for cut objects * For cut objects added menu item "Invalidate cut info" to disconnect related cut parts of initial object * If just one part is kept after cut performance, than don't apply a cut info for this object. + CutGizmo: Fixed selection of the mode An object has connectors -> Connectors mode An object doesn't has connectors -> CutPlane mode --- src/libslic3r/Model.cpp | 8 +++++- src/libslic3r/ObjectID.hpp | 2 +- src/slic3r/GUI/GUI_Factories.cpp | 22 +++++++++++++++++ src/slic3r/GUI/GUI_Factories.hpp | 1 + src/slic3r/GUI/GUI_ObjectList.cpp | 34 +++++++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectList.hpp | 2 ++ src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 13 +++++----- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 2 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 1 + src/slic3r/GUI/Plater.cpp | 18 +++++++------- 10 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 270ccb1bea..597152c06a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1261,7 +1261,9 @@ void ModelObject::invalidate_cut() { for (ModelObject* obj : m_model->objects) if (obj != this && obj->cut_id.is_equal(this->cut_id)) - obj->cut_id.ivalidate(); + obj->cut_id.invalidate(); + // invalidate own cut_id + this->cut_id.invalidate(); } void ModelObject::synchronize_model_after_cut() @@ -1276,6 +1278,10 @@ void ModelObject::synchronize_model_after_cut() void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) { + // we don't save cut information, if result will not contains all parts of initial object + if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower)) + return; + if (cut_id.id().invalid()) cut_id.init(); { diff --git a/src/libslic3r/ObjectID.hpp b/src/libslic3r/ObjectID.hpp index 452f620c47..f907b03e1e 100644 --- a/src/libslic3r/ObjectID.hpp +++ b/src/libslic3r/ObjectID.hpp @@ -161,7 +161,7 @@ public: return *this; } - void ivalidate() { + void invalidate() { set_invalid_id(); m_check_sum = 1; m_connectors_cnt = 0; diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 3cfc55adc8..5164c691e2 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -685,6 +685,24 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu) return menu_item_printable; } +void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu) +{ + const wxString menu_name = _L("Invalidate cut info"); + + bool is_cut = obj_list()->has_selected_cut_object(); + + auto menu_item_id = menu->FindItem(menu_name); + if (menu_item_id != wxNOT_FOUND) { + // Delete old menu item if selected object isn't cut + if (!is_cut) + menu->Destroy(menu_item_id); + } + else if (is_cut) + append_menu_item(menu, wxID_ANY, menu_name, "", + [](wxCommandEvent&) { obj_list()->invalidate_cut_info_for_selection(); }, "", menu, + []() { return true; }, m_parent); +} + void MenuFactory::append_menu_items_osx(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Rename"), "", @@ -821,6 +839,8 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/* ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject* object = obj_list()->object(obj_idx); + if (object->is_cut()) + return false; if (vol_idxs.empty()) { for (ModelVolume* volume : object->volumes) if (volume_respects_conversion(volume, conver_type)) @@ -1021,6 +1041,7 @@ wxMenu* MenuFactory::object_menu() append_menu_item_settings(&m_object_menu); append_menu_item_change_extruder(&m_object_menu); update_menu_items_instance_manipulation(mtObjectFFF); + append_menu_item_invalidate_cut_info(&m_object_menu); return &m_object_menu; } @@ -1030,6 +1051,7 @@ wxMenu* MenuFactory::sla_object_menu() append_menu_items_convert_unit(&m_sla_object_menu, 11); append_menu_item_settings(&m_sla_object_menu); update_menu_items_instance_manipulation(mtObjectSLA); + append_menu_item_invalidate_cut_info(&m_sla_object_menu); return &m_sla_object_menu; } diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index bbbc00d42b..7190edb64c 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -89,6 +89,7 @@ private: wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu); wxMenuItem* append_menu_item_printable(wxMenu* menu); + void append_menu_item_invalidate_cut_info(wxMenu *menu); void append_menu_items_osx(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); wxMenuItem* append_menu_item_simplify(wxMenu* menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d3f1d1bf27..cced147f8e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2443,9 +2443,41 @@ bool ObjectList::can_split_instances() return selection.is_multiple_full_instance() || selection.is_single_full_instance(); } +bool ObjectList::has_selected_cut_object() const +{ + wxDataViewItemArray sels; + GetSelections(sels); + if (sels.IsEmpty()) + return false; + + for (wxDataViewItem item : sels) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0 && object(obj_idx)->is_cut()) + return true; + } + + return false; +} + +void ObjectList::invalidate_cut_info_for_selection() +{ + wxDataViewItemArray sels; + GetSelections(sels); + if (sels.IsEmpty()) + return; + + for (wxDataViewItem item : sels) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0 && object(obj_idx)->is_cut()) + object(obj_idx)->invalidate_cut(); + } + + update_lock_icons_for_model(); +} + bool ObjectList::can_merge_to_multipart_object() const { - if (printer_technology() == ptSLA) + if (printer_technology() == ptSLA || has_selected_cut_object()) return false; wxDataViewItemArray sels; diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index cb498f87ef..3dd02ab8dc 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -277,6 +277,8 @@ public: bool is_splittable(bool to_objects); bool selected_instances_of_same_object(); bool can_split_instances(); + bool has_selected_cut_object() const; + void invalidate_cut_info_for_selection(); bool can_merge_to_multipart_object() const; bool can_merge_to_single_object() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index c90211d427..d751325424 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1226,6 +1226,7 @@ bool GLGizmoCut3D::update_bb() if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) { clear_selection(); m_selected.resize(selection->model_object()->cut_connectors.size(), false); + m_connectors_editing = !m_selected.empty(); } return true; @@ -1333,12 +1334,12 @@ void GLGizmoCut3D::adjust_window_position(float x, float y, float bottom_limit) ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - if (last_h != win_h || last_y != y) { + if (!is_approx(last_h, win_h) || !is_approx(last_y, y)) { // ask canvas for another frame to render the window in the correct position m_imgui->set_requires_extra_frame(); - if (last_h != win_h) + if (!is_approx(last_h, win_h)) last_h = win_h; - if (last_y != y) + if (!is_approx(last_y, y)) last_y = y; } } @@ -1773,9 +1774,9 @@ bool GLGizmoCut3D::can_perform_cut() const return tbb.contains(m_plane_center); } -void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, const bool has_connectors, bool &create_dowels_as_separate_object) +void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object) { - if (has_connectors && m_connector_mode == CutConnectorMode::Manual) { + if (m_connector_mode == CutConnectorMode::Manual) { clear_selection(); for (CutConnector&connector : mo->cut_connectors) { @@ -1824,7 +1825,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane")); // update connectors pos as offset of its center before cut performing - apply_connectors_in_model(mo, has_connectors, create_dowels_as_separate_object); + apply_connectors_in_model(mo, create_dowels_as_separate_object); } plater->cut(object_idx, instance_idx, assemble_transform(cut_center_offset) * m_rotation_m, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index c3916e4a8f..21d7c64f8a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -225,7 +225,7 @@ private: void render_connectors(); bool can_perform_cut() const; - void apply_connectors_in_model(ModelObject* mo, const bool has_connectors, bool &create_dowels_as_separate_object); + void apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object); bool cut_line_processing() const; void discard_cut_line_processing(); diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 0475fe395b..e2fca5faed 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -1807,6 +1807,7 @@ void ObjectDataViewModel::UpdateLockIcon(const wxDataViewItem& item, bool has_lo for (const wxDataViewItem& child : children) UpdateLockIcon(child, has_lock); } + ItemChanged(item); } } // namespace GUI diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 12a654175b..7c7fbc9898 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4786,7 +4786,8 @@ bool Plater::priv::can_split(bool to_objects) const bool Plater::priv::can_scale_to_print_volume() const { const BuildVolume::Type type = this->bed.build_volume().type(); - return !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle); + return !sidebar->obj_list()->has_selected_cut_object() && + !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle); } bool Plater::priv::layers_height_allowed() const @@ -4801,16 +4802,19 @@ bool Plater::priv::layers_height_allowed() const bool Plater::priv::can_mirror() const { - return get_selection().is_from_single_instance(); + return !sidebar->obj_list()->has_selected_cut_object() && get_selection().is_from_single_instance(); } bool Plater::priv::can_replace_with_stl() const { - return get_selection().get_volume_idxs().size() == 1; + return !sidebar->obj_list()->has_selected_cut_object() && get_selection().get_volume_idxs().size() == 1; } bool Plater::priv::can_reload_from_disk() const { + if (sidebar->obj_list()->has_selected_cut_object()) + return false; + #if ENABLE_RELOAD_FROM_DISK_REWORK // collect selected reloadable ModelVolumes std::vector> selected_volumes = reloadable_volumes(model, get_selection()); @@ -4939,9 +4943,7 @@ bool Plater::priv::can_increase_instances() const || q->canvas3D()->get_gizmos_manager().is_in_editing_mode()) return false; - int obj_idx = get_selected_object_idx(); - return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) - && !model.objects[obj_idx]->is_cut(); + return !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_decrease_instances() const @@ -4950,9 +4952,7 @@ bool Plater::priv::can_decrease_instances() const || q->canvas3D()->get_gizmos_manager().is_in_editing_mode()) return false; - int obj_idx = get_selected_object_idx(); - return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1) - && !model.objects[obj_idx]->is_cut(); + return !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_split_to_objects() const