New tab: no stale fillet preview, and + always opens a tab (#1533)
Co-Authored-By: Pablo López <pablopeza@users.noreply.github.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
3 files changed
+67
-3
No files matched your search
@@ -99,7 +99,7 @@ fn swap_in(app: &mut SolveApp, slot: DocSlot) -> DocSlot {
|
||||
app.cancel_view_animation();
|
||||
app.viewport.orbit_snap = None;
|
||||
app.viewport.orbit_free = None;
|
||||
app.preview = crate::preview::PreviewState::default();
|
||||
app.preview.reset();
|
||||
app.viewport.hover = None;
|
||||
app.menu.props = None;
|
||||
crate::sketch_attachment_ui::clear(app);
|
||||
@@ -199,6 +199,24 @@ pub fn new_design(app: &mut SolveApp) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The tab strip's +: always a new tab, except over the blank design the start page covers
|
||||
/// (a launch), which New takes as [`new_design`] does.
|
||||
pub fn new_tab(app: &mut SolveApp) {
|
||||
if app.file_picker_busy() {
|
||||
return;
|
||||
}
|
||||
if app.home.open && active_is_blank(app) {
|
||||
new_design(app);
|
||||
return;
|
||||
}
|
||||
app.home.open = false;
|
||||
if let Err(e) = open_tab(app, Session::default()) {
|
||||
app.set_status(e, true);
|
||||
} else {
|
||||
crate::prefs::apply_new_design(app);
|
||||
}
|
||||
}
|
||||
|
||||
/// Before opening a file: a fresh tab unless the active design is blank. The empty design,
|
||||
/// new or already showing, takes Units of new designs so a cancelled open is not millimetres
|
||||
/// when the preference says otherwise.
|
||||
@@ -455,7 +473,7 @@ pub fn tabs(app: &mut SolveApp, ui: &mut egui::Ui, r: Rect, x0: f32, x1: f32) {
|
||||
// A file loading into the window keeps the tabs as they are (dragging still moves it).
|
||||
let idle = !app.file_load.busy();
|
||||
if presp.on_hover_text("New Design (Ctrl+N)").clicked() && idle {
|
||||
new_design(app);
|
||||
new_tab(app);
|
||||
}
|
||||
match (shut, pick) {
|
||||
_ if !idle => {}
|
||||
@@ -703,6 +721,21 @@ mod tests {
|
||||
assert!(active_is_blank(&a) && a.home.open);
|
||||
}
|
||||
|
||||
/// The tab strip's + opens a tab every time, an empty design's included; over the start
|
||||
/// page's blank design (a launch) it uses that design.
|
||||
#[test]
|
||||
fn plus_opens_a_tab_every_time() {
|
||||
let mut a = app();
|
||||
a.home.open = true;
|
||||
new_tab(&mut a);
|
||||
assert_eq!(a.docs.count(), 1, "the launch's blank design is used");
|
||||
assert!(!a.home.open);
|
||||
new_tab(&mut a);
|
||||
new_tab(&mut a);
|
||||
assert_eq!(a.docs.count(), 3);
|
||||
assert_eq!(a.docs.active, 2);
|
||||
}
|
||||
|
||||
/// Quitting asks once per design with unsaved changes: Don't Save moves on (and keeps no
|
||||
/// recovery copy), Save saves and moves on, and the app quits after the last answer.
|
||||
#[test]
|
||||
|
||||
@@ -642,7 +642,7 @@ impl SolveApp {
|
||||
// applying cancellation hooks (such as restoring its timeline marker).
|
||||
self.dialog = None;
|
||||
self.tool = None;
|
||||
self.preview = preview::PreviewState::default();
|
||||
self.preview.reset();
|
||||
self.cam = Camera::default();
|
||||
self.fit_view();
|
||||
}
|
||||
|
||||
@@ -118,6 +118,15 @@ impl PreviewState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Drop the preview of a design that leaves the window. Its scene goes too: the viewport
|
||||
/// keeps drawing the last scene it took until the slot it reads hands it another, so a fresh
|
||||
/// state (another slot, empty) would leave the old preview drawn over the next design.
|
||||
pub fn reset(&mut self) {
|
||||
let (slot, key) = (std::mem::take(&mut self.slot), self.key);
|
||||
*self = PreviewState { slot, key, ..PreviewState::default() };
|
||||
self.set_scene(GpuScene::default());
|
||||
}
|
||||
|
||||
fn set_scene(&mut self, sc: GpuScene) {
|
||||
if let Ok(mut slot) = self.slot.lock() {
|
||||
*slot = Some(sc);
|
||||
@@ -1052,6 +1061,28 @@ mod tests {
|
||||
pv.poll(4, None);
|
||||
assert!(pv.error.is_none() && pv.shown_key == Some(1), "an old error is dropped");
|
||||
}
|
||||
|
||||
/// A design leaving the window (another tab) takes its preview off the viewport: an empty
|
||||
/// scene in the slot the viewport reads, under a new key. A fresh slot left the fillet
|
||||
/// preview of the old design drawn over the new tab's empty design.
|
||||
#[test]
|
||||
fn reset_hands_the_viewport_an_empty_scene() {
|
||||
let mut pv = PreviewState::default();
|
||||
let mut sc = GpuScene::default();
|
||||
sc.xray_tri([0.0; 3], [0.0, 0.0, 1.0], [255; 4]);
|
||||
pv.set_scene(sc);
|
||||
pv.active = true;
|
||||
pv.replaced = vec!["Body1".into()];
|
||||
let slot = pv.slot.clone();
|
||||
let key = pv.key;
|
||||
// The viewport took the scene.
|
||||
assert!(slot.lock().unwrap().take().is_some_and(|s| !s.xray.is_empty()));
|
||||
pv.reset();
|
||||
assert!(std::sync::Arc::ptr_eq(&slot, &pv.slot), "the slot the viewport reads");
|
||||
assert_ne!(pv.key, key, "a new key: the viewport takes the slot again");
|
||||
assert!(slot.lock().unwrap().as_ref().is_some_and(|s| s.xray.is_empty() && s.blocks.is_empty()));
|
||||
assert!(!pv.active && pv.replaced.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in new issue
Block a user