mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
Keep the UI-zoom tests: set the interface scale with ui.zoomFactor now that Cmd+Plus zooms the photo (#566)
The CLI snapshot test and the headless resize test sent Cmd+Plus to change egui's interface scale; with the keys handed to View > Zoom they no longer did. A ui.zoomFactor control request (0.5-3, documented) sets the scale explicitly. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
a677478b92
commit
835dcf6657
4 files changed
+32
-1
No files matched your search
@@ -233,6 +233,26 @@ fn snapshot_script_failure_exits_non_zero() {
|
||||
assert_eq!((d.width, d.height), (320, 200));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_ui_zoom_keeps_requested_pixel_dimensions() {
|
||||
let script = tmp("snap-ui-zoom.jsonl");
|
||||
std::fs::write(&script, format!("{}\n{}\n", json!({"method": "ui.zoomFactor", "params": {"factor": 1.1}}), json!({"method": "ui.inspect"})))
|
||||
.unwrap();
|
||||
for (size, scale, expected) in [("400x240", "1", (400, 240)), ("345x200", "0.9", (311, 180))] {
|
||||
let out = tmp(&format!("snap-ui-zoom-{scale}.png"));
|
||||
let o = Command::new(BIN)
|
||||
.args(["snapshot", "--script", script.to_str().unwrap(), "-o", out.to_str().unwrap(), "--size", size, "--scale", scale])
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(o.status.success(), "{}", String::from_utf8_lossy(&o.stderr));
|
||||
let replies: Vec<Value> = String::from_utf8_lossy(&o.stdout).lines().map(|line| serde_json::from_str(line).unwrap()).collect();
|
||||
assert!(replies.iter().all(|reply| reply["ok"] == true), "{replies:?}");
|
||||
assert!(replies[1]["result"]["pixelsPerPoint"].as_f64().unwrap() > scale.parse::<f64>().unwrap());
|
||||
let decoded = lightcraft_codecs::decode(&std::fs::read(out).unwrap(), Default::default()).unwrap();
|
||||
assert_eq!((decoded.width, decoded.height), expected);
|
||||
}
|
||||
}
|
||||
|
||||
/// Headless snapshots default to CPU photo rendering as well as CPU UI rasterization.
|
||||
#[test]
|
||||
fn snapshot_defaults_to_cpu_without_gpu_environment_overrides() {
|
||||
|
||||
@@ -340,6 +340,14 @@ pub fn handle(app: &mut LightcraftApp, ctx: &egui::Context, req: &ControlRequest
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::vec2(w, h)));
|
||||
ok(Value::Null)
|
||||
}
|
||||
"ui.zoomFactor" => match f("factor") {
|
||||
// egui's interface scale (its keyboard shortcuts are off: Cmd+= / Cmd+- zoom the photo)
|
||||
Some(factor) if factor.is_finite() && (0.5..=3.0).contains(&factor) => {
|
||||
ctx.set_zoom_factor(factor as f32);
|
||||
ok(Value::Null)
|
||||
}
|
||||
_ => err("ui.zoomFactor: factor must be a number from 0.5 to 3"),
|
||||
},
|
||||
"ui.screenshot" => {
|
||||
// never over a photo's original
|
||||
if let Some(Err(e)) = s("path").map(|path| app.session.check_write_target(path)) {
|
||||
|
||||
@@ -501,7 +501,9 @@ mod tests {
|
||||
app.ui.settings.gpu = false;
|
||||
let mut h = Headless::new(app, [480.0, 320.0], scale);
|
||||
let t = Duration::from_secs(5);
|
||||
assert_eq!(h.request("ui.key", json!({"key": "Plus", "cmd": true}), t)["ok"], true);
|
||||
assert_eq!(h.request("ui.zoomFactor", json!({"factor": 1.1}), t)["ok"], true);
|
||||
h.step();
|
||||
assert!(h.view.ctx.zoom_factor() > 1.0);
|
||||
let native_size = resized_viewport([320.0, 240.0], scale, h.view.ctx.zoom_factor()).unwrap();
|
||||
let expected = native_viewport_pixels([native_size.x, native_size.y], scale).unwrap();
|
||||
assert_eq!(h.request("ui.resize", json!({"width": 320, "height": 240}), t)["ok"], true);
|
||||
|
||||
@@ -42,6 +42,7 @@ mode ([mcp.md](mcp.md)) is a thin layer over this channel. Implementation:
|
||||
| `ui.set` | partial UI state, e.g. `{"view": "detail"}` | Resulting UI state |
|
||||
| `ui.dialog.confirm` / `ui.dialog.cancel` | — | Close the open dialog |
|
||||
| `ui.resize` | `{width, height}` | Resize the window |
|
||||
| `ui.zoomFactor` | `{factor}` | Set the interface scale (0.5–3; egui's zoom keys are off, Cmd+= / Cmd+- zoom the photo) |
|
||||
| `ui.screenshot` | `{path?, headless?}` | `{path, width, height}` once the frame (with finished renders) is captured. `headless: true` draws the UI on the CPU (no compositor needed); a windowed capture that gets no frame within 2 s falls back to headless automatically |
|
||||
| `engine.execute {command: "app.export", params}` | export params (see `docs/mcp.md`), plus `preset`, `dir` / `path`, `ids`, `background` | Writes the files and returns `{files}`; with `background: true` (what the Export dialog and menus use) it returns `{background: true, total}` at once and the batch runs on a worker thread — poll `ui.inspect` → `export` |
|
||||
| `ui.render` | `{id?, size?, path?}` | Render a photo (PNG to `path`), `{width, height}` |
|
||||
|
||||
Reference in new issue
Block a user