GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
refactor(widget): constant-fold and delete the dead backplate/plate flags (Phase 6at)
Census round 2 after the container-type deletion: seven Element methods
have zero overrides anywhere in the workspace — only the trait default
exists, so each is a constant. Five are pure constants and are folded at
every call site and deleted:
- capture_event: the capture-phase branch in propagate_event_impl was
unreachable (always false) — branch and method deleted.
- is_active: folded into the highlight_color default (focused || false).
- is_plate: constant false; no fold sites remain in cce-ui (designer's
parent_plate_rect machinery dies in its own repo).
- is_backplate / is_movable_backplate: constant false. Folded the drag
walks — UiContext::is_movable_backplate_at had become constant-false
on every path and is deleted; the Application-trait default now
returns false directly (apps that want drag-anywhere already override
with ctx.drag_allowed_at). Also folded the backplate-parent branches:
MenuBar/StatusBar theming + corners_against_parent (always all-false;
paint is now the plain background quad, corner_style still reports the
parent radius for children that read it through the parent pointer),
and Dropdown's backplate_ancestor concentric-corner walk (only the
app-owned corner_frame adjusts corners now).
corner_radii and mark_dirty also have zero overrides but carry real
derived logic — they die with the tree retype, not by folding.
Element: 112 -> 107 methods. 171 tests pass. A/B on the live
compositor: cce-files AE=0, settings audio AE=0, designer diff =
unrelated terminal text behind the translucent window.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk
src/backend/window_runner.rs | 11 +++----
src/context.rs | 70 ++++++----------------------------------
src/widget/container/menu.rs | 60 ++++------------------------------
src/widget/display/status_bar.rs | 61 ++++------------------------------
src/widget/input/dropdown.rs | 25 +++-----------
src/widget/mod.rs | 13 ++------
6 files changed, 34 insertions(+), 206 deletions(-)
diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 9c1c5c1..b22c4cd 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -1539,12 +1539,11 @@ pub trait Application: Sized + 'static {
None
}
- fn is_movable_backplate_at(&self, px: f32, py: f32) -> bool {
- if let Some(ctx) = self.ui_context() {
- ctx.is_movable_backplate_at(px, py)
- } else {
- false
- }
+ /// Whether a left-press at (px, py) should start a compositor window drag. Every root
+ /// `Backplate` is dissolved (Phase 6), so the default is "no" — apps that want
+ /// drag-anywhere override this with `ctx.drag_allowed_at(px, py)`.
+ fn is_movable_backplate_at(&self, _px: f32, _py: f32) -> bool {
+ false
}
fn clear_color(&self) -> [f32; 4] {
diff --git a/src/context.rs b/src/context.rs
index db0bad1..c58f467 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -248,12 +248,6 @@ impl UiContext {
return false;
}
- // 1. Capture Phase: parent intercepts
- if (*root).capture_event(event, self) {
- (*root).mark_dirty(self);
- return true;
- }
-
// For KeyInput, send directly to focused widget if it exists
if let Event::KeyInput(_) = event {
if let Some(focused) = self.focused_widget {
@@ -797,49 +791,9 @@ impl UiContext {
false
}
- pub fn is_movable_backplate_at(&self, px: f32, py: f32) -> bool {
- if self.point_in_active_popover(px, py) {
- return false;
- }
- let mut hit_backplate = false;
- let scroll_y = crate::widget::hover_animation::get_scroll_offset();
- let mut candidate_ids = self.spatial_grid.query(px, py).to_vec();
- if scroll_y != 0.0 {
- candidate_ids.extend_from_slice(self.spatial_grid.query(px, py + scroll_y));
- candidate_ids.sort_unstable();
- candidate_ids.dedup();
- }
- for &id in &candidate_ids {
- if let Some(ptr) = self.tree.get_ptr(id) {
- unsafe {
- if !ptr.is_null() {
- let w = &*ptr;
- let is_hit = if w.is_backplate() {
- w.hit_test(px, py, self)
- } else {
- w.hit_test(px, py, self) || (scroll_y != 0.0 && w.hit_test(px, py + scroll_y, self))
- };
- if is_hit {
- if w.is_backplate() {
- if w.is_movable_backplate() {
- hit_backplate = true;
- }
- } else if w.blocks_backplate_drag() {
- return false;
- }
- }
- }
- }
- }
- }
- hit_backplate
- }
-
- /// The drag question for windows whose root `Backplate` has been DISSOLVED (Phase 6): the
- /// surface itself is the movable plate, so all that matters is whether a drag-blocking
- /// widget sits under the cursor — the same walk as
- /// [`is_movable_backplate_at`](UiContext::is_movable_backplate_at) minus the requirement
- /// that a registered movable `Backplate` is hit.
+ /// The window-drag question (Phase 6: every root `Backplate` is dissolved, so the surface
+ /// itself is the movable plate): a drag may start anywhere no drag-blocking widget sits
+ /// under the cursor.
pub fn drag_allowed_at(&self, px: f32, py: f32) -> bool {
if self.point_in_active_popover(px, py) {
return false;
@@ -858,7 +812,7 @@ impl UiContext {
let w = &*ptr;
let is_hit = w.hit_test(px, py, self)
|| (scroll_y != 0.0 && w.hit_test(px, py + scroll_y, self));
- if is_hit && !w.is_backplate() && w.blocks_backplate_drag() {
+ if is_hit && w.blocks_backplate_drag() {
return false;
}
}
@@ -881,11 +835,9 @@ impl UiContext {
unsafe {
if !ptr.is_null() {
let w = &*ptr;
- if !w.is_backplate() {
- let is_hit = w.hit_test(px, py, self) || (scroll_y != 0.0 && w.hit_test(px, py + scroll_y, self));
- if is_hit && w.blocks_backplate_drag() {
- return true;
- }
+ let is_hit = w.hit_test(px, py, self) || (scroll_y != 0.0 && w.hit_test(px, py + scroll_y, self));
+ if is_hit && w.blocks_backplate_drag() {
+ return true;
}
}
}
@@ -934,9 +886,8 @@ mod tests {
}
}
- /// `drag_allowed_at` — the dissolved-root-Backplate drag question: allowed on empty
- /// surface, denied over a drag-blocking widget (same walk as `is_movable_backplate_at`
- /// minus the registered-Backplate requirement, which a dissolved window can't meet).
+ /// `drag_allowed_at` — the window-drag question: allowed on empty surface, denied over a
+ /// drag-blocking widget.
#[test]
fn drag_allowed_everywhere_except_blocking_widgets() {
let mut ctx = UiContext::new();
@@ -947,8 +898,5 @@ mod tests {
assert!(ctx.drag_allowed_at(200.0, 200.0), "empty surface is draggable");
assert!(!ctx.drag_allowed_at(20.0, 20.0), "a drag-blocking widget denies the drag");
- // The Backplate-rooted question stays false here — no movable Backplate exists,
- // which is exactly why dissolved windows need drag_allowed_at.
- assert!(!ctx.is_movable_backplate_at(200.0, 200.0));
}
}
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index 5ca5cae..c7c8a4c 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -225,20 +225,10 @@ impl MenuBar {
}
pub fn text_color(&self) -> [f32; 4] {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- return crate::colors::backplate_menubar_text_color();
- }
- }
crate::colors::menubar_tab_label_color()
}
pub fn is_blur_enabled(&self) -> bool {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- return crate::colors::backplate_menubar_blur();
- }
- }
self.blur
}
@@ -249,37 +239,9 @@ impl MenuBar {
}
fn bg_color(&self) -> [f32; 4] {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- return crate::colors::backplate_menubar_color();
- }
- }
self.color.unwrap_or_else(|| colors::sidebar_bg_color())
}
- fn corners_against_parent(&self, rect: Rect) -> (bool, bool, bool, bool) {
- if let Some(p_ptr) = self.parent {
- let is_bp = unsafe { (*p_ptr).is_backplate() };
- if is_bp {
- let (px, py, pw, ph) = unsafe { (*p_ptr).rect() };
- let (x, y, w, h) = (rect.x, rect.y, rect.width, rect.height);
- let is_at_top = (y - py).abs() < 0.1;
- let is_at_bottom = (y + h - (py + ph)).abs() < 0.1;
-
- if is_at_top && is_at_bottom {
- let is_at_left = (x - px).abs() < 0.1;
- let is_at_right = (x + w - (px + pw)).abs() < 0.1;
- return (is_at_left, is_at_right, is_at_right, is_at_left);
- } else if is_at_top {
- return (true, true, false, false);
- } else if is_at_bottom {
- return (false, false, true, true);
- }
- }
- }
- (false, false, false, false)
- }
-
/// Position the embedded strip inside `rect` — the legacy `set_rect` body, minus the
/// parent clamping (that lives in [`Layout::adjust_rect`]) and the base assignment (the
/// adapter's). Early-outs when the rect and content are unchanged, like legacy.
@@ -503,12 +465,14 @@ impl Paint for MenuBar {
self.bg_color()
}
- fn corner_style(&self, rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
+ fn corner_style(&self, _rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
+ // Corners never round (the backplate-adjacency source is gone); the radius is still
+ // reported for children that read it through the parent pointer.
let radius = match self.parent {
Some(p_ptr) => unsafe { (*p_ptr).corner_radius() },
None => 0.0,
};
- Some((radius, self.corners_against_parent(rect)))
+ Some((radius, (false, false, false, false)))
}
fn widget_font(&self) -> Option<String> {
@@ -521,19 +485,9 @@ impl Paint for MenuBar {
}
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- // Background: plain when cornerless (the legacy extra_quads bg), rounded against the
- // parent's corners otherwise (the legacy Element-default all_rounded_quads bg).
- let corners = self.corners_against_parent(rect);
- let bg = self.bg_color();
- if corners == (false, false, false, false) {
- ctx.quad(rect, bg);
- } else if bg[3].abs() > 0.001 {
- let radius = match self.parent {
- Some(p_ptr) => unsafe { (*p_ptr).corner_radius() },
- None => 0.0,
- };
- ctx.rounded_rect(rect, radius, corners, bg);
- }
+ // Background: always the plain quad — the rounded-against-parent variant required a
+ // backplate parent, which no longer exists.
+ ctx.quad(rect, self.bg_color());
// Title highlight while the context dropdown is open / hovered.
if !self.context_options.is_empty() {
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index a40a538..62f8fc7 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -47,58 +47,17 @@ impl StatusBar {
}
pub fn get_actual_text_color(&self) -> [f32; 4] {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- return crate::colors::backplate_statusbar_text_color();
- }
- }
self.text_color.unwrap_or([0.6666, 0.6666, 0.7333, 1.0])
}
pub fn is_blur_enabled(&self) -> bool {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- return crate::colors::backplate_statusbar_blur();
- }
- }
false
}
fn bg(&self) -> [f32; 4] {
- if let Some(p_ptr) = self.parent {
- if unsafe { (*p_ptr).is_backplate() } {
- let theme_color = crate::colors::backplate_statusbar_color();
- if theme_color[3] > 0.001 {
- return theme_color;
- }
- }
- }
self.bg_color.unwrap_or(colors::STATUS_BG)
}
- fn corners_against_parent(&self, rect: Rect) -> (bool, bool, bool, bool) {
- if let Some(p_ptr) = self.parent {
- let is_bp = unsafe { (*p_ptr).is_backplate() };
- if is_bp {
- let (px, py, pw, ph) = unsafe { (*p_ptr).rect() };
- let (x, y, w, h) = (rect.x, rect.y, rect.width, rect.height);
- let is_at_top = (y - py).abs() < 0.1;
- let is_at_bottom = (y + h - (py + ph)).abs() < 0.1;
-
- if is_at_top && is_at_bottom {
- let is_at_left = (x - px).abs() < 0.1;
- let is_at_right = (x + w - (px + pw)).abs() < 0.1;
- return (is_at_left, is_at_right, is_at_right, is_at_left);
- } else if is_at_top {
- return (true, true, false, false);
- } else if is_at_bottom {
- return (false, false, true, true);
- }
- }
- }
- (false, false, false, false)
- }
-
fn statusbar_font_size(&self) -> f32 {
let (_, font_size) = crate::layout::statusbar_font_parsed();
if font_size > 0.0 { font_size } else { 12.0 }
@@ -150,12 +109,14 @@ impl Paint for StatusBar {
self.bg()
}
- fn corner_style(&self, rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
+ fn corner_style(&self, _rect: Rect) -> Option<(f32, (bool, bool, bool, bool))> {
+ // Corners never round (the backplate-adjacency source is gone); the radius is still
+ // reported for children that read it through the parent pointer.
let radius = match self.parent {
Some(p_ptr) => unsafe { (*p_ptr).corner_radius() },
None => 0.0,
};
- Some((radius, self.corners_against_parent(rect)))
+ Some((radius, (false, false, false, false)))
}
/// `Element::set_text` lands here: swap the text and drop the shaped buffer so
@@ -172,17 +133,9 @@ impl Paint for StatusBar {
/// default `all_rounded_quads` path) — plus the text label (the legacy `text_labels`
/// body; deliberately no `widget_font`, see module docs).
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- let corners = self.corners_against_parent(rect);
- let bg = self.bg();
- if corners == (false, false, false, false) {
- ctx.quad(rect, bg);
- } else if bg[3].abs() > 0.001 {
- let radius = match self.parent {
- Some(p_ptr) => unsafe { (*p_ptr).corner_radius() },
- None => 0.0,
- };
- ctx.rounded_rect(rect, radius, corners, bg);
- }
+ // Always the plain background quad — the rounded-against-parent variant required a
+ // backplate parent, which no longer exists.
+ ctx.quad(rect, self.bg());
if !self.text.is_empty() {
let offset_x = self.text_offset_x.unwrap_or(12.0);
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 446a29f..a7b75c4 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -21,7 +21,7 @@ use crate::scene::layout::{Rect, Size};
use crate::scene::paint::PaintCtx;
use crate::widget::model::{Adapted, EventCtx, Input, Layout, Paint};
use crate::widget::{
- Control, Element, ElementState, Event, Key, MouseButton, NamedKey, UiContext,
+ Control, Element, ElementState, Event, Key, MouseButton, NamedKey,
};
/// Side-layout label inset — the legacy `Element::label_x_offset` default for non-exempt
@@ -201,21 +201,6 @@ impl Dropdown {
}
}
- /// The legacy backplate-ancestor lookup for concentric corners, walked from the tracked
- /// parent with a dummy ctx (field-based legacy `parent` impls answer; tree-only ones end
- /// the walk, so deep tree-linked chains lose the adjustment — flagged in the module docs).
- fn backplate_ancestor(&self) -> Option<*mut (dyn Element + 'static)> {
- let dummy = crate::context::UiContext::new();
- let mut curr = self.tracked_parent;
- while let Some(ptr) = curr {
- if unsafe { (*ptr).is_backplate() } {
- return Some(ptr);
- }
- curr = unsafe { (*ptr).parent(&dummy) };
- }
- None
- }
-
/// Emit the border + background geometry — the legacy `all_rounded_quads` body (rounded,
/// with the backplate-concentric corner adjustment) or `extra_quads` (plain) depending on
/// the configured radius, byte-for-byte on the same content rect.
@@ -245,11 +230,9 @@ impl Dropdown {
let mut outer_radii = [radius; 4];
let mut inner_radii = [inner_radius; 4];
- let frame = self.corner_frame.or_else(|| {
- self.backplate_ancestor().map(|bp| unsafe {
- ((*bp).rect(), (*bp).corner_radius(), (*bp).rounded_corners())
- })
- });
+ // Only an explicit corner_frame adjusts concentric corners now — the legacy fallback
+ // walked ancestors for a backplate, which no longer exists.
+ let frame = self.corner_frame;
if let Some(((px, py, pw, ph), pr, (pr1, pr2, pr3, pr4))) = frame {
let g_left = x - px;
let g_top = y - py;
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index ec7c145..070de74 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -189,10 +189,6 @@ pub trait Element {
event
}
- fn capture_event(&mut self, _event: &Event, _ctx: &mut UiContext) -> bool {
- false
- }
-
fn mark_dirty(&mut self, ctx: &mut UiContext) {
let mut parent_id = None;
if let Some(b) = self.base_mut() {
@@ -410,11 +406,9 @@ pub trait Element {
}
}
- fn is_active(&self) -> bool { false }
-
fn highlight_color(&self, ctx: &UiContext) -> Option<[f32; 4]> {
let is_focused = ctx.is_focused_addr(self as *const Self as *const () as usize);
- if is_focused || self.is_active() {
+ if is_focused {
Some(colors::highlight_primary_color())
} else if self.hovered() {
Some(colors::HIGHLIGHT_SECONDARY)
@@ -449,7 +443,7 @@ pub trait Element {
fn label_x_offset(&self) -> f32 {
let name = self.type_name();
- if name == "Label" || name == "Button" || name == "Checkbox" || name == "Toggle" || name == "Plate" || name == "Ramp" {
+ if name == "Label" || name == "Button" || name == "Checkbox" || name == "Toggle" || name == "Ramp" {
return 0.0;
}
if crate::layout::control_label_layout() == "side" && self.base().map_or(false, |b| b.label.is_some()) {
@@ -670,10 +664,7 @@ pub trait Element {
}
fn z_index(&self) -> i32 { 0 }
- fn is_plate(&self) -> bool { false }
fn is_page(&self) -> bool { false }
- fn is_backplate(&self) -> bool { false }
- fn is_movable_backplate(&self) -> bool { false }
fn is_scrollable(&self) -> bool { false }
fn blocks_backplate_drag(&self) -> bool { true }
fn rounded_corners(&self) -> (bool, bool, bool, bool) { (false, false, false, false) }