MCP demo v2: examples/demo/enclosure_ui_mcp.py builds the enclosure through the UI like a person (toolbar clicks, real dialogs, sketches on the model's faces, Look At and back out, orbits between features) with the parameters and their dimensions over MCP; record_v2.sh and overlay.py record it with captions (UI click / MCP call) and a drawn pointer with click ripples. Toolbar buttons, drop-down items and panel labels publish handles (toolbar:<id>, panel:<tab>:<panel>); control method ui.handles lists them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
78dd776152
commit
1d11898a2c
9 files changed
+444
No files matched your search
@@ -252,6 +252,11 @@ pub fn handle(app: &mut SolveApp, ctx: &egui::Context, req: &ControlRequest) ->
|
||||
_ => err("no dialog input with that index"),
|
||||
}
|
||||
}
|
||||
"ui.handles" => {
|
||||
// The handles drawn last frame (toolbar buttons `toolbar:<id>`, panels, browser rows…).
|
||||
let list = crate::scenario::handles(s("prefix").unwrap_or(""));
|
||||
ok(json!(list.into_iter().map(|(n, p)| json!({"name": n, "x": p.x, "y": p.y})).collect::<Vec<_>>()))
|
||||
}
|
||||
"ui.at" => {
|
||||
// A scenario point: {world: [x,y,z]} | {sketch: [x,y]} | {plane: "XY"} (the middle of an
|
||||
// origin plane's square) → screen point.
|
||||
|
||||
@@ -62,6 +62,11 @@ pub fn handle_at(name: &str) -> Option<egui::Pos2> {
|
||||
HANDLES.with(|h| h.borrow().iter().rfind(|(n, _)| n == name).map(|x| x.1))
|
||||
}
|
||||
|
||||
/// Every handle drawn last frame whose name starts with `prefix`.
|
||||
pub fn handles(prefix: &str) -> Vec<(String, egui::Pos2)> {
|
||||
HANDLES.with(|h| h.borrow().iter().filter(|(n, _)| n.starts_with(prefix)).cloned().collect())
|
||||
}
|
||||
|
||||
/// A painted part's rect this frame, by name ("toolbar", "workspace_switcher").
|
||||
pub fn publish_rect(name: &str, r: egui::Rect) {
|
||||
RECTS.with(|h| h.borrow_mut().push((name.to_string(), r)));
|
||||
|
||||
@@ -297,6 +297,7 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
let br = Rect::from_min_size(pos2(px + 4.0 + i as f32 * 40.0, top + 2.0), vec2(38.0, 38.0));
|
||||
let info = c.info(&app.session);
|
||||
let resp = ui.interact(br, ui.id().with(("cmd", c.id)), Sense::click());
|
||||
crate::scenario::publish_handle(&format!("toolbar:{}", c.id), br.center());
|
||||
if resp.hovered() && info.enabled {
|
||||
painter.rect_filled(br, 4.0, t.hover);
|
||||
}
|
||||
@@ -324,6 +325,7 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
let lr = Rect::from_min_size(pos2(px, top + 42.0), vec2(width, 18.0));
|
||||
let label = panel.to_string();
|
||||
let lresp = ui.interact(lr, ui.id().with(("panel", panel)), Sense::click());
|
||||
crate::scenario::publish_handle(&format!("panel:{tab}:{panel}"), lr.center());
|
||||
if lresp.hovered() && enabled_panel {
|
||||
painter.rect_filled(lr, 3.0, t.hover);
|
||||
}
|
||||
@@ -360,6 +362,7 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
let (ir, _) = ui.allocate_exact_size(vec2(18.0, 18.0), Sense::hover());
|
||||
icons::paint(ui.painter(), ir, c.icon, t.icon, t.icon_fill, t.accent);
|
||||
let b = ui.add_enabled(info.enabled, egui::Button::new(c.label).frame(false).shortcut_text(c.shortcut.unwrap_or("")));
|
||||
crate::scenario::publish_handle(&format!("toolbar:{}", c.id), b.rect.center());
|
||||
if b.clicked() {
|
||||
let id = c.id;
|
||||
app.start(id);
|
||||
|
||||
Reference in new issue
Block a user