feat: view.apply restores a named view or camera; MCP screenshot takes a named view or camera (#528) (#595)
New view.apply command restores a named view, a standard view or any camera (view state, not an undo step); the desktop viewport follows it and the browser's Restore uses it. The MCP screenshot tool takes a named view or a camera. Un-ignores the #528 regression test. Fixes #528. Co-authored-by: jonaswre <jonas.wrede@beyondit.gmbh>
This commit is contained in:
1 parent
e67cc0c747
commit
27f20f97cb
11 files changed
+159
-23
No files matched your search
+22
-7
@@ -155,10 +155,13 @@ pub fn tool_definitions() -> Vec<Value> {
|
||||
"Render the design and return it as a PNG image. Headless: a CPU render of the model, fitted to the view. \
|
||||
Connected to the app: a screenshot of the window (source \"window\", the default) or a render of the model \
|
||||
with the app's camera (source \"model\"). Both show an active section (inspect.section) with its cut face \
|
||||
capped. `view` first turns the camera to a standard view.",
|
||||
capped. `view` first turns the camera to a standard view or a saved named view (view.save), `camera` to any camera (as view.apply).",
|
||||
obj(
|
||||
json!({
|
||||
"view": {"type": "string", "enum": VIEWS, "description": "Standard view (default: keep the current one; headless starts at iso)"},
|
||||
"view": string(
|
||||
"Standard view (iso, home, front, back, top, bottom, left, right, fit) or the name of a saved named view (default: keep the current one; headless starts at iso)"
|
||||
),
|
||||
"camera": {"type": "object", "description": "Look from this camera instead: {target: [x,y,z], yaw, pitch, distance, fov?} (radians, mm; as view.save and view.apply)"},
|
||||
"path": string("Also keep the PNG at this path"),
|
||||
"width": {"type": "integer", "description": "Render width in pixels (model renders; default 960)"},
|
||||
"height": {"type": "integer", "description": "Render height in pixels (model renders; default 600)"},
|
||||
@@ -513,12 +516,24 @@ fn screenshot(b: &mut dyn Backend, a: &Map<String, Value>) -> Value {
|
||||
}
|
||||
|
||||
fn capture(b: &mut dyn Backend, a: &Map<String, Value>) -> Result<(Vec<u8>, Value), String> {
|
||||
if let Some(v) = str_arg(a, "view") {
|
||||
b.call("ui.view", json!({"view": v}))?;
|
||||
// Turning to a standard view also frames the model (like a axis view click).
|
||||
if v != "fit" && v != "home" {
|
||||
b.call("ui.view", json!({"view": "fit"}))?;
|
||||
let apply = |b: &mut dyn Backend, params: Value| b.call("engine.execute", json!({"command": "view.apply", "params": params}));
|
||||
match (str_arg(a, "view"), a.get("camera").filter(|c| !c.is_null())) {
|
||||
(Some(_), Some(_)) => return Err("screenshot: give `view` or `camera`, not both".into()),
|
||||
(None, Some(c)) => {
|
||||
apply(b, json!({"camera": c}))?;
|
||||
}
|
||||
(Some(v), None) if VIEWS.contains(&v) => {
|
||||
b.call("ui.view", json!({"view": v}))?;
|
||||
// Turning to a standard view also frames the model (like a axis view click).
|
||||
if v != "fit" && v != "home" {
|
||||
b.call("ui.view", json!({"view": "fit"}))?;
|
||||
}
|
||||
}
|
||||
// A saved named view.
|
||||
(Some(v), None) => {
|
||||
apply(b, json!({"view": v}))?;
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
let keep = str_arg(a, "path").filter(|p| !p.trim().is_empty()).map(str::to_string);
|
||||
let path = keep.clone().unwrap_or_else(|| {
|
||||
|
||||
Reference in new issue
Block a user