Design: re-editable Boolean features

Boolean features can now be re-edited from the feature tree (op, target/tool
body, keep-tool, fuzzy tolerance), funnelling through the same replace_feature
path as every other editable feature.

- on_edit_feature: route CadFeatureType::Boolean to the Boolean card.
- load_feature_into_dialog: populate the Boolean card from the saved feature.
- populate_body_choices(as_of_feature): when re-editing, list the bodies as they
  existed just before the boolean (replay the recipe truncated to that slot) so a
  consumed tool body still appears and the saved target/tool selections round-trip
  instead of collapsing to one entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
This commit is contained in:
Tommaso Bianchi
2026-06-30 07:56:30 +02:00
co-authored by Claude Opus 4.8
parent 71b7a73e86
commit 30713f0f23
2 changed files with 37 additions and 5 deletions
+33 -4
View File
@@ -2649,13 +2649,24 @@ void DesignPanel::on_add_pattern()
refresh_tree();
}
void DesignPanel::populate_body_choices()
void DesignPanel::populate_body_choices(int as_of_feature)
{
// Re-editing a Boolean: list the bodies as they existed just before it ran, so a tool body
// it consumed still shows and the saved target/tool selections round-trip. Replay a copy of
// the recipe truncated to [0, as_of_feature). Fall back to the live bodies if the replay is
// degenerate (e.g. fewer than the saved refs need).
const std::vector<CadBody>* src = &m_doc.bodies;
std::vector<CadBody> as_of;
if (as_of_feature >= 0 && as_of_feature <= int(m_doc.features.size())) {
CadDocument tmp = m_doc;
tmp.features.resize(as_of_feature);
if (tmp.recompute() && !tmp.bodies.empty()) { as_of = tmp.bodies; src = &as_of; }
}
auto fill = [&](wxChoice* c, int def) {
if (!c) return;
c->Clear();
for (size_t i = 0; i < m_doc.bodies.size(); ++i) {
const std::string& n = m_doc.bodies[i].name;
for (size_t i = 0; i < src->size(); ++i) {
const std::string& n = (*src)[i].name;
c->Append(n.empty() ? wxString::Format(_L("Body %zu"), i + 1) : wxString::FromUTF8(n));
}
if (c->GetCount() > 0)
@@ -4624,6 +4635,19 @@ void DesignPanel::load_feature_into_dialog(const CadFeature& f)
? wxString::Format(_L("Face %d"), f.draft_face)
: _L("(pick a side face)"));
break;
case CadFeatureType::Boolean:
// List the bodies available to the boolean (as-of its timeline slot), so the consumed
// tool body still appears and the saved selections below land on the right entries.
populate_body_choices(m_edit_index);
m_bool_op->SetSelection(f.mode == BooleanMode::Cut ? 1
: f.mode == BooleanMode::Intersect ? 2 : 0); // 0 = Union/Add
if (f.target_body >= 0 && f.target_body < int(m_bool_target->GetCount()))
m_bool_target->SetSelection(f.target_body);
if (f.bool_tool_body >= 0 && f.bool_tool_body < int(m_bool_tool->GetCount()))
m_bool_tool->SetSelection(f.bool_tool_body);
m_bool_keep->SetValue(f.bool_keep_tool);
m_bool_tol->SetValue(f.bool_tolerance);
break;
default: break;
}
}
@@ -4727,8 +4751,13 @@ void DesignPanel::on_edit_feature()
load_feature_into_dialog(f);
open_tool(Tool::Draft);
break;
case CadFeatureType::Boolean:
m_edit_index = sel;
load_feature_into_dialog(f);
open_tool(Tool::Boolean);
break;
default:
// Import / Boolean / Cut have no parametric edit dialog yet (follow-up
// Import / Cut have no parametric edit dialog yet (follow-up
// snaporca-nu9). Don't silently swallow the Edit click — tell the user.
m_status->SetForegroundColour(wxNullColour);
m_status->SetLabel(_L("This feature type can't be edited yet"));
+4 -1
View File
@@ -74,7 +74,10 @@ private:
void on_add_draft();
void on_add_boolean();
void on_add_cut(); // commit a plane Cut (split-by-plane)
void populate_body_choices(); // fill m_bool_target / m_bool_tool / m_cut_target from m_doc.bodies
// Fill m_bool_target / m_bool_tool / m_cut_target. as_of_feature < 0 = current bodies (add);
// >= 0 = the bodies as they existed just before that feature index (Boolean re-edit, so a
// consumed tool body still appears and its saved selection round-trips).
void populate_body_choices(int as_of_feature = -1);
// Import rigid 2D art (Text / SVG) as a new Sketch feature carrying
// imported_regions (no solver entities). on_add_text/on_import_svg gather
// input; add_imported_sketch builds the feature, refreshes tree + display.