Stand this part up? offer: handles for its buttons, and stand-up scripting (#1911)
Thanks @DuBearte.
This commit is contained in:
1 parent
64235ab12a
commit
67d4628753
9 files changed
+107
-14
No files matched your search
@@ -1438,8 +1438,9 @@ fn colour_vision_sample(ui: &mut egui::Ui, t: &Tokens) {
|
||||
}
|
||||
|
||||
/// The control channel's `ui.prefs`: `open` (a page name) opens the dialog there, `button`
|
||||
/// presses OK, Cancel, Apply or Restore Defaults, `stand_up: true` answers the stand-up offer;
|
||||
/// any other keys set preferences. Returns them all, the open page and the offer.
|
||||
/// presses OK, Cancel, Apply or Restore Defaults, `stand_up: true` answers the stand-up offer
|
||||
/// (`false` leaves the file as it is, like "Leave it"); any other keys set preferences. Returns
|
||||
/// them all, the open page and the offer.
|
||||
pub fn control(app: &mut SolveApp, p: &serde_json::Value) -> Result<serde_json::Value, String> {
|
||||
let mut rest = p.as_object().cloned().unwrap_or_default();
|
||||
if let Some(page) = rest.remove("open") {
|
||||
@@ -1450,8 +1451,10 @@ pub fn control(app: &mut SolveApp, p: &serde_json::Value) -> Result<serde_json::
|
||||
app.prefs_window.snapshot = Some(Snapshot::take(app));
|
||||
}
|
||||
}
|
||||
if rest.remove("stand_up").and_then(|v| v.as_bool()) == Some(true) {
|
||||
crate::stand_up::stand_up(app)?;
|
||||
match rest.remove("stand_up").and_then(|v| v.as_bool()) {
|
||||
Some(true) => crate::stand_up::stand_up(app)?,
|
||||
Some(false) => crate::stand_up::leave(app),
|
||||
None => {}
|
||||
}
|
||||
let button = rest.remove("button");
|
||||
let mut out = set(app, &serde_json::Value::Object(rest))?;
|
||||
|
||||
@@ -36,6 +36,12 @@ pub fn stand_up(app: &mut SolveApp) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Dismiss the offer and keep the file as it opened ("Leave it"); the preference stays on.
|
||||
pub fn leave(app: &mut SolveApp) {
|
||||
app.stand_up = None;
|
||||
app.stand_up_occurrence = None;
|
||||
}
|
||||
|
||||
/// The offer, under the toolbar.
|
||||
pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
if app.stand_up.is_none() {
|
||||
@@ -52,13 +58,21 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
ui.label(crate::i18n::tr_label("Stand it up: a quarter turn about X, as one Move feature you can undo."));
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button(crate::i18n::tr_label("Stand it up")).clicked() {
|
||||
let stand = ui.button(crate::i18n::tr_label("Stand it up"));
|
||||
crate::scenario::publish_handle("stand_up:stand", stand.rect.center());
|
||||
if stand.clicked() {
|
||||
act = Some("stand");
|
||||
}
|
||||
if ui.button(crate::i18n::tr_label("Leave it")).clicked() {
|
||||
let leave = ui.button(crate::i18n::tr_label("Leave it"));
|
||||
crate::scenario::publish_handle("stand_up:leave", leave.rect.center());
|
||||
if leave.clicked() {
|
||||
act = Some("leave");
|
||||
}
|
||||
if ui.button("Don't ask again").on_hover_text("Preferences › Design turns the offer back on").clicked() {
|
||||
let never = ui
|
||||
.button(crate::i18n::tr_label("Don't ask again"))
|
||||
.on_hover_text(crate::i18n::tr_label("Preferences › Design turns the offer back on"));
|
||||
crate::scenario::publish_handle("stand_up:never", never.rect.center());
|
||||
if never.clicked() {
|
||||
act = Some("never");
|
||||
}
|
||||
});
|
||||
@@ -69,13 +83,9 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
app.set_status(e, true);
|
||||
}
|
||||
}
|
||||
Some("leave") => {
|
||||
app.stand_up = None;
|
||||
app.stand_up_occurrence = None;
|
||||
}
|
||||
Some("leave") => leave(app),
|
||||
Some("never") => {
|
||||
app.stand_up = None;
|
||||
app.stand_up_occurrence = None;
|
||||
leave(app);
|
||||
app.preferences.offer_stand_up = false;
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
//! The "Stand this part up?" offer can be answered by handle (#1905): its buttons are published
|
||||
//! as `stand_up:stand`, `stand_up:leave` and `stand_up:never`, it stays up through a camera move
|
||||
//! and a command until answered, and `ui.prefs {"stand_up": false}` leaves the file as it is.
|
||||
use serde_json::json;
|
||||
use solidcraft_ui_egui::scenario::Harness;
|
||||
|
||||
/// A harness with a 10 × 40 × 5 mm box (Y up) just opened from STEP: the offer is up.
|
||||
fn opened() -> Harness {
|
||||
let mut src = Harness::new();
|
||||
let path = src.dir.join("tall_in_y.step").to_string_lossy().into_owned();
|
||||
src.app.run("solid.box", json!({"length": 10, "width": 40, "height": 5})).unwrap();
|
||||
src.app.run("file.export", json!({"path": path})).unwrap();
|
||||
let mut h = Harness::new();
|
||||
h.app.open_path(&path);
|
||||
h.frames(3);
|
||||
assert_eq!(h.app.stand_up.as_ref().map(Vec::len), Some(1), "the file's body is offered");
|
||||
h
|
||||
}
|
||||
|
||||
fn height(h: &Harness) -> f64 {
|
||||
let b = solidcraft_engine::view::bounds(&h.app.session);
|
||||
b.max.z - b.min.z
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_offer_buttons_are_handles() {
|
||||
let mut h = opened();
|
||||
for name in ["stand_up:stand", "stand_up:leave", "stand_up:never"] {
|
||||
assert!(h.at(&json!({"handle": name})).is_ok(), "{name} is published");
|
||||
}
|
||||
// Unanswered, it stays up through a camera move and a command.
|
||||
h.run(&json!([{"camera": {"yaw": 0.6, "pitch": 0.4}}, {"call": "engine.execute", "params": {"command": "solid.box", "params": {"length": 1, "width": 1, "height": 1}}}]))
|
||||
.unwrap();
|
||||
h.frames(3);
|
||||
assert!(h.app.stand_up.is_some(), "the offer waits for an answer");
|
||||
h.run(&json!([{"click": {"handle": "stand_up:stand"}}])).unwrap();
|
||||
h.frames(3);
|
||||
assert!(h.app.stand_up.is_none());
|
||||
assert!((height(&h) - 40.0).abs() < 1e-6, "stood up: {}", height(&h));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leave_it_keeps_the_file_and_the_preference() {
|
||||
let mut h = opened();
|
||||
h.run(&json!([{"click": {"handle": "stand_up:leave"}}])).unwrap();
|
||||
h.frames(3);
|
||||
assert!(h.app.stand_up.is_none());
|
||||
assert!(h.app.preferences.offer_stand_up);
|
||||
assert!((height(&h) - 5.0).abs() < 1e-6);
|
||||
assert!(h.at(&json!({"handle": "stand_up:leave"})).is_err(), "the offer is gone");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_ask_again_turns_the_offer_off() {
|
||||
let mut h = opened();
|
||||
h.run(&json!([{"click": {"handle": "stand_up:never"}}])).unwrap();
|
||||
h.frames(3);
|
||||
assert!(h.app.stand_up.is_none());
|
||||
assert!(!h.app.preferences.offer_stand_up);
|
||||
assert!((height(&h) - 5.0).abs() < 1e-6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prefs_stand_up_false_leaves_the_offer() {
|
||||
let mut h = opened();
|
||||
let r = h.call("ui.prefs", json!({"stand_up": false}));
|
||||
assert_eq!(r["result"]["stand_up_offer"], json!(null), "{r}");
|
||||
assert_eq!(r["result"]["offer_stand_up"], json!(true), "{r}");
|
||||
assert!((height(&h) - 5.0).abs() < 1e-6);
|
||||
}
|
||||
Reference in new issue
Block a user