diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index cf532160d..869c3e67f 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -126,6 +126,9 @@ void AppConfig::set_defaults() if (get("color_mapinulation_panel").empty()) set("color_mapinulation_panel", "0"); + + if (get("order_volumes").empty()) + set("order_volumes", "1"); } else { #ifdef _WIN32 diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ce359e7bf..bc6cb4236 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -652,19 +652,34 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) return v; } -ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh) +static void add_v_to_volumes(ModelVolumePtrs* volumes, ModelVolume* v) { - ModelVolume* v = new ModelVolume(this, std::move(mesh)); - this->volumes.push_back(v); + if (volumes->empty() || v->type() >= volumes->back()->type()) + volumes->push_back(v); + else { + for (int pos = volumes->size() - 1; pos >= 0; pos--) + if (v->type() >= (*volumes)[pos]->type()) { + volumes->insert(volumes->begin() + pos + 1, v); + break; + } + } +} + +ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/) +{ + ModelVolume* v = new ModelVolume(this, std::move(mesh), type); + add_v_to_volumes(&(this->volumes), v); v->center_geometry_after_creation(); this->invalidate_bounding_box(); return v; } -ModelVolume* ModelObject::add_volume(const ModelVolume &other) +ModelVolume* ModelObject::add_volume(const ModelVolume &other, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/) { ModelVolume* v = new ModelVolume(this, other); - this->volumes.push_back(v); + if (v->type() != type) + v->set_type(type); + add_v_to_volumes(&(this->volumes), v); // The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull. // v->center_geometry_after_creation(); // this->invalidate_bounding_box(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ed8030c9b..69229860b 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -216,6 +216,16 @@ private: friend class ModelObject; }; +// Declared outside of ModelVolume, so it could be forward declared. +enum class ModelVolumeType : int { + INVALID = -1, + MODEL_PART = 0, + NEGATIVE_VOLUME, + PARAMETER_MODIFIER, + SUPPORT_BLOCKER, + SUPPORT_ENFORCER, +}; + // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials), // and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials. // Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed, @@ -262,8 +272,8 @@ public: const Model* get_model() const { return m_model; } ModelVolume* add_volume(const TriangleMesh &mesh); - ModelVolume* add_volume(TriangleMesh &&mesh); - ModelVolume* add_volume(const ModelVolume &volume); + ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); + ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::MODEL_PART); ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); void delete_volume(size_t idx); void clear_volumes(); @@ -482,16 +492,6 @@ private: } }; -// Declared outside of ModelVolume, so it could be forward declared. -enum class ModelVolumeType : int { - INVALID = -1, - MODEL_PART = 0, - NEGATIVE_VOLUME, - PARAMETER_MODIFIER, - SUPPORT_BLOCKER, - SUPPORT_ENFORCER, -}; - enum class EnforcerBlockerType : int8_t { // Maximum is 3. The value is serialized in TriangleSelector into 2 bits! NONE = 0, @@ -717,7 +717,7 @@ private: // 1 -> is splittable mutable int m_is_splittable{ -1 }; - ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object) + ModelVolume(ModelObject *object, const TriangleMesh &mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART) : m_mesh(new TriangleMesh(mesh)), m_type(type), object(object) { assert(this->id().valid()); assert(this->config.id().valid()); @@ -731,8 +731,8 @@ private: if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } - ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : - m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) { + ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull, ModelVolumeType type = ModelVolumeType::MODEL_PART) : + m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(type), object(object) { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->supported_facets.id().valid()); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index f0fda5fa8..6dab61c77 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -156,8 +156,8 @@ const std::vector> MenuFactory::ADD_VOLUME_M {L("Add part"), "add_part" }, // ~ModelVolumeType::MODEL_PART {L("Add negative volume"), "add_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME {L("Add modifier"), "add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER + {L("Add support blocker"), "support_blocker"}, // ~ModelVolumeType::SUPPORT_BLOCKER {L("Add support enforcer"), "support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER - {L("Add support blocker"), "support_blocker"} // ~ModelVolumeType::SUPPORT_BLOCKER }; static Plater* plater() diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 58f94a289..0b1245494 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1135,8 +1135,44 @@ bool ObjectList::can_drop(const wxDataViewItem& item) const return false; // move volumes inside one object only - if (m_dragged_data.type() & itVolume) - return m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item); + if (m_dragged_data.type() & itVolume) { + if (m_dragged_data.obj_idx() != m_objects_model->GetObjectIdByItem(item)) + return false; + wxDataViewItem dragged_item = m_objects_model->GetItemByVolumeId(m_dragged_data.obj_idx(), m_dragged_data.sub_obj_idx()); + if (!dragged_item) + return false; + ModelVolumeType item_v_type = m_objects_model->GetVolumeType(item); + ModelVolumeType dragged_item_v_type = m_objects_model->GetVolumeType(dragged_item); + + if (dragged_item_v_type == item_v_type && dragged_item_v_type != ModelVolumeType::MODEL_PART) + return true; + if (wxGetApp().app_config->get("order_volumes") == "1" || // we can't reorder volumes outside of types + item_v_type >= ModelVolumeType::SUPPORT_BLOCKER) // support blockers/enforcers can't change its place + return false; + + bool only_one_solid_part = true; + auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes; + for (size_t cnt, id = cnt = 0; id < volumes.size() && cnt < 2; id ++) + if (volumes[id]->type() == ModelVolumeType::MODEL_PART) { + if (++cnt > 1) + only_one_solid_part = false; + } + + if (dragged_item_v_type == ModelVolumeType::MODEL_PART) { + if (only_one_solid_part) + return false; + return (m_objects_model->GetVolumeIdByItem(item) == 0 || + (m_dragged_data.sub_obj_idx()==0 && volumes[1]->type() == ModelVolumeType::MODEL_PART) || + (m_dragged_data.sub_obj_idx()!=0 && volumes[0]->type() == ModelVolumeType::MODEL_PART)); + } + if ((dragged_item_v_type == ModelVolumeType::NEGATIVE_VOLUME || dragged_item_v_type == ModelVolumeType::PARAMETER_MODIFIER)) { + if (only_one_solid_part) + return false; + return m_objects_model->GetVolumeIdByItem(item) != 0; + } + + return false; + } return true; } @@ -1375,8 +1411,7 @@ void ObjectList::load_part( ModelObject* model_object, } for (auto volume : object->volumes) { volume->translate(delta); - auto new_volume = model_object->add_volume(*volume); - new_volume->set_type(type); + auto new_volume = model_object->add_volume(*volume, type); new_volume->name = boost::filesystem::path(input_file).filename().string(); volumes_info.push_back(std::make_pair(from_u8(new_volume->name), new_volume->get_mesh_errors_count()>0)); @@ -1446,8 +1481,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode TriangleMesh mesh = create_mesh(type_name, instance_bb); // Mesh will be centered when loading. - ModelVolume *new_volume = model_object.add_volume(std::move(mesh)); - new_volume->set_type(type); + ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type); if (instance_idx != -1) { diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 297d8e3c9..43e364084 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -329,7 +329,25 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent if (insert_position >= 0) insert_position++; } - const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt); + size_t new_volume_id = root->m_volumes_cnt; + + // find insert_position in respect to the volume type + for (int pos = (insert_position < 0 ? (int)root->GetChildCount() : insert_position) - 1; pos >= 0; pos--) { + ObjectDataViewModelNode* node = root->GetNthChild(pos); + if (volume_type >= node->m_volume_type) { + insert_position = pos + 1; + new_volume_id = (size_t)(node->GetIdx()) + 1; + for (int new_pos = pos + 1; new_pos < (int)root->GetChildCount(); new_pos++) { + ObjectDataViewModelNode* new_node = root->GetNthChild(new_pos); + if (new_node->GetType() != itVolume) + break; + new_node->SetIdx(new_node->GetIdx() + 1); + } + break; + } + } + + const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, new_volume_id); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // if part with errors is added, but object wasn't marked, then mark it diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 38a31bf76..e884db13a 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -312,6 +312,14 @@ void PreferencesDialog::build() option = Option(def, "color_mapinulation_panel"); m_optgroup_gui->append_single_option_line(option); + def.label = L("Order object volumes by types"); + def.type = coBool; + def.tooltip = L("If enabled, volumes will be always ordered inside the object. Correct order is Model Part, Negative Volume, Modifier, Support Blocker and Support Enforcer. " + "If disabled, you can reorder Model Parts, Negative Volumes and Modifiers. But one of the model parts have to be on the first place."); + def.set_default_value(new ConfigOptionBool{ app_config->get("order_volumes") == "1" }); + option = Option(def, "order_volumes"); + m_optgroup_gui->append_single_option_line(option); + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually.");