GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
refactor(widget)!: DELETE ScrollBar (moved into settings); ScrollBox demoted off Element (Phase 6av)
ScrollBar's only consumer is cce-system-settings' page scrollbar (the
dissolved Page subtree's one surviving widget) — the file moves there
verbatim (its Page-downcast write-back died with Page in 6au) and the
cce-ui type is deleted.
ScrollBox is never registered into the ctx tree by either consumer
(TreeList and cce-test-interface's panel copy drive it entirely through
concrete calls), so its Element impl was pure dyn-dispatch ballast:
demoted to a plain struct. The former Element entry points the
consumers forward stay as inherent methods with default-derived
behavior preserved exactly (cursor_moved cover-check, tick/is_dragging
constant-false parity, hit_test over the bare rect). The legacy focus
claim on scrollbar clicks becomes focus::clear_focus() — its only
observable effect was unfocusing the previous holder (nothing ever
queried focus ON the scroll box, and its own unfocus was a no-op).
The scroll-ancestor text clamps in painter/model fold to None: with
ScrollBox off the trait, no tree parent can ever be one (they never
matched at runtime anyway — ScrollBox was never a registered parent).
TreeList drops its no-op scroll_box.prepare_text call.
169 tests pass (the two Element-focus/propagation-based ScrollBox tests
rewritten against the hover gate). A/B on the live compositor:
data-editor AE=0 with live wheel-scroll + scrollbar track jump-scroll
verified on a 100-key tree; settings processes page diff = live process
rows only; test-interface sub-threshold (launch animation).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk
src/scene/painter.rs | 18 +---
src/widget/container/mod.rs | 2 -
src/widget/container/scroll_bar.rs | 195 -------------------------------------
src/widget/container/scroll_box.rs | 130 +++++++++++++++----------
src/widget/container/treelist.rs | 1 -
src/widget/mod.rs | 2 +-
src/widget/model.rs | 34 +------
7 files changed, 88 insertions(+), 294 deletions(-)
diff --git a/src/scene/painter.rs b/src/scene/painter.rs
index 6897a55..ced2d4a 100644
--- a/src/scene/painter.rs
+++ b/src/scene/painter.rs
@@ -95,20 +95,10 @@ pub fn paint_legacy_leaf(
}
}
-/// The scroll-ancestor text clamp the deleted default fonted getter applied: the nearest
-/// ScrollBox/List ancestor's viewport, if any.
-pub fn scroll_ancestor_text_bounds(w: &dyn Element, ui: &UiContext) -> Option<[f32; 4]> {
- let mut curr = w.parent(ui);
- 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;
- return Some([sb_x, view_min, sb_x + sb_w, view_max]);
- }
- curr = parent.parent(ui);
- }
+/// The scroll-ancestor text clamp the deleted default fonted getter applied. Always `None`
+/// since Phase 6av: ScrollBox (the last scroll ancestor type) was demoted to a plain
+/// embedded struct — it never appeared as a tree parent, so the walk never matched.
+pub fn scroll_ancestor_text_bounds(_w: &dyn Element, _ui: &UiContext) -> Option<[f32; 4]> {
None
}
diff --git a/src/widget/container/mod.rs b/src/widget/container/mod.rs
index e1014c4..46d80a4 100644
--- a/src/widget/container/mod.rs
+++ b/src/widget/container/mod.rs
@@ -9,7 +9,6 @@ pub mod spreadsheet;
pub mod scroll_box;
pub mod switcher;
pub mod paginator;
-pub mod scroll_bar;
pub mod treelist;
pub mod vbox;
pub mod hbox;
@@ -25,7 +24,6 @@ pub use spreadsheet::Spreadsheet;
pub use scroll_box::ScrollBox;
pub use switcher::Switcher;
pub use paginator::Paginator;
-pub use scroll_bar::ScrollBar;
pub use treelist::{TreeList, TreeElement};
pub use vbox::VBox;
pub use hbox::HBox;
diff --git a/src/widget/container/scroll_bar.rs b/src/widget/container/scroll_bar.rs
deleted file mode 100644
index 3df499d..0000000
--- a/src/widget/container/scroll_bar.rs
+++ /dev/null
@@ -1,195 +0,0 @@
-use crate::widget::*;
-use crate::context::UiContext;
-
-pub struct ScrollBar {
- pub base: Widget,
- pub scroll_y: f32,
- pub content_h: f32,
- pub viewport_h: f32,
- pub dragging: bool,
- pub parent: Option<*mut (dyn Element + 'static)>,
- pub children: Vec<*mut (dyn Element + 'static)>,
-}
-
-impl std::fmt::Debug for ScrollBar {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("ScrollBar")
- .field("base", &self.base)
- .field("scroll_y", &self.scroll_y)
- .field("content_h", &self.content_h)
- .field("viewport_h", &self.viewport_h)
- .field("dragging", &self.dragging)
- .finish()
- }
-}
-
-impl Clone for ScrollBar {
- fn clone(&self) -> Self {
- Self {
- base: self.base.clone(),
- scroll_y: self.scroll_y,
- content_h: self.content_h,
- viewport_h: self.viewport_h,
- dragging: self.dragging,
- parent: self.parent,
- children: self.children.clone(),
- }
- }
-}
-
-impl ScrollBar {
- pub fn new() -> Self {
- let mut base = Widget::new();
- base.w = 6.0;
- Self {
- base,
- scroll_y: 0.0,
- content_h: 0.0,
- viewport_h: 0.0,
- dragging: false,
- parent: None,
- children: Vec::new(),
- }
- }
-
- pub fn update(&mut self, scroll_y: f32, content_h: f32, viewport_h: f32) {
- self.scroll_y = scroll_y;
- self.content_h = content_h;
- self.viewport_h = viewport_h;
- }
-
- pub fn get_thumb_rect(&self) -> Option<(f32, f32, f32, f32)> {
- if self.content_h <= self.viewport_h || self.viewport_h <= 0.0 || self.base.h <= 0.0 {
- return None;
- }
- let sb_x = self.base.x;
- let sb_w = self.base.w;
- let sb_track_h = self.base.h;
- let sb_track_y = self.base.y;
-
- let visible_ratio = self.viewport_h / self.content_h;
- let thumb_h = if sb_track_h <= 20.0 {
- sb_track_h
- } else {
- (sb_track_h * visible_ratio).clamp(20.0, sb_track_h)
- };
- let max_scroll = (self.content_h - self.viewport_h).max(0.0);
- let scroll_ratio = if max_scroll > 0.0 { self.scroll_y / max_scroll } else { 0.0 };
- let thumb_y = sb_track_y + scroll_ratio * (sb_track_h - thumb_h);
-
- Some((sb_x, thumb_y, sb_w, thumb_h))
- }
-}
-
-impl Element for ScrollBar {
- crate::impl_widget_base!(ScrollBar);
-
- fn color(&self) -> [f32; 4] {
- [0.0, 0.0, 0.0, 0.0]
- }
-
- 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 hit_margin = 6.0;
- px >= self.base.x - hit_margin && px <= self.base.x + self.base.w + hit_margin && py >= self.base.y && py <= self.base.y + self.base.h
- }
-
- fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- let mut changed = false;
- let is_hit = self.hit_test(px, py, ctx);
- if self.base.hovered != is_hit {
- self.base.hovered = is_hit;
- changed = true;
- }
-
- if self.dragging {
- if let Some((_, _, _, thumb_h)) = self.get_thumb_rect() {
- let sb_track_y = self.base.y;
- let sb_track_h = self.base.h;
- let track_scroll_range = sb_track_h - thumb_h;
- if track_scroll_range > 0.0 {
- let mouse_y_in_track = (py - sb_track_y).clamp(0.0, sb_track_h);
- let scroll_ratio = (mouse_y_in_track - thumb_h / 2.0) / track_scroll_range;
- let max_scroll = (self.content_h - self.viewport_h).max(0.0);
- let new_scroll_y = (scroll_ratio.clamp(0.0, 1.0) * max_scroll).clamp(0.0, max_scroll);
- if (self.scroll_y - new_scroll_y).abs() > 0.01 {
- self.scroll_y = new_scroll_y;
- changed = true;
- }
- }
- }
- }
- changed
- }
-
- fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
- if button == MouseButton::Left {
- match state {
- ElementState::Pressed => {
- if self.hit_test(px, py, ctx) {
- self.dragging = true;
- self.on_cursor_moved(px, py, ctx);
- return true;
- }
- }
- ElementState::Released => {
- if self.dragging {
- self.dragging = false;
- return true;
- }
- }
- }
- }
- false
- }
-
- fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
- let mut quads = Vec::new();
- if self.content_h > self.viewport_h && self.base.h > 0.0 {
- quads.push((self.base.x, self.base.y, self.base.w, self.base.h, [0.15, 0.15, 0.20, 0.3]));
-
- if let Some((sb_x, thumb_y, sb_w, thumb_h)) = self.get_thumb_rect() {
- let thumb_color = if self.dragging {
- [0.70, 0.70, 0.75, 0.6]
- } else if self.base.hovered {
- [0.65, 0.65, 0.70, 0.5]
- } else {
- [0.60, 0.60, 0.65, 0.4]
- };
- quads.push((sb_x, thumb_y, sb_w, thumb_h, thumb_color));
- }
- }
- quads
- }
-
- 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()
- }
-
- fn add_child(&mut self, child: *mut (dyn Element + 'static), _ctx: &mut UiContext) {
- self.children.push(child);
- }
-
- fn clear_children(&mut self, _ctx: &mut UiContext) {
- self.children.clear();
- }
-}
-
-impl Drop for ScrollBar {
- fn drop(&mut self) {
- clear_widget_references(self);
- }
-}
-
-unsafe impl Send for ScrollBar {}
-unsafe impl Sync for ScrollBar {}
diff --git a/src/widget/container/scroll_box.rs b/src/widget/container/scroll_box.rs
index 19f7151..9379d95 100644
--- a/src/widget/container/scroll_box.rs
+++ b/src/widget/container/scroll_box.rs
@@ -1,3 +1,10 @@
+//! Embedded scroll-math + scrollbar-chrome helper (Phase 6av: DEMOTED from `Element` to a
+//! plain struct). Never registered into the ctx tree by either consumer — TreeList and
+//! cce-test-interface's panel copy drive it entirely through concrete calls — so the
+//! `Element` impl was pure dyn-dispatch ballast. The former Element-default entry points the
+//! consumers forward (`cursor_moved`, `tick`, drag hooks, `is_dragging`) are kept as
+//! inherent methods with the exact default-derived behavior.
+
use crate::widget::*;
#[derive(Debug, Clone)]
@@ -11,7 +18,6 @@ pub struct ScrollBox {
viewport_offset_h: f32,
pub show_border: bool,
pub show_background: bool,
- pub parent: Option<*mut (dyn Element + 'static)>,
pub children: Vec<*mut (dyn Element + 'static)>,
pub scrollbar_dragging: bool,
pub drag_offset_y: f32,
@@ -29,7 +35,6 @@ impl ScrollBox {
viewport_offset_h: 0.0,
show_border: true,
show_background: true,
- parent: None,
children: Vec::new(),
scrollbar_dragging: false,
drag_offset_y: 0.0,
@@ -69,12 +74,8 @@ impl ScrollBox {
}
}
-impl Element for ScrollBox {
- crate::impl_widget_base!(ScrollBox);
- fn is_scrollable(&self) -> bool { true }
- fn blocks_backplate_drag(&self) -> bool { true }
-
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
+impl ScrollBox {
+ pub 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;
@@ -82,22 +83,33 @@ impl Element for ScrollBox {
self.viewport_y = y + self.viewport_offset_y;
self.viewport_h = h + self.viewport_offset_h;
}
- fn color(&self) -> [f32; 4] { crate::color::list_bg_color() }
- fn corner_radius(&self) -> f32 {
- crate::layout::list_corner_radius()
+ /// The legacy `Element` default hit test over the base rect (ScrollBox never carried a
+ /// label or row expansion, so those branches are folded away).
+ 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.base.x, self.base.y, self.base.w, self.base.h);
+ if w <= 0.0 || h <= 0.0 {
+ return false;
+ }
+ px >= x && px <= x + w && py >= y && py <= y + h
}
- fn focus(&mut self) {
- focus::set_focused(self);
+ /// The legacy focus claim on scrollbar/list clicks: its only observable effect was
+ /// unfocusing the previously focused widget (nothing ever queried focus ON the scroll
+ /// box through the thread-local, and its own `unfocus` was a no-op) — so just release
+ /// the current holder instead of storing a pointer to a non-Element.
+ fn claim_focus(&self) {
+ focus::clear_focus();
}
- fn unfocus(&mut self) {}
- fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
+ pub fn mouse_input(&mut self, button: MouseButton, state: ElementState, px: f32, py: f32, ctx: &mut UiContext) -> bool {
if button == MouseButton::Left {
if state == ElementState::Pressed {
if self.hit_test_scrollbar(px, py) {
- self.focus();
+ self.claim_focus();
self.scrollbar_dragging = true;
let sb_track_h = self.viewport_h - 8.0;
@@ -131,7 +143,7 @@ impl Element for ScrollBox {
self.scrollbar_dragging = false;
}
if self.hit_test(px, py, ctx) {
- self.focus();
+ self.claim_focus();
}
} else if state == ElementState::Released {
self.scrollbar_dragging = false;
@@ -140,13 +152,19 @@ impl Element for ScrollBox {
false
}
- fn draggable(&self) -> bool {
+ pub fn draggable(&self) -> bool {
self.scrollbar_dragging
}
- fn drag_begin(&mut self, _px: f32, _py: f32) {}
+ /// Legacy `Element` default parity: ScrollBox never overrode `is_dragging` — TreeList
+ /// forwards it and always got `false`.
+ pub fn is_dragging(&self) -> bool {
+ false
+ }
+
+ pub fn drag_begin(&mut self, _px: f32, _py: f32) {}
- fn drag_update(&mut self, _px: f32, py: f32) -> bool {
+ pub fn drag_update(&mut self, _px: f32, py: f32) -> bool {
if !self.scrollbar_dragging {
return false;
}
@@ -172,11 +190,26 @@ impl Element for ScrollBox {
(self.scroll_y - old_scroll).abs() > 0.01
}
- fn drag_end(&mut self) {
+ pub fn drag_end(&mut self) {
self.scrollbar_dragging = false;
}
- fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
+ /// The legacy `Element` default `cursor_moved` entry (cce-test-interface's panel copy
+ /// calls it): cover-check clears hover, otherwise falls into `on_cursor_moved`. The
+ /// MouseLeave dispatch the default performed was a no-op for ScrollBox.
+ pub fn cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
+ ctx.set_cursor_pos(px, py);
+ if ctx.is_coordinate_covered(self as *const Self as *const () as usize, px, py) {
+ let was = self.base.hovered;
+ if was {
+ self.base.hovered = false;
+ }
+ return was;
+ }
+ self.on_cursor_moved(px, py, ctx)
+ }
+
+ pub fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
let mut changed = false;
if self.scrollbar_dragging {
let sb_track_h = self.viewport_h - 8.0;
@@ -211,7 +244,12 @@ impl Element for ScrollBox {
changed
}
- fn mouse_wheel(&mut self, delta: &MouseScrollDelta, px: f32, py: f32, ctx: &mut UiContext) -> bool {
+ /// Legacy `Element` default parity (cce-test-interface's panel copy ticks it).
+ pub fn tick(&mut self, _dt: f32, _ctx: &mut UiContext) -> bool {
+ false
+ }
+
+ pub fn mouse_wheel(&mut self, delta: &MouseScrollDelta, px: f32, py: f32, ctx: &mut UiContext) -> bool {
if self.hit_test(px, py, ctx) {
let scroll_speed = 24.0;
let dy = match delta {
@@ -227,9 +265,9 @@ impl Element for ScrollBox {
}
}
- fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
+ pub fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
let mut quads = Vec::new();
-
+
// Background
if self.show_background {
quads.push((self.base.x, self.base.y, self.base.w, self.base.h, crate::color::list_bg_color()));
@@ -264,7 +302,7 @@ impl Element for ScrollBox {
quads
}
- fn keyboard_input(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
+ pub fn keyboard_input(&mut self, event: &KeyEvent, ctx: &mut UiContext) -> bool {
let self_addr = self as *const Self as *const () as usize;
let has_focus = ctx.is_focused_addr(self_addr) || {
let mut current = ctx.focused_widget;
@@ -339,21 +377,6 @@ impl Element for ScrollBox {
}
}
- 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() }
- fn add_child(&mut self, child: *mut (dyn Element + 'static), _ctx: &mut UiContext) { self.children.push(child); }
- fn clear_children(&mut self, _ctx: &mut UiContext) { self.children.clear(); }
-
- fn layout_ignore(&self) -> bool {
- true
- }
-}
-
-impl Drop for ScrollBox {
- fn drop(&mut self) {
- clear_widget_references(self);
- }
}
unsafe impl Send for ScrollBox {}
@@ -406,11 +429,12 @@ mod tests {
let mut sb = ScrollBox::new();
sb.set_rect(10.0, 20.0, 100.0, 100.0);
sb.update_bounds(300.0, 20.0, 100.0); // max_scroll = 200.0
-
+
let mut ctx = UiContext::new();
- // Focus the scroll box
- ctx.set_focused(&mut sb);
-
+ // Hover the scroll box (the focus path took a ctx-registered Element; as a plain
+ // struct the hovered branch is the live gate).
+ ctx.set_cursor_pos(50.0, 50.0);
+
// 1. ArrowDown key
let event_down = KeyEvent {
state: ElementState::Pressed,
@@ -473,16 +497,12 @@ mod tests {
}
#[test]
- fn test_scroll_box_non_focused_hovered_scrolling() {
+ fn test_scroll_box_keys_gated_on_hover() {
let mut sb = ScrollBox::new();
sb.set_rect(10.0, 20.0, 100.0, 100.0);
sb.update_bounds(300.0, 20.0, 100.0); // max_scroll = 200.0
let mut ctx = UiContext::new();
- ctx.register_widget(sb.base.id(), &mut sb);
-
- // Set cursor position over the scroll box
- ctx.set_cursor_pos(50.0, 50.0);
let event_down = KeyEvent {
state: ElementState::Pressed,
@@ -493,8 +513,14 @@ mod tests {
shift: false,
};
- let root_ptr = &mut sb as *mut ScrollBox as *mut (dyn Element + 'static);
- assert!(ctx.propagate_event(&Event::KeyInput(event_down), root_ptr));
+ // Cursor away from the box, nothing focused: keys are ignored.
+ ctx.set_cursor_pos(500.0, 500.0);
+ assert!(!sb.keyboard_input(&event_down, &mut ctx));
+ assert_eq!(sb.scroll_y, 0.0);
+
+ // Hovered: keys scroll.
+ ctx.set_cursor_pos(50.0, 50.0);
+ assert!(sb.keyboard_input(&event_down, &mut ctx));
assert_eq!(sb.scroll_y, 24.0);
}
}
diff --git a/src/widget/container/treelist.rs b/src/widget/container/treelist.rs
index 9b1fd4d..06d33bb 100644
--- a/src/widget/container/treelist.rs
+++ b/src/widget/container/treelist.rs
@@ -703,7 +703,6 @@ impl Paint for TreeList {
if self.add_key_popover_open {
self.add_key_popover_box.prepare_text(fs);
}
- self.scroll_box.prepare_text(fs);
if self.editing_key_idx.is_some() {
self.edit_box.prepare_text(fs);
}
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index d824809..6a81f9c 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -739,7 +739,7 @@ pub use self::container::{
ColumnsLayout, MosaicLayout, ReverseMosaicLayout,
Header, ContentBg, ParametersBg,
ScrollBox, MenuBar, Spreadsheet, Breadcrumb,
- Switcher, Paginator, ScrollBar, TreeList, TreeElement
+ Switcher, Paginator, TreeList, TreeElement
};
pub use self::display::{
TextLabel, Label, StyledLabel, LabelPrim, TextItem, Svg, UsageBar,
diff --git a/src/widget/model.rs b/src/widget/model.rs
index 5150e62..26b8506 100644
--- a/src/widget/model.rs
+++ b/src/widget/model.rs
@@ -848,7 +848,7 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
self.own_labels_with_prim_font(ctx, Paint::text_font(&self.inner))
}
- fn own_labels_with_prim_font(&self, ctx: &UiContext, prim_font: Option<String>) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
+ fn own_labels_with_prim_font(&self, _ctx: &UiContext, prim_font: Option<String>) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
let base_font = Paint::widget_font(&self.inner);
let mut fonted: Vec<(TextLabel, Option<String>)> = Vec::new();
if self.visible() {
@@ -874,36 +874,12 @@ impl<W: Layout + Paint + Input + 'static> Adapted<W> {
.collect();
}
- let mut labels = fonted
+ // The legacy scroll-ancestor clamp ended here: always a no-op since Phase 6av —
+ // ScrollBox (the last scroll ancestor type) never appeared as a tree parent.
+ fonted
.into_iter()
.map(|(l, font)| (l, font, None::<[f32; 4]>))
- .collect::<Vec<_>>();
- let mut curr = Element::parent(self, 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, _) = parent.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 {
- if let Some(ref mut b) = item.2 {
- b[0] = b[0].max(sb_bounds[0]);
- b[1] = b[1].max(sb_bounds[1]);
- b[2] = b[2].min(sb_bounds[2]);
- b[3] = b[3].min(sb_bounds[3]);
- } else {
- item.2 = Some(sb_bounds);
- }
- }
- }
- labels
+ .collect::<Vec<_>>()
}
/// The base-label text of a *detached*-label widget — a replica of the legacy default