GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
paint: Paint::paint_ui — the ui-aware hook paint_self runs; ParametersBg completes it
paint_self now routes through Paint::paint_ui(ui, rect, ctx), whose
default forwards to paint() — a behavioral no-op for every ordinary
widget. Composites whose own geometry aggregates context-dependent child
chrome (ParametersBg: rounded_quads takes the UiContext for the child
controls' all_rounded_quads) had no way to reach the context from the
paint path, leaving their modern emission incomplete forever.
ParametersBg::paint_ui emits the COMPLETE row chrome in the hosts'
canonical order: rounded wells, outline arcs, relief steps, section
throat fillets, slider-thumb spheres, scene rows, then the flat quads.
Plate, scrollbar, and text stay out by design — color() carries the
plate, hosts place the scrollbar's depth, and paint_self's own-labels
bridge carries per-row fonts and code-box bounds. Hosts clip to their
pane viewport (a rect clip pushed inside would not survive paint_self's
replay, which restores only clip_circle).
The uiless paint() keeps its old body for direct callers.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/widget/container/parameters_bg.rs | 44 ++++++++++++++++++++++++++++++++---
src/widget/model.rs | 11 ++++++++-
2 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index a1126af..200d3ff 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -1362,9 +1362,47 @@ impl Paint for ParametersBg {
Some(crate::layout::control_label_font())
}
- /// Scene-path emission (the designer renders through the legacy hatches instead): the row
- /// chrome plus the viewport-filtered labels. The background plate stays out — see
- /// [`color`](Paint::color).
+ /// The COMPLETE row chrome — everything the legacy hatches carry, in the hosts' canonical
+ /// draw order: the controls' rounded wells, the flat-style section outline fillets, the
+ /// relief steps (after the fills so the walls shade what they cross), the section carves'
+ /// concave throat fillets, the slider-thumb spheres, the scene-path rows, then the flat
+ /// plain-quad chrome. What stays OUT, deliberately: the background plate (see
+ /// [`color`](Paint::color)), the scrollbar (hosts place its depth — the designer straddles
+ /// it around the pane plate), and text (`paint_self`'s own-labels bridge carries the
+ /// per-row fonts and code-box bounds). Hosts clip this to their pane viewport — a rect
+ /// clip pushed here would not survive `paint_self`'s replay.
+ fn paint_ui(&self, ui: &UiContext, _rect: Rect, ctx: &mut PaintCtx) {
+ if !self.visible {
+ return;
+ }
+ for (qx, qy, qw, qh, qr, qc, corners) in self.rounded_quads(ui) {
+ ctx.rounded_rect(Rect { x: qx, y: qy, width: qw, height: qh }, qr, corners, qc);
+ }
+ for (acx, acy, ar, at, a0, a1, ac) in self.arcs() {
+ ctx.arc(acx, acy, ar, at, a0, a1, ac);
+ }
+ for (rx, ry, rw, rh, radii, rd, raised, edges) in self.reliefs() {
+ if raised {
+ ctx.boss_edges(Rect { x: rx, y: ry, width: rw, height: rh }, radii, rd, edges);
+ } else {
+ ctx.recess_edges(Rect { x: rx, y: ry, width: rw, height: rh }, radii, rd, edges);
+ }
+ }
+ for (fcx, fcy, fr, fd, fs) in self.section_fillets() {
+ ctx.concave_fillet(fcx, fcy, fr, fd, fs, false);
+ }
+ for (scx, scy, sr, sc) in self.spheres() {
+ ctx.sphere(scx, scy, sr, sc);
+ }
+ self.paint_scene_rows(ctx);
+ for (qx, qy, qw, qh, qc) in self.plain_quads() {
+ ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
+ }
+ }
+
+ /// Ui-less emission (the [`paint_ui`](Paint::paint_ui) override above is what `paint_self`
+ /// runs): the flat subset plus the scrollbar, kept for direct callers only. The background
+ /// plate stays out — see [`color`](Paint::color).
fn paint(&self, _rect: Rect, ctx: &mut PaintCtx) {
for (qx, qy, qw, qh, qc) in self.plain_quads() {
ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 6959633..808cf5a 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -165,6 +165,15 @@ pub trait Paint {
}
}
+ /// [`paint`](Paint::paint) with the live [`UiContext`] — what `paint_self` actually calls.
+ /// The default forwards to `paint`, so ordinary widgets implement only that. Override this
+ /// for composites whose own geometry aggregates hover/coverage-dependent child chrome that
+ /// needs the context (ParametersBg): child-holding widgets that never entered the arena tree
+ /// have no other way to reach it from the paint path.
+ fn paint_ui(&self, _ui: &UiContext, rect: Rect, ctx: &mut PaintCtx) {
+ self.paint(rect, ctx);
+ }
+
/// Whether the paint walk clips this widget's children to its `rect` (scroll/backplate
/// containers). Default: no.
fn clips_children(&self) -> bool {
@@ -1244,7 +1253,7 @@ impl<W: Layout + Paint + Input + 'static> WidgetHost for Adapted<W> {
fn paint_self(&self, ui: &UiContext, ctx: &mut PaintCtx) {
let mut tmp = PaintCtx::new();
- Paint::paint(&self.inner, self.content_rect(), &mut tmp);
+ Paint::paint_ui(&self.inner, ui, self.content_rect(), &mut tmp);
// Subtree painters (paints_own_subtree) author their COMPLETE text in paint() —
// per-child fonts and clip bounds included — so their Text prims pass through
// verbatim and the single-font own-labels re-derivation below is skipped