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

commitc80504eacdc6ba1ac1620fd7c9e74671d1d80acf
parent29edae6c44
authorLucas Galante <[email protected]>
date2026-07-21 18:21
style: rocker toggles pivot as flat angled faces, not stepped plateaus

The boss/recess halves read as steps; the pill now reads as a plate
pivoting about its horizontal midline — two flat ANGLED surfaces
meeting at the hinge: the state half tilts out into the light (uniform
white tint), the other into shadow (uniform black tint). Flat tints —
a tilted plane has one normal — so the faces are RoundedRect prims
riding the rounded-quad views and the params pane needs no toggle
relief entries at all (Toggle::rocker_reliefs is gone,
rocker_faces replaces it).

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

 src/widget/container/parameters_bg.rs | 14 ++--------
 src/widget/input/checkbox.rs          | 48 +++++++++++++++--------------------
 2 files changed, 22 insertions(+), 40 deletions(-)

diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index b1f5028..c2e5136 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -952,18 +952,8 @@ impl ParametersBg {
             } else if p.2 == "button" {
                 self.buttons[i].as_ref().map(|w| (w as &dyn WidgetHost, crate::layout::button_corner_radius(), true))
             } else if p.2 == "toggle" || p.2 == "checkbox" {
-                // The rocker halves, exactly the widget's own paint.
-                if let Some(t) = &self.toggles[i] {
-                    let (x, y, w, h) = t.rect();
-                    if w > 0.0 && h > 0.0 {
-                        let depth = crate::layout::bevel_width().min(h * 0.2);
-                        for (half, radii, edges, up) in
-                            t.inner().rocker_reliefs(Rect { x, y, width: w, height: h })
-                        {
-                            out.push((half.x, half.y, half.width, half.height, radii, depth, up, edges));
-                        }
-                    }
-                }
+                // The rocker's flat faces are RoundedRect prims — they arrive
+                // through the rounded-quad view; no relief entries.
                 None
             } else {
                 if let Some(s) = &self.sliders[i] {
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index 706043a..e0ab62c 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -265,31 +265,29 @@ impl Toggle {
         }
     }
 
-    /// The rocker's two relief halves over `rect`: (half rect, per-corner
-    /// radii, walls, raised). The STATE half — where the flat style paints its
-    /// gradient (top when on, bottom when off) — is raised; the other half is
-    /// recessed. The raised half owns the seam wall (all four edges), the
-    /// recessed half skips it, so the middle reads as one step down. Shared by
-    /// `paint` and hosts on the legacy relief views (`ParametersBg::reliefs`).
-    pub fn rocker_reliefs(
+    /// The rocker's two flat faces over `rect`: (half rect, corner flags,
+    /// tint). The pill reads as a plate pivoting about its horizontal midline —
+    /// two flat ANGLED surfaces meeting at the hinge, not stepped plateaus: the
+    /// STATE half (top when on, bottom when off) tilts out and catches the
+    /// light (white tint), the other tilts away into shadow (black tint). Flat
+    /// uniform tints — a tilted plane has one normal — so the faces flow
+    /// through the rounded-quad views with no relief machinery.
+    pub fn rocker_faces(
         &self,
         rect: Rect,
-    ) -> [(Rect, (f32, f32, f32, f32), (bool, bool, bool, bool), bool); 2] {
-        let r = crate::layout::toggle_corner_radius();
+    ) -> [(Rect, (bool, bool, bool, bool), [f32; 4]); 2] {
+        const LIT: [f32; 4] = [1.0, 1.0, 1.0, 0.10];
+        const SHADED: [f32; 4] = [0.0, 0.0, 0.0, 0.16];
         let half_h = rect.height / 2.0;
         let top = Rect { x: rect.x, y: rect.y, width: rect.width, height: half_h };
         let bottom =
             Rect { x: rect.x, y: rect.y + half_h, width: rect.width, height: rect.height - half_h };
+        let top_corners = (true, true, false, false);
+        let bottom_corners = (false, false, true, true);
         if self.toggled {
-            [
-                (top, (r, r, 0.0, 0.0), (true, true, true, true), true),
-                (bottom, (0.0, 0.0, r, r), (false, true, true, true), false),
-            ]
+            [(top, top_corners, LIT), (bottom, bottom_corners, SHADED)]
         } else {
-            [
-                (bottom, (0.0, 0.0, r, r), (true, true, true, true), true),
-                (top, (r, r, 0.0, 0.0), (true, true, false, true), false),
-            ]
+            [(bottom, bottom_corners, LIT), (top, top_corners, SHADED)]
         }
     }
 }
@@ -351,10 +349,9 @@ impl Paint for Toggle {
         let bg = colors::toggle_bg_color();
 
         if self.raised {
-            // The rocker: the state half raised, the other recessed — the
-            // physical read of the flat style's state gradient, which this
-            // style drops entirely. The halves' outer walls trace the pill
-            // silhouette, so no full-pill bevel is drawn under them.
+            // The rocker: two flat angled faces pivoting about the midline
+            // (see `rocker_faces`) — the physical read of the flat style's
+            // state gradient, which this style drops entirely.
             if bg[3] > 0.001 {
                 if radius > 0.0 {
                     ctx.rounded_rect(rect, radius, (true, true, true, true), bg);
@@ -362,13 +359,8 @@ impl Paint for Toggle {
                     ctx.quad(rect, bg);
                 }
             }
-            let depth = crate::layout::bevel_width().min(h * 0.2);
-            for (half, radii, edges, up) in self.rocker_reliefs(rect) {
-                if up {
-                    ctx.boss_edges(half, radii, depth, edges);
-                } else {
-                    ctx.recess_edges(half, radii, depth, edges);
-                }
+            for (half, corners, tint) in self.rocker_faces(rect) {
+                ctx.rounded_rect(half, radius, corners, tint);
             }
         } else if radius > 0.0 {
             ctx.rounded_rect(rect, radius, (true, true, true, true), bg);