GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
refactor(widget)!: set_parent/add_child off Element — linking is a tree op (6bd)
Element 69 -> 67 (series count). Both methods move to inherent Adapted<W>
(files' ten set_parent(None) sites resolve unchanged); the dyn callers were
three:
- focus::link_parent_child body: the add_child + set_parent pair became the
register + tree.link + tree.set_parent ops it always was (the container
parent-back extra produced the same symmetric link).
- TI's page-selector/StatusBar pair of dyn roster calls -> one
link_parent_child call.
- TI ControlPanel arrange_children's per-child dummy-ctx set_parent: deleted —
every effect was discarded with the dummy ctx (same class as the ramp
rituals).
Adapted::add_child keeps the has_container_children parent-back extra as
direct tree ops.
Verified: 163 tests; workspace builds; A/B TI gallery (the flat-walk
parent() skip still resolves — no page-selector double-draw) and dm greeter
(link_parent_child consumer) — both empty 8% masks.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk
src/widget/core.rs | 10 ++++---
src/widget/mod.rs | 32 +++-------------------
src/widget/model.rs | 76 +++++++++++++++++++++++++++++------------------------
3 files changed, 51 insertions(+), 67 deletions(-)
diff --git a/src/widget/core.rs b/src/widget/core.rs
index 45208cb..0a65d0e 100644
--- a/src/widget/core.rs
+++ b/src/widget/core.rs
@@ -83,11 +83,13 @@ pub mod focus {
std::mem::transmute::<*mut dyn Element, *mut (dyn Element + 'static)>(child as *mut dyn Element)
};
if let (Some(p_base), Some(c_base)) = (parent.base(), child.base()) {
- ctx.register_widget(p_base.id(), parent_ptr);
- ctx.register_widget(c_base.id(), child_ptr);
+ let (p_id, c_id) = (p_base.id(), c_base.id());
+ ctx.register_widget(p_id, parent_ptr);
+ ctx.register_widget(c_id, child_ptr);
+ // The old add_child + set_parent pair, as the tree ops they always were.
+ ctx.tree.link(p_id, c_id);
+ ctx.tree.set_parent(c_id, Some(p_id));
}
- parent.add_child(child_ptr, ctx);
- child.set_parent(Some(parent_ptr), ctx);
}
/// Keyboard tree navigation from the focused widget. `ctx` resolves the focused id to a
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index ad60b09..3e17518 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -574,24 +574,9 @@ pub trait Element {
}
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
- if let Some(base) = self.base() {
- let id = base.id();
- if let Some(p_ptr) = parent {
- if let Some(p_base) = unsafe { (*p_ptr).base() } {
- let p_id = p_base.id();
- ctx.register_widget(p_id, p_ptr);
- let self_ptr = self.as_ptr();
- ctx.register_widget(id, self_ptr);
- // Symmetric link (Phase 1b): unlike the legacy `parents.insert` this also
- // records the child under the parent, keeping `children()` consistent.
- ctx.tree.set_parent(id, Some(p_id));
- }
- } else {
- ctx.tree.set_parent(id, None);
- }
- }
- }
+ // `set_parent`/`add_child` are GONE from the trait (6bd batch 4): linking is a tree
+ // operation — concrete callers ride the inherent `Adapted` methods, dyn callers go
+ // through `focus::link_parent_child` or `ctx.tree` directly.
fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
match self.base() {
@@ -600,17 +585,6 @@ pub trait Element {
}
}
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- if let (Some(p_base), Some(c_base)) = (self.base(), unsafe { (*child).base() }) {
- let p_id = p_base.id();
- let c_id = c_base.id();
- let self_ptr = self.as_ptr();
- ctx.register_widget(p_id, self_ptr);
- ctx.register_widget(c_id, child);
- ctx.tree.link(p_id, c_id);
- }
- }
-
fn z_index(&self) -> i32 { 0 }
fn is_scrollable(&self) -> bool { false }
fn blocks_backplate_drag(&self) -> bool { true }
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 5862d5e..55d9f03 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -689,6 +689,48 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
ctx.clear_children_ids(self.base.id());
}
+ /// Register + link a child under this widget (off `Element` in 6bd batch 4; dyn callers
+ /// went to `focus::link_parent_child`/tree ops).
+ pub fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
+ // The old Element default's tree link…
+ if let Some(c_base) = unsafe { (*child).base() } {
+ let c_id = c_base.id();
+ let p_id = self.base.id();
+ let self_ptr = self.as_ptr();
+ ctx.register_widget(p_id, self_ptr);
+ ctx.register_widget(c_id, child);
+ ctx.tree.link(p_id, c_id);
+ }
+ // …plus, for containers, the legacy container extra: parent the child back (Layer,
+ // Switcher) — the symmetric tree link the child's own set_parent used to make.
+ if Layout::has_container_children(&self.inner) {
+ let self_ptr = self.as_ptr_mut();
+ if let Some(c_base) = unsafe { (*child).base() } {
+ let c_id = c_base.id();
+ ctx.register_widget(self.base.id(), self_ptr);
+ ctx.register_widget(c_id, child);
+ ctx.tree.set_parent(c_id, Some(self.base.id()));
+ }
+ }
+ }
+
+ /// Register + (un)link this widget under a parent (off `Element` in 6bd batch 4).
+ pub fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
+ // Replica of the old Element default: symmetric tree link.
+ let id = self.base.id();
+ if let Some(p_ptr) = parent {
+ if let Some(p_base) = unsafe { (*p_ptr).base() } {
+ let p_id = p_base.id();
+ ctx.register_widget(p_id, p_ptr);
+ let self_ptr = self.as_ptr();
+ ctx.register_widget(id, self_ptr);
+ ctx.tree.set_parent(id, Some(p_id));
+ }
+ } else {
+ ctx.tree.set_parent(id, None);
+ }
+ }
+
/// The model's intrinsic content size (off the `Element` trait since 6bd — the concrete
/// callers are fonts'/graph's hand-laid button/dropdown sizing).
pub fn intrinsic_size(&self) -> Option<Size> {
@@ -876,40 +918,6 @@ impl<W: Layout + Paint + Input + 'static> Element for Adapted<W> {
ctx.tree.children_ptrs(self.base.id())
}
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- // The Element default's tree link…
- if let Some(c_base) = unsafe { (*child).base() } {
- let c_id = c_base.id();
- let p_id = self.base.id();
- let self_ptr = self.as_ptr();
- ctx.register_widget(p_id, self_ptr);
- ctx.register_widget(c_id, child);
- ctx.tree.link(p_id, c_id);
- }
- // …plus, for containers, the legacy container extra: parent the child back (Layer,
- // Switcher). (The model-Vec record died with ParametersBg.children — zero overrides.)
- if Layout::has_container_children(&self.inner) {
- let self_ptr = self.as_ptr_mut();
- unsafe { (*child).set_parent(Some(self_ptr), ctx) };
- }
- }
-
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
- // Replica of the Element default: symmetric tree link.
- let id = self.base.id();
- if let Some(p_ptr) = parent {
- if let Some(p_base) = unsafe { (*p_ptr).base() } {
- let p_id = p_base.id();
- ctx.register_widget(p_id, p_ptr);
- let self_ptr = self.as_ptr();
- ctx.register_widget(id, self_ptr);
- ctx.tree.set_parent(id, Some(p_id));
- }
- } else {
- ctx.tree.set_parent(id, None);
- }
- }
-
fn is_child_visible(&self, child_id: WidgetId) -> bool {
if !Layout::has_container_children(&self.inner) {
return true;