GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Refactor ScrollingList to List and fix window decoration blur and styling
src/widget/container/backplate.rs | 5 +--
src/widget/container/breadcrumb.rs | 74 +++++++++++++++++++++++++---------
src/widget/container/mod.rs | 2 +-
src/widget/container/scrolling_list.rs | 14 +++----
src/widget/mod.rs | 2 +-
5 files changed, 65 insertions(+), 32 deletions(-)
diff --git a/src/widget/container/backplate.rs b/src/widget/container/backplate.rs
index 0ab957d..0d26a25 100644
--- a/src/widget/container/backplate.rs
+++ b/src/widget/container/backplate.rs
@@ -171,10 +171,7 @@ impl Element for Backplate {
let bg_color = self.color();
let (wx, wy, ww, wh) = self.rect();
- let (r1, r2, r3, r4) = self.rounded_corners();
- let has_rounded = r1 || r2 || r3 || r4;
-
- if bg_color[3] != 0.0 && !has_rounded {
+ if bg_color[3] != 0.0 {
quads.push((wx, wy, ww, wh, bg_color));
}
for &child_ptr in &self.children {
diff --git a/src/widget/container/breadcrumb.rs b/src/widget/container/breadcrumb.rs
index 3476180..05caff9 100644
--- a/src/widget/container/breadcrumb.rs
+++ b/src/widget/container/breadcrumb.rs
@@ -4,7 +4,7 @@ use crate::widget::display::TextLabel;
#[derive(Debug, Clone)]
pub struct Breadcrumb {
- x: f32, y: f32, w: f32, h: f32,
+ pub base: Widget,
hovered: bool,
path: Vec<String>,
hovered_seg: Option<usize>,
@@ -18,7 +18,7 @@ impl Breadcrumb {
}
pub fn new() -> Self {
- Self { x: 0.0, y: 0.0, w: 0.0, h: 0.0, hovered: false,
+ Self { base: Widget::new(), hovered: false,
path: Vec::new(), hovered_seg: None, clicked_seg: None, network_opacity: 1.0 }
}
@@ -31,7 +31,7 @@ impl Breadcrumb {
}
fn seg_at(&self, px: f32) -> Option<usize> {
- let mut cx = self.x + BREADCRUMB_PADDING;
+ let mut cx = self.base.x + BREADCRUMB_PADDING;
let segs = self.virtual_segs();
for (i, seg) in segs.iter().enumerate() {
let w = seg.len() as f32 * 7.5;
@@ -45,20 +45,10 @@ impl Breadcrumb {
}
impl Element for Breadcrumb {
- 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)
- }
+ crate::impl_widget_base!(Breadcrumb);
fn rounded_corners(&self) -> (bool, bool, bool, bool) { (true, true, false, false) }
- fn rect(&self) -> (f32, f32, f32, f32) { (self.x, self.y, self.w, self.h) }
- fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) { self.x = x; self.y = y; self.w = w; self.h = h; }
-
fn color(&self) -> [f32; 4] {
let c = crate::color::breadcrumb_bg_color();
[c[0], c[1], c[2], self.network_opacity]
@@ -103,30 +93,32 @@ impl Element for Breadcrumb {
fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
let mut quads = Vec::new();
- quads.push((self.x, self.y, self.w, self.h, self.color()));
+ let (x, y, w, h) = self.rect();
+ quads.push((x, y, w, h, self.color()));
if let Some(i) = self.hovered_seg {
- let mut cx = self.x + BREADCRUMB_PADDING;
+ let mut cx = x + BREADCRUMB_PADDING;
let segs = self.virtual_segs();
for j in 0..i {
let w = segs[j].len() as f32 * 7.5;
cx += w + SEGMENT_GAP;
}
let w = segs[i].len() as f32 * 7.5;
- quads.push((cx, self.y, w, self.h, [1.0, 1.0, 1.0, 0.06]));
+ quads.push((cx, y, w, h, [1.0, 1.0, 1.0, 0.06]));
}
quads
}
fn text_labels(&self) -> Vec<TextLabel> {
let mut labels = Vec::new();
- let mut cx = self.x + BREADCRUMB_PADDING;
+ let (x, y, _, _) = self.rect();
+ let mut cx = x + BREADCRUMB_PADDING;
let segs = self.virtual_segs();
let len = segs.len();
for (i, seg) in segs.iter().enumerate() {
labels.push(TextLabel {
text: seg.clone(),
x: cx,
- y: self.y + 6.0,
+ y: y + 6.0,
font_size: 12.0,
color: if i == len - 1 { [0xcc, 0xcc, 0xd4] } else { [0x88, 0x88, 0x99] },
});
@@ -144,3 +136,47 @@ impl PathController for Breadcrumb {
self.clicked_seg.take()
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::context::UiContext;
+ use crate::widget::Element;
+
+ #[test]
+ fn test_breadcrumb_clicks() {
+ let mut breadcrumb = Breadcrumb::new();
+ breadcrumb.set_path(&["home".to_string(), "lsgalante".to_string()]);
+ // Set coordinates: x=10.0, y=20.0, w=300.0, h=24.0
+ breadcrumb.set_rect(10.0, 20.0, 300.0, 24.0);
+
+ let ctx = UiContext::new();
+
+ // Let's test hit_test
+ assert!(breadcrumb.hit_test(15.0, 25.0, &ctx));
+
+ // Let's test seg_at:
+ // x + padding = 10.0 + 8.0 = 18.0
+ // Segment 0 ("/"): length 1. width = 1 * 7.5 = 7.5. range: [18.0, 25.5)
+ // GAP = 4.0. next = 25.5 + 4.0 = 29.5
+ // Segment 1 ("home/"): length 5. width = 5 * 7.5 = 37.5. range: [29.5, 67.0)
+ // GAP = 4.0. next = 67.0 + 4.0 = 71.0
+ // Segment 2 ("lsgalante/"): length 10. width = 10 * 7.5 = 75.0. range: [71.0, 146.0)
+
+ // Click in segment 0 (/)
+ let mut ui_ctx = UiContext::new();
+ assert!(breadcrumb.mouse_input(crate::widget::MouseButton::Left, crate::widget::ElementState::Pressed, 20.0, 25.0, &mut ui_ctx));
+ assert_eq!(breadcrumb.path_click(), Some(0));
+
+ // Click in segment 1 (home/)
+ assert!(breadcrumb.mouse_input(crate::widget::MouseButton::Left, crate::widget::ElementState::Pressed, 50.0, 25.0, &mut ui_ctx));
+ assert_eq!(breadcrumb.path_click(), Some(1));
+
+ // Click in segment 2 (lsgalante/)
+ // Wait, path.len() is 2. i = 2. 2 < 2 is false.
+ // So clicking the last segment should return false.
+ assert!(!breadcrumb.mouse_input(crate::widget::MouseButton::Left, crate::widget::ElementState::Pressed, 100.0, 25.0, &mut ui_ctx));
+ assert_eq!(breadcrumb.path_click(), None);
+ }
+}
+
diff --git a/src/widget/container/mod.rs b/src/widget/container/mod.rs
index 48d24b1..e9bb372 100644
--- a/src/widget/container/mod.rs
+++ b/src/widget/container/mod.rs
@@ -30,7 +30,7 @@ pub use menu::{Menu, MenuBar};
pub use breadcrumb::Breadcrumb;
pub use spreadsheet::Spreadsheet;
pub use scroll_box::ScrollBox;
-pub use scrolling_list::{ScrollingList, FontSelector};
+pub use scrolling_list::{List, FontSelector};
pub use plate::Plate;
pub use switcher::Switcher;
pub use layer::Layer;
diff --git a/src/widget/container/scrolling_list.rs b/src/widget/container/scrolling_list.rs
index 942486f..1b57743 100644
--- a/src/widget/container/scrolling_list.rs
+++ b/src/widget/container/scrolling_list.rs
@@ -5,13 +5,13 @@ pub use crate::widget::input::font_selector::FontSelector;
// Generic text item layout wrapper
#[derive(Debug, Clone)]
-pub struct ScrollingList {
+pub struct List {
pub scroll_box: ScrollBox,
pub item_height: f32,
pub item_gap: f32,
}
-impl ScrollingList {
+impl List {
pub fn new(item_height: f32, item_gap: f32) -> Self {
Self {
scroll_box: ScrollBox::new(),
@@ -41,13 +41,13 @@ impl ScrollingList {
}
}
-impl Default for ScrollingList {
+impl Default for List {
fn default() -> Self {
Self::new(24.0, 4.0)
}
}
-impl Element for ScrollingList {
+impl Element for List {
fn rect(&self) -> (f32, f32, f32, f32) {
self.scroll_box.rect()
}
@@ -179,7 +179,7 @@ impl Element for ScrollingList {
fn as_scroll_controller_mut(&mut self) -> Option<&mut dyn ScrollController> { Some(self) }
}
-impl ScrollController for ScrollingList {
+impl ScrollController for List {
fn update_bounds(&mut self, count: usize, viewport_y: f32, viewport_h: f32) {
self.update_bounds(count, viewport_y, viewport_h);
}
@@ -189,5 +189,5 @@ impl ScrollController for ScrollingList {
}
}
-unsafe impl Send for ScrollingList {}
-unsafe impl Sync for ScrollingList {}
+unsafe impl Send for List {}
+unsafe impl Sync for List {}
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 08ba79b..af691e0 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -678,7 +678,7 @@ pub use self::input::{
};
pub use self::container::{
Container, ContainerLayout, OverlayLayout, VerticalLayout, GridLayout, AdaptiveGridLayout,
- SectionContainer, Header, ContentBg, ViewportBg, ParametersBg, ScrollingList,
+ SectionContainer, Header, ContentBg, ViewportBg, ParametersBg, List,
ScrollBox, Menu, MenuBar, Spreadsheet, Breadcrumb, Plate,
Switcher, Layer, Page, Backplate, Paginator, ScrollBar, TreeList, TreeElement
};