Design: sketch means a tool — the offer works inside a sketch, and the app stops

contradicting itself about the plane

Reported from the rig: pick a plane, press Sketch, and you are told to pick a
plane. The app prescribed a sequence and then refused to acknowledge that you
had followed it. Right-click did nothing, so there was no way to reach a
drawing tool except the toolbar this tab exists to retire.

act_sketch was two lines: set the mode, then print "Click a face or a reference
plane in the viewport, then a sketch tool" — unconditionally, without ever
asking whether a plane was already chosen. The plane was never lost; m_ref_plane
held it and begin_sketch captures it when the first tool is armed. The sentence
was simply false.

It now asks. sketch_plane_target() is a companion to sketch_plane_from_selection
that distinguishes "the user chose XZ" from "nothing chosen, falling back to XY"
— a distinction m_ref_plane cannot express on its own, being always a valid
index, so m_plane_picked carries it. With a target the readout names it and the
offer opens on the Create row; without one the old prompt stands, because then
it is true. The card above the status line was a local wxStaticText that nothing
could update, so it went on asking for a plane two inches from a line saying the
plane was chosen. It is a member now and the two are written together.

Right-click inside a sketch was excluded wholesale so that it could end a
polyline chain, abandon an anchor, exit a tool. That made every sketch row in
the atlas unreachable. The honest test is not which mode we are in but whether
the tool actually USED this right-click, and only the tool knows: on_mouse now
wraps on_mouse_impl and records that once, for every terminator, instead of
threading a flag through the twenty-odd sites that consume a RightDown. The
canvas read-and-clears it on the matching release.

Underneath all of it was one confusion — MODE versus SESSION — at four sites.
begin_sketch does not run until the first tool is armed, so is_sketching() is
false for exactly the interval between "press Sketch" and "pick a tool", which
is precisely when the drawing tools must be on offer. The keyboard learned this
once already (snaporca-0ud, whose comment states the rule) and I reintroduced it
in offer_selection_kind and again in show_offer_menu, where the offer built from
the FEATURE map and rendered nine rows that all refused the sketch selection.
Both now call sketch_map_applies(), so they cannot drift apart again. The
keyboard keeps its own split: its "sketching" gates undo and delete-last-entity,
which genuinely need a live session.

Verified on :11 against a fresh build. Pick XZ, press Sketch: card reads
"Drawing on XZ", status reads "Sketching on XZ — pick a tool", offer opens with
Create and Reference live and the six rows needing geometry greyed. Right-click
while idle opens the offer. Right-click as a terminator does NOT — the chain
ends, the line lands on XZ, its length field arms at 49.36 mm. That last one is
the regression the blanket exclusion was buying and the reason this shape of fix
was chosen over a mode test.

Refs snaporca-6vs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyRwbuq6fjn3VV9U9UvhBM
This commit is contained in:
Tommaso Bianchi
2026-07-31 19:21:42 +02:00
co-authored by Claude Opus 5
parent bb403b82cf
commit 9f2b2bc511
5 changed files with 96 additions and 7 deletions
+4 -1
View File
@@ -816,7 +816,10 @@ void DesignCanvas::set_on_context_menu(std::function<void(const wxPoint&)> cb)
});
m_canvas_widget->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent& e) {
const wxPoint d = e.GetPosition() - m_ctx_press;
if (m_on_context_menu && !is_sketching() && !inline_busy()
// Always read-and-clear, even when another guard already rules the offer out, or a
// terminator recorded under one condition would still be pending under the next.
const bool terminated = m_sketch_tool.take_right_consumed();
if (m_on_context_menu && !terminated && !inline_busy()
&& std::max(std::abs(d.x), std::abs(d.y)) <= 8) {
m_on_context_menu(m_canvas_widget->ClientToScreen(e.GetPosition()));
return; // consumed