graphic design tool
git clone https://git.lucas.co/cce-designer.git
fix: a project loaded before the first configure opens clean
The startup load takes its saved baseline while the plates sit on the
placeholder window size; the first configure re-applies the saved plate
fractions at the real size, which moved the layout key and marked the
project changed on every launch.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
src/app.rs | 9 +++++++++
src/main.rs | 32 ++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/src/app.rs b/src/app.rs
index a20768c..8ce821b 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -8690,7 +8690,16 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Detail) -> (Vec<String>, Vec<V
self.window_configured = true;
if let Some(pg) = self.pending_plates.take() {
+ // The load took its saved baseline with the plates on the
+ // placeholder size. Landing them on the real one is the load
+ // finishing, not an edit — unless something was already
+ // unsaved, which stays so.
+ let clean = !self.has_unsaved_changes();
self.apply_plate_geometry(pg);
+ if clean {
+ self.last_saved_layout_json = self.pane_layout_json();
+ self.update_window_title();
+ }
}
self.sync_layout();
diff --git a/src/main.rs b/src/main.rs
index 512c88a..5a62d82 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1429,6 +1429,38 @@ mod tests {
let _ = fs::remove_dir_all(&dir);
}
+ /// The startup load takes its saved baseline before the first configure,
+ /// with the plates on the placeholder size; the configure then lands
+ /// them on the real one. That is the load finishing, not an edit, so
+ /// the project opens clean.
+ #[test]
+ fn a_project_loaded_before_the_first_configure_opens_clean() {
+ let dir = std::env::temp_dir().join(format!("cce_designer_cleanopen_{}", std::process::id()));
+ let _ = fs::remove_dir_all(&dir);
+ fs::create_dir_all(&dir).unwrap();
+ let mut a = State::new(false);
+ a.resize(1400.0, 1080.0, 1.0);
+ a.floating_network_layout.2 = 350.0;
+ a.floating_param_width = 310.0;
+ a.rebuild_positions();
+ a.save_to_file(&dir).expect("save");
+
+ let mut b = State::new(false);
+ b.load_from_file(&dir).expect("load");
+ assert!(!b.has_unsaved_changes(), "a fresh load is clean");
+ b.resize(1400.0, 1080.0, 1.0);
+ assert!(!b.has_unsaved_changes(), "the first configure is not an edit");
+
+ // What was unsaved before the configure still is after it.
+ let mut c = State::new(false);
+ c.load_from_file(&dir).expect("load");
+ c.set_pane_collapsed(crate::slots::PARAM_IDX, true);
+ c.resize(1400.0, 1080.0, 1.0);
+ assert!(c.has_unsaved_changes(), "the configure must not hide an edit");
+
+ let _ = fs::remove_dir_all(&dir);
+ }
+
/// A window briefly narrower than its plates squeezes them for as long as
/// it lasts and no longer: the layout used to store the clamped size, so
/// one transient shrink (a re-tile, a configure at startup) left every