diff --git a/crates/yakui-widgets/src/shorthand.rs b/crates/yakui-widgets/src/shorthand.rs index fc9a9890..a2a8d6ac 100644 --- a/crates/yakui-widgets/src/shorthand.rs +++ b/crates/yakui-widgets/src/shorthand.rs @@ -12,11 +12,11 @@ use yakui_core::{Alignment, ManagedTextureId, Response, TextureId}; use crate::widgets::{ Align, AlignResponse, Button, ButtonResponse, Canvas, CanvasResponse, Checkbox, CheckboxResponse, Circle, CircleResponse, ColoredBox, ColoredBoxResponse, ConstrainedBox, - ConstrainedBoxResponse, CountGrid, Draggable, DraggableResponse, Flexible, FlexibleResponse, - Image, ImageResponse, List, ListResponse, MaxWidth, MaxWidthResponse, NineSlice, Offset, - OffsetResponse, Opaque, OpaqueResponse, Pad, PadResponse, Reflow, ReflowResponse, Scrollable, - ScrollableResponse, Slider, SliderResponse, State, StateResponse, Text, TextBox, - TextBoxResponse, TextResponse, + ConstrainedBoxResponse, CountGrid, Divider, DividerResponse, Draggable, DraggableResponse, + Flexible, FlexibleResponse, Image, ImageResponse, List, ListResponse, MaxWidth, + MaxWidthResponse, NineSlice, Offset, OffsetResponse, Opaque, OpaqueResponse, Pad, PadResponse, + Reflow, ReflowResponse, Scrollable, ScrollableResponse, Slider, SliderResponse, State, + StateResponse, Text, TextBox, TextBoxResponse, TextResponse, }; /// See [List]. @@ -147,6 +147,11 @@ pub fn nineslice( NineSlice::new(texture, margins, scale).show(children) } +/// See [Divider]. +pub fn divider(color: Color, height: f32, thickness: f32) -> Response { + Divider::new(color, height, thickness).show() +} + /// See [Scrollable]. pub fn scroll_vertical(children: impl FnOnce()) -> Response { Scrollable::vertical().show(children) diff --git a/crates/yakui-widgets/src/widgets/divider.rs b/crates/yakui-widgets/src/widgets/divider.rs new file mode 100644 index 00000000..2c3a4587 --- /dev/null +++ b/crates/yakui-widgets/src/widgets/divider.rs @@ -0,0 +1,95 @@ +use yakui_core::geometry::{Color, Constraints, Rect, Vec2}; +use yakui_core::paint::PaintRect; +use yakui_core::widget::{LayoutContext, PaintContext, Widget}; +use yakui_core::Response; + +/// A horizontal divider line. Will take up the whole width of the parent. +/// +/// Responds with [DividerResponse]. +#[derive(Debug)] +#[non_exhaustive] +pub struct Divider { + /// The color of the divider. + pub color: Color, + /// The thickness of the divider. + pub thickness: f32, + /// The height of the divider. + /// How much vertical space it takes up. + pub height: f32, + /// The indent of the divider from the left. + pub indent: f32, + /// The indent of the divider from the right. + pub end_indent: f32, +} + +impl Divider { + pub fn new(color: Color, height: f32, thickness: f32) -> Self { + Self { + color, + thickness, + height, + indent: 0.0, + end_indent: 0.0, + } + } + + pub fn show(self) -> Response { + crate::util::widget::(self) + } +} + +#[derive(Debug)] +pub struct DividerWidget { + props: Divider, +} + +pub type DividerResponse = (); + +impl Widget for DividerWidget { + type Props<'a> = Divider; + type Response = DividerResponse; + + fn new() -> Self { + Self { + props: Divider::new(Color::WHITE, 0.0, 0.0), + } + } + + fn update(&mut self, props: Self::Props<'_>) -> Self::Response { + self.props = props; + } + + fn layout(&self, _ctx: LayoutContext<'_>, input: Constraints) -> Vec2 { + Vec2::new( + input.min.x, + self.props.height.clamp(input.min.y, input.max.y), + ) + } + + fn paint(&self, ctx: PaintContext<'_>) { + // We get the parent's width during the paint phase because + // using constraints.max.x is often useless as it is often infinite. + + let id = ctx.dom.current(); + let Some(parent) = ctx.dom.get(id).unwrap().parent else { + return; + }; + let line_width = ctx.layout.get(parent).unwrap().rect.size().x; + + let outer_rect = ctx.layout.get(id).unwrap().rect; + + let line_pos = outer_rect.pos() + + Vec2::new( + self.props.indent, + (outer_rect.size().y - self.props.thickness) / 2.0, + ); + let line_size = Vec2::new( + line_width - self.props.indent - self.props.end_indent, + self.props.thickness, + ); + + let mut line_rect = PaintRect::new(Rect::from_pos_size(line_pos, line_size)); + line_rect.color = self.props.color; + line_rect.add(ctx.paint); + } +} diff --git a/crates/yakui-widgets/src/widgets/mod.rs b/crates/yakui-widgets/src/widgets/mod.rs index 5e6e3f2a..39314031 100644 --- a/crates/yakui-widgets/src/widgets/mod.rs +++ b/crates/yakui-widgets/src/widgets/mod.rs @@ -7,6 +7,7 @@ mod colored_box; mod constrained_box; mod count_grid; mod cutout; +mod divider; mod draggable; mod flexible; mod image; @@ -39,6 +40,7 @@ pub use self::colored_box::*; pub use self::constrained_box::*; pub use self::count_grid::*; pub use self::cutout::*; +pub use self::divider::*; pub use self::draggable::*; pub use self::flexible::*; pub use self::image::*; diff --git a/crates/yakui/examples/leaderboard.rs b/crates/yakui/examples/leaderboard.rs index a5f02ab7..5b13735e 100644 --- a/crates/yakui/examples/leaderboard.rs +++ b/crates/yakui/examples/leaderboard.rs @@ -35,20 +35,21 @@ pub fn run() { stat_column(|| { label("Name"); for datum in &data { + divider(); label(datum.name); } }); - stat_column(|| { label("Score"); for datum in &data { + divider(); label(format!("{}", datum.score)); } }); - stat_column(|| { label("Money"); for datum in &data { + divider(); label(format!("{}", datum.currency)); } }); @@ -58,6 +59,10 @@ pub fn run() { }); } +fn divider() { + yakui_widgets::divider(Color::GRAY, 1.0, 1.0); +} + fn stat_column(children: impl FnOnce()) { let mut col = List::column(); col.main_axis_size = MainAxisSize::Min;