GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
refactor(widget)!: DELETE Backplate, Plate, List, ControlPanel, SectionContainer(+SectionHeader) (Phase 6as)
Zero applications construct them (the Phase 6 dissolutions ended with the
test-interface gallery going app-local). Removed: the five container
files, the SectionHeader half of label.rs, every re-export, the List
branches of the scroll-ancestor walks (painter + Adapted — no List can be
an ancestor), and Adapted's now-unconsumed own_labels_with_font_and_bounds
bridge. The backplate-drag machinery keeps its is_backplate() flag paths
(now uniformly false — dead-quiet, same behavior dissolved windows already
had); TreeList's drag tests re-assert the contract through
drag_allowed_at, the dissolved-window form of the same question. The
ListColumn/ColumnWidth column data types move to cce-files' RowList, their
only consumer. Five in-file tests went with the deleted widgets (176→171).
Still alive by design: Layer + Page (embedded by the live Paginator),
ScrollBox (embedded by TreeList and the gallery's local panel copy),
ScrollBar (settings), JsonLayout (cloud's host).
Verified: settings audio cursor-only; data-editor loaded tree AE=0; full
workspace builds; 171 tests.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk
src/scene/painter.rs | 5 -
src/widget/container/backplate.rs | 409 ----------------
src/widget/container/control_panel.rs | 592 -----------------------
src/widget/container/mod.rs | 10 -
src/widget/container/plate.rs | 645 --------------------------
src/widget/container/scrolling_list.rs | 747 ------------------------------
src/widget/container/section_container.rs | 157 -------
src/widget/container/treelist.rs | 41 +-
src/widget/display/label.rs | 45 +-
src/widget/display/mod.rs | 2 +-
src/widget/mod.rs | 8 +-
src/widget/model.rs | 15 -
12 files changed, 20 insertions(+), 2656 deletions(-)
diff --git a/src/scene/painter.rs b/src/scene/painter.rs
index 743a5ba..6897a55 100644
--- a/src/scene/painter.rs
+++ b/src/scene/painter.rs
@@ -106,11 +106,6 @@ pub fn scroll_ancestor_text_bounds(w: &dyn Element, ui: &UiContext) -> Option<[f
let view_min = scroll_box.viewport_y + 4.0;
let view_max = scroll_box.viewport_y + scroll_box.viewport_h - 4.0;
return Some([sb_x, view_min, sb_x + sb_w, view_max]);
- } else if let Some(list) = parent.as_any().downcast_ref::<crate::widget::List>() {
- let (sb_x, _, sb_w, _) = list.rect();
- let view_min = list.scroll_box.viewport_y + 4.0;
- let view_max = list.scroll_box.viewport_y + list.scroll_box.viewport_h - 4.0;
- return Some([sb_x, view_min, sb_x + sb_w, view_max]);
}
curr = parent.parent(ui);
}
diff --git a/src/widget/container/backplate.rs b/src/widget/container/backplate.rs
deleted file mode 100644
index 8eb1a16..0000000
--- a/src/widget/container/backplate.rs
+++ /dev/null
@@ -1,409 +0,0 @@
-use crate::widget::*;
-use crate::context::UiContext;
-
-
-#[derive(Debug, Clone)]
-pub struct Backplate {
- pub base: Widget,
- pub children: Vec<*mut (dyn Element + 'static)>,
- pub parent: Option<*mut (dyn Element + 'static)>,
- pub border_color: Option<[f32; 4]>,
- pub border_thickness: f32,
- pub radius: f32,
- pub background_color: Option<[f32; 4]>,
- pub visible: bool,
- pub movable: bool,
- pub bevel: bool,
- pub bevel_thickness: f32,
-}
-
-impl Backplate {
- pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
- Self {
- base: Widget::new_rect(x, y, w, h),
- children: Vec::new(),
- parent: None,
- border_color: None,
- border_thickness: 1.0,
- radius: -1.0,
- background_color: None,
- visible: true,
- movable: true,
- bevel: false,
- bevel_thickness: 1.5,
- }
- }
-
- pub fn with_movable(mut self, movable: bool) -> Self {
- self.movable = movable;
- self
- }
-
- pub fn with_border(mut self, color: [f32; 4], thickness: f32) -> Self {
- self.border_color = Some(color);
- self.border_thickness = thickness;
- self
- }
-
- pub fn with_background(mut self, color: [f32; 4]) -> Self {
- self.background_color = Some(color);
- self
- }
-
- pub fn with_radius(mut self, radius: f32) -> Self {
- self.radius = radius;
- self
- }
-
- pub fn with_bevel(mut self, bevel: bool, thickness: f32) -> Self {
- self.bevel = bevel;
- self.bevel_thickness = thickness;
- self
- }
-}
-
-impl Element for Backplate {
- fn base(&self) -> Option<&Widget> {
- Some(&self.base)
- }
-
- fn base_mut(&mut self) -> Option<&mut Widget> {
- Some(&mut self.base)
- }
-
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
-
- fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
- self
- }
-
- fn as_ptr(&self) -> *mut (dyn Element + 'static) {
- self as *const Self as *mut Self as *mut (dyn Element + 'static)
- }
-
- fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
- self as *mut Self as *mut (dyn Element + 'static)
- }
-
- fn rect(&self) -> (f32, f32, f32, f32) {
- (self.base.x, self.base.y, self.base.w, self.base.h)
- }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- self.base.x = x;
- self.base.y = y;
- self.base.w = w;
- self.base.h = h;
- }
-
- fn color(&self) -> [f32; 4] {
- let mut base_color = self.background_color.unwrap_or_else(|| crate::color::page_low_color());
- if base_color[3] > 0.001 {
- base_color[3] = crate::color::active_backplate_opacity();
- }
- base_color
- }
-
- fn visible(&self) -> bool {
- self.visible
- }
-
- fn set_visible(&mut self, visible: bool) {
- self.visible = visible;
- }
-
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- let id = self.base.id();
- let self_ptr = self.as_ptr_mut();
- self.children.push(child);
- unsafe {
- if let Some(c_id) = (*child).base().map(|b| b.id()) {
- ctx.register_widget(c_id, child);
- ctx.link_ids(id, c_id);
- (*child).set_parent(Some(self_ptr), ctx);
- }
- }
- }
-
- fn clear_children(&mut self, ctx: &mut UiContext) {
- self.children.clear();
- let id = self.base.id();
- ctx.clear_children_ids(id);
- }
-
- fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- self.children.clone()
- }
-
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, _ctx: &mut UiContext) {
- self.parent = parent;
- }
-
- fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
- self.parent
- }
-
- fn set_modifiers(&mut self, ctrl: bool, shift: bool, alt: bool) {
- for &child_ptr in &self.children {
- unsafe {
- (*child_ptr).set_modifiers(ctrl, shift, alt);
- }
- }
- }
-
- fn solid_border(&self) -> Option<([f32; 4], f32)> {
- self.border_color.map(|c| (c, self.border_thickness))
- }
-
- fn plate_bevel(&self) -> Option<f32> {
- if self.bevel {
- Some(self.bevel_thickness)
- } else {
- None
- }
- }
-
- fn corner_radius(&self) -> f32 {
- if self.radius < 0.0 {
- crate::color::backplate_corner_radius()
- } else {
- self.radius
- }
- }
-
- fn rounded_corners(&self) -> (bool, bool, bool, bool) {
- if self.corner_radius() > 0.1 {
- (true, true, true, true)
- } else {
- (false, false, false, false)
- }
- }
-
- fn all_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- if !self.visible {
- return Vec::new();
- }
- let mut quads = Vec::new();
- let bg_color = self.color();
- let (wx, wy, ww, wh) = self.rect();
- let has_rounded = self.rounded_corners() != (false, false, false, false);
- if bg_color[3] != 0.0 && !has_rounded {
- quads.push((wx, wy, ww, wh, bg_color));
- }
- for &child_ptr in &self.children {
- let widget = unsafe { &*child_ptr };
- let mut child_quads = Vec::new();
- let (cx, cy, cw, ch) = widget.rect();
- let has_rounded = widget.rounded_corners() != (false, false, false, false);
- for (qx, qy, qw, qh, qc) in widget.all_quads(ctx) {
- if has_rounded && (qx - cx).abs() < 0.1 && (qy - cy).abs() < 0.1 && (qw - cw).abs() < 0.1 && (qh - ch).abs() < 0.1 {
- continue;
- }
- child_quads.push((qx, qy, qw, qh, qc));
- }
-
- for (qx, qy, qw, qh, qc) in child_quads {
- let x0 = qx.max(wx);
- let y0 = qy.max(wy);
- let x1 = (qx + qw).min(wx + ww);
- let y1 = (qy + qh).min(wy + wh);
- if x1 > x0 && y1 > y0 {
- quads.push((x0, y0, x1 - x0, y1 - y0, qc));
- }
- }
- }
- quads
- }
-
- 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 quads = Vec::new();
- let (wx, wy, ww, wh) = self.rect();
- let radius = self.corner_radius();
- let (r1, r2, r3, r4) = self.rounded_corners();
- if r1 || r2 || r3 || r4 {
- let bg_color = self.color();
- if bg_color[3] > 0.001 {
- quads.push((wx, wy, ww, wh, radius, bg_color, (r1, r2, r3, r4)));
- }
- }
- for &child_ptr in &self.children {
- let widget = unsafe { &*child_ptr };
- let mut child_quads = Vec::new();
- for (qx, qy, qw, qh, qr, qc, (cr1, cr2, cr3, cr4)) in widget.all_rounded_quads(ctx) {
- child_quads.push((qx, qy, qw, qh, qr, qc, (cr1, cr2, cr3, cr4)));
- }
-
- for (qx, qy, qw, qh, qr, qc, (cr1, cr2, cr3, cr4)) in child_quads {
- let x0 = qx.max(wx);
- let y0 = qy.max(wy);
- let x1 = (qx + qw).min(wx + ww);
- let y1 = (qy + qh).min(wy + wh);
- if x1 > x0 && y1 > y0 {
- quads.push((x0, y0, x1 - x0, y1 - y0, qr, qc, (cr1, cr2, cr3, cr4)));
- }
- }
- }
- quads
- }
-
- fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
- if ctx.is_coordinate_covered(self as *const Self as *const () as usize, px, py) {
- return false;
- }
- let (x, y, w, h) = self.rect();
- if px < x || px >= x + w || py < y || py >= y + h {
- return false;
- }
- let r = self.corner_radius().min(w * 0.5).min(h * 0.5);
- if r <= 0.1 {
- return true;
- }
- if px < x + r && py < y + r {
- let dx = px - (x + r);
- let dy = py - (y + r);
- return dx * dx + dy * dy <= r * r;
- }
- if px >= x + w - r && py < y + r {
- let dx = px - (x + w - r);
- let dy = py - (y + r);
- return dx * dx + dy * dy <= r * r;
- }
- if px >= x + w - r && py >= y + h - r {
- let dx = px - (x + w - r);
- let dy = py - (y + h - r);
- return dx * dx + dy * dy <= r * r;
- }
- if px < x + r && py >= y + h - r {
- let dx = px - (x + r);
- let dy = py - (y + h - r);
- return dx * dx + dy * dy <= r * r;
- }
- true
- }
-
- fn is_backplate(&self) -> bool {
- true
- }
-
- fn is_movable_backplate(&self) -> bool {
- self.movable
- }
-}
-
-impl Drop for Backplate {
- fn drop(&mut self) {
- clear_widget_references(self);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_backplate_creation_and_builders() {
- let win = Backplate::new(10.0, 20.0, 100.0, 200.0)
- .with_background([0.1, 0.2, 0.3, 0.4])
- .with_border([1.0, 0.0, 0.0, 1.0], 2.5)
- .with_radius(8.0);
-
- assert_eq!(win.rect(), (10.0, 20.0, 100.0, 200.0));
- assert_eq!(win.background_color, Some([0.1, 0.2, 0.3, 0.4]));
- assert_eq!(win.solid_border(), Some(([1.0, 0.0, 0.0, 1.0], 2.5)));
- assert_eq!(win.corner_radius(), 8.0);
- assert_eq!(win.rounded_corners(), (true, true, true, true));
- assert!(win.is_movable_backplate());
-
- let non_movable_win = win.with_movable(false);
- assert!(!non_movable_win.is_movable_backplate());
- }
-
- #[test]
- fn test_backplate_visibility() {
- let mut win = Backplate::new(0.0, 0.0, 100.0, 100.0);
- assert!(win.visible());
- assert!(win.visible);
-
- win.set_visible(false);
- assert!(!win.visible());
- assert!(!win.visible);
- }
-
- #[test]
- fn test_backplate_children_and_parent() {
- let mut ctx = UiContext::new();
- let mut win = Backplate::new(0.0, 0.0, 100.0, 100.0);
- let child = Layer::new(10.0, 10.0, 50.0, 50.0);
-
- assert_eq!(win.children(&ctx).len(), 0);
-
- win.add_child(child.as_ptr(), &mut ctx);
- assert_eq!(win.children(&ctx).len(), 1);
- assert_eq!(unsafe { (*win.children(&ctx)[0]).rect() }, (10.0, 10.0, 50.0, 50.0));
-
- // Child's parent should point to Backplate
- assert_eq!(unsafe { (*child.as_ptr()).parent(&ctx) }, Some(win.as_ptr()));
-
- win.clear_children(&mut ctx);
- assert_eq!(win.children(&ctx).len(), 0);
- }
-
- struct TestRenderTarget;
- impl crate::layout::RenderTarget for TestRenderTarget {
- fn rect(&mut self, _color: [f32; 4], _x: f32, _y: f32, _w: f32, _h: f32) {}
- fn text(&mut self, _content: &str, _x: f32, _y: f32, _size: f32, _color: [f32; 4]) {}
- }
-
- #[test]
- fn test_paginator_blocks_backplate_drag() {
- let mut ctx = UiContext::new();
- let mut win = Backplate::new(0.0, 0.0, 800.0, 600.0);
- let mut paginator = Paginator::new(vec!["Page 1".to_string(), "Page 2".to_string()]);
-
- win.add_child(paginator.as_ptr_mut(), &mut ctx);
-
- // Let's set the rect
- crate::layout::render_widget(&mut TestRenderTarget, &mut paginator, 0.0, 0.0, 54.0, 600.0, &mut ctx);
-
- // Let's tick to register children
- ctx.tick(0.016);
- ctx.clear_dirty(); // This triggers rebuild_spatial_grid()
-
- // Now, click in the sidebar at x=10, y=20
- let is_movable = ctx.is_movable_backplate_at(10.0, 20.0);
- assert!(!is_movable, "Clicking the sidebar should block backplate drag!");
- }
-
- #[test]
- fn test_menubar_statusbar_do_not_block_backplate_drag() {
- let mut ctx = UiContext::new();
- let mut win = Backplate::new(0.0, 0.0, 800.0, 600.0).with_movable(true);
- let mut menubar = MenuBar::new(0.0, 0.0, 800.0, 42.0);
- let mut statusbar = StatusBar::new();
- statusbar.set_rect(0.0, 570.0, 800.0, 30.0);
-
- ctx.register_widget(win.base().unwrap().id(), win.as_ptr_mut());
- win.add_child(menubar.as_ptr_mut(), &mut ctx);
- win.add_child(statusbar.as_ptr_mut(), &mut ctx);
-
- // Render to assign coordinates and register with layout hierarchy
- crate::layout::render_widget(&mut TestRenderTarget, &mut menubar, 0.0, 0.0, 800.0, 42.0, &mut ctx);
- crate::layout::render_widget(&mut TestRenderTarget, &mut statusbar, 0.0, 570.0, 800.0, 30.0, &mut ctx);
-
- ctx.tick(0.016);
- ctx.clear_dirty(); // Triggers rebuild_spatial_grid()
-
- // Check if clicking menubar allows dragging
- let drag_menubar = ctx.is_movable_backplate_at(100.0, 20.0);
- assert!(drag_menubar, "Clicking the menubar should not block backplate drag!");
-
- // Check if clicking statusbar allows dragging
- let drag_statusbar = ctx.is_movable_backplate_at(100.0, 580.0);
- assert!(drag_statusbar, "Clicking the statusbar should not block backplate drag!");
- }
-}
diff --git a/src/widget/container/control_panel.rs b/src/widget/container/control_panel.rs
deleted file mode 100644
index 004877d..0000000
--- a/src/widget/container/control_panel.rs
+++ /dev/null
@@ -1,592 +0,0 @@
-use crate::colors;
-use crate::widget::*;
-use crate::widget::container::scroll_box::ScrollBox;
-
-pub struct ControlPanel {
- pub base: Widget,
- pub children: Vec<*mut (dyn Element + 'static)>,
- pub parent: Option<*mut (dyn Element + 'static)>,
- pub scroll_box: ScrollBox,
- pub active_drag_widget: Option<*mut (dyn Element + 'static)>,
-}
-
-impl ControlPanel {
- pub fn new() -> Self {
- let mut sb = ScrollBox::new();
- sb.show_border = false;
- sb.show_background = false;
- Self {
- base: Widget::new(),
- children: Vec::new(),
- parent: None,
- scroll_box: sb,
- active_drag_widget: None,
- }
- }
-
- pub fn add_child(&mut self, child: *mut (dyn Element + 'static)) {
- self.children.push(child);
- self.scroll_box.children.push(child);
- }
-
- pub fn with_label(mut self, label: &str) -> Self {
- self.base.label = Some(label.to_string());
- self
- }
-}
-
-impl Element for ControlPanel {
- crate::impl_widget_base!(ControlPanel);
-
- fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
- if ctx.is_coordinate_covered(self as *const Self as *const () as usize, px, py) {
- return false;
- }
-
- // Check if cursor is inside child popovers first (scrolled coordinates)
- if let Some(pop_rect) = self.popover_rect() {
- if px >= pop_rect.0 && px <= pop_rect.0 + pop_rect.2 && py >= pop_rect.1 && py <= pop_rect.1 + pop_rect.3 {
- return true;
- }
- }
-
- // Otherwise check the panel itself
- let (x, y, w, h) = self.rect();
- if w <= 0.0 || h <= 0.0 {
- return false;
- }
- px >= x && px <= x + w && py >= y && py <= y + h
- }
-
- fn tick(&mut self, dt: f32, ctx: &mut UiContext) -> bool {
- let mut changed = self.scroll_box.tick(dt, ctx);
- unsafe {
- for child_ptr in &self.children {
- if (**child_ptr).tick(dt, ctx) {
- changed = true;
- }
- }
- }
- changed
- }
-
- fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> { self.parent }
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, _ctx: &mut UiContext) {
- self.parent = parent;
- }
-
- fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- self.children.clone()
- }
-
- // ControlPanel is a legacy scroll frame: children are laid out UNSCROLLED and the
- // scroll offset is applied at aggregate time (all_* / the fonted getter). The walk
- // must emit those aggregates and not descend — descending would paint the children
- // unshifted, desyncing text from geometry as soon as the panel scrolls.
- fn renders_own_subtree(&self) -> bool {
- true
- }
-
- fn paint_self(&self, ui: &UiContext, ctx: &mut crate::scene::paint::PaintCtx) {
- crate::scene::painter::paint_legacy_leaf(self, ui, ctx, self.scrolled_child_labels(ui));
- }
-
- fn color(&self) -> [f32; 4] {
- colors::control_panel_color()
- }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- self.base.x = x;
- self.base.y = y;
- self.base.w = w;
- self.base.h = h;
-
- self.scroll_box.set_rect(x, y, w, h);
-
- let self_ptr = self.as_ptr_mut();
- let mut dummy = crate::context::UiContext::new();
- let self_ptr_option = Some(self_ptr);
-
- let padding = crate::layout::control_panel_padding();
- let gap = crate::layout::control_panel_gap();
- let mut col = ColumnLayout::new(x, y, w - 12.0, gap, padding); // 12px reserved for scrollbar track
-
- unsafe {
- let mut create_btn: Option<*mut dyn Element> = None;
- let mut tile_btn: Option<*mut dyn Element> = None;
- let mut opacity_toggle: Option<*mut dyn Element> = None;
- let mut enable_toggle: Option<*mut dyn Element> = None;
- let mut slider: Option<*mut dyn Element> = None;
- let mut slider_label: Option<*mut dyn Element> = None;
- let mut type_dd: Option<*mut dyn Element> = None;
- let mut shape_dd: Option<*mut dyn Element> = None;
- let mut border_style_dd: Option<*mut dyn Element> = None;
- let mut width_spin: Option<*mut dyn Element> = None;
- let mut height_spin: Option<*mut dyn Element> = None;
- let mut backplate_toggle: Option<*mut dyn Element> = None;
- let mut menubar_toggle: Option<*mut dyn Element> = None;
- let mut statusbar_toggle: Option<*mut dyn Element> = None;
- let mut border_sec: Option<*mut dyn Element> = None;
- let mut bevel_toggle: Option<*mut dyn Element> = None;
- let mut border_width_spin: Option<*mut dyn Element> = None;
- let mut bevel_depth_spin: Option<*mut dyn Element> = None;
- let mut win_sec: Option<*mut dyn Element> = None;
- let mut bevel_shape_btn: Option<*mut dyn Element> = None;
-
- for &child_ptr in &self.children {
- let child = &mut *child_ptr;
- child.set_parent(self_ptr_option, &mut dummy);
- let label = child.base().and_then(|b| b.label.as_ref()).map(|s| s.as_str()).unwrap_or("");
- match label {
- "Create Window" => create_btn = Some(child_ptr),
- "Tile Windows" => tile_btn = Some(child_ptr),
- "Opacity" => opacity_toggle = Some(child_ptr),
- "Enable" => enable_toggle = Some(child_ptr),
- "Transparency Level" => slider_label = Some(child_ptr),
- "Border" => border_sec = Some(child_ptr),
- "Window Elements" => win_sec = Some(child_ptr),
- "Window Type" => type_dd = Some(child_ptr),
- "Window Shape" => shape_dd = Some(child_ptr),
- "Border Style" => border_style_dd = Some(child_ptr),
- "Width" => width_spin = Some(child_ptr),
- "Height" => height_spin = Some(child_ptr),
- "Backplate" => backplate_toggle = Some(child_ptr),
- "MenuBar" => menubar_toggle = Some(child_ptr),
- "StatusBar" => statusbar_toggle = Some(child_ptr),
- "Bevel" => bevel_toggle = Some(child_ptr),
- "Border Width" => border_width_spin = Some(child_ptr),
- "Bevel Depth" => bevel_depth_spin = Some(child_ptr),
- "Bevel Shape..." => bevel_shape_btn = Some(child_ptr),
- _ => {
- if child.base().is_some() && child.base().unwrap().label.is_none() {
- slider = Some(child_ptr);
- }
- }
- }
- }
-
- if let (Some(c), Some(t)) = (create_btn, tile_btn) {
- col.add_row(&[c, t], 28.0, 12.0);
- } else {
- if let Some(c) = create_btn {
- col.add_widget(&mut *c, 28.0);
- }
- if let Some(t) = tile_btn {
- col.add_widget(&mut *t, 28.0);
- }
- }
-
- if let (Some(w_sp), Some(h_sp)) = (width_spin, height_spin) {
- col.add_row(&[w_sp, h_sp], 42.0, 12.0);
- } else {
- if let Some(w_sp) = width_spin {
- col.add_widget(&mut *w_sp, 42.0);
- }
- if let Some(h_sp) = height_spin {
- col.add_widget(&mut *h_sp, 42.0);
- }
- }
-
- if let Some(t_dd) = type_dd {
- col.add_widget(&mut *t_dd, 44.0);
- }
- if let Some(s_dd) = shape_dd {
- col.add_widget(&mut *s_dd, 44.0);
- }
- if let Some(op_t) = opacity_toggle {
- col.add_widget(&mut *op_t, 28.0);
- }
- if let Some(en_t) = enable_toggle {
- col.add_widget(&mut *en_t, 28.0);
- }
- if let Some(sl_lbl) = slider_label {
- col.add_widget(&mut *sl_lbl, 12.0);
- }
- if let Some(sl) = slider {
- col.add_widget(&mut *sl, 20.0);
- }
-
- if let Some(w_s) = win_sec {
- col.add_widget(&mut *w_s, 20.0);
- }
- let toggles = [backplate_toggle, menubar_toggle, statusbar_toggle];
- let active_toggles: Vec<*mut dyn Element> = toggles.iter().filter_map(|&t| t).collect();
- if !active_toggles.is_empty() {
- col.add_row(&active_toggles, 28.0, 10.0);
- }
-
- if let Some(b_s) = border_sec {
- col.add_widget(&mut *b_s, 20.0);
- }
- if let Some(bs_dd) = border_style_dd {
- col.add_widget(&mut *bs_dd, 44.0);
- }
- if let Some(bev_t) = bevel_toggle {
- col.add_widget(&mut *bev_t, 28.0);
- }
-
- if let (Some(bw_sp), Some(bd_sp)) = (border_width_spin, bevel_depth_spin) {
- col.add_row(&[bw_sp, bd_sp], 42.0, 12.0);
- } else {
- if let Some(bw_sp) = border_width_spin {
- col.add_widget(&mut *bw_sp, 42.0);
- }
- if let Some(bd_sp) = bevel_depth_spin {
- col.add_widget(&mut *bd_sp, 42.0);
- }
- }
- if let Some(bs_btn) = bevel_shape_btn {
- col.add_widget(&mut *bs_btn, 28.0);
- }
-
- let total_h = col.current_y();
- self.scroll_box.update_bounds(total_h, y, h);
- }
- }
-
- fn rounded_corners(&self) -> (bool, bool, bool, bool) {
- (true, true, true, true)
- }
-
- fn all_rounded_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))> {
- let mut quads = Vec::new();
- let (x, y, w, h) = self.rect();
-
- // 1. Background
- quads.push((x, y, w, h, 0.0, self.color(), (false, false, false, false)));
-
- // 2. Borders
- let border_color = colors::control_panel_border_color();
- quads.push((x, y, w, 1.0, 0.0, border_color, (false, false, false, false)));
- quads.push((x, y + h - 1.0, w, 1.0, 0.0, border_color, (false, false, false, false)));
- quads.push((x, y, 1.0, h, 0.0, border_color, (false, false, false, false)));
- quads.push((x + w - 1.0, y, 1.0, h, 0.0, border_color, (false, false, false, false)));
-
- // 3. Child elements clipped to viewport bounds
- let scroll_y = self.scroll_box.scroll_y;
- let y_start = y;
- let y_end = y + h;
-
- unsafe {
- for child_ptr in &self.children {
- let child = &**child_ptr;
- let solid_border_opt = if child.type_name() == "Toggle" { None } else { child.solid_border() };
- let (cx, cy, cw, ch) = child.rect();
-
- if let Some((b_color, _thickness)) = solid_border_opt {
- let cy_shifted = cy - scroll_y;
- let cy_top = cy_shifted;
- let cy_bottom = cy_shifted + ch;
- if cy_bottom > y_start && cy_top < y_end {
- let visible_top = cy_top.max(y_start);
- let visible_bottom = cy_bottom.min(y_end);
- let visible_h = visible_bottom - visible_top;
- if visible_h > 0.0 {
- let radii_adjusted = if visible_top > cy_top || visible_bottom < cy_bottom {
- 0.0
- } else {
- child.corner_radius()
- };
- quads.push((
- cx,
- visible_top,
- cw,
- visible_h,
- radii_adjusted,
- b_color,
- child.rounded_corners(),
- ));
- }
- }
- }
-
- for (qx, qy, qw, qh, qr, qc, qcorners) in child.all_rounded_quads(ctx) {
- let mut rx = qx;
- let mut ry = qy;
- let mut rw = qw;
- let mut rh = qh;
- let mut rqr = qr;
-
- if let Some((_, thickness)) = solid_border_opt {
- if (qx - cx).abs() < 0.1 && (qy - cy).abs() < 0.1 && (qw - cw).abs() < 0.1 && (qh - ch).abs() < 0.1 {
- rx += thickness;
- ry += thickness;
- rw -= 2.0 * thickness;
- rh -= 2.0 * thickness;
- rqr = (qr - thickness).max(0.0);
- }
- }
-
- let qy_shifted = ry - scroll_y;
- let qy_top = qy_shifted;
- let qy_bottom = qy_shifted + rh;
- if qy_bottom > y_start && qy_top < y_end {
- let visible_top = qy_top.max(y_start);
- let visible_bottom = qy_bottom.min(y_end);
- let visible_h = visible_bottom - visible_top;
- if visible_h > 0.0 {
- let radii_adjusted = if visible_top > qy_top || visible_bottom < qy_bottom {
- 0.0
- } else {
- rqr
- };
- quads.push((rx, visible_top, rw, visible_h, radii_adjusted, qc, qcorners));
- }
- }
- }
- }
- }
-
- // 4. Scrollbar
- for (sx, sy, sw, sh, sc) in self.scroll_box.extra_quads() {
- quads.push((sx, sy, sw, sh, 0.0, sc, (false, false, false, false)));
- }
-
- quads
- }
-
- fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- let mut quads = Vec::new();
- let (_x, y, _w, h) = self.rect();
- let scroll_y = self.scroll_box.scroll_y;
- let y_start = y;
- let y_end = y + h;
- let ctx_dummy = crate::context::UiContext::new();
-
- unsafe {
- for child_ptr in &self.children {
- let child = &**child_ptr;
- let (cx, cy, cw, ch) = child.rect();
- let has_rounded = child.rounded_corners() != (false, false, false, false);
- let has_bg = child.color()[3].abs() > 0.001;
-
- for (qx, qy, qw, qh, qc) in child.all_quads(&ctx_dummy) {
- if has_rounded && has_bg && (qx - cx).abs() < 0.1 && (qy - cy).abs() < 0.1 && (qw - cw).abs() < 0.1 && (qh - ch).abs() < 0.1 {
- continue;
- }
- let qy_shifted = qy - scroll_y;
- let qy_top = qy_shifted;
- let qy_bottom = qy_shifted + qh;
- if qy_bottom > y_start && qy_top < y_end {
- let visible_top = qy_top.max(y_start);
- let visible_bottom = qy_bottom.min(y_end);
- let visible_h = visible_bottom - visible_top;
- if visible_h > 0.0 {
- quads.push((qx, visible_top, qw, visible_h, qc));
- }
- }
- }
- }
- }
-
- quads.extend(self.scroll_box.extra_quads());
- quads
- }
-
- fn extra_arcs(&self) -> Vec<(f32, f32, f32, f32, f32, f32, [f32; 4])> {
- let mut arcs = Vec::new();
- let scroll_y = self.scroll_box.scroll_y;
- let y_start = self.base.y;
- let y_end = self.base.y + self.base.h;
-
- unsafe {
- for child_ptr in &self.children {
- let child = &**child_ptr;
- for (cx, cy, r, t, start, end, color) in child.extra_arcs() {
- let cy_shifted = cy - scroll_y;
- if cy_shifted + r > y_start && cy_shifted - r < y_end {
- arcs.push((cx, cy_shifted, r, t, start, end, color));
- }
- }
- }
- }
- arcs
- }
-
- fn popover_rect(&self) -> Option<(f32, f32, f32, f32)> {
- let scroll_y = self.scroll_box.scroll_y;
- unsafe {
- for child_ptr in &self.children {
- let child = &mut **child_ptr;
- let old_y = child.base().map(|b| b.y).unwrap_or(0.0);
- if let Some(b) = child.base_mut() {
- b.y = old_y - scroll_y;
- }
- let res = child.popover_rect();
- if let Some(b) = child.base_mut() {
- b.y = old_y;
- }
- if res.is_some() {
- return res;
- }
- }
- }
- None
- }
-
- fn render_popover(&self, pc: &mut dyn crate::layout::RenderTarget) {
- let scroll_y = self.scroll_box.scroll_y;
- unsafe {
- for child_ptr in &self.children {
- if (**child_ptr).popover_rect().is_some() {
- let child = &mut **child_ptr;
- let old_y = child.base().map(|b| b.y).unwrap_or(0.0);
- if let Some(b) = child.base_mut() {
- b.y = old_y - scroll_y;
- }
- child.render_popover(pc);
- if let Some(b) = child.base_mut() {
- b.y = old_y;
- }
- }
- }
- }
- }
-
- fn draggable(&self) -> bool {
- self.scroll_box.draggable() || self.active_drag_widget.is_some()
- }
-
- fn drag_begin(&mut self, px: f32, py: f32) {
- if self.scroll_box.hit_test_scrollbar(px, py) {
- self.scroll_box.drag_begin(px, py);
- return;
- }
-
- let scroll_y = self.scroll_box.scroll_y;
- let py_translated = py + scroll_y;
- if let Some(child_ptr) = self.active_drag_widget {
- unsafe {
- (*child_ptr).drag_begin(px, py_translated);
- }
- }
- }
-
- fn drag_update(&mut self, px: f32, py: f32) -> bool {
- if self.scroll_box.draggable() {
- return self.scroll_box.drag_update(px, py);
- }
-
- let scroll_y = self.scroll_box.scroll_y;
- let py_translated = py + scroll_y;
- if let Some(child_ptr) = self.active_drag_widget {
- unsafe {
- return (*child_ptr).drag_update(px, py_translated);
- }
- }
- false
- }
-
- fn drag_end(&mut self) {
- self.scroll_box.drag_end();
- if let Some(child_ptr) = self.active_drag_widget {
- unsafe {
- (*child_ptr).drag_end();
- }
- self.active_drag_widget = None;
- }
- }
-
- fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if state == ElementState::Pressed {
- self.active_drag_widget = None;
- }
-
- if self.scroll_box.mouse_input(button, state, px, py, ctx) {
- return true;
- }
-
- let scroll_y = self.scroll_box.scroll_y;
- let py_translated = py + scroll_y;
- let (_x, y, _w, h) = self.rect();
-
- unsafe {
- for child_ptr in &self.children {
- let has_popover = (**child_ptr).popover_rect().is_some();
- // Only dispatch if the click Y is inside the viewport or the child has an active popover
- if has_popover || (py >= y && py <= y + h) {
- if (**child_ptr).mouse_input(button, state, px, py_translated, ctx) {
- if state == ElementState::Pressed && (**child_ptr).draggable() {
- self.active_drag_widget = Some(*child_ptr);
- }
- return true;
- }
- }
- }
- }
- false
- }
-
- fn cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- let mut changed = self.scroll_box.cursor_moved(px, py, ctx);
-
- let scroll_y = self.scroll_box.scroll_y;
- let py_translated = py + scroll_y;
- unsafe {
- for child_ptr in &self.children {
- if (**child_ptr).cursor_moved(px, py_translated, ctx) {
- changed = true;
- }
- }
- }
- changed
- }
-
- fn mouse_wheel(&mut self, delta: &MouseScrollDelta, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if self.scroll_box.mouse_wheel(delta, px, py, ctx) {
- return true;
- }
-
- let scroll_y = self.scroll_box.scroll_y;
- let py_translated = py + scroll_y;
- unsafe {
- for child_ptr in &self.children {
- if (**child_ptr).mouse_wheel(delta, px, py_translated, ctx) {
- return true;
- }
- }
- }
- false
- }
-
-}
-
-impl Drop for ControlPanel {
- fn drop(&mut self) {
- clear_widget_references(self);
- }
-}
-
-impl ControlPanel {
- /// Children's walk text with the panel's scroll shift and viewport clamp — what the
- /// deleted fonted getter served: children are laid out UNSCROLLED and the offset is
- /// an aggregate-time transform.
- pub(crate) fn scrolled_child_labels(&self, ctx: &UiContext) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
- let scroll_y = self.scroll_box.scroll_y;
- let (x, y, w, h) = self.rect();
- let mut labels = Vec::new();
- for &child_ptr in &self.children {
- let mut scratch = crate::scene::paint::PaintCtx::new();
- crate::scene::painter::append_widget_text(ctx, unsafe { &*child_ptr }, &mut scratch);
- for item in scratch.finish().items {
- if let crate::scene::paint::Prim::Text { text, x: lx, y: ly, font_size, color, font, bounds, .. } = item.prim {
- let new_bounds = if let Some([l, t, r, b]) = bounds {
- let nl = l.max(x);
- let nt = (t - scroll_y).max(y);
- let nr = r.min(x + w);
- let nb = (b - scroll_y).min(y + h);
- Some([nl, nt, nr, nb])
- } else {
- Some([x, y, x + w, y + h])
- };
- labels.push((
- TextLabel { text, x: lx, y: ly - scroll_y, font_size, color },
- font,
- new_bounds,
- ));
- }
- }
- }
- labels
- }
-}
diff --git a/src/widget/container/mod.rs b/src/widget/container/mod.rs
index 7af6d25..0ea25cc 100644
--- a/src/widget/container/mod.rs
+++ b/src/widget/container/mod.rs
@@ -1,6 +1,5 @@
pub mod container;
pub mod container_layout;
-pub mod section_container;
pub mod header;
pub mod content_bg;
pub mod parameters_bg;
@@ -8,23 +7,17 @@ pub mod menu;
pub mod breadcrumb;
pub mod spreadsheet;
pub mod scroll_box;
-pub mod scrolling_list;
-pub mod plate;
pub mod switcher;
pub mod layer;
pub mod page;
-pub mod backplate;
pub mod paginator;
pub mod scroll_bar;
pub mod treelist;
-pub mod control_panel;
pub mod vbox;
pub mod hbox;
pub use container::Container;
-pub use control_panel::ControlPanel;
pub use container_layout::{ContainerLayout, OverlayLayout, ManualLayout, VerticalLayout, GridLayout, AdaptiveGridLayout, ColumnsLayout, MosaicLayout, ReverseMosaicLayout};
-pub use section_container::SectionContainer;
pub use header::Header;
pub use content_bg::ContentBg;
pub use parameters_bg::ParametersBg;
@@ -32,12 +25,9 @@ pub use menu::MenuBar;
pub use breadcrumb::Breadcrumb;
pub use spreadsheet::Spreadsheet;
pub use scroll_box::ScrollBox;
-pub use scrolling_list::{List, FontSelector, ListColumn, ListRow, ColumnWidth};
-pub use plate::Plate;
pub use switcher::Switcher;
pub use layer::Layer;
pub use page::Page;
-pub use backplate::Backplate;
pub use paginator::Paginator;
pub use scroll_bar::ScrollBar;
pub use treelist::{TreeList, TreeElement};
diff --git a/src/widget/container/plate.rs b/src/widget/container/plate.rs
deleted file mode 100644
index 30a86ef..0000000
--- a/src/widget/container/plate.rs
+++ /dev/null
@@ -1,645 +0,0 @@
-use crate::colors;
-use crate::widget::*;
-
-
-#[derive(Debug, Clone)]
-pub struct Plate {
- pub base: Layer,
- pub dragging: bool,
- pub drag_ox: f32,
- pub drag_oy: f32,
- pub drag_start_x: f32,
- pub drag_start_y: f32,
- pub bounds: Option<(f32, f32, f32, f32)>,
- pub color: Option<[f32; 4]>,
- pub curved_circle: Option<(f32, f32, f32)>,
- pub network_opacity: f32,
- pub blur: bool,
- pub visible: bool,
- pub draggable: bool,
- pub solid_border: Option<([f32; 4], f32)>,
- pub selected: bool,
- pub padding: Option<f32>,
- /// Optional scene layout-engine style (Phase 2b). When set, the app can route this Plate
- /// through `scene::bridge::layout_subtree` to lay out its children by the engine. `None`
- /// (default) leaves the Plate on its legacy `set_rect` path.
- pub engine_layout: Option<crate::scene::layout::Style>,
-}
-
-impl Plate {
- pub fn set_network_opacity(&mut self, opacity: f32) {
- self.network_opacity = opacity;
- }
-
- pub fn set_curved_circle(&mut self, circle: Option<(f32, f32, f32)>) {
- self.curved_circle = circle;
- }
-
- pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
- Self {
- base: Layer::new(x, y, w, h),
- dragging: false,
- drag_ox: 0.0,
- drag_oy: 0.0,
- drag_start_x: 0.0,
- drag_start_y: 0.0,
- bounds: None,
- color: None,
- curved_circle: None,
- network_opacity: 1.0,
- blur: true,
- visible: true,
- draggable: true,
- solid_border: None,
- selected: false,
- padding: None,
- engine_layout: None,
- }
- }
-
- pub fn with_color(mut self, color: [f32; 4]) -> Self {
- self.color = Some(color);
- self
- }
-
- pub fn with_label(mut self, label: &str) -> Self {
- self.base.base.label = Some(label.to_string());
- self
- }
-
- pub fn with_blur(mut self, blur: bool) -> Self {
- self.blur = blur;
- self
- }
-
- pub fn with_draggable(mut self, draggable: bool) -> Self {
- self.draggable = draggable;
- self
- }
-
- pub fn with_solid_border(mut self, color: [f32; 4], thickness: f32) -> Self {
- self.solid_border = Some((color, thickness));
- self
- }
-
- pub fn with_padding(mut self, padding: f32) -> Self {
- self.padding = Some(padding);
- self
- }
-
- /// Set the scene layout-engine style so this Plate's children can be laid out via
- /// `scene::bridge::layout_subtree`. See [`Plate::engine_layout`].
- pub fn with_engine_layout(mut self, style: crate::scene::layout::Style) -> Self {
- self.engine_layout = Some(style);
- self
- }
-
- pub fn set_bounds(&mut self, bx: f32, by: f32, bw: f32, bh: f32) {
- self.bounds = Some((bx, by, bw, bh));
- }
-}
-
-impl Element for Plate {
- fn base(&self) -> Option<&Widget> { Some(&self.base.base) }
- fn base_mut(&mut self) -> Option<&mut Widget> { Some(&mut self.base.base) }
- fn layout_style(&self) -> Option<crate::scene::layout::Style> { self.engine_layout }
- fn as_any(&self) -> &dyn std::any::Any { self }
- fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
- fn as_ptr(&self) -> *mut (dyn Element + 'static) {
- self as *const Self as *mut Self as *mut (dyn Element + 'static)
- }
- fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
- self as *mut Self as *mut (dyn Element + 'static)
- }
-
- fn is_plate(&self) -> bool { true }
- fn rounded_corners(&self) -> (bool, bool, bool, bool) {
- let r = crate::layout::plate_corner_radius();
- if r > 0.0 {
- (true, true, true, true)
- } else {
- (false, false, false, false)
- }
- }
- fn corner_radius(&self) -> f32 {
- crate::layout::plate_corner_radius()
- }
- fn highlight_quad(&self, _ctx: &UiContext) -> Option<(f32, f32, f32, f32, [f32; 4])>{ None }
-
-
- fn solid_border(&self) -> Option<([f32; 4], f32)> {
- if self.selected {
- Some((colors::active_theme().primary_accent, 1.5))
- } else if let Some(border) = self.solid_border {
- Some(border)
- } else if let Some(bc) = colors::plate_border_color() {
- Some((bc, colors::plate_border_thickness()))
- } else {
- None
- }
- }
-
- fn set_selected(&mut self, selected: bool) {
- self.selected = selected;
- }
-
- /// Walk emission: the legacy default now emits NO text for containers (Plate's
- /// `text_labels` aggregates children, which the walk reaches itself), but a Plate's OWN
- /// label lives here — geometry identical to the default, plus that one label (plain text,
- /// matching the legacy `widget_font: None`).
- fn paint_self(&self, ui: &UiContext, ctx: &mut crate::scene::paint::PaintCtx) {
- use crate::scene::layout::Rect;
- let (x, y, w, h) = self.rect();
- let rect = Rect { x, y, width: w, height: h };
- let color = Element::color(self);
-
- if self.children(ui).is_empty() {
- 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 {
- let cr = self.corner_radii();
- let radii = (cr.top_left, cr.top_right, cr.bottom_right, cr.bottom_left);
- if let Some(depth) = self.plate_bevel() {
- ctx.bevel(rect, radii, color, depth);
- } else if let Some((border_color, thickness)) = Element::solid_border(self) {
- ctx.border(rect, radii, color, border_color, thickness);
- } else if color[3].abs() > 0.001 {
- let (r1, r2, r3, r4) = Element::rounded_corners(self);
- if r1 || r2 || r3 || r4 {
- ctx.rounded_rect(rect, Element::corner_radius(self), (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);
- }
- for (cx, cy, r, c) in self.extra_circles() {
- ctx.circle(cx, cy, r, c);
- }
-
- if self.visible {
- if let Some(ref label) = self.base.base.label {
- let (_, font_size) = crate::layout::control_label_font_parsed();
- ctx.text(label.clone(), self.base.base.x, self.base.base.y, font_size, colors::control_label_color_u8());
- }
- }
- }
-
- fn set_modifiers(&mut self, ctrl: bool, shift: bool, alt: bool) {
- for &child_ptr in &self.base.children {
- unsafe {
- (*child_ptr).set_modifiers(ctrl, shift, alt);
- }
- }
- }
-
- fn visible(&self) -> bool {
- self.visible
- }
-
- fn set_visible(&mut self, visible: bool) {
- self.visible = visible;
- self.base.visible = visible;
- }
-
- fn color(&self) -> [f32; 4] {
- let mut c = if let Some(c) = self.color {
- c
- } else if let Some(c) = colors::plate_color() {
- c
- } else if self.dragging {
- let base = colors::page_low_color();
- [
- (base[0] + 0.10).min(1.0),
- (base[1] + 0.15).min(1.0),
- (base[2] + 0.12).min(1.0),
- base[3],
- ]
- } else {
- colors::page_low_color()
- };
- c[3] *= crate::layout::plate_opacity();
- c[3] *= self.network_opacity;
-
- let use_blur = self.blur && colors::plate_blur();
- if use_blur {
- c[3] = -c[3].abs();
- }
- c
- }
-
- fn set_drag_bounds(&mut self, bx: f32, by: f32, bw: f32, bh: f32) {
- self.bounds = Some((bx, by, bw, bh));
- }
-
- fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
- if ctx.is_coordinate_covered(self as *const Self as *const () as usize, px, py) {
- return false;
- }
- if let Some((cx, cy, r)) = self.curved_circle {
- let dx = px - cx;
- let dy = py - cy;
- return dx * dx + dy * dy <= r * r;
- }
-
- let (x, y, w, h) = self.rect();
- if px < x || px >= x + w || py < y || py >= y + h {
- return false;
- }
-
- let r = crate::layout::plate_corner_radius().min(w * 0.5).min(h * 0.5);
-
- if r <= 0.1 {
- return true;
- }
-
- // Check corners
- if px < x + r && py < y + r {
- let dx = px - (x + r);
- let dy = py - (y + r);
- return dx * dx + dy * dy <= r * r;
- }
- if px >= x + w - r && py < y + r {
- let dx = px - (x + w - r);
- let dy = py - (y + r);
- return dx * dx + dy * dy <= r * r;
- }
- if px >= x + w - r && py >= y + h - r {
- let dx = px - (x + w - r);
- let dy = py - (y + h - r);
- return dx * dx + dy * dy <= r * r;
- }
- if px < x + r && py >= y + h - r {
- let dx = px - (x + r);
- let dy = py - (y + h - r);
- return dx * dx + dy * dy <= r * r;
- }
-
- true
- }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- let label_off = self.base.base.label_offset();
- let (clamped_x, clamped_y, clamped_w, clamped_h) = if let Some(parent_ptr) = self.base.parent {
- let (px, py, pw, ph) = unsafe { (*parent_ptr).rect() };
- let cx = x.clamp(px, px + pw.max(0.0));
- let cy = y.clamp(py, py + ph.max(0.0));
- let cw = w.min((px + pw.max(0.0) - cx).max(0.0));
- let ch = h.min((py + ph.max(0.0) - cy).max(0.0));
- (cx, cy, cw, ch)
- } else {
- (x, y, w, h)
- };
-
- self.base.base.x = clamped_x;
- self.base.base.y = clamped_y;
- self.base.base.w = clamped_w;
- self.base.base.h = clamped_h;
-
- if !self.base.visible {
- return;
- }
-
- let pad = self.padding.unwrap_or_else(|| crate::layout::plate_padding());
- let padding_x = pad;
- let padding_y = pad;
- let left_x = clamped_x + padding_x;
- let available_w = (clamped_w - 2.0 * padding_x).max(1.0);
- let start_y = clamped_y + label_off + padding_y;
- let available_h = (clamped_h - 2.0 * padding_y).max(1.0);
-
- let center_x = left_x + available_w / 2.0;
- let center_y = start_y + available_h / 2.0;
- let aspect_ratio = available_w / available_h;
-
- let mut active_widgets = Vec::new();
- for &w_ptr in &self.base.children {
- let w = unsafe { &*w_ptr };
- if !w.layout_ignore() {
- active_widgets.push(w_ptr);
- }
- }
-
- let mut total_diagonal = 0.0;
- let mut count = 0;
- for &w_ptr in &active_widgets {
- let w = unsafe { &*w_ptr };
- let (_, _, ww, wh) = w.rect();
- let use_w = if ww > 0.0 { ww.min(available_w) } else { available_w };
- let use_h = if wh > 0.0 { wh } else { 50.0 };
- total_diagonal += (use_w * use_w + use_h * use_h).sqrt();
- count += 1;
- }
- let avg_diagonal = if count > 0 { total_diagonal / count as f32 } else { 100.0 };
- let base_spacing = (avg_diagonal * 0.55).max(60.0);
-
- for (i, &w_ptr) in active_widgets.iter().enumerate() {
- let w = unsafe { &mut *w_ptr };
- let (_, _, ww, wh) = w.rect();
- let use_w = if ww > 0.0 { ww.min(available_w) } else { available_w };
- let use_h = if wh > 0.0 { wh } else { 50.0 };
-
- if i == 0 {
- let cx = (center_x - use_w / 2.0).clamp(left_x, (left_x + available_w - use_w).max(left_x));
- let cy = (center_y - use_h / 2.0).clamp(start_y, (start_y + available_h - use_h).max(start_y));
- let cw = use_w.min(clamped_x + clamped_w - padding_x - cx);
- let ch = use_h.min(clamped_y + label_off + clamped_h - padding_y - cy);
- w.set_rect(cx, cy, cw, ch);
- } else {
- let mut ring = 1;
- let mut ring_start = 1;
- let mut placed = false;
- while !placed {
- let ring_capacity = ring * 6;
- if i < ring_start + ring_capacity {
- let pos_in_ring = i - ring_start;
- let angle = (pos_in_ring as f32) * (2.0 * std::f32::consts::PI / ring_capacity as f32);
- let radius = (ring as f32) * base_spacing;
-
- let x_offset = radius * angle.cos() * aspect_ratio;
- let y_offset = radius * angle.sin();
-
- let raw_x = center_x + x_offset - use_w / 2.0;
- let raw_y = center_y + y_offset - use_h / 2.0;
-
- let cx = raw_x.clamp(left_x, (left_x + available_w - use_w).max(left_x));
- let cy = raw_y.clamp(start_y, (start_y + available_h - use_h).max(start_y));
- let cw = use_w.min(clamped_x + clamped_w - padding_x - cx);
- let ch = use_h.min(clamped_y + label_off + clamped_h - padding_y - cy);
-
- w.set_rect(cx, cy, cw, ch);
- placed = true;
- } else {
- ring_start += ring_capacity;
- ring += 1;
- }
- }
- }
- }
- }
-
- fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
- self.base.parent
- }
-
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
- self.base.parent = parent;
- let id = self.base.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);
- ctx.register_widget(id, self as *mut Self as *mut (dyn Element + 'static));
- ctx.link_ids(p_id, id);
- }
- } else {
- ctx.tree.set_parent(id, None);
- }
- }
-
- fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- self.base.children.clone()
- }
-
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- self.base.children.push(child);
- let id = self.base.base.id();
- let self_ptr = self.as_ptr();
- if let Some(c_base) = unsafe { (*child).base() } {
- let c_id = c_base.id();
- ctx.register_widget(id, self_ptr);
- ctx.register_widget(c_id, child);
- ctx.link_ids(id, c_id);
- }
- unsafe {
- (*child).set_parent(Some(self_ptr), ctx);
- }
- }
-
- fn clear_children(&mut self, ctx: &mut UiContext) {
- self.base.children.clear();
- let id = self.base.base.id();
- ctx.clear_children_ids(id);
- }
-
- 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 quads = Vec::new();
- let (r1, r2, r3, r4) = self.rounded_corners();
- if r1 || r2 || r3 || r4 {
- let (x, y, w, h) = self.rect();
- let label_off = self.base.base.label_offset();
- let radius = self.corner_radius();
- let c = self.color();
- if c[3].abs() > 0.001 {
- quads.push((x, y + label_off, w, h - label_off, radius, c, (r1, r2, r3, r4)));
- }
- }
- for &child_ptr in &self.base.children {
- let widget = unsafe { &*child_ptr };
- quads.extend(widget.all_rounded_quads(ctx));
- }
- quads
- }
-
- fn all_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- if !self.visible {
- return Vec::new();
- }
- let mut quads = Vec::new();
- let (px, py, pw, ph) = self.rect();
- let has_rounded = self.rounded_corners() != (false, false, false, false);
- if !has_rounded {
- let label_off = self.base.base.label_offset();
- quads.push((px, py + label_off, pw, ph - label_off, self.color()));
- }
-
- for &child_ptr in &self.base.children {
- let widget = unsafe { &*child_ptr };
- let (wx, wy, ww, wh) = widget.rect();
- let has_rounded = widget.rounded_corners() != (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
- }
-
- fn prepare_text(&mut self, fs: &mut glyphon::FontSystem) {
- if !self.visible {
- return;
- }
- for &child_ptr in &self.base.children {
- unsafe {
- (*child_ptr).prepare_text(fs);
- }
- }
- }
-
- fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if !self.visible {
- return false;
- }
- let mut changed = false;
- for &widget_ptr in &self.base.children {
- let widget = unsafe { &mut *widget_ptr };
- if widget.is_dragging() {
- if widget.drag_update(px, py) {
- changed = true;
- }
- } else if widget.cursor_moved(px, py, ctx) {
- changed = true;
- }
- }
- changed
- }
-
- fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if !self.visible {
- return false;
- }
- for &widget_ptr in self.base.children.iter().rev() {
- let widget = unsafe { &mut *widget_ptr };
- if widget.popover_rect().is_some() {
- if widget.mouse_input(button, state, px, py, ctx) {
- return true;
- }
- }
- }
- for &widget_ptr in self.base.children.iter().rev() {
- let widget = unsafe { &mut *widget_ptr };
- if widget.mouse_input(button, state, px, py, ctx) {
- return true;
- }
- if state == ElementState::Pressed && !widget.hit_test(px, py, ctx) {
- widget.unfocus();
- }
- }
-
- if !self.draggable { return false; }
- if button != MouseButton::Left { return false; }
- match state {
- ElementState::Pressed => {
- if self.hit_test(px, py, ctx) {
- self.drag_begin(px, py);
- return true;
- }
- }
- ElementState::Released => {
- if self.dragging { self.drag_end(); return true; }
- }
- }
- false
- }
-
- fn keyboard_input(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
- if !self.visible {
- return false;
- }
- for &widget_ptr in &self.base.children {
- let widget = unsafe { &mut *widget_ptr };
- if widget.keyboard_input(event, ctx) {
- return true;
- }
- }
- false
- }
-
- fn mouse_wheel(&mut self, delta: &MouseScrollDelta, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if !self.visible {
- return false;
- }
- for &widget_ptr in self.base.children.iter().rev() {
- let widget = unsafe { &mut *widget_ptr };
- if widget.mouse_wheel(delta, px, py, ctx) {
- return true;
- }
- }
- false
- }
-
- fn popover_rect(&self) -> Option<(f32, f32, f32, f32)> {
- if !self.visible {
- return None;
- }
- for &widget_ptr in self.base.children.iter().rev() {
- let widget = unsafe { &*widget_ptr };
- if let Some(r) = widget.popover_rect() {
- return Some(r);
- }
- }
- None
- }
-
- fn render_popover(&self, pc: &mut dyn crate::layout::RenderTarget) {
- if !self.visible {
- return;
- }
- for &widget_ptr in self.base.children.iter().rev() {
- let widget = unsafe { &*widget_ptr };
- widget.render_popover(pc);
- }
- }
-
- fn tick(&mut self, dt: f32, ctx: &mut UiContext) -> bool {
- if !self.visible {
- return false;
- }
- let mut changed = false;
- for &widget_ptr in &self.base.children {
- let widget = unsafe { &mut *widget_ptr };
- if widget.tick(dt, ctx) {
- changed = true;
- }
- }
- changed
- }
-
- fn drag_update(&mut self, px: f32, py: f32) -> bool {
- let nx = px - self.drag_ox;
- let ny = py - self.drag_oy;
- let (nx, ny) = if let Some((bx, by, bw, bh)) = self.bounds {
- (nx.clamp(bx, bx + bw - self.base.base.w), ny.clamp(by, by + bh - self.base.base.h))
- } else {
- (nx, ny)
- };
- if (nx - self.base.base.x).abs() > 0.01 || (ny - self.base.base.y).abs() > 0.01 {
- let dx = nx - self.base.base.x;
- let dy = ny - self.base.base.y;
- self.base.base.x = nx;
- self.base.base.y = ny;
-
- for &child_ptr in &self.base.children {
- unsafe {
- let (cx, cy, cw, ch) = (*child_ptr).rect();
- (*child_ptr).set_rect(cx + dx, cy + dy, cw, ch);
- }
- }
- return true;
- }
- false
- }
-
- fn drag_begin(&mut self, px: f32, py: f32) {
- self.dragging = true;
- self.drag_ox = px - self.base.base.x;
- self.drag_oy = py - self.base.base.y;
- self.drag_start_x = self.base.base.x;
- self.drag_start_y = self.base.base.y;
- }
-
- fn drag_end(&mut self) { self.dragging = false; }
-}
-
-unsafe impl Send for Plate {}
-unsafe impl Sync for Plate {}
diff --git a/src/widget/container/scrolling_list.rs b/src/widget/container/scrolling_list.rs
deleted file mode 100644
index 6c45c66..0000000
--- a/src/widget/container/scrolling_list.rs
+++ /dev/null
@@ -1,747 +0,0 @@
-use crate::widget::*;
-use super::scroll_box::ScrollBox;
-use crate::widget::display::TextLabel;
-use crate::context::UiContext;
-pub use crate::widget::input::font_selector::FontSelector;
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ColumnWidth {
- Flex,
- Absolute(f32),
- RightOffset(f32),
-}
-
-#[derive(Debug, Clone)]
-pub struct ListColumn {
- pub name: String,
- pub width: ColumnWidth,
- pub justification: Justification,
-}
-
-#[derive(Debug, Clone)]
-pub struct ListRow {
- pub cells: Vec<String>,
- pub icon: Option<String>,
- pub selected: bool,
-}
-
-#[derive(Debug, Clone)]
-pub struct List {
- pub base: Widget,
- pub scroll_box: ScrollBox,
- pub item_height: f32,
- pub item_gap: f32,
- pub columns: Option<Vec<ListColumn>>,
- pub rows: Vec<ListRow>,
- pub hovered_row: Option<usize>,
- pub pressed_row: Option<usize>,
- pub clicked_row: Option<usize>,
- pub double_clicked_row: Option<usize>,
- pub last_click_time: Option<std::time::Instant>,
- pub search_enabled: bool,
- pub search_visible: bool,
- pub search_box: crate::widget::Adapted<TextBox>,
-}
-
-impl List {
- pub fn new(item_height: f32, item_gap: f32) -> Self {
- let (_, font_size) = crate::layout::list_font_parsed();
- let adjusted_item_height = item_height.max(font_size + 14.0);
- Self {
- base: Widget::new(),
- scroll_box: ScrollBox::new(),
- item_height: adjusted_item_height,
- item_gap,
- columns: None,
- rows: Vec::new(),
- hovered_row: None,
- pressed_row: None,
- clicked_row: None,
- double_clicked_row: None,
- last_click_time: None,
- search_enabled: false,
- search_visible: false,
- search_box: TextBox::new(String::new()).with_placeholder("Search...").with_update_on_type(true),
- }
- }
-
- pub fn with_search(mut self, enabled: bool) -> Self {
- self.search_enabled = enabled;
- self
- }
-
- pub fn with_columns(mut self, columns: Vec<ListColumn>) -> Self {
- self.columns = Some(columns);
- self
- }
-
- pub fn get_column_bounds(&self, list_w: f32) -> Vec<(f32, f32)> {
- let cols = match &self.columns {
- Some(c) => c,
- None => return Vec::new(),
- };
- let mut bounds = vec![(0.0, 0.0); cols.len()];
- let mut flex_indices = Vec::new();
- let mut reserved_width = 0.0;
-
- // Pass 1: Resolve Absolute and RightOffset columns
- for (i, col) in cols.iter().enumerate() {
- match col.width {
- ColumnWidth::Absolute(w) => {
- bounds[i] = (0.0, w);
- reserved_width += w;
- }
- ColumnWidth::RightOffset(offset) => {
- let x = list_w - offset;
- let mut next_x = list_w;
- for j in (i + 1)..cols.len() {
- if let ColumnWidth::RightOffset(o) = cols[j].width {
- next_x = list_w - o;
- break;
- }
- }
- let w = (next_x - x).max(0.0);
- bounds[i] = (x, w);
- }
- ColumnWidth::Flex => {
- flex_indices.push(i);
- }
- }
- }
-
- // Pass 2: Layout left-aligned columns (Flex and Absolute)
- let mut current_x = 0.0;
- let mut right_boundary = list_w;
- for (_, col) in cols.iter().enumerate() {
- if let ColumnWidth::RightOffset(offset) = col.width {
- if list_w - offset < right_boundary {
- right_boundary = list_w - offset;
- }
- }
- }
-
- let left_space = (right_boundary - current_x).max(0.0);
- let flex_share = if !flex_indices.is_empty() {
- let flex_total = (left_space - reserved_width).max(0.0);
- flex_total / flex_indices.len() as f32
- } else {
- 0.0
- };
-
- for (i, col) in cols.iter().enumerate() {
- match col.width {
- ColumnWidth::Absolute(w) => {
- bounds[i] = (current_x, w);
- current_x += w;
- }
- ColumnWidth::Flex => {
- bounds[i] = (current_x, flex_share);
- current_x += flex_share;
- }
- ColumnWidth::RightOffset(_) => {
- // Already resolved
- }
- }
- }
-
- bounds
- }
-
- pub fn take_click(&mut self) -> Option<usize> {
- self.clicked_row.take()
- }
-
- pub fn take_double_click(&mut self) -> Option<usize> {
- self.double_clicked_row.take()
- }
-
- pub fn update_bounds(&mut self, count: usize, viewport_y: f32, viewport_h: f32) {
- let item_height_full = self.item_height + self.item_gap;
- let content_h = count as f32 * item_height_full + 4.0;
- self.scroll_box.update_bounds(content_h, viewport_y, viewport_h);
- }
-
- pub fn update_bounds_from_rows(&mut self) {
- let item_height_full = self.item_height + self.item_gap;
- let content_h = self.rows.len() as f32 * item_height_full + 4.0;
- let (_, _, _, h) = self.rect();
- self.scroll_box.update_bounds(content_h, self.scroll_box.viewport_y, h);
- }
-
- pub fn get_item_draw_y(&self, idx: usize, offset: f32) -> Option<f32> {
- let item_height_full = self.item_height + self.item_gap;
- let virtual_y = idx as f32 * item_height_full + offset;
- self.scroll_box.get_item_draw_y(virtual_y, self.item_height)
- }
-
- pub fn scroll_y(&self) -> f32 {
- self.scroll_box.scroll_y
- }
-
- pub fn set_scroll_y(&mut self, val: f32) {
- self.scroll_box.scroll_y = val;
- }
-
- pub fn handle_list_navigation(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
- if self.columns.is_none() {
- return false;
- }
- if event.state == ElementState::Pressed {
- let mut current_selected = None;
- for (idx, r) in self.rows.iter().enumerate() {
- if r.selected {
- current_selected = Some(idx);
- break;
- }
- }
-
- let mut next_selected = None;
- if event.logical_key == Key::Named(NamedKey::ArrowDown) {
- if let Some(curr) = current_selected {
- if curr + 1 < self.rows.len() {
- next_selected = Some(curr + 1);
- }
- } else if !self.rows.is_empty() {
- next_selected = Some(0);
- }
- } else if event.logical_key == Key::Named(NamedKey::ArrowUp) {
- if let Some(curr) = current_selected {
- if curr > 0 {
- next_selected = Some(curr - 1);
- }
- }
- }
-
- if let Some(next) = next_selected {
- for (idx, r) in self.rows.iter_mut().enumerate() {
- r.selected = idx == next;
- }
- self.clicked_row = Some(next);
-
- let item_height_full = self.item_height + self.item_gap;
- let item_y = next as f32 * item_height_full + 2.0;
- let viewport_h = self.scroll_box.viewport_h;
-
- if item_y < self.scroll_box.scroll_y {
- self.scroll_box.scroll_y = item_y;
- } else if item_y + self.item_height > self.scroll_box.scroll_y + viewport_h {
- self.scroll_box.scroll_y = item_y + self.item_height - viewport_h;
- }
-
- self.mark_dirty(ctx);
- return true;
- }
- }
- false
- }
-}
-
-impl Default for List {
- fn default() -> Self {
- Self::new(24.0, 4.0)
- }
-}
-
-impl Element for List {
- fn base(&self) -> Option<&Widget> { Some(&self.base) }
- fn base_mut(&mut self) -> Option<&mut Widget> { Some(&mut self.base) }
-
- fn rect(&self) -> (f32, f32, f32, f32) {
- (self.base.x, self.base.y, self.base.w, self.base.h)
- }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- self.base.x = x;
- self.base.y = y;
- self.base.w = w;
- self.base.h = h;
- if self.search_enabled && self.search_visible {
- let search_margin_y = 6.0;
- let search_h = 26.0;
- let offset_y = search_h + 2.0 * search_margin_y;
- self.scroll_box.set_rect(x, y, w, h - offset_y);
- self.search_box.set_rect(x + 8.0, y + h - offset_y + search_margin_y, w - 16.0, search_h);
- } else {
- self.scroll_box.set_rect(x, y, w, h);
- self.search_box.set_rect(x, y + h, w, 0.0);
- }
- if self.columns.is_some() && !self.rows.is_empty() {
- self.update_bounds_from_rows();
- }
- }
-
- fn color(&self) -> [f32; 4] {
- self.scroll_box.color()
- }
-
- fn rounded_corners(&self) -> (bool, bool, bool, bool) {
- (true, true, true, true)
- }
-
- fn corner_radius(&self) -> f32 {
- crate::layout::list_corner_radius()
- }
-
- fn solid_border(&self) -> Option<([f32; 4], f32)> {
- let is_focused = focus::is_focused(self) || focus::is_focused(&self.scroll_box);
- let is_hovered = self.hovered() || self.scroll_box.base.hovered;
- if self.scroll_box.show_border {
- let box_border_color = if is_focused {
- [0.30, 0.50, 0.32, 1.0]
- } else if is_hovered {
- [0.25, 0.25, 0.35, 1.0]
- } else {
- [0.18, 0.18, 0.24, 1.0]
- };
- Some((box_border_color, 1.0))
- } else {
- None
- }
- }
-
- fn as_ptr(&self) -> *mut (dyn Element + 'static) {
- self as *const Self as *mut Self as *mut (dyn Element + 'static)
- }
- fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
- self as *mut Self as *mut (dyn Element + 'static)
- }
-
- fn set_hovered(&mut self, v: bool) {
- self.scroll_box.set_hovered(v);
- if !v {
- self.hovered_row = None;
- }
- }
-
- fn hovered(&self) -> bool {
- self.scroll_box.hovered()
- }
-
- fn highlight_color(&self, ctx: &UiContext) -> Option<[f32; 4]> {
- self.scroll_box.highlight_color(ctx)
- }
-
- fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- let mut handled = false;
- if self.search_enabled && self.search_visible {
- if self.search_box.on_cursor_moved(px, py, ctx) {
- handled = true;
- }
- }
- self.scroll_box.cursor_moved(px, py, ctx);
- if self.columns.is_none() {
- return handled;
- }
- let (x, _, w, _) = self.rect();
- let item_height_full = self.item_height + self.item_gap;
-
- let mut new_hovered = None;
- for idx in 0..self.rows.len() {
- let virtual_y = idx as f32 * item_height_full + 2.0;
- if let Some(draw_y) = self.scroll_box.get_item_draw_y(virtual_y, self.item_height) {
- if px >= x + 2.0 && px <= x + w - 2.0 && py >= draw_y && py <= draw_y + self.item_height {
- new_hovered = Some(idx);
- break;
- }
- }
- }
-
- let changed = self.hovered_row != new_hovered;
- self.hovered_row = new_hovered;
- changed || handled
- }
-
- fn mouse_wheel(&mut self, delta: &MouseScrollDelta, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- self.scroll_box.mouse_wheel(delta, px, py, ctx)
- }
-
- fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if self.search_enabled && self.search_visible {
- if self.search_box.mouse_input(button, state, px, py, ctx) {
- ctx.set_focused(&mut self.search_box);
- return true;
- }
- }
- let (x, _, w, _) = self.rect();
- let was_scroll = self.scroll_box.mouse_input(button, state, px, py, ctx);
-
- if self.columns.is_none() || button != MouseButton::Left {
- return was_scroll;
- }
-
- let item_height_full = self.item_height + self.item_gap;
- let mut clicked_idx = None;
- for idx in 0..self.rows.len() {
- let virtual_y = idx as f32 * item_height_full + 2.0;
- if let Some(draw_y) = self.scroll_box.get_item_draw_y(virtual_y, self.item_height) {
- if px >= x + 2.0 && px <= x + w - 2.0 && py >= draw_y && py <= draw_y + self.item_height {
- clicked_idx = Some(idx);
- break;
- }
- }
- }
-
- match state {
- ElementState::Pressed => {
- if let Some(idx) = clicked_idx {
- self.pressed_row = Some(idx);
- self.scroll_box.focus();
- ctx.set_focused_ptr(self.as_ptr_mut());
- return true;
- }
- }
- ElementState::Released => {
- let mut clicked = false;
- if let Some(idx) = clicked_idx {
- if self.pressed_row == Some(idx) {
- self.scroll_box.focus();
- let now = std::time::Instant::now();
- if let Some(last) = self.last_click_time {
- if now.duration_since(last) < std::time::Duration::from_millis(400) {
- self.double_clicked_row = Some(idx);
- }
- }
- self.last_click_time = Some(now);
- self.clicked_row = Some(idx);
- clicked = true;
- }
- }
- self.pressed_row = None;
- return clicked || was_scroll;
- }
- }
- was_scroll
- }
-
- fn focus(&mut self) {
- self.scroll_box.focus();
- }
-
- fn unfocus(&mut self) {
- self.scroll_box.unfocus();
- }
-
- fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- let mut quads = self.scroll_box.extra_quads();
- if self.columns.is_none() {
- return quads;
- }
- let (x, _, w, _) = self.rect();
- let item_height_full = self.item_height + self.item_gap;
-
- let (r1, r2, r3, r4) = self.rounded_corners();
- if r1 || r2 || r3 || r4 {
- if !quads.is_empty() {
- quads.remove(0);
- }
- }
-
- for idx in 0..self.rows.len() {
- let virtual_y = idx as f32 * item_height_full + 2.0;
- if let Some(draw_y) = self.scroll_box.get_item_draw_y(virtual_y, self.item_height) {
- let row = &self.rows[idx];
- let is_hovered = self.hovered_row == Some(idx);
- let is_pressed = self.pressed_row == Some(idx);
-
- let bg_color = if row.selected {
- if is_pressed { [0.30, 0.52, 0.78, 0.6] }
- else if is_hovered { [0.30, 0.52, 0.78, 0.5] }
- else { [0.20, 0.40, 0.65, 0.4] }
- } else {
- if is_pressed { [0.20, 0.20, 0.25, 0.25] }
- else if is_hovered { [0.20, 0.20, 0.25, 0.15] }
- else { [0.0, 0.0, 0.0, 0.0] }
- };
-
- if bg_color[3] > 0.001 {
- quads.push((x + 2.0, draw_y, w - 4.0, self.item_height, bg_color));
- }
- }
- }
- quads
- }
-
- fn all_rounded_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))> {
- let mut quads = Vec::new();
- let (r1, r2, r3, r4) = self.rounded_corners();
- let has_rounded = r1 || r2 || r3 || r4;
- if !has_rounded {
- for &child_ptr in &self.children(ctx) {
- let widget = unsafe { &*child_ptr };
- quads.extend(widget.all_rounded_quads(ctx));
- }
- return quads;
- }
-
- let radius = self.corner_radius();
- let (x, y, w, h) = self.rect();
-
- if let Some((border_color, thickness)) = self.solid_border() {
- quads.push((x, y, w, h, radius, border_color, (r1, r2, r3, r4)));
- quads.push((x + thickness, y + thickness, w - 2.0 * thickness, h - 2.0 * thickness, radius - thickness, crate::color::list_bg_color(), (r1, r2, r3, r4)));
- } else {
- quads.push((x, y, w, h, radius, crate::color::list_bg_color(), (r1, r2, r3, r4)));
- }
-
- for &child_ptr in &self.children(ctx) {
- let widget = unsafe { &*child_ptr };
- quads.extend(widget.all_rounded_quads(ctx));
- }
- quads
- }
-
- fn keyboard_input(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
- if self.search_enabled {
- let open_key = crate::color::list_open_search_key();
- let close_key = crate::color::list_close_search_key();
-
- if event.state == ElementState::Pressed {
- if self.search_visible && match_key_shortcut(event, &close_key) {
- self.search_visible = false;
- self.search_box.text.clear();
- self.search_box.edit_buffer.clear();
- self.search_box.just_changed = true;
- self.search_box.unfocus();
- ctx.clear_focus();
-
- let (lx, ly, lw, lh) = (self.base.x, self.base.y, self.base.w, self.base.h);
- self.set_rect(lx, ly, lw, lh);
- self.mark_dirty(ctx);
- return true;
- }
-
- if !self.search_visible && match_key_shortcut(event, &open_key) {
- self.search_visible = true;
- let (lx, ly, lw, lh) = (self.base.x, self.base.y, self.base.w, self.base.h);
- self.set_rect(lx, ly, lw, lh);
- ctx.set_focused(&mut self.search_box);
- self.search_box.focus();
- self.mark_dirty(ctx);
- return true;
- }
- }
-
- let is_arrow = event.logical_key == Key::Named(NamedKey::ArrowDown) || event.logical_key == Key::Named(NamedKey::ArrowUp);
- if is_arrow {
- if self.handle_list_navigation(event, ctx) {
- return true;
- }
- }
-
- if self.search_visible {
- if self.search_box.keyboard_input(event, ctx) {
- return true;
- }
- }
- }
-
- if self.scroll_box.keyboard_input(event, ctx) {
- return true;
- }
- if self.handle_list_navigation(event, ctx) {
- return true;
- }
- false
- }
-
- fn widget_font(&self) -> Option<String> {
- let f = crate::layout::list_font();
- if f.is_empty() {
- None
- } else {
- Some(f)
- }
- }
-
- fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> { self.scroll_box.parent(_ctx) }
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
- self.scroll_box.set_parent(parent, ctx);
- if parent.is_some() {
- let self_ptr = self as *mut Self;
- let self_id = self.base.id();
- unsafe {
- let sb_ptr = (*self_ptr).search_box.as_ptr_mut();
- let sb_id = (*self_ptr).search_box.base().unwrap().id();
- ctx.register_widget(sb_id, sb_ptr);
- ctx.link_ids(self_id, sb_id);
- (*sb_ptr).set_parent(Some(self_ptr), ctx);
- }
- }
- }
- fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- let mut list = self.scroll_box.children(ctx);
- if self.search_enabled && self.search_visible {
- let self_ptr = self as *const Self as *mut Self;
- unsafe {
- list.push((*self_ptr).search_box.as_ptr_mut());
- }
- }
- list
- }
-
- // List renders its own subtree: column-mode rows are List-drawn cells (no child
- // widgets), and columns=None rows live behind the internal ScrollBox with the
- // viewport offset/clip applied by the aggregates — the walk emits those and must
- // not also descend.
- fn renders_own_subtree(&self) -> bool {
- true
- }
-
- fn paint_self(&self, ui: &UiContext, ctx: &mut crate::scene::paint::PaintCtx) {
- crate::scene::painter::paint_legacy_leaf(self, ui, ctx, self.own_fonted_labels(ui));
- }
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) { self.scroll_box.add_child(child, ctx); }
- fn clear_children(&mut self, ctx: &mut UiContext) { self.scroll_box.clear_children(ctx); }
- fn prepare_text(&mut self, fs: &mut glyphon::FontSystem) {
- if self.search_enabled && self.search_visible {
- self.search_box.prepare_text(fs);
- }
- }
- fn tick(&mut self, dt: f32, ctx: &mut UiContext) -> bool {
- let mut changed = false;
- if self.scroll_box.tick(dt, ctx) {
- changed = true;
- }
- if self.search_enabled && self.search_visible {
- if self.search_box.tick(dt, ctx) {
- changed = true;
- }
- }
- changed
- }
-}
-
-unsafe impl Send for List {}
-unsafe impl Sync for List {}
-
-impl List {
- pub(crate) fn own_fonted_labels(&self, ctx: &UiContext) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
- if !self.visible() {
- return Vec::new();
- }
- if self.columns.is_none() {
- let font = self.widget_font();
- let mut labels = crate::scene::painter::base_control_label(self).into_iter().map(|l| (l, font.clone(), None::<[f32; 4]>)).collect::<Vec<_>>();
- let mut curr = self.parent(ctx);
- let mut scroll_box_bounds = None;
- while let Some(parent_ptr) = curr {
- let parent = unsafe { &*parent_ptr };
- if let Some(scroll_box) = parent.as_any().downcast_ref::<crate::widget::ScrollBox>() {
- let (sb_x, _, sb_w, _) = scroll_box.rect();
- let view_min = scroll_box.viewport_y + 4.0;
- let view_max = scroll_box.viewport_y + scroll_box.viewport_h - 4.0;
- scroll_box_bounds = Some([sb_x, view_min, sb_x + sb_w, view_max]);
- break;
- }
- curr = parent.parent(ctx);
- }
- if let Some(sb_bounds) = scroll_box_bounds {
- for item in &mut labels {
- item.2 = Some(sb_bounds);
- }
- }
- if self.search_enabled && self.search_visible {
- labels.extend(self.search_box.own_labels_with_font_and_bounds(ctx));
- }
- return labels;
- }
- let (x, _, w, _) = self.rect();
- let mut result = Vec::new();
-
- let item_height_full = self.item_height + self.item_gap;
- let col_bounds = self.get_column_bounds(w);
-
- let fg = [230, 230, 242];
- let text_dim = [140, 140, 153];
- let list_font = self.widget_font();
-
- let view_min = self.scroll_box.viewport_y + 4.0;
- let view_max = self.scroll_box.viewport_y + self.scroll_box.viewport_h - 4.0;
- let clipping_bounds = Some([x, view_min, x + w, view_max]);
-
- for idx in 0..self.rows.len() {
- let virtual_y = idx as f32 * item_height_full + 2.0;
- if let Some(draw_y) = self.scroll_box.get_item_draw_y(virtual_y, self.item_height) {
- let row = &self.rows[idx];
- let row_fg = if row.selected { fg } else { [178, 178, 191] };
- let row_dim = if row.selected { fg } else { text_dim };
-
- let (_, config_size) = crate::layout::list_font_parsed();
- let primary_size = config_size;
- let secondary_size = (config_size - 1.0).max(8.0);
-
- let y_primary = crate::layout::center_text_y(draw_y, self.item_height, primary_size);
- let y_secondary = crate::layout::center_text_y(draw_y, self.item_height, secondary_size);
-
- let mut start_text_offset = 8.0;
- if let Some(ref icon) = row.icon {
- if !col_bounds.is_empty() {
- result.push((
- TextLabel {
- text: icon.clone(),
- x: x + col_bounds[0].0 + 12.0,
- y: y_primary,
- font_size: primary_size,
- color: row_fg,
- },
- list_font.clone(),
- clipping_bounds,
- ));
- start_text_offset = 32.0;
- }
- }
-
- for (c_idx, cell_text) in row.cells.iter().enumerate() {
- if c_idx >= col_bounds.len() {
- break;
- }
- let (col_x, col_w) = col_bounds[c_idx];
- if col_w <= 0.0 {
- continue;
- }
-
- let cell_color = if c_idx == 0 { row_fg } else { row_dim };
- let cell_y = if c_idx == 0 { y_primary } else { y_secondary };
- let cell_size = if c_idx == 0 { primary_size } else { secondary_size };
-
- let cell_draw_x = if c_idx == 0 {
- x + col_x + start_text_offset
- } else {
- x + col_x
- };
-
- let max_w = if c_idx == 0 {
- col_w - start_text_offset - 8.0
- } else {
- col_w - 8.0
- };
- let char_w = cell_size * 0.65;
- let max_chars = (max_w / char_w).max(4.0) as usize;
- let cell_text_truncated = if cell_text.chars().count() > max_chars {
- let mut s: String = cell_text.chars().take(max_chars - 3).collect();
- s.push_str("...");
- s
- } else {
- cell_text.clone()
- };
-
- result.push((
- TextLabel {
- text: cell_text_truncated,
- x: cell_draw_x,
- y: cell_y,
- font_size: cell_size,
- color: cell_color,
- },
- list_font.clone(),
- clipping_bounds,
- ));
- }
- }
- }
- if self.search_enabled && self.search_visible {
- result.extend(self.search_box.own_labels_with_font_and_bounds(ctx));
- }
- result
- }
-}
diff --git a/src/widget/container/section_container.rs b/src/widget/container/section_container.rs
deleted file mode 100644
index a8fd19e..0000000
--- a/src/widget/container/section_container.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-use crate::widget::*;
-use crate::context::UiContext;
-
-use super::container::Container;
-use super::container_layout::ContainerLayout;
-
-#[derive(Clone)]
-pub struct SectionContainer {
- pub header: SectionHeader,
- pub container: Container,
- pub base: Widget,
- pub parent: Option<*mut (dyn Element + 'static)>,
- pub draw_children: bool,
-}
-
-impl SectionContainer {
- pub fn new(title: &str) -> Self {
- Self {
- header: SectionHeader::new(title),
- container: Container::new(),
- base: Widget::new(),
- parent: None,
- draw_children: true,
- }
- }
-
- pub fn with_layout<L: ContainerLayout + 'static>(mut self, layout: L) -> Self {
- let container = std::mem::replace(&mut self.container, Container::new());
- self.container = container.with_layout(layout);
- self
- }
-
- pub fn with_draw_children(mut self, draw: bool) -> Self {
- self.draw_children = draw;
- self
- }
-
- pub fn set_draw_children(&mut self, draw: bool) {
- self.draw_children = draw;
- }
-}
-
-impl Default for SectionContainer {
- fn default() -> Self {
- Self::new("")
- }
-}
-
-impl Element for SectionContainer {
- fn base(&self) -> Option<&Widget> { Some(&self.base) }
- fn blocks_backplate_drag(&self) -> bool { false }
- fn base_mut(&mut self) -> Option<&mut Widget> { Some(&mut self.base) }
- fn color(&self) -> [f32; 4] { [0.0, 0.0, 0.0, 0.0] }
- fn as_ptr(&self) -> *mut (dyn Element + 'static) {
- self as *const Self as *mut Self as *mut (dyn Element + 'static)
- }
- fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
- self as *mut Self as *mut (dyn Element + 'static)
- }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- self.base.x = x;
- self.base.y = y;
- self.base.w = w;
- self.base.h = h;
-
- self.header.set_rect(x, y, w, 24.0);
- self.container.set_rect(x, y + 28.0, w, (h - 28.0).max(0.0));
- }
-
- fn measure(&self, constraints: LayoutConstraints, ctx: &UiContext) -> Size {
- let remaining_constraints = LayoutConstraints::new(
- constraints.min_width,
- constraints.max_width,
- (constraints.min_height - 28.0).max(0.0),
- (constraints.max_height - 28.0).max(0.0),
- );
- let container_size = self.container.measure(remaining_constraints, ctx);
- Size {
- width: container_size.width,
- height: container_size.height + 28.0,
- }
- }
-
- fn layout(&mut self, origin: Point, constraints: LayoutConstraints, ctx: &mut UiContext) {
- let size = self.measure(constraints, ctx);
- self.set_rect(origin.x, origin.y, size.width, size.height);
-
- let self_ptr = self.as_ptr_mut();
- self.header.set_parent(Some(self_ptr), ctx);
- self.container.set_parent(Some(self_ptr), ctx);
-
- self.header.layout(origin, LayoutConstraints::new(size.width, size.width, 24.0, 24.0), ctx);
- self.container.layout(
- Point { x: origin.x, y: origin.y + 28.0 },
- LayoutConstraints::new(size.width, size.width, (size.height - 28.0).max(0.0), (size.height - 28.0).max(0.0)),
- ctx,
- );
- }
-
- fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> { self.parent }
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, _ctx: &mut UiContext) { self.parent = parent; }
-
- fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- vec![
- &self.header as *const SectionHeader as *mut SectionHeader as *mut (dyn Element + 'static),
- &self.container as *const Container as *mut Container as *mut (dyn Element + 'static),
- ]
- }
-
- fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- self.container.add_child(child, ctx);
- let id = self.base.id();
- unsafe {
- let c_id = (*child).base().map(|b| b.id()).unwrap();
- ctx.register_widget(c_id, child);
- ctx.link_ids(id, c_id);
- (*child).set_parent(Some(self.container.as_ptr_mut()), ctx);
- }
- }
-
- fn clear_children(&mut self, ctx: &mut UiContext) {
- self.container.clear_children(ctx);
- ctx.clear_children_ids(self.base.id());
- }
-
- fn all_quads(&self, ctx: &UiContext) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- if !self.draw_children {
- return Vec::new();
- }
- let mut quads = self.header.all_quads(ctx);
- quads.extend(self.container.all_quads(ctx));
- quads
- }
-
- 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();
- }
- if !self.draw_children {
- return self.header.all_rounded_quads(ctx);
- }
- let mut quads = self.header.all_rounded_quads(ctx);
- quads.extend(self.container.all_rounded_quads(ctx));
- quads
- }
-
- fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
- self.header.hit_test(px, py, ctx) || self.container.hit_test(px, py, ctx)
- }
-}
-
-impl Drop for SectionContainer {
- fn drop(&mut self) {
- clear_widget_references(self);
- }
-}
diff --git a/src/widget/container/treelist.rs b/src/widget/container/treelist.rs
index bbc066b..9b1fd4d 100644
--- a/src/widget/container/treelist.rs
+++ b/src/widget/container/treelist.rs
@@ -1263,52 +1263,39 @@ unsafe impl Sync for TreeList {}
#[cfg(test)]
mod tests {
use super::*;
- use crate::widget::container::Backplate;
use crate::context::UiContext;
#[test]
- fn test_treelist_blocks_backplate_drag() {
+ fn test_treelist_blocks_window_drag() {
+ // Backplate is DELETED: dissolved windows ask `drag_allowed_at` instead — same
+ // walk, minus the registered-movable-Backplate requirement.
let mut ctx = UiContext::new();
- let mut win = Backplate::new(0.0, 0.0, 800.0, 600.0).with_movable(true);
let mut tree_list = TreeList::new();
tree_list.set_rect(10.0, 52.0, 380.0, 500.0);
-
- ctx.register_widget(win.base().unwrap().id(), win.as_ptr_mut());
- win.add_child(tree_list.as_ptr_mut(), &mut ctx);
-
- // Let's tick and clear dirty to build the spatial grid
+
+ ctx.register_widget(tree_list.base().unwrap().id(), tree_list.as_ptr_mut());
ctx.tick(0.016);
ctx.clear_dirty();
-
- // Now, click at x=100, y=200, which is inside tree_list rect
- let is_movable = ctx.is_movable_backplate_at(100.0, 200.0);
- assert!(!is_movable, "Clicking the TreeList should block backplate drag!");
+
+ assert!(!ctx.drag_allowed_at(100.0, 200.0), "clicking the TreeList must block the window drag");
+ assert!(ctx.drag_allowed_at(600.0, 300.0), "empty surface stays draggable");
}
#[test]
fn test_exact_app_layout_blocks_drag() {
+ // The data-editor shape: a parentless tree registered directly (dissolved root).
let mut ctx = UiContext::new();
- let mut root_window = Backplate::new(0.0, 0.0, 800.0, 600.0).with_movable(true);
let mut tree_list = TreeList::new();
-
- // 1. Initial register (like in view)
- ctx.register_widget(root_window.base().unwrap().id(), root_window.as_ptr_mut());
+
ctx.register_widget(tree_list.base().unwrap().id(), tree_list.as_ptr_mut());
- root_window.add_child(tree_list.as_ptr_mut(), &mut ctx);
ctx.rebuild_spatial_grid();
-
- // 2. Set rect (like in view)
- root_window.set_rect(0.0, 0.0, 800.0, 600.0);
+
let list_top = 52.0;
let list_bottom = 600.0 - 180.0;
- let list_height = list_bottom - list_top;
- tree_list.set_rect(10.0, list_top, 380.0, list_height);
-
+ tree_list.set_rect(10.0, list_top, 380.0, list_bottom - list_top);
ctx.rebuild_spatial_grid();
-
- // 3. Test click at logical x=100.0, y=200.0
- let is_movable = ctx.is_movable_backplate_at(100.0, 200.0);
- assert!(!is_movable, "Clicking TreeList under exact app layout should block backplate drag!");
+
+ assert!(!ctx.drag_allowed_at(100.0, 200.0), "clicking the TreeList under the app layout must block the drag");
}
#[test]
diff --git a/src/widget/display/label.rs b/src/widget/display/label.rs
index fc8f3f3..19987c2 100644
--- a/src/widget/display/label.rs
+++ b/src/widget/display/label.rs
@@ -1,5 +1,5 @@
use crate::widget::*;
-use crate::widget::display::{TextLabel, TextItem};
+use crate::widget::display::TextItem;
use crate::scene::layout::{Rect, Size};
use crate::scene::paint::PaintCtx;
@@ -113,37 +113,6 @@ mod tests {
}
}
-#[derive(Clone)]
-pub struct SectionHeader {
- base: Widget,
-}
-
-impl SectionHeader {
- pub fn new(title: &str) -> Self {
- let mut base = Widget::new();
- base.label = Some(title.to_string());
- Self { base }
- }
-}
-
-impl Element for SectionHeader {
- crate::impl_widget_base!(SectionHeader);
-
- // Leaf legacy widget: own fonted labels via paint_self (the default no longer
- // drains the text getters).
- fn paint_self(&self, ui: &UiContext, ctx: &mut crate::scene::paint::PaintCtx) {
- crate::scene::painter::paint_legacy_leaf(
- self, ui, ctx,
- crate::scene::painter::fonted_leaf_labels(self, ui, self.own_labels()),
- );
- }
- fn blocks_backplate_drag(&self) -> bool { false }
- fn color(&self) -> [f32; 4] { [0.0, 0.0, 0.0, 0.0] }
- fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- vec![(self.base.x + 8.0, self.base.y + 22.0, self.base.w - 16.0, 1.0, [0.18, 0.18, 0.27, 1.0])]
- }
-
-}
// Styled label builder with optional strikethrough
#[derive(Debug)]
@@ -298,15 +267,3 @@ impl StyledLabel {
}
}
}
-
-impl SectionHeader {
- pub(crate) fn own_labels(&self) -> Vec<TextLabel> {
- vec![TextLabel {
- text: self.base.label.clone().unwrap_or_default(),
- x: self.base.x + 12.0,
- y: self.base.y,
- font_size: 14.0,
- color: [212, 212, 212],
- }]
- }
-}
diff --git a/src/widget/display/mod.rs b/src/widget/display/mod.rs
index 061b52f..052c41c 100644
--- a/src/widget/display/mod.rs
+++ b/src/widget/display/mod.rs
@@ -25,7 +25,7 @@ pub(crate) use self::text_label::make_widget_text_buffer;
pub use self::sidebar::Sidebar;
pub use self::panel::Panel;
pub use self::node::Node;
-pub use self::label::{Label, SectionHeader, StyledLabel, LabelPrim};
+pub use self::label::{Label, StyledLabel, LabelPrim};
pub use self::svg::Svg;
pub use self::float3::Float3;
pub use self::progress_bar::ProgressBar;
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index feff48b..ec7c145 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -755,12 +755,12 @@ pub use self::input::{
pub use self::container::{
Container, ContainerLayout, OverlayLayout, ManualLayout, VerticalLayout, GridLayout, AdaptiveGridLayout,
ColumnsLayout, MosaicLayout, ReverseMosaicLayout,
- SectionContainer, Header, ContentBg, ParametersBg, List, ListColumn, ListRow, ColumnWidth,
- ScrollBox, MenuBar, Spreadsheet, Breadcrumb, Plate,
- Switcher, Layer, Page, Backplate, Paginator, ScrollBar, TreeList, TreeElement, ControlPanel
+ Header, ContentBg, ParametersBg,
+ ScrollBox, MenuBar, Spreadsheet, Breadcrumb,
+ Switcher, Layer, Page, Paginator, ScrollBar, TreeList, TreeElement
};
pub use self::display::{
- TextLabel, Label, SectionHeader, StyledLabel, LabelPrim, TextItem, Svg, UsageBar,
+ TextLabel, Label, StyledLabel, LabelPrim, TextItem, Svg, UsageBar,
LayoutPreview, FontPreview, InfoBox, StatusDot, InteractiveListItem,
GraphNode, Graph, Float3, ProgressBar, StatusBar, Splitter, Node, Separator,
DotStatus, PreviewLayoutMode, Sidebar, Panel, PreviewState, ImagePreviewData, serialize_widgets,
diff --git a/src/widget/model.rs b/src/widget/model.rs
index e5b4f37..5150e62 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -841,15 +841,6 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
out
}
- /// Own text with font + bounds: [`Paint::text_bounds`] when the widget provides it, else a
- /// replica of the deleted `Element` default's scroll-ancestor viewport clipping, with
- /// `widget_font` on every label (the legacy tuple convention). pub(crate) so legacy
- /// composites (TreeList, List) can read their concrete Adapted fields' labels now that
- /// the trait getters are gone.
- pub(crate) fn own_labels_with_font_and_bounds(&self, ctx: &UiContext) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
- self.own_labels_with_prim_font(ctx, Paint::widget_font(&self.inner))
- }
-
/// The paint-walk view of `own_labels_with_font_and_bounds`: prim-derived text carries the
/// widget's content font ([`Paint::text_font`]); the detached base label keeps
/// `widget_font` either way (via `own_labels_with_prim_font`).
@@ -897,12 +888,6 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
let view_max = scroll_box.viewport_y + scroll_box.viewport_h - 4.0;
scroll_box_bounds = Some([sb_x, view_min, sb_x + sb_w, view_max]);
break;
- } else if let Some(list) = parent.as_any().downcast_ref::<crate::widget::List>() {
- let (sb_x, _, sb_w, _) = parent.rect();
- let view_min = list.scroll_box.viewport_y + 4.0;
- let view_max = list.scroll_box.viewport_y + list.scroll_box.viewport_h - 4.0;
- scroll_box_bounds = Some([sb_x, view_min, sb_x + sb_w, view_max]);
- break;
}
curr = parent.parent(ctx);
}