git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

commit55030fb08ec9459508601957ba5a1eb454730744
parent423268f55c
authorLucas Galante <lsgalante12@gmail.com>
date2026-09-30 12:41
refactor: a camera node has no Square Aspect or Show Camera Pivot

Both were written onto the active camera when the viewport's toggles
flipped, and read by nothing: the settings are the viewport's and ride
the project's view state. The params, their writer and its two calls
are gone, and the merge drops them from a save that still has them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 CLAUDE.md         |  3 +--
 nodes/camera.json | 12 ------------
 src/app.rs        | 38 +++++++-------------------------------
 src/main.rs       | 24 ++++++++++++++++++++++--
 4 files changed, 30 insertions(+), 47 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index d4b88a0..5b5757a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -532,8 +532,7 @@ save writes `ProjectViewState::display` — a `DisplaySettings`, the viewport
 and render blocks of `DesignSettings` without the startup pointer, taken by
 `State::display_settings` (which `save_settings` builds from as well) — and
 both `load_from_file` paths apply it through `apply_display_settings`, before
-the Default Camera view so a camera node's own Square Aspect and pivot
-still win. The apply sets every field, regenerates the baked meshes, relays
+the Default Camera view so a camera node's own Pivot still wins. The apply sets every field, regenerates the baked meshes, relays
 the two pane-shaped ones (network plate, circular pane), re-checks the
 menubar marks, and saves state.kdl, so state.kdl holds the LAST-USED look:
 what New and an older save (no block, which changes nothing) open with.
diff --git a/nodes/camera.json b/nodes/camera.json
index eb168e4..3a5a743 100644
--- a/nodes/camera.json
+++ b/nodes/camera.json
@@ -27,18 +27,6 @@
       "min": -10.0,
       "max": 10.0,
       "description": "The point in world units the camera looks at and orbits around. Panning and framing move it."
-    },
-    {
-      "name": "Square Aspect",
-      "type": "toggle",
-      "default": "false",
-      "description": "Records the viewport's Square Aspect setting (a 1:1 view) for this camera; it is updated when that toggle is flipped while this camera is active."
-    },
-    {
-      "name": "Show Camera Pivot",
-      "type": "toggle",
-      "default": "false",
-      "description": "Records the viewport's Show Camera Pivot setting for this camera; it is updated when that toggle is flipped while this camera is active."
     }
   ]
 }
diff --git a/src/app.rs b/src/app.rs
index 4c31883..febd3e9 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1135,6 +1135,13 @@ pub fn merge_template_defs(root: &mut FsNode, templates: &[NodeTemplate]) {
         }
     }
     fn merge_node(node: &mut FsNode, templates: &[NodeTemplate]) {
+        // A camera's Square Aspect and Show Camera Pivot were written when
+        // the viewport's toggles flipped under it and read by nothing: the
+        // settings are the viewport's, and ride the project's view state.
+        // Retired, and dropped from a save that still has them.
+        if node.node_type == "camera" {
+            node.params.retain(|p| p.name != "Square Aspect" && p.name != "Show Camera Pivot");
+        }
         // Visualize's Mix blend was Set under another name (Opacity fades
         // every blend alike) and is retired; a save holding it is Set, or
         // it would load as a choice the row no longer offers.
@@ -4428,34 +4435,6 @@ impl State {
         true
     }
 
-    /// Rewrite the Main node's setting toggles from live app state, so the
-    /// switches show the real value even after panes/settings were changed
-    /// through the menus or keyboard while another node was selected.
-    /// Write a per-camera display toggle (Square Aspect / Show Camera Pivot)
-    /// back to the ACTIVE camera node — the setting's home — so the next
-    /// settings apply doesn't revert a menu/shortcut flip. No-op under
-    /// Default Camera, which has no node: the live value stands alone.
-    fn write_active_camera_toggle(&mut self, name: &str, val: bool) {
-        if self.active_camera == "Default Camera" {
-            return;
-        }
-        let active = self.active_camera.clone();
-        if let Some(cam) = self
-            .current_dir_mut()
-            .children
-            .iter_mut()
-            .find(|c| c.node_type == "camera" && c.name == active)
-        {
-            if let Some(p) = cam.params.iter_mut().find(|p| p.name == name) {
-                p.set_value(crate::app::ParamValue::Bool(val));
-            }
-        }
-    }
-
-
-
-
-
     pub fn sync_parameters_pane(&mut self) {
         // Selection reads through the param-editor accessors: whichever
         // network editor took the last node click feeds the pane, at ITS
@@ -9054,7 +9033,6 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Detail) -> (Vec<String>, Vec<V
             Action::ToggleCameraPivot => {
                 let val = !self.viewport().show_camera_pivot;
                 self.viewport_mut().show_camera_pivot = val;
-                self.write_active_camera_toggle("Show Camera Pivot", val);
                 self.menu_mut(RIGHT_MENUBAR_IDX).set_item_checked(GUIDES_MENU, GUIDE_CAMERA_PIVOT, val);
                 settings_changed = true;
             }
@@ -9141,8 +9119,6 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Detail) -> (Vec<String>, Vec<V
             }
             Action::ToggleSquareViewport => {
                 self.square_viewport = !self.square_viewport;
-                let val = self.square_viewport;
-                self.write_active_camera_toggle("Square Aspect", val);
                 settings_changed = true;
             }
             Action::ToggleConfigure => {
diff --git a/src/main.rs b/src/main.rs
index 2bc4d56..076ba42 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4967,6 +4967,26 @@ mod tests {
             .expect("a known kind is added");
     }
 
+    /// A camera node has no Square Aspect or Show Camera Pivot: they were
+    /// written when the viewport's toggles flipped under it and read by
+    /// nothing. A save that has them loads without them.
+    #[test]
+    fn a_camera_carries_no_viewport_toggles() {
+        let templates_root = crate::app::load_fs_tree();
+        let templates = crate::app::flatten_node_templates(&templates_root);
+        let t = templates_root.children.iter().find(|t| t.node_type == "camera").unwrap();
+        let names: Vec<&str> = t.params.iter().map(|p| p.name.as_str()).collect();
+        assert_eq!(names, ["Position", "Rotation", "Pivot"]);
+        let mut old = t.clone();
+        old.params.push(crate::app::ParamDef::new("Square Aspect", "toggle", "true"));
+        old.params.push(crate::app::ParamDef::new("Show Camera Pivot", "toggle", "true"));
+        let mut root = templates_root.clone();
+        root.children = vec![old];
+        crate::app::merge_template_defs(&mut root, &templates);
+        let names: Vec<&str> = root.children[0].params.iter().map(|p| p.name.as_str()).collect();
+        assert_eq!(names, ["Position", "Rotation", "Pivot"]);
+    }
+
     /// Visualize's Blend has no Mix: it was Set under another name, Opacity
     /// fading every blend alike. A save that chose it loads as Set, a
     /// valid choice, rather than as a text the row no longer offers.
@@ -6744,8 +6764,8 @@ mod tests {
         let _ = std::fs::remove_dir_all(&dir);
 
         let mut a = State::new(false);
-        // The Default Camera is active: a camera NODE's own Square Aspect and
-        // pivot params would override the saved view's, by design.
+        // The Default Camera is active: a camera NODE's own Pivot would
+        // override the saved view's, by design.
         a.active_camera = "Default Camera".to_string();
         a.square_viewport = true;
         a.viewport_mut().show_camera_pivot = true;