mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-19 15:03:05 +00:00
Design: a body knows what made it, so "Delete Body" can exist
Reported by Tommaso: select a body, and there is no Delete in the offer. Two independent faults stacked behind that. FIRST, clicking a body never selects the body. Whole-body picking is deliberately unbound (DesignSketchTool.cpp) pending the rubber band, so a viewport click only ever yields Face/Edge/Vertex. The offer therefore saw face_planar, and "delete" accepted body_solid but no face kind, so the row was filtered out entirely — while the status line read "Body 1 face 0 selected", which actively teaches the wrong model. SECOND, even selecting the body from the Bodies list, Delete refused in red: "Select the FEATURE that created this body". CadBody had no link back to its maker, so the offer was advertising a verb it could not perform — worse than the action:null rows fixed earlier this session, because this one is ENABLED and its refusal reads like user error. CadBody::source_feature fixes the second. It is stamped in ONE place, the recompute loop, and the rule is just "still unset?". That is sufficient because of an invariant worth stating: no feature ever replaces a whole CadBody. Every in-place op writes only .shape (boolean, cut, mirror-fuse, transform, dress-up — all 8 sites checked), so a body keeps the stamp it was born with; a consumed body is erased outright, taking its stamp with it; and the only bodies still at -1 are the ones the current feature just pushed. A feature type added later needs no change here as long as it keeps to that invariant. "Delete Body" fixes the first, sitting beside "Delete Face" in Modify and reachable by pointing at any face/edge/vertex. The two names cannot be confused, and "delete" gave up the body kinds so both can never appear for one selection. Deleting a body removes the feature that made it, which is a real edit to the recipe, so it asks first and NAMES the feature — a body vanishing from the viewport is not evidence of which feature went, and this is the one action here that cannot be eyeballed. Multi-body delete is NOT offered. bodies_2 was in the first draft of the verb; the handler deletes exactly one body, so a two-body selection would have silently deleted whichever was m_sel_solid_body. Caught before it reached a binary, at the cost of one rebuild. Verified on BOTH rigs, full round trip: click a face -> Modify > Delete Body -> "Delete Extrude2?" -> body gone, Sketch1 correctly left behind, panel falls back to the idle hint -> Undo -> Extrude2 and Body 1 restored.
This commit is contained in:
@@ -938,6 +938,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
fadd("color", b_color);
|
||||
m_verb_actions["btn:colour"] = [this] { on_set_body_color(); };
|
||||
m_verb_actions["btn:delete"] = [this] { on_delete_feature(); };
|
||||
m_verb_actions["btn:delete_body"] = [this] { on_delete_body(); };
|
||||
m_verb_actions["btn:edit"] = [this] { on_edit_feature(); };
|
||||
m_verb_actions["btn:mass"] = [this] { on_mass_properties(); };
|
||||
|
||||
@@ -6059,6 +6060,49 @@ void DesignPanel::on_new_design()
|
||||
set_status_ok();
|
||||
}
|
||||
|
||||
// The verb the offer names when you point at a body, or at any face/edge/vertex of one. A body
|
||||
// is a recomputed RESULT, so what actually gets deleted is the feature that created it
|
||||
// (CadBody::source_feature). That is an edit to the recipe and can take other features with it,
|
||||
// so it asks first and NAMES the feature: a body disappearing from the viewport is not by itself
|
||||
// evidence of which feature went, and this is the one action here that cannot be eyeballed.
|
||||
void DesignPanel::on_delete_body()
|
||||
{
|
||||
const int nb = int(m_doc.bodies.size());
|
||||
if (m_sel_solid_body < 0 || m_sel_solid_body >= nb) {
|
||||
m_status->SetForegroundColour(wxColour(235, 110, 110));
|
||||
set_status(_L("Select a body first"));
|
||||
m_status->Refresh();
|
||||
return;
|
||||
}
|
||||
const int src = m_doc.bodies[m_sel_solid_body].source_feature;
|
||||
if (src < 0 || src >= int(m_doc.features.size())) {
|
||||
// Only reachable for a body no feature claims — a stale recipe, or a feature type that
|
||||
// broke the "never replace a whole CadBody" invariant recompute() relies on.
|
||||
m_status->SetForegroundColour(wxColour(235, 110, 110));
|
||||
set_status(_L("This body has no feature to delete — use New Design to start over"));
|
||||
m_status->Refresh();
|
||||
return;
|
||||
}
|
||||
const std::string& raw = m_doc.features[src].name;
|
||||
const wxString fname = raw.empty() ? wxString::Format(_L("feature %d"), src + 1)
|
||||
: wxString::FromUTF8(raw);
|
||||
if (wxMessageBox(wxString::Format(
|
||||
_L("Delete %s?\n\nThat is the feature this body was made from. "
|
||||
"Features built on it may be removed or stop working."), fname),
|
||||
_L("Delete body"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION, this) != wxYES)
|
||||
return;
|
||||
// A card left open over a feature that is about to vanish goes stale — same reason
|
||||
// on_delete_feature() closes it.
|
||||
if (m_active != Tool::None || m_edit_index >= 0) {
|
||||
reset_edit_state();
|
||||
close_tool();
|
||||
}
|
||||
m_doc.checkpoint(); // undo boundary: deleting a body's feature
|
||||
m_sel_solid_body = m_sel_solid_face = m_sel_solid_edge = -1; // the selection is about to
|
||||
m_sel_solid_vertex = false; // name a body that is gone
|
||||
after_tree_edit(m_doc.remove_feature(src));
|
||||
}
|
||||
|
||||
void DesignPanel::on_delete_feature()
|
||||
{
|
||||
// A Body row has no directly-removable feature (bodies are recomputed results); guide the
|
||||
|
||||
Reference in New Issue
Block a user