From 3c998b8a62360f950ef8c2b149e0ccdb4a7b5df3 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Sat, 1 Aug 2026 08:48:05 +0200 Subject: [PATCH] Design: a tool's options come from the tool, not from a card on the left MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror of snaporca 6d5510734b (DesignPanel.cpp applied as a patch; parity re-checked at 30 lines, shared files byte-identical). Polygon's Sides/Circumscribed card is deleted — the choice is made in Create > Polygon, which names the counts and the two fits, because the side count cannot be recovered after drawing. Dress-up, Combine and Pattern were single verbs hiding several behind a combo and now name each one in the offer. Fixes fillet and chamfer both carrying key:S+F, which made the offer's Chamfer open a Fillet. Built green and verified on the rig: the Dress-up card opened from Chamfer reads Chamfer. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LyRwbuq6fjn3VV9U9UvhBM --- docs/ux/tool_atlas.json | 221 +++++++++++++++++++++++++++++++-- src/slic3r/GUI/DesignOffer.hpp | 22 +++- src/slic3r/GUI/DesignPanel.cpp | 96 ++++++++------ src/slic3r/GUI/DesignPanel.hpp | 11 +- 4 files changed, 290 insertions(+), 60 deletions(-) diff --git a/docs/ux/tool_atlas.json b/docs/ux/tool_atlas.json index 95e407bb26..c52f45b04e 100644 --- a/docs/ux/tool_atlas.json +++ b/docs/ux/tool_atlas.json @@ -329,7 +329,7 @@ }, { "id": "boolean", - "name": "Combine", + "name": "Union", "slot": "add", "key": "Shift+B", "feature": "Boolean", @@ -342,7 +342,43 @@ }, "refusal": "Boolean needs two bodies — create or import a second solid", "gui": true, - "action": "key:S+B" + "action": "btn:bool#0" + }, + { + "id": "bool_subtract", + "name": "Subtract", + "slot": "add", + "key": null, + "feature": "Boolean", + "mcp": null, + "accepts": [ + "bodies_2" + ], + "needs": { + "bodies": 2 + }, + "refusal": "Boolean needs two bodies — create or import a second solid", + "gui": true, + "action": "btn:bool#1", + "mode": null + }, + { + "id": "bool_intersect", + "name": "Intersect", + "slot": "add", + "key": null, + "feature": "Boolean", + "mcp": null, + "accepts": [ + "bodies_2" + ], + "needs": { + "bodies": 2 + }, + "refusal": "Boolean needs two bodies — create or import a second solid", + "gui": true, + "action": "btn:bool#2", + "mode": null }, { "id": "surf_extrude", @@ -530,7 +566,7 @@ }, "refusal": "Pick an edge to round", "gui": true, - "action": "key:S+F" + "action": "btn:dress#0" }, { "id": "chamfer", @@ -550,7 +586,7 @@ }, "refusal": "Pick an edge to bevel", "gui": true, - "action": "key:S+F" + "action": "btn:dress#1" }, { "id": "draft", @@ -589,7 +625,7 @@ }, { "id": "pattern", - "name": "Pattern", + "name": "Linear pattern", "slot": "repeat", "key": "Shift+N", "feature": "Pattern", @@ -605,7 +641,28 @@ }, "refusal": "Create a solid body to pattern first", "gui": true, - "action": "key:S+N" + "action": "btn:pat#0" + }, + { + "id": "pattern_circular", + "name": "Circular pattern", + "slot": "repeat", + "key": null, + "feature": "Pattern", + "mcp": null, + "accepts": [ + "body_solid", + "face_planar", + "sk_loop", + "art" + ], + "needs": { + "bodies": 1 + }, + "refusal": "Create a solid body to pattern first", + "gui": true, + "action": "btn:pat#1", + "mode": null }, { "id": "mirror", @@ -1292,9 +1349,72 @@ "gui": true, "action": "key:B" }, + { + "id": "sk_poly_3", + "name": "Triangle", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:poly#3", + "mode": "sketch", + "family": "Polygon" + }, + { + "id": "sk_poly_4", + "name": "Square", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:poly#4", + "mode": "sketch", + "family": "Polygon" + }, + { + "id": "sk_poly_5", + "name": "Pentagon", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:poly#5", + "mode": "sketch", + "family": "Polygon" + }, { "id": "sk_polygon", - "name": "Polygon", + "name": "Hexagon", "slot": "create", "key": "G", "feature": "Sketch", @@ -1310,7 +1430,92 @@ "needs": {}, "refusal": null, "gui": true, - "action": "key:G" + "action": "btn:poly#6", + "family": "Polygon" + }, + { + "id": "sk_poly_8", + "name": "Octagon", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:poly#8", + "mode": "sketch", + "family": "Polygon" + }, + { + "id": "sk_poly_12", + "name": "Dodecagon", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:poly#12", + "mode": "sketch", + "family": "Polygon" + }, + { + "id": "sk_poly_inscribed", + "name": "Inscribed", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:polyfit#0", + "mode": "sketch", + "family": "Polygon" + }, + { + "id": "sk_poly_circumscribed", + "name": "Circumscribed", + "slot": "create", + "key": null, + "feature": "Sketch", + "mcp": null, + "accepts": [ + "sk_none", + "sk_point", + "sk_line", + "sk_arc", + "sk_2ent" + ], + "needs": {}, + "refusal": null, + "gui": true, + "action": "btn:polyfit#1", + "mode": "sketch", + "family": "Polygon" }, { "id": "sk_point_t", diff --git a/src/slic3r/GUI/DesignOffer.hpp b/src/slic3r/GUI/DesignOffer.hpp index 46d5b40019..67199b83b9 100644 --- a/src/slic3r/GUI/DesignOffer.hpp +++ b/src/slic3r/GUI/DesignOffer.hpp @@ -86,7 +86,9 @@ static const OfferVerb kOfferVerbs[] = { {"loft", "Loft", 1, "Shift+L", "key:S+L", "Create at least two profile sketches to loft", 0x00004000u, 0, 2, false, false, nullptr}, {"thicken", "Thicken", 1, nullptr, "fly:material#4", "Thicken needs a solid body — add or import one first", 0x0000000au, 1, 0, false, false, nullptr}, {"rib", "Rib", 1, nullptr, "fly:material#5", "Rib needs a solid body — add or import one first", 0x00010000u, 1, 0, false, false, nullptr}, - {"boolean", "Combine", 1, "Shift+B", "key:S+B", "Boolean needs two bodies — create or import a second solid", 0x00000200u, 2, 0, false, false, nullptr}, + {"boolean", "Union", 1, "Shift+B", "btn:bool#0", "Boolean needs two bodies — create or import a second solid", 0x00000200u, 2, 0, false, false, nullptr}, + {"bool_subtract", "Subtract", 1, nullptr, "btn:bool#1", "Boolean needs two bodies — create or import a second solid", 0x00000200u, 2, 0, false, false, nullptr}, + {"bool_intersect", "Intersect", 1, nullptr, "btn:bool#2", "Boolean needs two bodies — create or import a second solid", 0x00000200u, 2, 0, false, false, nullptr}, {"surf_extrude", "Surface Extrude", 1, "Shift+G", "key:S+G", "Create a sketch first", 0x00004000u, 0, 0, false, false, nullptr}, {"surf_revolve", "Surface Revolve", 1, nullptr, "fly:surface#1", "Create a sketch profile to revolve first", 0x00004000u, 0, 0, false, false, nullptr}, {"surf_loft", "Surface Loft", 1, nullptr, "fly:surface#2", "Create at least two profile sketches to loft", 0x00004000u, 0, 2, false, false, nullptr}, @@ -97,11 +99,12 @@ static const OfferVerb kOfferVerbs[] = { {"shell", "Shell", 2, "Shift+K", "key:S+K", "Shell needs a solid body", 0x00000082u, 1, 0, false, false, nullptr}, {"cut", "Cut", 2, "Shift+X", "key:S+X", "Create a solid body to cut first", 0x00000480u, 1, 0, false, false, nullptr}, {"split", "Split", 2, nullptr, nullptr, "Split needs a solid body", 0x00000080u, 1, 0, false, false, nullptr}, - {"fillet", "Fillet", 3, "Shift+F", "key:S+F", "Pick an edge to round", 0x000000b2u, 1, 0, false, false, nullptr}, - {"chamfer", "Chamfer", 3, nullptr, "key:S+F", "Pick an edge to bevel", 0x000000b2u, 1, 0, false, false, nullptr}, + {"fillet", "Fillet", 3, "Shift+F", "btn:dress#0", "Pick an edge to round", 0x000000b2u, 1, 0, false, false, nullptr}, + {"chamfer", "Chamfer", 3, nullptr, "btn:dress#1", "Pick an edge to bevel", 0x000000b2u, 1, 0, false, false, nullptr}, {"draft", "Draft", 3, "Shift+D", "key:S+D", "Pick a face to taper", 0x0000000au, 1, 0, false, false, nullptr}, {"surf_offset", "Surface Offset", 3, nullptr, "fly:surface#4", "target is not a sheet body", 0x00000100u, 0, 0, true, false, nullptr}, - {"pattern", "Pattern", 4, "Shift+N", "key:S+N", "Create a solid body to pattern first", 0x00006082u, 1, 0, false, false, nullptr}, + {"pattern", "Linear pattern", 4, "Shift+N", "btn:pat#0", "Create a solid body to pattern first", 0x00006082u, 1, 0, false, false, nullptr}, + {"pattern_circular", "Circular pattern", 4, nullptr, "btn:pat#1", "Create a solid body to pattern first", 0x00006082u, 1, 0, false, false, nullptr}, {"mirror", "Mirror", 4, "Shift+Z", "key:S+Z", "Mirror needs a body — add or import one first", 0x00000480u, 1, 0, false, false, nullptr}, {"pat_curve", "Pattern on Curve", 4, nullptr, nullptr, "Pattern on curve needs a body and a curve", 0x00000090u, 1, 0, false, false, nullptr}, {"transform", "Move", 5, "Shift+Y", "key:S+Y", "Transform needs a body — add or import one first", 0x00002180u, 1, 0, false, false, nullptr}, @@ -136,7 +139,14 @@ static const OfferVerb kOfferVerbs[] = { {"sk_ellipse", "Ellipse", 0, "E", "key:E", nullptr, 0x000f8000u, 0, 0, false, true, "Ellipse"}, {"sk_ellipse_arc", "Elliptical arc", 0, nullptr, "fly:design_ellipse#1", nullptr, 0x000f8000u, 0, 0, false, true, "Ellipse"}, {"sk_spline", "Spline", 0, "B", "key:B", nullptr, 0x000f8000u, 0, 0, false, true, nullptr}, - {"sk_polygon", "Polygon", 0, "G", "key:G", nullptr, 0x000f8000u, 0, 0, false, true, nullptr}, + {"sk_poly_3", "Triangle", 0, nullptr, "btn:poly#3", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_4", "Square", 0, nullptr, "btn:poly#4", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_5", "Pentagon", 0, nullptr, "btn:poly#5", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_polygon", "Hexagon", 0, "G", "btn:poly#6", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_8", "Octagon", 0, nullptr, "btn:poly#8", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_12", "Dodecagon", 0, nullptr, "btn:poly#12", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_inscribed", "Inscribed", 0, nullptr, "btn:polyfit#0", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, + {"sk_poly_circumscribed", "Circumscribed", 0, nullptr, "btn:polyfit#1", nullptr, 0x000f8000u, 0, 0, false, true, "Polygon"}, {"sk_point_t", "Point", 0, "P", "key:P", nullptr, 0x000f8000u, 0, 0, false, true, nullptr}, {"sk_offset", "Offset", 1, "O", "key:O", nullptr, 0x000b0000u, 0, 0, false, true, nullptr}, {"sk_trim", "Trim", 2, "T", "key:T", nullptr, 0x000b0000u, 0, 0, false, true, nullptr}, @@ -154,7 +164,7 @@ static const OfferVerb kOfferVerbs[] = { {"sk_extend", "Extend", 7, "X", "key:X", nullptr, 0x000b0000u, 0, 0, false, true, nullptr}, {"sk_delete", "Delete", 7, "Del", "btn:delete", nullptr, 0x000f0000u, 0, 0, false, true, nullptr}, }; -static const int kOfferVerbCount = 74; +static const int kOfferVerbCount = 84; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index cbfa26b244..36cfbe9f21 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -358,7 +358,6 @@ DesignPanel::DesignPanel(wxWindow* parent) m_viewport->set_sketch_tool(mode); } m_viewport->set_sketch_construction(m_construction->GetValue()); - show_polygon_card(mode == DesignSketchTool::Mode::Polygon); m_status->SetForegroundColour(wxNullColour); m_status->SetLabel(m_sketch_on.IsEmpty() ? hint : wxString::Format(_L("%s · on %s"), hint, m_sketch_on)); @@ -1196,12 +1195,53 @@ DesignPanel::DesignPanel(wxWindow* parent) {"design_array", DesignSketchTool::Mode::Array, _L("Linear array"), _L("Pick entities, drag the spacing handle, click the count; click empty to apply")}, {"design_polararray", DesignSketchTool::Mode::PolarArray, _L("Polar array (about centroid)"), _L("Pick entities, drag the sweep handle, click the count; click empty to apply")} }); - // Polygon's side count / circumscribed flag used to sit inline in this row; they are - // tool parameters, so they live in the sidebar card that opens with the tool. - auto* b_poly = icon_btn("design_polygon", _L("Polygon")); - b_poly->Bind(wxEVT_BUTTON, [this, select_tool](wxCommandEvent&) { + // Polygon's side count and fit are TOOL PARAMETERS, so they are chosen from the tool: + // the offer's Create > Polygon submenu. They used to sit inline in this row, then in a + // sidebar card; both put the choice somewhere you had to leave the geometry to reach, + // and the count cannot be recovered afterwards (a drawn polygon's inline editor offers + // Side and Angle, never the count). snaporca-e1p. + auto arm_polygon = [this, select_tool] { push_polygon_params(); - select_tool(DesignSketchTool::Mode::Polygon, _L("Click center then a vertex")); }); + select_tool(DesignSketchTool::Mode::Polygon, + wxString::Format(_L("Click center then a vertex — %d sides, %s"), + m_poly_sides, + m_poly_circumscribed ? _L("circumscribed") : _L("inscribed"))); + }; + for (int n : {3, 4, 5, 6, 8, 12}) + m_verb_actions["btn:poly#" + std::to_string(n)] = + [this, arm_polygon, n] { m_poly_sides = n; arm_polygon(); }; + for (int c : {0, 1}) + m_verb_actions["btn:polyfit#" + std::to_string(c)] = + [this, arm_polygon, c] { m_poly_circumscribed = (c == 1); arm_polygon(); }; + + // Same defect, one level up: a combo whose entries are different VERBS wearing a single + // name. "Dress-up" is Fillet or Chamfer; "Combine" is union, subtract or intersect; + // "Pattern" is linear or circular. The choice decides WHAT YOU ARE DOING, so it belongs + // where you chose the tool — not behind a card you must open to discover it existed. + // Each address opens the tool exactly as its shortcut does, then says which one. + // The members are read at INVOCATION, not capture: the cards are built after this row. + // snaporca-e1p. + auto open_feature = [this](int key) { + auto it = m_keys_feature.find(key); + if (it != m_keys_feature.end() && it->second) it->second(); + }; + // SHIFT() is a constructor-local helper, so resolve the codes here rather than inside + // the stored lambdas, which outlive it. + const int k_dress = SHIFT('F'), k_bool = SHIFT('B'), k_pat = SHIFT('N'); + m_verb_actions["btn:dress#0"] = [this, open_feature, k_dress] { + open_feature(k_dress); if (m_dressup_type) m_dressup_type->SetSelection(0); }; + m_verb_actions["btn:dress#1"] = [this, open_feature, k_dress] { + open_feature(k_dress); if (m_dressup_type) m_dressup_type->SetSelection(1); }; + for (int op = 0; op < 3; ++op) + m_verb_actions["btn:bool#" + std::to_string(op)] = [this, open_feature, k_bool, op] { + open_feature(k_bool); + if (m_bool_op) { m_bool_op->SetSelection(op); refresh_preview(); } }; + for (int t = 0; t < 2; ++t) + m_verb_actions["btn:pat#" + std::to_string(t)] = [this, open_feature, k_pat, t] { + open_feature(k_pat); if (m_pattern_type) m_pattern_type->SetSelection(t); }; + + auto* b_poly = icon_btn("design_polygon", _L("Polygon")); + b_poly->Bind(wxEVT_BUTTON, [arm_polygon](wxCommandEvent&) { arm_polygon(); }); sadd(b_poly); add_sep(m_tb_sketch); m_construction->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { @@ -1494,28 +1534,11 @@ DesignPanel::DesignPanel(wxWindow* parent) // --- Polygon (sketch tool options) --- { - auto* pform = two_col_form(); - m_sides = new wxSpinCtrl(m_cards, wxID_ANY, "6", wxDefaultPosition, wxSize(90, -1)); - m_sides->SetRange(3, 64); - m_sides->SetValue(6); - m_sides->Bind(wxEVT_SPINCTRL, [this](wxSpinEvent&) { - if (m_viewport) m_viewport->set_sketch_polygon_sides(m_sides->GetValue()); }); - pform->Add(new wxStaticText(m_cards, wxID_ANY, _L("Sides")), 0, wxALIGN_CENTER_VERTICAL); - pform->Add(m_sides, 0, wxEXPAND); - - m_poly_circ = new CheckBox(m_cards); - m_poly_circ->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& e) { - if (m_viewport) m_viewport->set_sketch_polygon_circumscribed(m_poly_circ->GetValue()); - e.Skip(); }); - pform->Add(new wxStaticText(m_cards, wxID_ANY, _L("Circumscribed")), 0, wxALIGN_CENTER_VERTICAL); - pform->Add(m_poly_circ, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - - m_box_polygon = new wxBoxSizer(wxVERTICAL); - m_box_polygon->Add(card_header(m_cards, "design_polygon", _L("Polygon"), m_hdr_polygon), 0, - wxLEFT | wxRIGHT | wxTOP, 12); - m_box_polygon->Add(new wxStaticLine(m_cards), 0, wxEXPAND | wxALL, 8); - m_box_polygon->Add(pform, 0, wxEXPAND | wxALL, 12); - cards->Add(m_box_polygon, 0, wxEXPAND); + // NO polygon card. Sides and Circumscribed are tool parameters and are chosen from the + // tool — the offer's Create > Polygon submenu names the common side counts and the two + // fits, and arming from there sets both. A spin field on the left could not be reached + // without leaving the geometry, and the count is unrecoverable afterwards: the inline + // editor a drawn polygon opens offers Side and Angle, never the count. snaporca-e1p. } // --- Extrude dialog (consumes the selected sketch) --- @@ -2959,7 +2982,6 @@ DesignPanel::DesignPanel(wxWindow* parent) root->Show(m_parts_box, false, false); // no bodies on a fresh document root->Show(m_cards, false, false); // no tool open yet: don't draw an empty frame cards->Show(m_box_sketch, false, true); - cards->Show(m_box_polygon, false, true); cards->Show(m_box_move, false, true); cards->Show(m_box_extrude, false, true); cards->Show(m_box_revolve, false, true); @@ -8704,21 +8726,13 @@ void DesignPanel::show_move_card(bool show) if (m_form) { m_form->Layout(); m_form->FitInside(); } } -// Polygon's options live in a sidebar card that is shown only while the tool is armed. -void DesignPanel::show_polygon_card(bool show) -{ - if (m_box_polygon == nullptr || m_cards == nullptr || m_cards->GetSizer() == nullptr) return; - m_cards->GetSizer()->Show(m_box_polygon, show, true); - update_cards_frame(); - if (m_form) { m_form->Layout(); m_form->FitInside(); } -} - -// Push the card's current values into the live sketch tool before Polygon starts. +// Push the tool's current parameters into the live sketch tool before Polygon starts. They +// come from the offer's Polygon submenu (or from the last choice made there), never from a card. void DesignPanel::push_polygon_params() { if (m_viewport == nullptr) return; - m_viewport->set_sketch_polygon_sides(m_sides ? m_sides->GetValue() : 6); - m_viewport->set_sketch_polygon_circumscribed(m_poly_circ && m_poly_circ->GetValue()); + m_viewport->set_sketch_polygon_sides(m_poly_sides); + m_viewport->set_sketch_polygon_circumscribed(m_poly_circumscribed); } void DesignPanel::open_tool(Tool t) diff --git a/src/slic3r/GUI/DesignPanel.hpp b/src/slic3r/GUI/DesignPanel.hpp index d4fd56c77f..d3680ebea0 100644 --- a/src/slic3r/GUI/DesignPanel.hpp +++ b/src/slic3r/GUI/DesignPanel.hpp @@ -276,7 +276,6 @@ private: StaticBox* m_parts_box{nullptr}; // framed bodies section (hidden while empty) StaticBox* m_cards{nullptr}; // one framed panel holding every tool dialog (one visible at a time) void update_cards_frame(); // show that frame iff some card inside it is visible - void show_polygon_card(bool show); void show_move_card(bool show); void apply_move_card(); // numeric move/rotate -> same xform the gizmo builds void push_polygon_params(); @@ -284,7 +283,6 @@ private: wxSizer* m_tb_doc{nullptr}; // toolbar document/view actions (new, commit, export, section, place) CheckBox* m_show_bed{nullptr}; // view option: draw the printer bed + plate grid, or not wxSizer* m_box_move{nullptr}; // Move/Rotate numeric options (distance, axis, angle) - wxSizer* m_box_polygon{nullptr}; // Polygon tool options (sides / circumscribed) wxSizer* m_box_sketch{nullptr}; wxSizer* m_box_extrude{nullptr}; wxSizer* m_box_dressup{nullptr}; @@ -325,7 +323,6 @@ private: // Onshape-style dialog-card title rows (icon + bold feature name), retitled // per tool in open_tool() (edit-mode shows the feature's actual name). - wxStaticText* m_hdr_polygon{nullptr}; wxStaticText* m_hdr_move{nullptr}; wxStaticText* m_hdr_sketch{nullptr}; // Onshape sketch-entry card (plane/orientation) that opens on "New sketch" and @@ -395,8 +392,12 @@ private: wxSpinCtrlDouble* m_move_dz{nullptr}; ComboBox* m_move_axis{nullptr}; // rotation axis: X/Y/Z wxSpinCtrlDouble* m_move_angle{nullptr}; // rotation angle (deg) - wxSpinCtrl* m_sides{nullptr}; // polygon sides - CheckBox* m_poly_circ{nullptr}; // polygon circumscribed toggle (Orca teal check) + // Polygon's two parameters are chosen FROM THE TOOL, in the offer's Polygon submenu, not + // from a card on the left: the side count cannot be edited after drawing (the inline editor + // offers Side and Angle only), so it has to be settled at the moment the tool is armed — + // which is exactly where the offer already is. snaporca-e1p. + int m_poly_sides{6}; // 3..64; the submenu names the common ones + bool m_poly_circumscribed{false}; // Which reference plane a sketch falls back to when no face is picked: 0/1/2 = XY/XZ/YZ, // >=3 indexes resolve_datum_planes(). Set by CLICKING a ghost plane in the viewport — there is