Design tab: M6 variables panel + per-feature expression bindings

M6 landed the kernel side as two plain public maps — CadDocument::variables and
CadFeature::expr — reachable only through MCP's set_variable / set_feature_expr.
Nothing in the GUI could create a variable, so the parametric layer was
unreachable from the Design tab.

Variables get a wxListCtrl (name, expression) with add/edit/remove below the
feature tree, since they are document-scope and must not live in a card that
only exists while a tool is open. Expression bindings get one generic row in the
feature-edit path — a field-name combo plus an expression box — rather than an
extra control on each of 32 cards.

Every mutation copies McpControl's sequence exactly, and the rollback is the
part that matters: checkpoint, mutate, recompute, undo() on failure. Without it
one typo leaves the recipe permanently unrecomputable, since load() replays the
whole list. Removing a variable a feature still references fails that recompute,
so it reports the reference rather than a bare evaluation error.

The field-name combo is deliberately editable: only 11 feature types get a
curated field list, and free text is what makes the other 21 reachable. That is
safe because assign_field() throws "unknown parameter: <name>" for anything it
does not know, inside recompute()'s try block — so a wrong name gives a clear
message and a rollback, never a silently dead binding.

Two fixes on top of the generated wiring:
- make_combo() passes wxCB_READONLY, under which Orca's ComboBox HIDES its text
  ctrl (ComboBox.cpp:51). There is no SetEditable() to undo that, so the field
  combo is constructed directly with style 0; that shows the ctrl with
  wxTE_PROCESS_ENTER and makes GetValue() return typed text.
- the field-list helper had been made a file-static function taking
  DesignPanel::Tool, which required moving Tool out of private and into the
  public API. It is now a private static member instead: 32 values of internal
  card state should not be published to satisfy a signature.

Compiles clean (0 errors); kernel suite unchanged at 139 cases / 1960
assertions. Phase B is complete on this fork — all 16 previously GUI-less tools
plus the variables panel. Not yet exercised on a display.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tommaso Bianchi
2026-07-25 15:14:32 +02:00
co-authored by Claude Opus 5
parent cf97b7aba8
commit 6372b3b505
2 changed files with 359 additions and 1 deletions
+26
View File
@@ -52,6 +52,10 @@ public:
private:
enum class Tool { None, Sketch, Extrude, Dressup, Hole, Thread, Shell, Revolve, Sweep, Pattern, Plane, Loft, Draft, Boolean, Cut, Insert, Axis, CoordSys, SurfaceExtrude, SurfaceRevolve, SurfaceLoft, SurfaceFill, SurfaceOffset, ThickenSurface, Transform, Mirror, Thicken, Rib, Project, DeleteFace, Helix, Mate };
// Which numeric fields an expression can be bound to, per feature type. A member rather
// than a file-static helper so Tool — 32 values of purely internal card state — does not
// have to become part of this panel's public API just to be named in a signature.
static std::vector<std::string> fields_for_tool(Tool t);
// Plane tool: which datum reference the next solid pick fills (declared early so the
// method decls + card lambdas below can name it).
enum class PlanePick { None, FaceA, FaceB, EdgeA, EdgeB };
@@ -284,6 +288,7 @@ private:
wxSizer* m_box_helix{nullptr};
wxSizer* m_box_mate{nullptr};
wxSizer* m_box_insert{nullptr}; // Confirm/Cancel card for placing Text/SVG art
wxSizer* m_box_expr{nullptr}; // expression binding card (visible during edit only)
int m_insert_feat{-1}; // provisional imported-art feature awaiting Confirm
// Move-body gizmo runs through the unified action bar too: Confirm keeps the placement,
// Cancel reverts to the pose captured when the move started.
@@ -492,6 +497,27 @@ private:
wxStaticText* m_offset_label{nullptr};
wxStaticText* m_angle_label{nullptr};
// Expression binding (per-feature, visible during edit only)
ComboBox* m_expr_field{nullptr}; // field-name picker (editable)
wxTextCtrl* m_expr_text{nullptr}; // expression string
wxButton* m_expr_set_btn{nullptr}; // Apply / bind
wxButton* m_expr_clear_btn{nullptr}; // Remove binding
wxStaticText* m_expr_status{nullptr}; // shows current bindings for the edited feature
void populate_expr_fields(Tool t); // fill m_expr_field from feature-type fields
void on_set_expr(); // checkpoint + write -> recompute -> undo on fail
void on_clear_expr(); // remove selected binding
// Document variables panel (below the feature tree / parts)
StaticBox* m_var_box{nullptr};
wxListCtrl* m_var_list{nullptr};
wxButton* m_btn_add_var{nullptr};
wxButton* m_btn_edit_var{nullptr};
wxButton* m_btn_del_var{nullptr};
void refresh_variables(); // rebuild m_var_list from m_doc.variables
void on_add_variable();
void on_edit_variable();
void on_remove_variable();
// Feature-tree button
ScalableButton* m_btn_interfere{nullptr};