mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
The offer ladder: drive right-click, and fix the two things it found
The gesture ladder proved the TARGET — a complex closed profile, exact in vertices, lengths, arcs
and symmetry, voids correctly attributed. It proved it by arming every tool with a letter key,
which leaves the goal's own MECHANISM untested: the design logic pivots on right-click, and the
verbs offered are supposed to adapt to the element under the cursor. 47 of 86 Design-tab verbs
have a GUI action and no shortcut, so a key-driven ladder cannot reach more than half of them.
scripts/offer-ladder.py drives the menu. It asserts nothing from pixels: show_offer_menu emits an
[OFFER] trace from the same loop that builds the rows (behind the existing SNAPORCA_KEYTRACE), so
what the ladder reads cannot drift from what the user is shown, and the expected row set is
predicted by parsing DesignOffer.hpp rather than transcribed by hand. 25 properties, four rungs:
what each element type offers, that the menu equals the table for four selections AND that the
four differ, a 120 x 80 profile authored entirely through the menu, and a tool with no keyboard
route at all driven from the only door it has.
Two real defects, both found by it, both fixed here:
snaporca-ghcz (P1) — right-click was a black hole while any draw tool was armed. Every draw case
ended with `if (evt.RightDown()) { m_points.clear(); return true; }` and returned true even with
nothing to abandon; on_mouse records that in m_right_consumed and DesignCanvas suppresses the
offer whenever it is set. Measured: with Line armed, two right-clicks in a row produced no menu
and no tool change; only Escape freed it. Same rule snaporca-xmh6 wrote for the selection —
clearing nothing is not a gesture terminator. One shared right_abandon() now consumes the click
only when an anchor was really down; 16 sites, plus Polyline/BSpline (which end a chain, correct
only when there IS one) and Point (which has no anchor at all).
snaporca-lnri (P2) — right-clicking a sketch point offered the empty vocabulary. select_at_screen
tests hit_test_point first and records the hit in m_point_sel, but the offer counts m_selection
only, so a Point entity could never reach the entity branch and SkPoint was unreachable by
construction. A Point IS its own handle, so it is selected as an entity; other entities keep the
handle pick, since a line's endpoint is a drag target, not a vocabulary.
Offer ladder 25/25, gesture ladder 93/93 (no regression), both on the rig. The offer ladder joins
scripts/ladder-all.sh as the fifth rung.
snaporca-ghcz snaporca-lnri
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
This commit is contained in:
co-authored by
Claude Opus 5
parent
12047e4085
commit
8c4b05ae9d
@@ -12,6 +12,7 @@
|
||||
#include <Standard_Failure.hxx>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg> // offer_trace: diagnostic row dump for the offer ladder
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <wx/sizer.h>
|
||||
@@ -5968,6 +5969,22 @@ wxMenuItem* DesignPanel::append_offer_item(wxMenu* menu, int id, const wxString&
|
||||
return item;
|
||||
}
|
||||
|
||||
// Diagnostic only: what the offer is about to show, line per row, on stderr. Costs one getenv
|
||||
// per menu when off. The ladder that drives right-click needs to assert the ROW SET, and the only
|
||||
// honest source for that is the loop that builds the rows.
|
||||
static void offer_trace(const char* fmt, ...)
|
||||
{
|
||||
static const bool on = std::getenv("SNAPORCA_KEYTRACE") != nullptr;
|
||||
if (!on) return;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[OFFER] ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
{
|
||||
const int kind = offer_selection_kind();
|
||||
@@ -5977,6 +5994,11 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
// is_sketching() the offer opened on entering a sketch showing the FEATURE rows, every one
|
||||
// of them refusing the sketch selection, so it read as a menu of nine dead entries.
|
||||
const bool sketching = sketch_map_applies();
|
||||
// The offer ladder reads THIS, not the pixels: the trace is emitted from the same loop that
|
||||
// builds the menu, so it cannot drift from what the user is shown. Gated on the existing
|
||||
// SNAPORCA_KEYTRACE so a rig run needs one env var, not two. snaporca-<offer ladder>.
|
||||
offer_trace("open kind=%d sketching=%d bodies=%d", kind, sketching ? 1 : 0,
|
||||
int(m_doc.bodies.size()));
|
||||
|
||||
const int bodies = int(m_doc.bodies.size());
|
||||
int sketches = 0;
|
||||
@@ -6046,9 +6068,13 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
s += wxString::FromUTF8(" — ") + tr(why);
|
||||
else if (OfferSel(kind) == OfferSel::None)
|
||||
s += wxString::FromUTF8(" — ") + _L("select something first");
|
||||
offer_trace("row=%d %s DISABLED (%s)", row, kOfferRowNames[row],
|
||||
why ? why : "no verb accepts this selection");
|
||||
menu.Append(base + int(bound.size()), s)->Enable(false);
|
||||
bound.push_back(nullptr);
|
||||
} else if (live.size() == 1) {
|
||||
offer_trace("row=%d %s -> %s%s", row, kOfferRowNames[row], live[0]->id,
|
||||
live[0]->action ? "" : " (no GUI route)");
|
||||
append_offer_item(&menu, base + int(bound.size()), label(*live[0]), *live[0])
|
||||
->Enable(live[0]->action != nullptr);
|
||||
bound.push_back(live[0]);
|
||||
@@ -6073,6 +6099,10 @@ void DesignPanel::show_offer_menu(const wxPoint& screen_pos)
|
||||
target = it->second;
|
||||
}
|
||||
}
|
||||
offer_trace("row=%d %s > %s%s%s%s", row, kOfferRowNames[row],
|
||||
(v->family && *v->family) ? v->family : "",
|
||||
(v->family && *v->family) ? " > " : "", v->id,
|
||||
v->action ? "" : " (no GUI route)");
|
||||
append_offer_item(target, base + int(bound.size()), label(*v), *v)
|
||||
->Enable(v->action != nullptr);
|
||||
bound.push_back(v);
|
||||
|
||||
Reference in New Issue
Block a user