GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
ColorSelector: keep the alpha checker out of the legacy plain-quad view
The rgba preview paints its checker in the right order — grey base,
white cells, the colour fill over them — but the cells were plain
quads, and the adapter's legacy plain-quad view (own_plain_quads) is
the paint filtered to Prim::Quad: it carried the cells and not the
rounded fill above them. A host that reads that view beside the paint
(the designer, through ParametersBg::plain_quads) draws it AFTER the
prims, so the cells landed a second time OVER the colour: every colour
but white showed a black-and-white checker as if it were transparent.
Invisible with the default white, which is how it hid.
The cells are zero-radius rounded rects now — the same pixels, out of
the plain view, nothing drawn twice. A test paints an opaque black
swatch and asserts the cells sit under the fill, none is a plain quad,
and the adapter's plain view carries no white cell.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
src/widget/input/color_selector.rs | 53 +++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/src/widget/input/color_selector.rs b/src/widget/input/color_selector.rs
index 25b2f49..bc063f3 100644
--- a/src/widget/input/color_selector.rs
+++ b/src/widget/input/color_selector.rs
@@ -359,6 +359,15 @@ impl Paint for ColorSelector {
ctx.rounded_rect(swatch, sr, right_end, [0.8, 0.8, 0.8, 1.0]);
// The white cells, those at the right edge trimmed to the end's
// arc at their own row (the Breadcrumb's banded-wash sampling).
+ //
+ // Zero-radius rounded rects, NOT plain quads. The adapter's
+ // legacy plain-quad view (`own_plain_quads`) is this paint
+ // filtered to `Prim::Quad`, and a host that reads that view
+ // beside the paint — the designer, through ParametersBg's
+ // `plain_quads` — draws it AFTER the prims. As quads the
+ // cells came back a second time OVER the colour fill below,
+ // so every colour but white showed a checker as if it were
+ // transparent (invisible with the default white, 2026-09-21).
let grid = 6.0;
let cols = (swatch.width / grid).ceil() as i32;
let rows = (swatch.height / grid).ceil() as i32;
@@ -381,7 +390,12 @@ impl Paint for ColorSelector {
let right_edge = swatch.x + swatch.width - arc(qy + qh * 0.5);
let qw = grid.min(right_edge - qx);
if qw > 0.0 && qh > 0.0 {
- ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, [1.0, 1.0, 1.0, 1.0]);
+ ctx.rounded_rect(
+ Rect { x: qx, y: qy, width: qw, height: qh },
+ 0.0,
+ (false, false, false, false),
+ [1.0, 1.0, 1.0, 1.0],
+ );
}
}
}
@@ -1035,5 +1049,42 @@ mod tests {
assert_eq!(cs.color, [255, 0, 0]);
assert_eq!(cs.alpha, 171);
}
+ /// The alpha preview's checker must not reach the legacy plain-quad
+ /// view: a host that draws that view beside the paint draws it AFTER the
+ /// prims, and the white cells then landed over the colour fill — a black
+ /// swatch read as a black-and-white checker. The paint keeps its order
+ /// (base, cells, colour on top) and the plain view carries no cells.
+ #[test]
+ fn alpha_checker_stays_out_of_the_plain_quad_view() {
+ use crate::scene::paint::Prim;
+ let mut cs = ColorSelector::new_rgba([0, 0, 0, 255]);
+ cs.recessed = Some(true);
+ let rect = Rect { x: 0.0, y: 0.0, width: 200.0, height: 40.0 };
+ crate::widget::WidgetHost::set_rect(&mut cs, rect.x, rect.y, rect.width, rect.height);
+ let mut pc = PaintCtx::new();
+ let inner: &ColorSelector = &cs;
+ crate::widget::Paint::paint(inner, rect, &mut pc);
+ let items = pc.finish().items;
+ let last_fill = items
+ .iter()
+ .rposition(|it| matches!(it.prim, Prim::RoundedRect { color, .. } if color == [0.0, 0.0, 0.0, 1.0]))
+ .expect("the colour fill is painted");
+ let white_cells: Vec<usize> = items
+ .iter()
+ .enumerate()
+ .filter(|(_, it)| matches!(it.prim, Prim::RoundedRect { color, radius, .. } if color == [1.0; 4] && radius == 0.0))
+ .map(|(i, _)| i)
+ .collect();
+ assert!(!white_cells.is_empty(), "the checker is painted");
+ assert!(white_cells.iter().all(|&i| i < last_fill), "every cell is under the colour fill");
+ assert!(
+ !items.iter().any(|it| matches!(it.prim, Prim::Quad { color, .. } if color == [1.0; 4])),
+ "no cell is a plain quad, so the legacy plain view cannot carry it"
+ );
+ let plain = crate::widget::WidgetHost::extra_quads(&cs);
+ assert!(plain.iter().all(|q| q.4 != [1.0, 1.0, 1.0, 1.0]), "the plain view has no white cells: {plain:?}");
+ }
+
}
+