Add Feature to disable snapping to buildplate (#11801)

* identified code for snapping to buidlplate

* rename internal name to ensure_on_bed to be consistent, saves option in 2mf, finish Move UI, use in both ensure_on_bed() functions

* makes auto_drop a per-object setting, removes global setting

* remove adUndef, add auto_drop to constructor/serialize

* fixes drop() button

* add "auto_drop" checkmark to "load as single object" dialog,
nothing changes if auto_drop == yes || "load as single object",
if auto_drop == false and "load as single object" == false the objects now retain their relative position to each other

* retains auto_drop (and printable) state when assembling or splitting objects,
adds ObjectList::printable_state_changed()  overload to be able to only provide ModelObject* vector

* adds dialog when splitting to ask if auto_drop should be disabled,
only shows when auto_drop enabled and atleast one volume  floating

* adds arrow indicator on bounding box if auto_drop == false

* removes unneeded code, keeps "auto_drop" naming consistent

* makes for loop simpler in set_printable, set_auto_drop and get_auto_drop,
makes get_auto_drop const,
fixes wording in Snapshot text

---------

Co-authored-by: Hanno Witzleb <hannowitzleb@gmail.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
This commit is contained in:
Hanno Witzleb
2026-04-15 16:36:25 +02:00
committed by GitHub
parent f02aa7200e
commit f7ef8a14bd
15 changed files with 583 additions and 213 deletions

View File

@@ -914,15 +914,15 @@ void ObjectList::object_config_options_changed(const ObjectVolumeID& ov_id)
}
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
void ObjectList::printable_state_changed(const std::vector<ModelObject*> model_objects)
{
std::vector<size_t> obj_idxs;
for (const ObjectVolumeID ov_id : ov_ids) {
if (ov_id.object == nullptr)
for (const ModelObject* mo : model_objects) {
if (mo == nullptr)
continue;
ModelInstance* mi = ov_id.object->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(ov_id.object);
ModelInstance* mi = mo->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(mo);
m_objects_model->SetObjectPrintableState(mi->printable ? piPrintable : piUnprintable, obj_item);
int obj_idx = m_objects_model->GetObjectIdByItem(obj_item);
@@ -939,6 +939,19 @@ void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_i
wxGetApp().plater()->update();
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
{
std::vector<ModelObject*> model_objects;
model_objects.reserve(ov_ids.size());
for (const ObjectVolumeID& ov_id : ov_ids) {
if (ov_id.object != nullptr)
model_objects.emplace_back(ov_id.object);
}
printable_state_changed(model_objects);
}
void ObjectList::assembly_plate_object_name()
{
m_objects_model->assembly_name();
@@ -1748,6 +1761,8 @@ void ObjectList::key_event(wxKeyEvent& event)
decrease_instances();
else if (event.GetUnicodeKey() == 'p')
toggle_printable_state();
else if (event.GetUnicodeKey() == 'd')
toggle_auto_drop();
else if (filaments_count() > 1) {
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
wxChar key_char = event.GetUnicodeKey();
@@ -3044,6 +3059,17 @@ void ObjectList::merge(bool to_multipart_object)
volume->config.set_key_value("extruder", option->clone());
}
// merge printable and auto_drop values
// non-default have priority -> if one object has printable == false,
// then merged object will also have printable == false
if (object->instances[0]->printable == false) {
new_object->printable = false;
new_object->instances[0]->printable = false;
}
if (object->instances[0]->auto_drop == false) {
new_object->instances[0]->auto_drop = false;
}
// merge layers
for (const auto& range : object->layer_config_ranges)
new_object->layer_config_ranges.emplace(range);
@@ -3077,6 +3103,9 @@ void ObjectList::merge(bool to_multipart_object)
// Add new object(merged) to the object_list
add_object_to_list(m_objects->size() - 1);
if (new_object->printable == false) {
wxGetApp().obj_list()->printable_state_changed({new_object});
}
select_item(m_objects_model->GetItemById(m_objects->size() - 1));
update_selections_on_canvas();
}
@@ -6600,6 +6629,52 @@ void ObjectList::toggle_printable_state()
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::toggle_auto_drop()
{
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.IsEmpty())
return;
for (auto item : sels) {
ItemType type = m_objects_model->GetItemType(item);
if (!(type & (itObject | itInstance)))
return;
}
const bool current_auto_drop = wxGetApp().plater()->get_selection().get_auto_drop();
take_snapshot("");
std::vector<size_t> obj_idxs;
for (auto item : sels) {
int obj_idx = m_objects_model->GetObjectIdByItem(item);
ModelObject* obj = object(obj_idx);
obj_idxs.emplace_back(static_cast<size_t>(obj_idx));
ItemType type = m_objects_model->GetItemType(item);
// set auto_drop value for selected instance/instances in object
if (type == itInstance) {
int inst_idx = m_objects_model->GetInstanceIdByItem(item);
obj->instances[inst_idx]->auto_drop = !current_auto_drop;
} else {
for (auto inst : obj->instances)
inst->auto_drop = !current_auto_drop;
if (current_auto_drop == false)
obj->ensure_on_bed();
}
}
sort(obj_idxs.begin(), obj_idxs.end());
obj_idxs.erase(unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
// update scene
wxGetApp().plater()->update();
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::enable_layers_editing()
{
wxDataViewItemArray sels;