Files
vectorcraft/crates/mcp/src/tests_place.rs
T
bflatasticandClaude Opus 5.5 76b7d960f2 M4.25: Drop files on the canvas to place them; several placed files load the place cursor
Files dropped on the canvas of an open document are placed at the drop point (linked; Shift
embeds); dropped on the tab bar or with no document open they open and join Open Recent Files.
The canvas is outlined while files are dragged over it. On the web, drag events give the drop
point and the files arrive through the inbox.

File > Place picks several files. file.place.queue loads the place cursor (the `place` tool):
a click places the current file at 100% with its top-left corner there, a drag places it at the
dragged size with its aspect kept, the arrow keys cycle the files and Esc discards one; the
previous tool returns after the last. The cursor shows the file's thumbnail and a count badge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 08:42:30 +07:00

59 lines
2.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! File → Place over MCP, headless: `file.place` through `run_command`, and the place cursor driven
//! by pointer gestures and keys.
use serde_json::{Value, json};
use crate::{Backend, Headless, call_tool};
fn text(r: &crate::ToolResult) -> Value {
assert!(!r.is_error, "{r:?}");
serde_json::from_str(r.content[0]["text"].as_str().unwrap()).unwrap()
}
/// A headless session with a 400×300 document, and a 30×20 PNG as base64.
fn setup() -> (Headless, String) {
let mut h = Headless::new();
h.call("engine.execute", json!({"command": "file.new", "params": {"width": 30, "height": 20}})).unwrap();
let png = h.call("engine.execute", json!({"command": "document.serialize", "params": {"format": "png"}})).unwrap();
h.call("engine.execute", json!({"command": "file.new", "params": {"width": 400, "height": 300}})).unwrap();
(h, png["dataBase64"].as_str().unwrap().to_string())
}
fn images(h: &Headless) -> usize {
let mut n = 0;
h.session.doc().unwrap().doc.walk(|x| n += usize::from(matches!(x.kind, vectorcraft_doc::NodeKind::Image(_))));
n
}
#[test]
fn headless_run_command_file_place() {
let (mut h, png) = setup();
let r = text(&call_tool(
&mut h,
"run_command",
&json!({"command": "file.place", "params": {"name": "tile.png", "dataBase64": png, "at": [100, 50]}}),
));
assert_eq!((r["format"].as_str(), r["width"].as_f64(), r["height"].as_f64()), (Some("png"), Some(30.0), Some(20.0)), "{r}");
assert_eq!(images(&h), 1);
let sel = h.session.doc().unwrap().selection.objects.clone();
assert_eq!(sel.len(), 1);
assert_eq!(sel[0].0, r["ids"][0].as_u64().unwrap());
}
#[test]
fn headless_place_cursor_places_on_clicks_and_esc_ends_it() {
let (mut h, png) = setup();
let files = json!([{"name": "a.png", "dataBase64": png}, {"name": "b.png", "dataBase64": png}, {"name": "c.png", "dataBase64": png}]);
let r = text(&call_tool(&mut h, "run_command", &json!({"command": "file.place.queue", "params": {"files": files}})));
assert_eq!(r["count"], 3);
assert_eq!(h.session.tool_id(), "place");
let click = |x: f64| json!({"events": [{"kind": "down", "x": x, "y": 10}, {"kind": "up", "x": x, "y": 10}]});
text(&call_tool(&mut h, "pointer_gesture", &click(10.0)));
text(&call_tool(&mut h, "pointer_gesture", &click(60.0)));
assert_eq!(images(&h), 2);
let r = text(&call_tool(&mut h, "press_key", &json!({"key": "Escape"})));
assert_eq!(r["handledBy"], "tool");
assert_eq!(h.session.tool_id(), "selection", "the last file discarded: back to the previous tool");
assert_eq!(images(&h), 2);
}