git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit4d487080d3c2d1780b662b555ace220cf6ecab76
parent8c833a269b
authorLucas Galante <[email protected]>
date2026-08-03 12:53
feat: cce-bevel persists plate opacity to its per-app config

window { opacity } in ~/.config/cce/cce-bevel/config.kdl — the popup's
own look, deliberately not the DE-wide material, so it lives in the
per-app slot instead of the shared config.kdl. Seeded at startup
(falling back to the DE backplate opacity), written whenever the
transparency dialog closes (toggle, press-outside, Escape) and on Save.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/bin/cce-bevel.rs | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/src/bin/cce-bevel.rs b/src/bin/cce-bevel.rs
index 2362a42..299d786 100644
--- a/src/bin/cce-bevel.rs
+++ b/src/bin/cce-bevel.rs
@@ -405,6 +405,9 @@ impl BevelPopup {
         }
         if self.opacity_button.take_click() {
             self.opacity_open = !self.opacity_open;
+            if !self.opacity_open {
+                self.persist_opacity();
+            }
             self.needs_rebuild = true;
         }
         if self.opacity_slider.take_change() {
@@ -414,6 +417,23 @@ impl BevelPopup {
         }
     }
 
+    /// Persist the plate opacity to THIS APP's config
+    /// (`~/.config/cce/cce-bevel/config.kdl`, `window { opacity }`) — a
+    /// per-popup look, not the DE-wide material, so it deliberately does not
+    /// touch the shared config.kdl. Runs when the dialog closes and on Save.
+    fn persist_opacity(&mut self) {
+        let path = cce_ui::config::get_app_config_path("cce-bevel");
+        let p = path.to_string_lossy().into_owned();
+        if cce_ui::config::write_config_value(
+            &p,
+            "window.opacity",
+            &format!("{:.3}", self.plate_opacity),
+            "window",
+        ) {
+            println!("opacity-saved {p}");
+        }
+    }
+
     /// Persist the current material to the shared config
     /// (`style.surface.relief` — the same keys every app reads at startup).
     /// Untouched sections write the identity sentinel (= analytic); the knob
@@ -442,6 +462,7 @@ impl BevelPopup {
         } else {
             "Save FAILED — see config.kdl permissions.".to_string()
         };
+        self.persist_opacity();
     }
 
     /// Back to the analytic material, live only (Save persists it): knobs to
@@ -488,6 +509,17 @@ impl Application for BevelPopup {
         let width = cce_ui::layout::bevel_width();
         let (dmin, dmax) = DEPTH_RANGE;
         let (wmin, wmax) = WIDTH_RANGE;
+        // The persisted per-app plate opacity, falling back to the DE look.
+        let plate_opacity = std::fs::read_to_string(cce_ui::config::get_app_config_path("cce-bevel"))
+            .ok()
+            .map(|c| cce_ui::config::parse_kdl_to_json(&c))
+            .and_then(|v| {
+                v.get("window")
+                    .and_then(|w| w.get("opacity"))
+                    .and_then(|o| o.as_f64())
+                    .map(|f| (f as f32).clamp(0.0, 1.0))
+            })
+            .unwrap_or_else(|| cce_ui::color::active_backplate_opacity());
         Self {
             profile_dropdown: Dropdown::new(
                 vec![
@@ -520,13 +552,13 @@ impl Application for BevelPopup {
             opacity_button: Button::new(0.0, 0.0, 0.0, 0.0).with_label("Opacity"),
             opacity_slider: Slider::new()
                 .with_label("Opacity")
-                .with_value(cce_ui::color::active_backplate_opacity().clamp(0.0, 1.0))
+                .with_value(plate_opacity)
                 .with_readout(true)
                 .with_decimals(2)
                 .with_scroll(true)
                 .with_band(true),
             opacity_open: false,
-            plate_opacity: cce_ui::color::active_backplate_opacity(),
+            plate_opacity,
             dialog_rect: Rect::ZERO,
             opacity_btn_rect: Rect::ZERO,
             status: "Edits apply live; Save writes config.kdl.".to_string(),
@@ -836,6 +868,7 @@ impl Application for BevelPopup {
             };
             if !inside(d) && !inside(b) {
                 self.opacity_open = false;
+                self.persist_opacity();
                 *needs_rebuild = true;
                 self.needs_rebuild = true;
                 return None;
@@ -901,6 +934,7 @@ impl Application for BevelPopup {
             if event.logical_key == Key::Named(NamedKey::Escape) {
                 if self.opacity_open {
                     self.opacity_open = false;
+                    self.persist_opacity();
                     *needs_rebuild = true;
                     self.needs_rebuild = true;
                     return None;