diff --git a/CHANGELOG.md b/CHANGELOG.md index b49f26c..46feeb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -203,6 +203,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [plotters][plotters] crate. `Graphics::as_plot_area()` is a new function that returns a `plotters::DrawingArea` that can be used to draw any plot that the `plotters` crate supports. +- `Delimiter` is a new widget that is similar to html's `hr` tag. [plotters]: https://github.com/plotters-rs/plotters diff --git a/src/widgets.rs b/src/widgets.rs index 6a3e067..5121144 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -9,6 +9,7 @@ pub mod color; pub mod container; mod custom; mod data; +pub mod delimiter; pub mod disclose; mod expand; pub mod grid; @@ -40,6 +41,7 @@ pub use self::collapse::Collapse; pub use self::container::Container; pub use self::custom::Custom; pub use self::data::Data; +pub use self::delimiter::Delimiter; pub use self::disclose::Disclose; pub use self::expand::Expand; pub use self::grid::Grid; diff --git a/src/widgets/delimiter.rs b/src/widgets/delimiter.rs new file mode 100644 index 0000000..090225e --- /dev/null +++ b/src/widgets/delimiter.rs @@ -0,0 +1,114 @@ +//! A visual delimiter widget. + +use figures::units::{Lp, UPx}; +use figures::{Point, ScreenScale, Size}; +use kludgine::shapes::{PathBuilder, StrokeOptions}; +use kludgine::Color; + +use crate::context::{GraphicsContext, LayoutContext}; +use crate::styles::components::TextColor; +use crate::styles::{Dimension, FlexibleDimension}; +use crate::value::{IntoValue, Value}; +use crate::widget::Widget; +use crate::ConstraintLimit; + +#[derive(Debug)] +enum Orientation { + Horizontal, + Vertical, +} + +/// A visual delimiter that can be horizontal or vertical. +/// +/// This is similar to html's `
` tag. +#[derive(Debug)] +pub struct Delimiter { + size: Value, + orientation: Orientation, +} + +impl Default for Delimiter { + fn default() -> Self { + Self::horizontal() + } +} + +impl Delimiter { + fn new(orientation: Orientation) -> Self { + Self { + size: Value::Constant(FlexibleDimension::Auto), + orientation, + } + } + + /// Returns a horizontal delimiter. + #[must_use] + pub fn horizontal() -> Self { + Self::new(Orientation::Horizontal) + } + + /// Returns a vertical delimiter. + #[must_use] + pub fn vertical() -> Self { + Self::new(Orientation::Vertical) + } + + /// Sets the size of the delimiter. + /// + /// If auto, a theme-derived size is used. + #[must_use] + pub fn size(mut self, size: impl IntoValue) -> Self { + self.size = size.into_value(); + self + } + + fn get_size(&self, context: &mut GraphicsContext<'_, '_, '_, '_>) -> Dimension { + match self.size.get_tracking_invalidate(context) { + FlexibleDimension::Auto => context.get(&DelimiterSize), + FlexibleDimension::Dimension(dimension) => dimension, + } + } +} + +impl Widget for Delimiter { + fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_>) { + let line_width = self.get_size(context).into_upx(context.gfx.scale()); + let half_line = line_width / 2; + let end = dbg!(match self.orientation { + Orientation::Horizontal => Point::new(context.gfx.size().width - half_line, half_line), + Orientation::Vertical => Point::new(half_line, context.gfx.size().height - half_line), + }); + let color = context.get(&DelimiterColor); + context.gfx.draw_shape( + &PathBuilder::new(Point::squared(half_line)) + .line_to(end) + .build() + .stroke(StrokeOptions { + color, + line_width, + ..StrokeOptions::default() + }), + ); + } + + fn layout( + &mut self, + available_space: Size, + context: &mut LayoutContext<'_, '_, '_, '_>, + ) -> Size { + let size = dbg!(self.get_size(context).into_upx(context.gfx.scale())); + match self.orientation { + Orientation::Horizontal => Size::new(dbg!(available_space.width).max(), size), + Orientation::Vertical => Size::new(size, available_space.height.max()), + } + } +} + +define_components! { + Delimiter { + /// The [`Dimension`] to use as the size of a [`Delimiter`] widget. + DelimiterSize(Dimension, "size", Dimension::Lp(Lp::new(2))) + /// The [`Color`] draw a [`Delimiter`] widget using. + DelimiterColor(Color, "color", @TextColor) + } +}