GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat: ParametersBg reliefs view — control_relief for legacy-view hosts
The control_relief styling (boss rims, recess wells) lives only in the
widgets' modern paint(), so a host rendering the panel through the
legacy flat views (plain/rounded quads) lost it entirely — with the
DE's transparent control backgrounds the controls all but vanished.
reliefs() returns the row controls' relief steps as edges-only variants
(the flat views own the faces, the widgets' own transparent-fill
bevel→boss degradation), plus Slider::track_relief for the recessed
track's sub-rect carve.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/widget/container/parameters_bg.rs | 55 +++++++++++++++++++++++++++++++++++
src/widget/input/slider.rs | 14 +++++++++
2 files changed, 69 insertions(+)
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index c0bd54b..33f952d 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -891,6 +891,61 @@ impl ParametersBg {
out
}
+ /// The relief companion to [`Self::rounded_quads`]: the row controls'
+ /// raised/recessed step prims (boss rims, recess wells), which the flat
+ /// views cannot carry — a host rendering this panel through the legacy
+ /// views must read this getter too or the `control_relief` styling is lost
+ /// entirely (with the DE's transparent control backgrounds the controls all
+ /// but vanish). Edges-only variants throughout: the flat views own the
+ /// faces, exactly the widgets' own transparent-fill bevel→boss degradation.
+ /// Returned unclipped; the host clips to the pane's scroll viewport and
+ /// draws these AFTER the flat quads, so the walls' shading modulates the
+ /// fills they cross (the order the widgets' own paints use). Tuple:
+ /// (x, y, w, h, radius, depth, raised) — raised maps to `PaintCtx::boss`,
+ /// flat to `PaintCtx::recess`.
+ pub fn reliefs(&self) -> Vec<(f32, f32, f32, f32, f32, f32, bool)> {
+ if !self.visible || !crate::layout::control_relief() {
+ return Vec::new();
+ }
+ let mut out = Vec::new();
+ let hidden = self.hidden_rows();
+ for (i, p) in self.display_params.iter().enumerate() {
+ if hidden[i] {
+ continue;
+ }
+ // (control, its configured corner radius, raised vs recessed)
+ let ctl: Option<(&dyn WidgetHost, f32, bool)> = if p.2 == "text" {
+ self.texts[i].as_ref().map(|w| (w as &dyn WidgetHost, crate::layout::textbox_corner_radius(), false))
+ } else if p.2.starts_with("choice") {
+ self.choices[i].as_ref().map(|w| (w as &dyn WidgetHost, crate::layout::dropdown_corner_radius(), true))
+ } 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" {
+ self.toggles[i].as_ref().map(|w| (w as &dyn WidgetHost, crate::layout::toggle_corner_radius(), true))
+ } else {
+ if let Some(s) = &self.sliders[i] {
+ let (x, y, w, h) = s.rect();
+ if let Some((rx, ry, rw, rh, rr, rd)) = s.inner().track_relief(Rect { x, y, width: w, height: h }) {
+ out.push((rx, ry, rw, rh, rr, rd, false));
+ }
+ }
+ None
+ };
+ if let Some((w, radius, raised)) = ctl {
+ let (x, y, ww, h) = w.rect();
+ if ww <= 0.0 || h <= 0.0 {
+ continue;
+ }
+ // The side-label inset the widget's own paint applies (0 for the
+ // exempt kinds — button, toggle).
+ let lx = w.label_x_offset();
+ let depth = crate::layout::bevel_width().min(h * 0.2);
+ out.push((x + lx, y, ww - lx, h, radius, depth, raised));
+ }
+ }
+ out
+ }
+
}
impl Layout for ParametersBg {
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index 24e721a..5b0c96c 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -112,6 +112,20 @@ impl Slider {
}
}
+ /// The recessed track's carve for hosts that draw this control through the
+ /// legacy flat views (see `ParametersBg::reliefs`): (x, y, w, h, radius,
+ /// depth) over the widget's assigned `rect`, or None when the style is off.
+ /// The same geometry `paint` carves.
+ pub fn track_relief(&self, rect: Rect) -> Option<(f32, f32, f32, f32, f32, f32)> {
+ if !self.recessed {
+ return None;
+ }
+ let g = self.geom(rect);
+ let radius = crate::layout::slider_corner_radius();
+ let depth = crate::layout::bevel_width().min(g.h * 0.2);
+ Some((g.track_x, g.y, g.track_w, g.h, radius, depth))
+ }
+
fn geom(&self, rect: Rect) -> SliderGeom {
let side = side_offset(&self.label);
let x = rect.x + side;