The old ids live only in crates/engine/src/legacy_ids.rs (the legacy migration table): find_command maps them, so old scripts, recipes and control calls keep working, and saved shortcuts, recent and pinned commands are migrated on load (designs store no command ids). Parity maps the observed catalog ids to ours through xtask/data/fusion-ids.tsv. The agent rule now reads: our own dotted id, never another product's. Cargo.toml's repository points at github.com/bherbruck/solvecraft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
3.4 KiB
Rust
93 lines
3.4 KiB
Rust
//! Every command dialog and every window stays within the width limits of `frame`: started
|
|
//! through the control channel (the toolbar's way) and measured as drawn.
|
|
|
|
use serde_json::json;
|
|
use solvecraft_ui_egui::frame::{DIALOG_MAX_W, DIALOG_MIN_W, DIALOG_WIDE_MAX_W, WINDOW_WIDE_MAX_W};
|
|
use solvecraft_ui_egui::scenario::Harness;
|
|
|
|
/// Widths of the windows on screen (their areas in the middle layer).
|
|
fn window_widths(h: &Harness) -> Vec<(String, f32)> {
|
|
h.ctx.memory(|m| {
|
|
m.areas()
|
|
.visible_layer_ids()
|
|
.into_iter()
|
|
.filter(|l| l.order == egui::Order::Middle)
|
|
.filter_map(|l| m.area_rect(l.id).map(|r| (format!("{:?}", l.id), r.width())))
|
|
.collect()
|
|
})
|
|
}
|
|
|
|
fn fresh() -> Harness {
|
|
let mut h = Harness::new();
|
|
h.call("engine.execute", json!({"command": "solid.box", "params": {"length": 40, "width": 30, "height": 20}}));
|
|
h.frames(3);
|
|
h
|
|
}
|
|
|
|
#[test]
|
|
fn command_dialogs_shrink_to_their_content_within_limits() {
|
|
let mut h = fresh();
|
|
let mut bad = Vec::new();
|
|
// The frame border and shadow add a little to the content limits.
|
|
let slack = 4.0;
|
|
for spec in solvecraft_engine::command_specs() {
|
|
h.call("ui.start", json!({"command": spec.id}));
|
|
h.frames(4);
|
|
let wide = h.app.dialog.as_ref().is_some_and(|d| d.is_wide());
|
|
let max = if wide { DIALOG_WIDE_MAX_W } else { DIALOG_MAX_W };
|
|
for (layer, w) in window_widths(&h) {
|
|
// Floating windows a command opened (Parameters…) have their own limit.
|
|
let limit = if h.app.dialog.is_some() { max } else { WINDOW_WIDE_MAX_W };
|
|
if w > limit + slack {
|
|
bad.push(format!("{} ({layer}): {w} px", spec.id));
|
|
}
|
|
}
|
|
// The docked dialog shrinks to its content: most dialogs stay well under the maximum.
|
|
if h.app.dialog.is_some() && !wide {
|
|
for (_, w) in window_widths(&h) {
|
|
if w < DIALOG_MIN_W - slack {
|
|
bad.push(format!("{}: {w} px is narrower than {DIALOG_MIN_W}", spec.id));
|
|
}
|
|
}
|
|
}
|
|
h.app.dialog = None;
|
|
h.app.params = None;
|
|
h.app.tool = None;
|
|
if h.app.session.active_sketch.is_some() {
|
|
h.app.finish_sketch();
|
|
}
|
|
h.frames(2);
|
|
}
|
|
assert!(bad.is_empty(), "windows too wide or too narrow:\n{}", bad.join("\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn common_dialogs_are_not_stretched() {
|
|
// Simple dialogs have room to spare: they must not be pushed out to the maximum.
|
|
let mut h = fresh();
|
|
for id in ["solid.extrude", "solid.fillet", "solid.shell", "solid.move", "solid.hole"] {
|
|
h.call("ui.start", json!({"command": id}));
|
|
h.frames(6);
|
|
let w: f32 = window_widths(&h).iter().map(|x| x.1).fold(0.0, f32::max);
|
|
assert!(w < DIALOG_MAX_W - 20.0, "{id} is stretched to {w} px");
|
|
h.app.dialog = None;
|
|
h.frames(2);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn floating_windows_stay_within_limits() {
|
|
let mut h = fresh();
|
|
h.app.prefs_window.open = true;
|
|
h.app.keymap.open = true;
|
|
h.app.help.about = true;
|
|
h.app.ui.palette_open = true;
|
|
solvecraft_ui_egui::params_dialog::open(&mut h.app);
|
|
h.frames(6);
|
|
let ws = window_widths(&h);
|
|
assert!(ws.len() >= 4, "windows on screen: {ws:?}");
|
|
for (layer, w) in ws {
|
|
assert!(w <= WINDOW_WIDE_MAX_W + 4.0, "{layer} is {w} px wide");
|
|
}
|
|
}
|