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

commit3791b031577429f8267fa98d6b12fa344fc27976
parentb7893de2ce
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-08 17:50
refactor(widget): the legacy tuple views are gone

extra_quads, extra_arcs, extra_circles, all_quads, all_rounded_quads,
highlight_quad and the host-side corner_style leave WidgetHostExt, with the
Paint hooks that served only them (serves_legacy_plain_quads /
legacy_plain_quads, aggregates_child_extra_quads, forwarded_highlight), the
painter's paint_legacy_leaf and the tessellator's widget_vertices /
push_widget_vertices. Every app host already paints through paint_self.

The toolkit's own readers: ParametersBg, the ramp and the menubar read their
children's painted prims (widget::shown_prims / shown_quads /
shown_rounded_quads, crate-private); Adapted::paint_self computes the
TextBox's focus highlight itself; corner_radii and the flat-host bridge read
Paint::corner_style, which stays as what a widget says about its
silhouette. append_widget_plate is the plate alone: it also drew the
widget's arcs, which a host painting the widget after it drew twice. The
WidgetHost::paint_self default (test shims only) is the plate plus the
model's non-text prims. Tests that asserted on the views read painted_prims.

Pixel A/B in a scale-2 shadow: the designer (five pane layouts) and the
gallery identical before and after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 CLAUDE.md                             |  29 ++--
 docs/rfc-core-rebuild.md              |  13 ++
 src/backend/tessellate.rs             |  19 ---
 src/engine.rs                         |   2 +-
 src/layout/bridge.rs                  |   3 +-
 src/scene/paint.rs                    |   6 +-
 src/scene/painter.rs                  |  41 +-----
 src/widget/container/menu.rs          |  20 ++-
 src/widget/container/paginator.rs     |  43 ++----
 src/widget/container/parameters_bg.rs |  95 +++++--------
 src/widget/container/spreadsheet.rs   |   2 +-
 src/widget/container/treelist.rs      |   3 +-
 src/widget/display/graph.rs           |  58 ++++----
 src/widget/display/progress_bar.rs    |  13 +-
 src/widget/display/separator.rs       |   2 +-
 src/widget/display/status_bar.rs      |   9 +-
 src/widget/display/status_dot.rs      |   4 +-
 src/widget/display/usage_bar.rs       |   6 +-
 src/widget/input/button.rs            |   5 +-
 src/widget/input/checkbox.rs          |   5 +-
 src/widget/input/color_selector.rs    |   2 +-
 src/widget/input/ramp.rs              |   9 +-
 src/widget/input/slider.rs            |   5 +-
 src/widget/input/text_box.rs          |  19 +--
 src/widget/mod.rs                     | 258 ++++++++--------------------------
 src/widget/model.rs                   |  79 ++---------
 26 files changed, 236 insertions(+), 514 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 6b20c7c..f7886fa 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1690,14 +1690,24 @@ host, `dyn` included, carries what used to be one-line forwards: `focus_role`, `
 `blocks_root_plate_drag`, `wants_tick`, `is_scrollable`, the `a11y_*` reads and acts,
 `set_modifiers`, `context_action`, `color`, `solid_border`, `widget_font`,
 `clips_children`, `renders_own_subtree`, `z_index`, `preferred_height`, plus the pure
-derivations `label`, `corner_radii`, `mark_dirty` — and the legacy tuple views
-(`extra_quads`, `extra_arcs`, `extra_circles`, `all_quads`, `all_rounded_quads`,
-`highlight_quad`, `corner_style`): what a widget paints projected onto the
-pre-display-list surface, computed from `paint_model().paint(content_rect())` the way
-`Adapted` computed them, for the hosts that still draw a widget through them rather than
-`paint_self` (the designer's render loop, the gallery, the display manager's greeter, the
-settings app's flat collector, cce-secrets, the flat-host bridge). Call them as before, with
-`cce_ui::widget::WidgetHostExt` in scope. A method stays ON the trait only when the host
+derivations `label`, `corner_radii`, `mark_dirty`, and `content_rect` / `painted_prims` (what
+the widget's model paints, as prims). Call them with `cce_ui::widget::WidgetHostExt` in
+scope.
+
+**The legacy tuple views are gone** (2026-10-08): `extra_quads`, `extra_arcs`,
+`extra_circles`, `all_quads`, `all_rounded_quads`, `highlight_quad` and the host-side
+`corner_style` — what a widget paints projected onto the pre-display-list surface — with
+the model hooks that served only them (`serves_legacy_plain_quads` / `legacy_plain_quads`,
+`aggregates_child_extra_quads`, `forwarded_highlight`), the painter's `paint_legacy_leaf`
+and the tessellator's `widget_vertices`. Every host paints a widget through `paint_self` or
+the paint walk (the designer, the gallery, the greeter, the settings app and cce-secrets
+moved the same day, each checked by pixel A/B). A composite that draws a child's chrome in
+its own order — the params pane's rows, the ramp's key editor, the menubar's strip — reads
+the child's `painted_prims` (`widget::shown_prims` / `shown_quads` / `shown_rounded_quads`,
+crate-private). `Paint::corner_style` stays: it is what a widget says about its silhouette,
+read by `corner_radii`, `append_widget_plate` and the bridge. `append_widget_plate` is the
+plate alone now; it drew the widget's arcs too, which a host painting the widget after it
+drew twice. A method stays ON the trait only when the host
 adds something the model cannot (visibility gating, the content rect, child recursion,
 registry state). `plate_bevel` is gone: nothing overrode it, so it was always `None`.
 `Owned` forwards the trait's methods and the four accessors; the extension trait needs no
@@ -2054,8 +2064,7 @@ NOTHING until this change, when the wires were a hard-coded cyan 3 px.
   `Graph::paint_wires` (also on `GraphController`), `Prim::Vector`s and
   `Prim::Arc`s, since only one style is axis-aligned. `Paint::paint` calls
   it after the grid; a host drawing the quads itself (the designer) calls
-  it between `paint_grid` and the bodies. The legacy `extra_quads` view has
-  no wires.
+  it between `paint_grid` and the bodies.
 - **The run across is on the first lattice line below the source**
   (`Graph::wire_turn_y`, since 2026-10-06), for orthogonal and rounded
   wires running down. It was halfway between the ports, so a wire spanning
diff --git a/docs/rfc-core-rebuild.md b/docs/rfc-core-rebuild.md
index 540983b..ba0c381 100644
--- a/docs/rfc-core-rebuild.md
+++ b/docs/rfc-core-rebuild.md
@@ -2073,6 +2073,19 @@ Constraint respected: **each crate still builds standalone** — the new core is
     radius, is-Ramp flag) at re-parent time instead of the pointer —
     same refresh cadence, no deref of potentially-dead memory; watch
     the one-frame rect lag on resize if reads move to snapshots.
+  - **The legacy tuple views retired (the same day).** The five apps moved to `paint_self`
+    (cce-secrets, the greeter, the settings app's dropdown and search box, the gallery, the
+    designer's render loop), then the toolkit's own readers: `ParametersBg`, the ramp and the
+    menubar read their children's `painted_prims`; `Adapted::paint_self` computes the
+    TextBox's focus highlight itself; the bridge and `corner_radii` read `Paint::corner_style`;
+    `append_widget_plate` stopped drawing the widget's arcs; `paint_legacy_leaf` and
+    `widget_vertices` / `push_widget_vertices` had no callers left. The views and the hooks
+    that served only them (`serves_legacy_plain_quads`, `legacy_plain_quads`,
+    `aggregates_child_extra_quads`, `forwarded_highlight`) are deleted, and the tests that
+    asserted on them read `painted_prims`. Pixel A/B in a scale-2 shadow: the designer (five
+    pane layouts) and the gallery identical before and after the toolkit change; each app's
+    own move is described in its commit (cce-secrets and the greeter changed look by choice,
+    the settings dropdown gained its face plate, the gallery lost a stray outline).
   - **WidgetHost 38 → 31 (the same day).** The legacy tuple views (`extra_quads`,
     `extra_arcs`, `extra_circles`, `all_quads`, `all_rounded_quads`, `highlight_quad`,
     `corner_style`) moved to `WidgetHostExt` too, computed from the paint model exactly as
diff --git a/src/backend/tessellate.rs b/src/backend/tessellate.rs
index 288878d..3ab7499 100644
--- a/src/backend/tessellate.rs
+++ b/src/backend/tessellate.rs
@@ -1240,25 +1240,6 @@ pub fn push_plate_solid_border_vertices_legacy(
     push_plate_solid_border_vertices(x, y, ww, h, radii, t, sw, sh, color, clip_circle, out);
 }
 
-pub fn widget_vertices(w: &dyn crate::widget::WidgetHost, sw: f32, sh: f32, clip_circle: [f32; 3]) -> Vec<Vertex> {
-    let mut verts = Vec::new();
-    push_widget_vertices(w, sw, sh, clip_circle, &mut verts);
-    verts
-}
-
-pub fn push_widget_vertices(w: &dyn crate::widget::WidgetHost, sw: f32, sh: f32, clip_circle: [f32; 3], out: &mut Vec<Vertex>) {
-    let (x, y, ww, h) = w.rect();
-    let radii = w.corner_radii();
-    push_rounded_rect_vertices_corners(x, y, ww, h, radii, sw, sh, w.color(), clip_circle, None, out);
-    if let Some((color, thickness)) = w.solid_border() {
-        push_plate_solid_border_vertices(x, y, ww, h, radii, thickness, sw, sh, color, clip_circle, out);
-    }
-
-    for (cx, cy, r, t, start, end, qc) in w.extra_arcs() {
-        push_arc_background_vertices(cx, cy, r, t, start, end, sw, sh, qc, 16, clip_circle, out);
-    }
-}
-
 /// A contiguous run of vertices sharing one scissor rect (Phase 3 single paint path) and one
 /// rounded-rect clip. `scissor` is a logical-pixel clip (`None` = unclipped); `clip_rrect` is
 /// the paint walk's `[cx, cy, bx, by, r]` rounded clip in logical px (`None` = unclipped),
diff --git a/src/engine.rs b/src/engine.rs
index 0f58940..20809f3 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -14,7 +14,7 @@ pub use crate::backend::tessellate::{
     quad_vertices, quad_vertices_with_clip, quad_vertices_clipped, line_vertices,
     vector_vertices, rounded_rect_vertices_corners, push_rounded_rect_vertices_corners,
     rounded_rect_vertices, push_rounded_rect_vertices, plate_bevel_vertices,
-    push_plate_bevel_vertices, widget_vertices, push_widget_vertices,
+    push_plate_bevel_vertices,
     extra_quad_vertices, push_extra_quad_vertices, extra_quad_vertices_clipped,
     push_extra_quad_vertices_clipped, circle_vertices, circle_border_vertices,
     arc_background_vertices, push_arc_background_vertices, push_plate_solid_border_vertices,
diff --git a/src/layout/bridge.rs b/src/layout/bridge.rs
index 0a2d707..48c926c 100644
--- a/src/layout/bridge.rs
+++ b/src/layout/bridge.rs
@@ -193,7 +193,8 @@ pub fn render_widget<T: WidgetHost + 'static>(pc: &mut dyn RenderTarget, w: &mut
     if let Ok(mut fs) = crate::geometry_font_system().lock() {
         w.prepare_text(&mut fs);
     }
-    let (style_r, corners) = w.corner_style();
+    let (style_r, corners) =
+        w.paint_model().corner_style(w.content_rect()).unwrap_or((0.0, (false, false, false, false)));
     let r = if corners != (false, false, false, false) { style_r } else { 0.0 };
     let (wx, mut wy, www, mut whh) = w.rect();
     let top_room = w.label_strip();
diff --git a/src/scene/paint.rs b/src/scene/paint.rs
index 0193467..f9da9ad 100644
--- a/src/scene/paint.rs
+++ b/src/scene/paint.rs
@@ -437,11 +437,11 @@ impl DropletFinish for DropletSpec {
 pub enum Prim {
     Quad { rect: Rect, color: [f32; 4] },
     RoundedRect { rect: Rect, radius: f32, corners: (bool, bool, bool, bool), color: [f32; 4] },
-    /// A rounded fill plus a solid border stroke — a widget's own "plate" (mirrors
-    /// `push_widget_vertices`' non-bevel branch: rounded bg + `push_plate_solid_border_vertices`).
+    /// A rounded fill plus a solid border stroke — a widget's own "plate"
+    /// (`append_widget_plate`'s non-bevel branch).
     Border { rect: Rect, radii: Radii, fill: [f32; 4], border: [f32; 4], thickness: f32 },
     /// A beveled plate: a rounded fill at full size plus a light/shadow overlay lip
-    /// (mirrors `push_widget_vertices`' bevel branch). `tint` colours the
+    /// (`append_widget_plate`'s bevel branch). `tint` colours the
     /// roll's light and shadow — neutral white normally; a host sets it to a
     /// highlight color to mark the plate (the focused-pane treatment) without a
     /// separate border ring: the light goes to the tint, the shadow to a dark
diff --git a/src/scene/painter.rs b/src/scene/painter.rs
index b2b8aea..b920976 100644
--- a/src/scene/painter.rs
+++ b/src/scene/painter.rs
@@ -53,40 +53,10 @@ pub fn append_widget_text(ui: &UiContext, root: &dyn WidgetHost, pc: &mut PaintC
     }
 }
 
-/// The `WidgetHost` default `paint_self`'s LEAF branch as a reusable body: leaf geometry
-/// (rounded quads, plain quads, arcs, circles) followed by the widget's fonted labels.
-/// Legacy leaf widgets' `paint_self` overrides call this with their own labels — the
-/// labels are PASSED IN rather than fetched through the per-widget text getters, so this
-/// helper (and every override built on it) survives the getters' deletion. `pub` so
-/// app-local legacy widgets (display-manager's status/session widgets, cloud's fuzzel)
-/// can use it too.
-pub fn paint_legacy_leaf(
-    w: &dyn WidgetHost,
-    ui: &UiContext,
-    pc: &mut PaintCtx,
-    labels: Vec<(TextLabel, Option<String>, Option<[f32; 4]>)>,
-) {
-    for (x, y, qw, qh, r, c, corners) in w.all_rounded_quads(ui) {
-        pc.rounded_rect(Rect { x, y, width: qw, height: qh }, r, corners, c);
-    }
-    for (x, y, qw, qh, c) in w.all_quads(ui) {
-        pc.quad(Rect { x, y, width: qw, height: qh }, c);
-    }
-    for (cx, cy, r, t, s, e, c) in w.extra_arcs() {
-        pc.arc(cx, cy, r, t, s, e, c);
-    }
-    for (cx, cy, r, c) in w.extra_circles() {
-        pc.circle(cx, cy, r, c);
-    }
-    for (tl, font, bounds) in labels {
-        pc.text_with(tl.text, tl.x, tl.y, tl.font_size, tl.color, font, bounds);
-    }
-}
-
-/// The prim-level mirror of the backend's `push_widget_vertices`: the widget's own plate —
-/// beveled, or rounded fill + optional solid border — plus its extra arcs. For hosts that
-/// hand-build their display list in their own draw order (the designer) instead of walking
-/// `paint_self`, but want a widget's background exactly as the vertex path drew it.
+/// The widget's own plate — beveled, or rounded fill + optional solid border — for hosts that
+/// hand-build their display list in their own draw order (the designer) and paint the widget
+/// on it with `paint_self`. The plate only: until 2026-10-08 it carried the widget's arcs too,
+/// which a host then painting the widget drew twice.
 pub fn append_widget_plate(w: &dyn WidgetHost, pc: &mut PaintCtx) {
     append_widget_plate_tinted(w, pc, None);
 }
@@ -121,9 +91,6 @@ pub fn append_widget_plate_radii(w: &dyn WidgetHost, pc: &mut PaintCtx, tint: Op
     } else {
         pc.border(rect, radii_tuple, w.color(), [0.0; 4], 0.0);
     }
-    for (cx, cy, r, t, s, e, c) in w.extra_arcs() {
-        pc.arc(cx, cy, r, t, s, e, c);
-    }
 }
 
 /// The scroll-ancestor text clamp the deleted default fonted getter applied. Always `None`
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index 3ab1262..7597b71 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -547,9 +547,12 @@ impl Paint for MenuBar {
         // separate groove rings), and the strip's full-height square state
         // quads are replaced by the trigger fills — open matches the context
         // dropdown's open tint rather than the strip's legacy palette.
+        let strip = crate::widget::shown_prims(&self.menus);
         if flat_modes {
-            for (qx, qy, qw, qh, qc) in self.menus.extra_quads() {
-                ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
+            for prim in &strip {
+                if let crate::scene::paint::Prim::Quad { rect, color } = prim {
+                    ctx.quad(*rect, *color);
+                }
             }
         } else {
             for i in 0..self.menus.buttons.len() {
@@ -567,11 +570,14 @@ impl Paint for MenuBar {
                 trough_chrome(ctx, r, fill);
             }
         }
-        for (cx, cy, r, t, start, end, c) in self.menus.extra_arcs() {
-            ctx.arc(cx, cy, r, t, start, end, c);
-        }
-        for (cx, cy, r, c) in self.menus.extra_circles() {
-            ctx.circle(cx, cy, r, c);
+        for prim in strip {
+            match prim {
+                crate::scene::paint::Prim::Arc { cx, cy, radius, thickness, start, end, color } => {
+                    ctx.arc(cx, cy, radius, thickness, start, end, color);
+                }
+                crate::scene::paint::Prim::Circle { cx, cy, radius, color } => ctx.circle(cx, cy, radius, color),
+                _ => {}
+            }
         }
 
         // Text: the sidebar label (vertical), the title (curved / vertical / horizontal), and
diff --git a/src/widget/container/paginator.rs b/src/widget/container/paginator.rs
index ab27673..b386d87 100644
--- a/src/widget/container/paginator.rs
+++ b/src/widget/container/paginator.rs
@@ -4,22 +4,16 @@
 //! containers toggled visible/hidden) is gone — its only observable output, the page-area
 //! background quad, is painted directly here.
 //!
-//! Two legacy behaviors ride hooks from the 5r migration:
-//! - [`Layout::register_embedded_children`]: legacy `tick`/`layout` re-registered the strip into
-//!   the ctx registry every frame — load-bearing for the spatial grid (the registered strip is
-//!   what makes the sidebar block root plate drags).
-//! - [`Paint::aggregates_child_extra_quads`] + [`Paint::forwarded_highlight`]: legacy
-//!   `extra_quads` served the strip's chrome only (cce-layout-interface renders the tab
-//!   column through that getter plus `all_rounded_quads`, which carries the strip's rounded
-//!   state fills — the paginator's own backgrounds live in `all_rounded_quads` alone), and
-//!   legacy `highlight_quad` forwarded to the strip's (the hovered-tab tint
-//!   cce-layout-interface draws directly).
+//! One legacy behavior rides a hook from the 5r migration:
+//! [`Layout::register_embedded_children`]: legacy `tick`/`layout` re-registered the strip into
+//! the ctx registry every frame — load-bearing for the spatial grid (the registered strip is
+//! what makes the sidebar block root plate drags).
 
 use crate::colors;
 use crate::scene::layout::Rect;
 use crate::scene::paint::PaintCtx;
 use crate::widget::input::ButtonStrip;
-use crate::widget::{Adapted, WidgetHost, Event, EventCtx, Input, Layout, MenuController, PageSelector, Paint, UiContext, WidgetId, WidgetHostExt};
+use crate::widget::{Adapted, WidgetHost, Event, EventCtx, Input, Layout, MenuController, PageSelector, Paint, UiContext, WidgetId};
 
 pub struct Paginator {
     /// In an [`Owned`](crate::widget::Owned) box of its own, so the registry points at a
@@ -196,19 +190,6 @@ impl Paint for Paginator {
             }
         }
     }
-
-    /// Legacy `extra_quads` served the strip's + selected page's chrome only —
-    /// cce-layout-interface draws the tab column through this getter (and the strip's rounded
-    /// state fills through `all_rounded_quads`), over its own backgrounds.
-    fn aggregates_child_extra_quads(&self) -> bool {
-        true
-    }
-
-    /// Legacy `highlight_quad` forwarded to the strip's (the hovered-tab tint
-    /// cce-layout-interface draws directly).
-    fn forwarded_highlight(&self, ctx: &UiContext) -> Option<Option<(f32, f32, f32, f32, [f32; 4])>> {
-        Some(self.sidebar_menu.highlight_quad(ctx))
-    }
 }
 
 impl Input for Paginator {
@@ -310,23 +291,19 @@ mod tests {
     }
 
     #[test]
-    fn plain_quads_split_like_legacy_and_registration_heals_on_tick() {
+    fn the_sidebar_bg_is_rounded_and_registration_heals_on_tick() {
         let mut ctx = UiContext::new();
         let mut p = paginator();
         ctx.register_host(&mut p);
 
-        // Legacy split: `extra_quads` is the children's chrome only; the sidebar background
-        // (a rounded rect) lives in `all_rounded_quads` alone (layout-interface draws its
-        // own backgrounds under `extra_quads`).
-        let extra = crate::widget::WidgetHostExt::extra_quads(&p);
-        let strip_extra = p.sidebar_menu.extra_quads();
-        assert_eq!(extra.len(), strip_extra.len(), "children-only plain view (pages emit none)");
+        // The sidebar background is a rounded rect of the paginator's own paint, never a
+        // plain quad.
         let bg = colors::sidebar_bg_color();
         if bg[3] > 0.0 {
             let r = crate::layout::plate_corner_radius();
             let bg_quad = (0.0, 0.0, 400.0, 300.0, r, bg, (true, true, true, true));
-            assert!(!extra.iter().any(|q| q.4 == bg && q.2 == 400.0), "no own bg in extra_quads");
-            assert!(crate::widget::WidgetHostExt::all_rounded_quads(&p, &ctx).contains(&bg_quad), "own bg in all_rounded_quads");
+            assert!(!crate::widget::shown_quads(&p).iter().any(|q| q.4 == bg && q.2 == 400.0), "no plain bg");
+            assert!(crate::widget::shown_rounded_quads(&p).contains(&bg_quad), "a rounded bg");
         }
 
         // The embedded strip + pages land in the registry on tick (the spatial grid feeds off
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index b1b51d8..1d24a9e 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -9,13 +9,11 @@
 //! working unchanged.
 //!
 //! The model caches its laid-out rect via [`Layout::rect_assigned`] (all row geometry derives
-//! from it — the TextBox pattern), and serves BOTH legacy escape hatches: the plain-quad view
-//! ([`Paint::serves_legacy_plain_quads`] — the designer renders params through raw
-//! `extra_quads`, and the panel's own background is drawn by the host from
-//! [`Paint::color`]/[`Paint::corner_style`], NOT emitted here), and the per-label text view
-//! ([`Paint::serves_legacy_labels`], new with this migration — each label clips to the
-//! viewport but the code editor's clip to the code box, in monospace, which the one-font
-//! one-bounds prim bridge can't express).
+//! from it — the TextBox pattern). The panel's own background is drawn by the host from
+//! [`Paint::color`]/[`Paint::corner_style`], NOT emitted here, and its text rides the
+//! per-label view ([`Paint::serves_legacy_labels`] — each label clips to the viewport but
+//! the code editor's clip to the code box, in monospace, which the one-font one-bounds prim
+//! bridge can't express).
 //!
 //! The code row is an editor, not a text box (2026-09-24): a line-number gutter, shift+arrow /
 //! shift+click selection with ctrl+c / ctrl+x / ctrl+v through the toolkit clipboard, tab and
@@ -1486,10 +1484,9 @@ impl ParametersBg {
         self.focused_param = None;
     }
 
-    /// The legacy `extra_quads` body: section border boxes, every row's chrome (slider/spinbox
-    /// backgrounds read via `rect()`+`color()`, the code editor's box/border/cursor), the raw
-    /// children via [`collect_child_quads`], all clipped to the viewport — plus the unclipped
-    /// scrollbar. Served verbatim through [`Paint::legacy_plain_quads`].
+    /// The pane's plain quads: section border boxes, every row's chrome (slider/spinbox
+    /// backgrounds read via `rect()`+`color()`, the code editor's box/border/cursor), the
+    /// controls' own plain quads, all clipped to the viewport — plus the unclipped scrollbar.
     fn plain_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
         if !self.visible {
             return Vec::new();
@@ -1534,7 +1531,7 @@ impl ParametersBg {
                 if let Some(s) = &self.sliders[i] {
                     let (sx, sy, sw, sh) = s.rect();
                     param_quads.push((sx, sy, sw, sh, s.color()));
-                    param_quads.extend(s.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(s));
                 }
             } else if p.2 == "section" {
                 // Section header line is handled by the border box top border now
@@ -1544,7 +1541,7 @@ impl ParametersBg {
                 param_quads.push((r.0 + 6.0, r.1, (r.2 - 12.0).max(0.0), 1.0, [c[0], c[1], c[2], c[3] * 0.8]));
             } else if is_vec_row(&p.2) {
                 if let Some(f) = &self.float3s[i] {
-                    param_quads.extend(f.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(f));
                 }
             } else if p.2 == "code" {
                 let (bx, by, bw, bh) = (r.0, r.1 + Self::CODE_BOX_TOP, r.2, r.3 - Self::CODE_BOX_TOP);
@@ -1608,31 +1605,31 @@ impl ParametersBg {
                 param_quads.push((bx + bw - 1.0, by, 1.0, bh, border_color));
             } else if is_text_row(&p.2) {
                 if let Some(tb) = &self.texts[i] {
-                    param_quads.extend(tb.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(tb));
                 }
                 if let Some(d) = &self.choices[i] {
-                    param_quads.extend(d.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(d));
                 }
             } else if p.2.starts_with("choice") {
                 if let Some(d) = &self.choices[i] {
-                    param_quads.extend(d.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(d));
                 }
             } else if p.2 == "button" {
                 if let Some(b) = &self.buttons[i] {
-                    param_quads.extend(b.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(b));
                 }
             } else if p.2.starts_with("spinbox") {
                 if let Some(sb) = &self.spinboxes[i] {
                     { let (bx, by, bw, bh) = sb.rect(); param_quads.push((bx, by, bw, bh, sb.color())); }
-                    param_quads.extend(sb.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(sb));
                 }
             } else if p.2 == "toggle" || p.2 == "checkbox" {
                 if let Some(cb) = &self.toggles[i] {
-                    param_quads.extend(cb.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(cb));
                 }
             } else if p.2.starts_with("color") || p.2 == "rgb" || p.2 == "rgba" {
                 if let Some(c) = &self.colors[i] {
-                    param_quads.extend(c.extra_quads());
+                    param_quads.extend(crate::widget::shown_quads(c));
                 }
             }
         }
@@ -1651,15 +1648,11 @@ impl ParametersBg {
     }
 
     /// The rounded companion to [`Self::plain_quads`]: the row controls whose boxes are
-    /// `Prim::RoundedRect` (textbox, dropdown, button, toggle, color selector). Those
-    /// backgrounds never reach the plain view — `own_plain_quads` keeps `Prim::Quad` only —
-    /// so a host that renders this panel through the legacy plain-quad hatch must read this
-    /// getter too or the controls draw as bare text. Returned unclipped; the host clips to
-    /// the pane's scroll viewport when it pushes vertices. Tuple layout matches
-    /// `all_rounded_quads`: (x, y, w, h, radius, color, (tl, tr, br, bl)).
+    /// `Prim::RoundedRect` (textbox, dropdown, button, toggle, color selector), which the
+    /// plain list does not carry. Returned unclipped; the pane's paint clips them to its
+    /// scroll viewport. (x, y, w, h, radius, color, (tl, tr, br, bl)).
     pub fn rounded_quads(
         &self,
-        ctx: &UiContext,
     ) -> Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))> {
         if !self.visible {
             return Vec::new();
@@ -1672,27 +1665,27 @@ impl ParametersBg {
             }
             if is_text_row(&p.2) {
                 if let Some(tb) = &self.texts[i] {
-                    out.extend(tb.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(tb));
                 }
                 if let Some(d) = &self.choices[i] {
-                    out.extend(d.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(d));
                 }
             } else if p.2.starts_with("slider") {
                 // Track (square style only — the recessed style has no track
                 // background), value fill, and readout box; the thumb knob is a
                 // `Prim::Sphere` and rides `spheres()` instead.
                 if let Some(s) = &self.sliders[i] {
-                    out.extend(s.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(s));
                 }
             } else if is_vec_row(&p.2) {
                 // Three slider rows: the same set per row (readout boxes,
                 // square-style tracks and fills), through the group's own paint.
                 if let Some(f) = &self.float3s[i] {
-                    out.extend(f.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(f));
                 }
             } else if p.2.starts_with("choice") {
                 if let Some(d) = &self.choices[i] {
-                    out.extend(d.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(d));
                 }
             } else if p.2.starts_with("spinbox") {
                 // The spinbox's whole chrome (frame, display well, +/- button
@@ -1700,19 +1693,19 @@ impl ParametersBg {
                 // transparent and it has no extra_quads, so skipping it here
                 // renders the row as bare text.
                 if let Some(sb) = &self.spinboxes[i] {
-                    out.extend(sb.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(sb));
                 }
             } else if p.2 == "button" {
                 if let Some(b) = &self.buttons[i] {
-                    out.extend(b.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(b));
                 }
             } else if p.2 == "toggle" || p.2 == "checkbox" {
                 if let Some(cb) = &self.toggles[i] {
-                    out.extend(cb.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(cb));
                 }
             } else if p.2.starts_with("color") || p.2 == "rgb" || p.2 == "rgba" {
                 if let Some(c) = &self.colors[i] {
-                    out.extend(c.all_rounded_quads(ctx));
+                    out.extend(crate::widget::shown_rounded_quads(c));
                 }
             }
         }
@@ -2128,7 +2121,7 @@ impl Paint for ParametersBg {
     }
 
     /// The panel IS its own background plate (the host draws it from `color()` + the corner
-    /// style via `push_widget_vertices`) — there is no separate plate widget behind it, so
+    /// style via `append_widget_plate`) — there is no separate plate widget behind it, so
     /// this carries the full plate treatment: `PARAM_BG` scaled by the global plate opacity,
     /// with the alpha negated as the scenefx blur marker when plate blur is on. Transparent
     /// while hidden. It must not ALSO be emitted as a quad anywhere or it would double-blend.
@@ -2164,13 +2157,13 @@ impl Paint for ParametersBg {
     /// 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) {
+    fn paint_ui(&self, _ui: &UiContext, _rect: Rect, ctx: &mut PaintCtx) {
         if !self.visible {
             return;
         }
         self.claim_typing(ctx);
         self.paint_row_floors(ctx);
-        for (qx, qy, qw, qh, qr, qc, corners) in self.rounded_quads(ui) {
+        for (qx, qy, qw, qh, qr, qc, corners) in self.rounded_quads() {
             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() {
@@ -2251,14 +2244,6 @@ impl Paint for ParametersBg {
         }
     }
 
-    fn serves_legacy_plain_quads(&self) -> bool {
-        true
-    }
-
-    fn legacy_plain_quads(&self, _rect: Rect) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        self.plain_quads()
-    }
-
     fn serves_legacy_labels(&self) -> bool {
         true
     }
@@ -4721,21 +4706,19 @@ mod tests {
     }
 
     #[test]
-    fn plain_view_serves_row_chrome_and_all_quads_stays_empty() {
+    fn the_row_chrome_is_the_panes_and_the_plate_the_hosts() {
         let ctx = UiContext::new();
         let p = panel_with(&[("Size", "1.00", "slider:0:2")]);
-        // The designer's plain path: extra_quads carries the row chrome (clipped), including
-        // the slider background it reads via rect()+color()...
-        let extra = crate::widget::WidgetHostExt::extra_quads(&p);
-        assert!(!extra.is_empty(), "row chrome served through extra_quads");
+        // The pane's plain quads carry the row chrome (clipped), including the slider
+        // background it reads via rect()+color()...
+        let plain = p.plain_quads();
+        assert!(!plain.is_empty(), "row chrome in the pane's plain quads");
         // ...but NOT the panel's own PARAM_BG plate (the host draws that from color()).
         let (x, y, w, h) = WidgetHost::rect(&p);
         assert!(
-            !extra.iter().any(|q| (q.0, q.1, q.2, q.3) == (x, y, w, h)),
-            "panel bg plate is the host's, not extra_quads'"
+            !plain.iter().any(|q| (q.0, q.1, q.2, q.3) == (x, y, w, h)),
+            "panel bg plate is the host's, not the pane's"
         );
-        // The no-double-draw contract of the plain-quad hatch.
-        assert!(crate::widget::WidgetHostExt::all_quads(&p, &ctx).is_empty());
         // Per-label hatch: the walk's text prims carry the widget font and viewport bounds.
         let mut scratch = crate::scene::paint::PaintCtx::new();
         crate::scene::painter::append_widget_text(&ctx, &p, &mut scratch);
diff --git a/src/widget/container/spreadsheet.rs b/src/widget/container/spreadsheet.rs
index 73acf35..758f92d 100644
--- a/src/widget/container/spreadsheet.rs
+++ b/src/widget/container/spreadsheet.rs
@@ -28,7 +28,7 @@
 //! strings) still works: its cells become text columns.
 //!
 //! The `PARAM_BG` background is NOT emitted here: the designer's render path draws every
-//! widget's background itself from `color()` + `corner_style()` (`push_widget_vertices`), and
+//! widget's background itself from `color()` + `corner_style()` (`append_widget_plate`), and
 //! `PARAM_BG` is translucent — emitting it again would double-blend. This widget's own
 //! geometry starts at the header strip, exactly like the legacy `extra_quads`.
 
diff --git a/src/widget/container/treelist.rs b/src/widget/container/treelist.rs
index 0f71937..6d30537 100644
--- a/src/widget/container/treelist.rs
+++ b/src/widget/container/treelist.rs
@@ -1669,7 +1669,6 @@ mod tests {
 
     #[test]
     fn test_treelist_separators() {
-        let ctx = UiContext::new();
         let mut tree_list = TreeList::new();
         tree_list.set_rect(10.0, 52.0, 380.0, 500.0);
         tree_list.set_flat_keys(vec![
@@ -1687,7 +1686,7 @@ mod tests {
         println!("scroll_box scroll_y: {}", tree_list.scroll_box.scroll_y);
         println!("item_height: {}", tree_list.item_height);
         
-        let quads = tree_list.all_rounded_quads(&ctx);
+        let quads = crate::widget::shown_rounded_quads(&tree_list);
         println!("Rounded quads count: {}", quads.len());
         for (i, q) in quads.iter().enumerate() {
             println!("Quad {}: {:?}", i, q);
diff --git a/src/widget/display/graph.rs b/src/widget/display/graph.rs
index 55560a3..fe9219a 100644
--- a/src/widget/display/graph.rs
+++ b/src/widget/display/graph.rs
@@ -2,12 +2,10 @@
 //! draggable nodes with geometry toggles, input/output ports, wire routing, and interactive
 //! connection dragging. [`GraphController`] rides the `Input` capability hooks.
 //!
-//! Rendering serves the legacy dual-geometry contract through the adapter's escape hatch:
-//! [`Paint::paint`] emits the ROUNDED view (what `render_widget` hosts — cce-files — and the
-//! scene walk — cce-graph — consume), while [`Paint::legacy_plain_quads`] serves the same
-//! geometry as plain quads for raw `extra_quads` readers (the designer's render path), with
-//! `all_quads` emptied by the adapter so no host draws it twice. Node-name text is clipped to
-//! the widget rect via [`Paint::text_bounds`]. All grid geometry is in absolute screen space
+//! [`Paint::paint`] emits the graph as rounded geometry (what `render_widget` hosts — cce-files —
+//! and the scene walk — cce-graph — consume); a host that draws the nodes in its own order (the
+//! designer) reads [`Graph::geometry_quads_tagged`] and calls [`Graph::paint_wires`] itself. Node-name
+//! text is clipped to the widget rect via [`Paint::text_bounds`]. All grid geometry is in absolute screen space
 //! (hosts pan by moving `grid_origin`); the widget rect only culls and clips.
 //!
 //! The WIRES are not quads: they are strokes in a [`WireStyle`] — orthogonal, rounded,
@@ -901,15 +899,6 @@ impl Graph {
         quads
     }
 
-    /// [`geometry_quads_tagged`](Self::geometry_quads_tagged) with the cell tags
-    /// stripped — the unchanged legacy `extra_quads` shape.
-    fn geometry_quads(&self, rect: Rect) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        self.geometry_quads_tagged(rect)
-            .into_iter()
-            .map(|(qx, qy, qw, qh, qc, _)| (qx, qy, qw, qh, qc))
-            .collect()
-    }
-
     /// The rounded view of the same geometry — the legacy `all_rounded_quads` conversion: the
     /// widget background, then each plain quad either as a grid cell (superellipse cell arcs),
     /// a node body (node corner radius, all corners), or with the widget's edge-corner
@@ -1112,14 +1101,6 @@ impl Paint for Graph {
         }
     }
 
-    fn serves_legacy_plain_quads(&self) -> bool {
-        true
-    }
-
-    fn legacy_plain_quads(&self, rect: Rect) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        self.geometry_quads(rect)
-    }
-
     fn text_bounds(&self, rect: Rect) -> Option<[f32; 4]> {
         Some([rect.x, rect.y, rect.x + rect.width, rect.y + rect.height])
     }
@@ -2265,21 +2246,34 @@ mod tests {
     }
 
     #[test]
-    fn dual_geometry_views_stay_consistent() {
+    fn the_painted_geometry_is_the_tagged_geometry_rounded() {
+        use crate::widget::WidgetHostExt;
         let g = two_nodes();
-        let ctx = UiContext::new();
 
-        // The plain view (designer path) and the rounded view (render_widget path) describe
-        // the same quads: the rounded view adds only the widget background entry up front.
-        let plain = crate::widget::WidgetHostExt::extra_quads(&g);
-        let rounded = crate::widget::WidgetHostExt::all_rounded_quads(&g, &ctx);
+        // What a host drawing the nodes itself reads (the designer) and what the graph paints
+        // describe the same quads: the paint adds only the widget background up front.
+        let plain: Vec<_> = g
+            .geometry_quads_tagged(g.content_rect())
+            .into_iter()
+            .map(|(qx, qy, qw, qh, qc, _)| (qx, qy, qw, qh, qc))
+            .collect();
+        let rounded: Vec<_> = g
+            .painted_prims()
+            .into_iter()
+            .filter_map(|prim| match prim {
+                crate::scene::paint::Prim::RoundedRect { rect, radius, corners, color } => {
+                    Some((rect.x, rect.y, rect.width, rect.height, radius, color, corners))
+                }
+                _ => None,
+            })
+            .collect();
         assert!(!plain.is_empty());
         assert_eq!(rounded.len(), plain.len() + 1);
         for ((px, py, pw, ph, pc), (rx, ry, rw, rh, _, rc, _)) in plain.iter().zip(rounded.iter().skip(1)) {
             assert_eq!((px, py, pw, ph, pc), (rx, ry, rw, rh, rc));
         }
 
-        // Node bodies carry the node corner radius in the rounded view.
+        // Node bodies carry the node corner radius.
         let node_radius = crate::layout::graph_node_corner_radius();
         let node_entries: Vec<_> = rounded
             .iter()
@@ -2290,9 +2284,5 @@ mod tests {
             assert_eq!(entry.4, node_radius);
             assert_eq!(entry.6, (true, true, true, true));
         }
-
-        // And `all_quads` stays empty so render_widget hosts (reading BOTH getters) never
-        // draw the geometry twice — the legacy Graph override's contract.
-        assert!(crate::widget::WidgetHostExt::all_quads(&g, &ctx).is_empty());
     }
 }
diff --git a/src/widget/display/progress_bar.rs b/src/widget/display/progress_bar.rs
index 9c8ba89..91d38e1 100644
--- a/src/widget/display/progress_bar.rs
+++ b/src/widget/display/progress_bar.rs
@@ -96,17 +96,16 @@ impl Input for ProgressBar {}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::widget::{WidgetHost, UiContext};
+    use crate::widget::WidgetHost;
 
     /// The reverse bridge reproduces the legacy `all_rounded_quads` output: track quad at the
     /// content rect, fill quad at `w * value` with the radius clamped to half the height.
     #[test]
     fn reverse_bridge_matches_legacy_geometry() {
-        let ctx = UiContext::new();
         let mut bar = ProgressBar::new(0.5).with_recessed(false);
         WidgetHost::set_rect(&mut bar, 10.0, 20.0, 100.0, 8.0);
 
-        let quads = crate::widget::WidgetHostExt::all_rounded_quads(&bar, &ctx);
+        let quads = crate::widget::shown_rounded_quads(&bar);
         let radius = crate::layout::slider_corner_radius();
         assert_eq!(quads.len(), 2, "track + fill");
         assert_eq!(quads[0], (10.0, 20.0, 100.0, 8.0, radius, colors::progress_bg(), (true, true, true, true)));
@@ -119,15 +118,14 @@ mod tests {
     /// Value is clamped like the legacy widget: over 1.0 fills the whole track, 0 emits no fill.
     #[test]
     fn fill_clamps_to_track() {
-        let ctx = UiContext::new();
         let mut over = ProgressBar::new(2.0).with_recessed(false);
         WidgetHost::set_rect(&mut over, 0.0, 0.0, 100.0, 8.0);
-        let quads = crate::widget::WidgetHostExt::all_rounded_quads(&over, &ctx);
+        let quads = crate::widget::shown_rounded_quads(&over);
         assert_eq!(quads[1].2, 100.0, "over-1 value fills the whole track");
 
         let mut empty = ProgressBar::new(0.0).with_recessed(false);
         WidgetHost::set_rect(&mut empty, 0.0, 0.0, 100.0, 8.0);
-        assert_eq!(crate::widget::WidgetHostExt::all_rounded_quads(&empty, &ctx).len(), 1, "zero value emits track only");
+        assert_eq!(crate::widget::shown_rounded_quads(&empty).len(), 1, "zero value emits track only");
     }
 
     /// The recessed style draws no track of its own: the fill on the well floor, then
@@ -152,7 +150,6 @@ mod tests {
     /// strip is read back from the widget).
     #[test]
     fn label_strip_heads_the_block_and_insets_paint() {
-        let ctx = UiContext::new();
         let mut bar = ProgressBar::new(0.5).with_recessed(false).with_label("Progress");
         let offset = WidgetHost::label_strip(&bar);
         assert!(offset > 0.0, "a labeled bar carries a strip");
@@ -162,7 +159,7 @@ mod tests {
         assert_eq!(h, 8.0 + offset, "the rect is the block it was given");
         assert_eq!(y, 10.0, "origin is unchanged");
 
-        let quads = crate::widget::WidgetHostExt::all_rounded_quads(&bar, &ctx);
+        let quads = crate::widget::shown_rounded_quads(&bar);
         assert_eq!(quads[0].1, 10.0 + offset, "track is painted below the label region");
         assert_eq!(quads[0].3, 8.0, "track keeps the assigned height");
 
diff --git a/src/widget/display/separator.rs b/src/widget/display/separator.rs
index 520ca7f..5b8e754 100644
--- a/src/widget/display/separator.rs
+++ b/src/widget/display/separator.rs
@@ -89,7 +89,7 @@ mod tests {
         assert!(!crate::widget::WidgetHostExt::blocks_root_plate_drag(&sep));
         if !crate::layout::control_relief() {
             assert_eq!(crate::widget::WidgetHostExt::color(&sep), [0.3, 0.3, 0.3, 1.0]);
-            assert_eq!(crate::widget::WidgetHostExt::extra_quads(&sep), vec![(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0])]);
+            assert_eq!(crate::widget::shown_quads(&sep), vec![(100.0, 0.0, 1.0, 24.0, [0.3, 0.3, 0.3, 1.0])]);
         }
     }
 
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index 947199f..6085e94 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -231,10 +231,11 @@ mod tests {
         assert!(bar.text_buf.is_some());
         assert_eq!(bar.text, "world");
 
-        // Parentless: cornerless plain bg through the plain-quad bridge, at STATUS_BG.
-        let extra = crate::widget::WidgetHostExt::extra_quads(&bar);
-        assert_eq!(extra.len(), 1, "cornerless bg quad");
-        assert_eq!(crate::widget::WidgetHostExt::corner_style(&bar).1, (false, false, false, false));
+        // Parentless: a cornerless plain bg quad, at STATUS_BG.
+        let plain = crate::widget::shown_quads(&bar);
+        assert_eq!(plain.len(), 1, "cornerless bg quad");
+        let cr = crate::widget::WidgetHostExt::corner_radii(&bar);
+        assert_eq!((cr.top_left, cr.top_right, cr.bottom_right, cr.bottom_left), (0.0, 0.0, 0.0, 0.0));
         assert!(!crate::widget::WidgetHostExt::blocks_root_plate_drag(&bar));
     }
 
diff --git a/src/widget/display/status_dot.rs b/src/widget/display/status_dot.rs
index dfa5526..10bb150 100644
--- a/src/widget/display/status_dot.rs
+++ b/src/widget/display/status_dot.rs
@@ -79,11 +79,11 @@ mod tests {
         let mut dot = StatusDot::new(DotStatus::Warning);
         WidgetHost::set_rect(&mut dot, 5.0, 6.0, 10.0, 10.0);
         assert_eq!(
-            crate::widget::WidgetHostExt::all_rounded_quads(&dot, &UiContext::new()),
+            crate::widget::shown_rounded_quads(&dot),
             vec![(5.0, 6.0, 10.0, 10.0, 5.0, [0.90, 0.60, 0.10, 1.0], (true, true, true, true))],
             "a disc: the rect at half-side radius",
         );
-        assert!(crate::widget::WidgetHostExt::extra_quads(&dot).is_empty(), "nothing on the plain path (apps read both)");
+        assert!(crate::widget::shown_quads(&dot).is_empty(), "nothing on the plain path (apps read both)");
         // Drags pass through, as legacy declared.
         assert!(!crate::widget::WidgetHostExt::blocks_root_plate_drag(&dot));
         // State mutation through Deref, as call sites write it.
diff --git a/src/widget/display/usage_bar.rs b/src/widget/display/usage_bar.rs
index 4becbcb..34c3979 100644
--- a/src/widget/display/usage_bar.rs
+++ b/src/widget/display/usage_bar.rs
@@ -110,13 +110,13 @@ mod tests {
         let radius = crate::layout::slider_corner_radius();
         let all = (true, true, true, true);
         assert_eq!(
-            crate::widget::WidgetHostExt::all_rounded_quads(&bar, &crate::widget::UiContext::new()),
+            crate::widget::shown_rounded_quads(&bar),
             vec![
                 (12.0, 30.0, 200.0, 8.0, radius, [0.4, 0.5, 0.6, 1.0], all),
                 (12.0, 30.0, 100.0, 8.0, radius.min(4.0), [0.1, 0.2, 0.3, 1.0], all),
             ],
         );
-        assert!(crate::widget::WidgetHostExt::extra_quads(&bar).is_empty(), "no plain quad leaks to flat hosts");
+        assert!(crate::widget::shown_quads(&bar).is_empty(), "no plain quad leaks to flat hosts");
     }
 
     /// Recessed: no bg quad at all — the fill on the floor, then the carve.
@@ -130,7 +130,7 @@ mod tests {
         assert_eq!(prims.len(), 2, "{prims:?}");
         assert!(matches!(prims[0], Prim::RoundedRect { .. }));
         assert!(matches!(prims[1], Prim::Recess { .. }));
-        assert!(crate::widget::WidgetHostExt::extra_quads(&bar).is_empty(), "no plain bg quad leaks to flat hosts");
+        assert!(crate::widget::shown_quads(&bar).is_empty(), "no plain bg quad leaks to flat hosts");
     }
 
     #[test]
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 8413391..673d342 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -840,14 +840,13 @@ mod tests {
     /// radius, and the label through the prim-derived text bridge with center justification.
     #[test]
     fn geometry_and_label_parity() {
-        let ctx = UiContext::new();
         // Pin the flat style: this test is about the legacy quad-bridge paths,
         // which the config-default raised plate bypasses entirely.
         let b = Button::new(0.0, 0.0, 100.0, 24.0).with_label("Go").with_raised(false);
 
         let radius = crate::layout::button_corner_radius();
-        let rounded = crate::widget::WidgetHostExt::all_rounded_quads(&b, &ctx);
-        let plain = crate::widget::WidgetHostExt::extra_quads(&b);
+        let rounded = crate::widget::shown_rounded_quads(&b);
+        let plain = crate::widget::shown_quads(&b);
         if radius > 0.0 {
             assert!(!rounded.is_empty() && plain.is_empty(), "rounded config -> rounded path only");
             assert_eq!(rounded[0].4, radius);
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index d6362f8..229b22d 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -707,7 +707,10 @@ mod tests {
         let (fcx, fcy) = (f.rect.x + f.rect.width * 0.5, f.rect.y + f.rect.height * 0.5);
         assert!((pcx - fcx).abs() < 1e-3 && (pcy - fcy).abs() < 1e-3, "centred");
         assert!(!p.has_well(), "the plate is all run");
-        assert!(crate::widget::WidgetHostExt::extra_circles(&cb).is_empty(), "no mark");
+        assert!(
+            !crate::widget::shown_prims(&cb).iter().any(|p| matches!(p, crate::scene::paint::Prim::Circle { .. })),
+            "no mark"
+        );
 
         if crate::layout::control_relief() {
             cb.inner_mut().set_checked(false);
diff --git a/src/widget/input/color_selector.rs b/src/widget/input/color_selector.rs
index 061d750..7f6ad90 100644
--- a/src/widget/input/color_selector.rs
+++ b/src/widget/input/color_selector.rs
@@ -1094,7 +1094,7 @@ mod tests {
             !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::WidgetHostExt::extra_quads(&cs);
+        let plain = crate::widget::shown_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:?}");
     }
 
diff --git a/src/widget/input/ramp.rs b/src/widget/input/ramp.rs
index f137029..93cec65 100644
--- a/src/widget/input/ramp.rs
+++ b/src/widget/input/ramp.rs
@@ -385,11 +385,10 @@ impl Paint for ColorRamp {
         }
         
         if self.selected_key_idx.is_some() {
-            let ctx_dummy = crate::context::UiContext::new();
-            quads.extend(self.r_slider.all_quads(&ctx_dummy));
-            quads.extend(self.g_slider.all_quads(&ctx_dummy));
-            quads.extend(self.b_slider.all_quads(&ctx_dummy));
-            quads.extend(self.del_button.all_quads(&ctx_dummy));
+            quads.extend(crate::widget::shown_quads(&self.r_slider));
+            quads.extend(crate::widget::shown_quads(&self.g_slider));
+            quads.extend(crate::widget::shown_quads(&self.b_slider));
+            quads.extend(crate::widget::shown_quads(&self.del_button));
         }
         
         quads
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index ba11444..6d5dc20 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -1120,12 +1120,11 @@ mod tests {
 fn probe_slider_bridge() {
     
     
-    let ctx = UiContext::new();
     let mut sl = Slider::new().with_label("Slider");
     WidgetHost::set_rect(&mut sl, 20.0, 220.0, 200.0, 40.0);
     eprintln!("rect         = {:?}", WidgetHost::rect(&sl));
-    eprintln!("extra_quads  = {:?}", crate::widget::WidgetHostExt::extra_quads(&sl));
-    eprintln!("rounded      = {:?}", crate::widget::WidgetHostExt::all_rounded_quads(&sl, &ctx));
+    eprintln!("quads        = {:?}", crate::widget::shown_quads(&sl));
+    eprintln!("rounded      = {:?}", crate::widget::shown_rounded_quads(&sl));
     eprintln!("labels       = {:?}", sl.own_text_labels().iter().map(|l| l.text.clone()).collect::<Vec<_>>());
 }
 
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 91dca63..ce588db 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -2811,24 +2811,17 @@ mod tests {
 
     #[test]
     fn test_textbox_multiline_selection_highlight() {
-        let dummy = crate::context::UiContext::new();
         let mut tb = TextBox::new("Line 1\nLine 2\nLine 3".to_string()).with_multiline(true);
         tb.set_rect(10.0, 10.0, 200.0, 100.0);
         tb.select_anchor = Some(7); // starts at "Line 2"
         tb.cursor_idx = 13;        // ends at end of "Line 2"
 
-        let has_rounded = crate::widget::WidgetHostExt::corner_style(&tb).1 != (false, false, false, false);
-        let has_highlight = if has_rounded {
-            let rounded = tb.all_rounded_quads(&dummy);
-            println!("Rounded quads: {:?}", rounded);
-            let quads = tb.all_quads(&dummy);
-            rounded.iter().any(|q| q.5 == [0.20, 0.50, 0.85, 0.3])
-                || quads.iter().any(|q| q.4 == [0.20, 0.50, 0.85, 0.3])
-        } else {
-            let extra = tb.extra_quads();
-            println!("Extra quads: {:?}", extra);
-            extra.iter().any(|q| q.4 == [0.20, 0.50, 0.85, 0.3])
-        };
+        use crate::scene::paint::Prim;
+        let highlight = [0.20, 0.50, 0.85, 0.3];
+        let has_highlight = crate::widget::shown_prims(&tb).iter().any(|p| match p {
+            Prim::Quad { color, .. } | Prim::RoundedRect { color, .. } => *color == highlight,
+            _ => false,
+        });
         assert!(has_highlight, "Should have a highlight quad!");
     }
 
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 4da0d65..828f145 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -389,57 +389,36 @@ pub trait WidgetHost {
     
 
     /// Emit this widget's OWN primitives (non-recursive) into the single paint pass (Phase 3).
-    /// The default composes the pieces the legacy recursive `all_*` emit for one node: rounded
-    /// background, plain/decoration quads, circles, and own text. Widgets with richer painting
-    /// (borders, relief primitives, arcs, vectors, SVGs) can override. Recursion into children and clipping
-    /// are handled by the paint walk (`scene::painter`), not here.
+    /// Every production host overrides this (`Adapted`, and `Owned` forwarding to it); the
+    /// default serves a host with no widget of its own (the test shims): its plate — a solid
+    /// border, or a rounded fill in its colour where its corner style rounds — then what its
+    /// model paints, text aside. Recursion into children and clipping are the paint walk's
+    /// (`scene::painter`), not this.
     fn paint_self(&self, ui: &UiContext, ctx: &mut crate::scene::paint::PaintCtx) {
         use crate::scene::layout::Rect;
+        use crate::scene::paint::{PaintCtx, Prim};
         let (x, y, w, h) = self.rect();
         let rect = Rect { x, y, width: w, height: h };
         let color = self.color();
-
-        if ui.tree.children_ptrs(self.base().id()).is_empty() {
-            // Leaf: its rounded background, from its colour and corner style, then the rounded
-            // quads its model paints. (Every production host overrides `paint_self`; this
-            // default serves a host without a model of its own.)
-            let (radius, corners) = self.corner_style();
+        if let Some((border_color, thickness)) = self.solid_border() {
+            let cr = self.corner_radii();
+            ctx.border(rect, (cr.top_left, cr.top_right, cr.bottom_right, cr.bottom_left), color, border_color, thickness);
+        } else if let Some((radius, corners)) = self.paint_model().corner_style(self.content_rect()) {
             if corners != (false, false, false, false) && color[3].abs() > 0.001 {
                 ctx.rounded_rect(rect, radius, corners, color);
             }
-            for (qx, qy, qw, qh, r, c, corners) in self.all_rounded_quads(ui) {
-                ctx.rounded_rect(Rect { x: qx, y: qy, width: qw, height: qh }, r, corners, c);
-            }
-        } else {
-            // Container: reconstruct its own plate (bevel / border / rounded background) — mirrors
-            // `push_widget_vertices`. Its children are drawn by the paint walk, so we must NOT call
-            // `all_rounded_quads` here (that would recurse and double-draw them).
-            let cr = self.corner_radii();
-            let radii = (cr.top_left, cr.top_right, cr.bottom_right, cr.bottom_left);
-            if let Some((border_color, thickness)) = self.solid_border() {
-                ctx.border(rect, radii, color, border_color, thickness);
-            } else if color[3].abs() > 0.001 {
-                let (radius, (r1, r2, r3, r4)) = self.corner_style();
-                if r1 || r2 || r3 || r4 {
-                    ctx.rounded_rect(rect, radius, (r1, r2, r3, r4), color);
-                }
-            }
         }
-
-        for (qx, qy, qw, qh, c) in self.all_quads(ui) {
-            ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, c);
-        }
-        for (cx, cy, r, t, start, end, c) in self.extra_arcs() {
-            ctx.arc(cx, cy, r, t, start, end, c);
+        if !self.visible() {
+            return;
         }
-        for (cx, cy, r, c) in self.extra_circles() {
-            ctx.circle(cx, cy, r, c);
+        // Text: none. A host with text of its own overrides this; emitting the model's text
+        // here would double what the walk's descent draws for a container (the Phase 6d trap).
+        let mut tmp = PaintCtx::new();
+        self.paint_model().paint_ui(ui, self.content_rect(), &mut tmp);
+        for item in tmp.finish().items {
+            // `replay` emits every prim but Text, which it hands back; dropping it is the point.
+            let _text: Option<Prim> = ctx.replay(item.prim);
         }
-        // Text: NONE by default. Every live legacy widget with own text carries a
-        // paint_self override (most via `scene::painter::paint_legacy_leaf` + its own
-        // labels); containers' text_labels aggregates are covered by the walk's descent
-        // (emitting them here would double-draw every descendant's text — the Phase 6d
-        // trap). Migrated widgets go through `Adapted::paint_self`, never this default.
     }
 
 
@@ -448,8 +427,7 @@ pub trait WidgetHost {
 
     // The per-widget text getters (text_labels / text_labels_with_bounds /
     // text_labels_with_font_and_bounds / get_text_items) are GONE: every widget emits
-    // its own text as display-list prims via paint_self (Adapted::paint_self for
-    // migrated widgets; paint_legacy_leaf-based overrides for the legacy leaves). The
+    // its own text as display-list prims via paint_self (Adapted::paint_self). The
     // deleted default's base-label synthesis lives on in Adapted's base-label fallback,
     // and its scroll-ancestor clamp in scene::painter::scroll_ancestor_text_bounds.
 
@@ -616,7 +594,8 @@ pub trait WidgetHostExt: WidgetHost {
     }
 
     fn corner_radii(&self) -> CornerRadii {
-        let (r, (tl, tr, br, bl)) = self.corner_style();
+        let (r, (tl, tr, br, bl)) =
+            self.paint_model().corner_style(self.content_rect()).unwrap_or((0.0, (false, false, false, false)));
         CornerRadii::new(
             if tl { r } else { 0.0 },
             if tr { r } else { 0.0 },
@@ -640,14 +619,11 @@ pub trait WidgetHostExt: WidgetHost {
         }
     }
 
-    // ── The legacy tuple views ──────────────────────────────────────────────────
-    // What a widget paints, projected onto the pre-display-list surface: plain quads,
-    // rounded quads, arcs, circles, the shared highlight, the corner style. Hosts that
-    // still draw a widget through these rather than `paint_self` — the designer's render
-    // loop, the gallery, the display manager, the settings app's flat collector,
-    // cce-secrets, the flat-host bridge — read them here. They were `WidgetHost` methods
-    // until 2026-10-08, each implemented by `Adapted` from its widget's `Paint`; they are
-    // computed from the models now, the same way.
+    // ── What the widget paints, read from its model ──────────────────────────────
+    // The legacy tuple views (`extra_quads`, `all_quads`, `all_rounded_quads`,
+    // `extra_arcs`, `extra_circles`, `highlight_quad`, `corner_style`) are gone since
+    // 2026-10-08: every host paints a widget through `paint_self` / the paint walk, and a
+    // composite that draws a child's chrome in its own order reads `painted_prims`.
 
     /// The rect the widget's model paints into: the host's rect below its detached label.
     fn content_rect(&self) -> crate::scene::layout::Rect {
@@ -674,159 +650,43 @@ pub trait WidgetHostExt: WidgetHost {
         }
         model.container_children().into_iter().filter(|c| model.child_visible(*c)).collect()
     }
+}
 
-    /// The corner radius and which corners it rounds; 12 and none for a widget without a
-    /// corner style.
-    fn corner_style(&self) -> (f32, (bool, bool, bool, bool)) {
-        self.paint_model().corner_style(self.content_rect()).unwrap_or((12.0, (false, false, false, false)))
-    }
-
-    /// The legacy hover/focus highlight over the row span: only for a widget that opts into
-    /// it ([`Paint::legacy_focus_highlight`], the TextBox) or forwards one
-    /// ([`Paint::forwarded_highlight`], the Paginator's ButtonStrip). Primary tint when
-    /// focused, secondary when hovered.
-    fn highlight_quad(&self, ctx: &UiContext) -> Option<(f32, f32, f32, f32, [f32; 4])> {
-        if let Some(forwarded) = self.paint_model().forwarded_highlight(ctx) {
-            return forwarded;
-        }
-        if !self.paint_model().legacy_focus_highlight() {
-            return None;
-        }
-        let b = self.base();
-        let hc = if ctx.is_focused_id(b.id()) {
-            colors::highlight_primary_color()
-        } else if b.hovered {
-            colors::HIGHLIGHT_SECONDARY
-        } else {
-            return None;
-        };
-        let hx = if b.row_w > 0.0 { b.row_x } else { b.x };
-        let hw = if b.row_w > 0.0 { b.row_w } else { b.w };
-        Some((hx, b.y, hw, b.h, hc))
-    }
-
-    /// The widget's own plain-quad prims.
-    fn own_plain_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        self.painted_prims()
-            .into_iter()
-            .filter_map(|prim| match prim {
-                crate::scene::paint::Prim::Quad { rect, color } => Some((rect.x, rect.y, rect.width, rect.height, color)),
-                _ => None,
-            })
-            .collect()
-    }
-
-    /// The plain-quad view: a widget's own plain quads, or the legacy view it serves
-    /// ([`Paint::legacy_plain_quads`]), or — for an aggregating container (the Paginator) —
-    /// its visible children's.
-    fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        if !self.visible() {
-            return Vec::new();
-        }
-        if self.paint_model().serves_legacy_plain_quads() {
-            return self.paint_model().legacy_plain_quads(self.content_rect());
-        }
-        if self.paint_model().aggregates_child_extra_quads() {
-            let mut out = Vec::new();
-            for child in self.visible_children() {
-                out.extend(unsafe { &*child }.extra_quads());
-            }
-            return out;
-        }
-        self.own_plain_quads()
-    }
+impl<T: WidgetHost + ?Sized> WidgetHostExt for T {}
 
-    /// Every plain quad the widget and its visible children draw, the opted-in highlight
-    /// included (not the hover tint), a rounded child's background left to
-    /// [`all_rounded_quads`](Self::all_rounded_quads). Empty for a widget serving the
-    /// legacy plain-quad view, which reaches flat hosts through `all_rounded_quads` only.
-    fn all_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        if self.paint_model().serves_legacy_plain_quads() {
-            return Vec::new();
-        }
-        let mut quads = if self.visible() { self.own_plain_quads() } else { Vec::new() };
-        if self.paint_model().legacy_focus_highlight() {
-            if let Some(hq) = self.highlight_quad(ctx) {
-                if hq.4 != colors::HIGHLIGHT_SECONDARY {
-                    quads.push(hq);
-                }
+/// A shown widget's prims as its model paints them, nothing while it is hidden — for a
+/// composite that draws a child's chrome in its own order rather than walking it (the params
+/// pane's rows, the ramp's key editor, the menubar's strip).
+pub(crate) fn shown_prims<W: WidgetHost + ?Sized>(w: &W) -> Vec<crate::scene::paint::Prim> {
+    if w.visible() { w.painted_prims() } else { Vec::new() }
+}
+
+/// The plain quads among [`shown_prims`], as `(x, y, w, h, colour)`.
+pub(crate) fn shown_quads<W: WidgetHost + ?Sized>(w: &W) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
+    shown_prims(w)
+        .into_iter()
+        .filter_map(|prim| match prim {
+            crate::scene::paint::Prim::Quad { rect, color } => Some((rect.x, rect.y, rect.width, rect.height, color)),
+            _ => None,
+        })
+        .collect()
+}
+
+/// The rounded quads among [`shown_prims`], as `(x, y, w, h, radius, colour, corners)`.
+pub(crate) fn shown_rounded_quads<W: WidgetHost + ?Sized>(
+    w: &W,
+) -> Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))> {
+    shown_prims(w)
+        .into_iter()
+        .filter_map(|prim| match prim {
+            crate::scene::paint::Prim::RoundedRect { rect, radius, corners, color } => {
+                Some((rect.x, rect.y, rect.width, rect.height, radius, color, corners))
             }
-        }
-        if self.visible() {
-            for child in self.visible_children() {
-                let widget = unsafe { &*child };
-                let (wx, wy, ww, wh) = widget.rect();
-                let has_rounded = widget.corner_style().1 != (false, false, false, false);
-                for (qx, qy, qw, qh, qc) in widget.all_quads(ctx) {
-                    if has_rounded
-                        && (qx - wx).abs() < 0.1
-                        && (qy - wy).abs() < 0.1
-                        && (qw - ww).abs() < 0.1
-                        && (qh - wh).abs() < 0.1
-                    {
-                        continue;
-                    }
-                    quads.push((qx, qy, qw, qh, qc));
-                }
-            }
-        }
-        quads
-    }
-
-    /// Every rounded quad the widget and its visible children draw.
-    fn all_rounded_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))> {
-        if !self.visible() {
-            return Vec::new();
-        }
-        let mut out: Vec<_> = self
-            .painted_prims()
-            .into_iter()
-            .filter_map(|prim| match prim {
-                crate::scene::paint::Prim::RoundedRect { rect, radius, corners, color } => {
-                    Some((rect.x, rect.y, rect.width, rect.height, radius, color, corners))
-                }
-                _ => None,
-            })
-            .collect();
-        for child in self.visible_children() {
-            out.extend(unsafe { &*child }.all_rounded_quads(ctx));
-        }
-        out
-    }
-
-    /// The widget's arc prims.
-    fn extra_arcs(&self) -> Vec<(f32, f32, f32, f32, f32, f32, [f32; 4])> {
-        if !self.visible() {
-            return Vec::new();
-        }
-        self.painted_prims()
-            .into_iter()
-            .filter_map(|prim| match prim {
-                crate::scene::paint::Prim::Arc { cx, cy, radius, thickness, start, end, color } => {
-                    Some((cx, cy, radius, thickness, start, end, color))
-                }
-                _ => None,
-            })
-            .collect()
-    }
-
-    /// The widget's circle prims.
-    fn extra_circles(&self) -> Vec<(f32, f32, f32, [f32; 4])> {
-        if !self.visible() {
-            return Vec::new();
-        }
-        self.painted_prims()
-            .into_iter()
-            .filter_map(|prim| match prim {
-                crate::scene::paint::Prim::Circle { cx, cy, radius, color } => Some((cx, cy, radius, color)),
-                _ => None,
-            })
-            .collect()
-    }
+            _ => None,
+        })
+        .collect()
 }
 
-impl<T: WidgetHost + ?Sized> WidgetHostExt for T {}
-
 /// The narrow traits' defaults, for a host that has no widget model of its own (the test
 /// shims that implement `WidgetHost` directly): transparent, no focus role, no value.
 pub struct NoModel;
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 4993467..ab43e38 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -175,10 +175,9 @@ pub trait Paint {
 
     /// Corner rounding `(radius, per-corner flags)` of the widget's background, given its
     /// laid-out rect (MenuBar's corners depend on where it sits against its parent's edges).
-    /// **Transitional:** this exists only for legacy render paths that draw widget backgrounds
-    /// themselves from style properties (`widget_vertices` / `push_widget_vertices` readers of
-    /// `WidgetHost::corner_radius` + `rounded_corners`) — the widget's real geometry is whatever
-    /// [`paint`](Paint::paint) emits. Dies with those paths. Default: sharp corners.
+    /// What a host drawing the widget's PLATE reads — `WidgetHostExt::corner_radii`, the
+    /// designer's `append_widget_plate`, the flat-host bridge; the widget's own geometry is
+    /// whatever [`paint`](Paint::paint) emits. Default: sharp corners.
     fn corner_style(&self, _rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
         None
     }
@@ -231,25 +230,6 @@ pub trait Paint {
     /// base-label machinery.
     fn sync_label(&mut self, _label: &str) {}
 
-    // --- Legacy dual-geometry escape hatch (transitional; Graph is the only user). Legacy
-    // hosts read DIFFERENT getters: the designer's raw render path draws `extra_quads` as
-    // PLAIN quads, while `render_widget` and the scene walk consume the rounded view
-    // (`all_rounded_quads` / `paint_self`). Legacy Graph served both by overriding all three
-    // getters. A migrated widget emits the rounded view from `paint`; when it also serves a
-    // plain view, the adapter returns it verbatim from `extra_quads` and empties `all_quads`
-    // (mirroring legacy Graph's highlight-only override) so render_widget-style hosts that
-    // read BOTH getters never draw the geometry twice. Dies with `WidgetHost`.
-
-    /// Whether this widget serves [`legacy_plain_quads`](Paint::legacy_plain_quads).
-    fn serves_legacy_plain_quads(&self) -> bool {
-        false
-    }
-
-    /// The plain-quad view of this widget's geometry for legacy `extra_quads` readers.
-    fn legacy_plain_quads(&self, _rect: Rect) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        Vec::new()
-    }
-
     /// Clip rect `[x1, y1, x2, y2]` for this widget's text on the legacy bounded-text paths
     /// (`text_labels_with_bounds` / `text_labels_with_font_and_bounds`). `None` (default) keeps
     /// the legacy behavior: unbounded, except inside a scroll ancestor. Graph clips its node
@@ -274,38 +254,13 @@ pub trait Paint {
     }
 
 
-    /// Whether the adapter re-enables the legacy shared focus/hover highlight overlay
-    /// (`WidgetHost::highlight_quad`'s default) for this widget. The adapter suppresses it for
-    /// migrated widgets — matching the `None` overrides most legacy controls carried — but
-    /// legacy TextBox kept the default: the focused editor gets the primary-highlight tint
-    /// over its background (data-editor's teal editing wash). Default: suppressed.
+    /// Whether the widget wears the shared focus highlight: the primary tint over its row
+    /// span while it holds focus, drawn by the adapter over its background. Only the TextBox
+    /// opts in (the focused editor's teal wash in the data editor). Default: none.
     fn legacy_focus_highlight(&self) -> bool {
         false
     }
 
-    /// Legacy container `extra_quads` aggregation: when `true`, the adapter's `extra_quads`
-    /// serves the visible children's `extra_quads` — and ONLY those, like the legacy container
-    /// overrides (Paginator returned its strip's + selected page's chrome; its own background
-    /// quad lived in `all_quads` alone). Hosts that render a container through the plain
-    /// `extra_quads` getter (cce-mail's and cce-layout-interface's sidebar draw) read exactly
-    /// this view. The widget's own [`paint`](Paint::paint) prims still reach `all_quads` and
-    /// the scene walk. Default: off (a leaf's `extra_quads` is its own prims).
-    fn aggregates_child_extra_quads(&self) -> bool {
-        false
-    }
-
-    /// Forward the legacy `WidgetHost::highlight_quad` to somewhere else entirely — Paginator
-    /// served its ButtonStrip's highlight (the hovered-tab tint cce-layout-interface draws by
-    /// calling `highlight_quad` directly). Outer `Some` replaces the adapter's highlight logic
-    /// with the inner value; `None` (default) keeps the standard behavior
-    /// ([`legacy_focus_highlight`](Paint::legacy_focus_highlight)). A forwarded highlight is
-    /// served ONLY through the direct `highlight_quad` getter — the adapter keeps it out of
-    /// `all_quads`/`paint_self`, where the child's own aggregation already carries it (legacy
-    /// containers likewise excluded it from their `all_quads` overrides).
-    fn forwarded_highlight(&self, _ctx: &UiContext) -> Option<Option<(f32, f32, f32, f32, [f32; 4])>> {
-        None
-    }
-
     /// Whether this widget serves
     /// [`legacy_labels_with_font_and_bounds`](Paint::legacy_labels_with_font_and_bounds) —
     /// the text sibling of the dual-geometry escape hatch. The adapter's standard text bridge
@@ -1297,15 +1252,12 @@ impl<W: Layout + Paint + Input + 'static> WidgetHost for Adapted<W> {
                 ctx.pop_clip_circle();
             }
         }
-        // The legacy default `paint_self` drained `all_quads`, which carries the focus
-        // highlight — replicate for opt-in widgets, over the background (same draw order).
-        // Forwarded highlights stay out: the paint walk reaches the owning child itself.
-        if Paint::legacy_focus_highlight(&self.inner) {
-            if let Some((hx, hy, hw, hh, hc)) = crate::widget::WidgetHostExt::highlight_quad(self, ui) {
-                if hc != crate::colors::HIGHLIGHT_SECONDARY {
-                    ctx.quad(Rect { x: hx, y: hy, width: hw, height: hh }, hc);
-                }
-            }
+        // The focus highlight a widget opts into (the TextBox): the primary tint over the
+        // row span while focused, over the background. (The hover tint never drew here.)
+        if Paint::legacy_focus_highlight(&self.inner) && ui.is_focused_id(self.base.id()) {
+            let b = &self.base;
+            let (hx, hw) = if b.row_w > 0.0 { (b.row_x, b.row_w) } else { (b.x, b.w) };
+            ctx.quad(Rect { x: hx, y: b.y, width: hw, height: b.h }, crate::colors::highlight_primary_color());
         }
         // Own text with per-label font+bounds: the hatch view verbatim for hatched widgets
         // (caveat: its contract includes raw container children — those few widgets keep the
@@ -1346,13 +1298,6 @@ impl<W: Layout + Paint + Input + 'static> WidgetHost for Adapted<W> {
     // detached base label), and composites that need a concrete Adapted child's labels
     // call `own_labels_with_font_and_bounds` directly (pub(crate)).
 
-    // --- Reverse bridges: [`Paint::paint`] output converted back to the legacy geometry
-    // getters external render loops read (cce-test-interface's `all_*` calls, `render_widget`'s
-    // `all_quads` loop, the demo's `extra_*` loops). Each prim kind maps to the getter legacy
-    // widgets used for it — plain quads to `extra_quads` (→ `all_quads`), rounded to
-    // `all_rounded_quads` — so apps that read BOTH getters draw each prim exactly once. Covers
-    // the widget's OWN geometry only: adapted widgets are leaves for now; recursion belongs to
-    // `scene::painter`.