// SPDX-License-Identifier: LGPL-2.1-only // Copyright (C) 2026 Liberux Labs, S. L. use crate::types::{ Color, Length, Rect }; use crate::render::Canvas; use super::Element; mod theme; /// A horizontal divider line. /// /// Renders a thin line across the full width of its layout rect, /// with vertical padding above and below. Use to break a column into /// visual sections — between settings groups, list categories or content /// blocks. The line takes the divider colour from the active theme by /// default; override with [`Self::color`] for custom palettes. /// /// ```rust,no_run /// # use ltk::{ column, separator, text, Element }; /// # #[ derive( Clone ) ] enum Msg {} /// # fn _ex() -> Element { /// // In view(): /// column() /// .push( text( "General" ) ) /// .push( separator() ) /// .push( text( "Network" ) ) /// .into() /// # } /// ``` pub struct Separator { /// Stroke colour. Defaults to the theme's `divider` palette slot. pub( crate ) color: Color, /// Line thickness. `None` follows the process [`crate::WidgetScaling`] /// mode; `Some( len )` pins it (including `Length::px( 0.0 )`). pub( crate ) thickness: Option, /// Vertical padding above and below the line, baked into /// `preferred_size` so the divider visually centres in the row a /// parent column allocates. `None` follows the /// [`crate::WidgetScaling`] mode; `Some( len )` pins it — pass /// `Length::px( 0.0 )` for a flush, padding-less divider. pub( crate ) pad_v: Option, } impl Default for Separator { fn default() -> Self { Self::new() } } impl Separator { /// Create a separator with the theme's default divider colour; the /// thickness follows the widget-scaling default unless overridden. pub fn new() -> Self { Self { color: theme::color(), thickness: None, pad_v: None, } } /// Resolve the line thickness: an explicit value wins, otherwise the /// widget-scaling default. fn resolved_thickness( &self, canvas: &Canvas ) -> f32 { self.thickness .map( |l| canvas.resolve_geom( l ) ) .unwrap_or_else( || canvas.geom_px( theme::THICKNESS ) ) } /// Resolve the vertical padding: an explicit value wins, otherwise the /// widget-scaling default. fn resolved_pad_v( &self, canvas: &Canvas ) -> f32 { self.pad_v .map( |l| canvas.resolve_geom( l ) ) .unwrap_or_else( || canvas.geom_px( theme::PAD_V ) ) } /// Override the stroke colour. Useful for emphasised dividers between /// destructive actions. pub fn color( mut self, color: Color ) -> Self { self.color = color; self } /// Override the line thickness. Accepts logical `f32` pixels or any /// [`Length`]. Without this it follows the widget-scaling mode. pub fn thickness( mut self, t: impl Into ) -> Self { self.thickness = Some( t.into() ); self } /// Override the vertical padding above and below the line. Accepts /// logical `f32` pixels or any [`Length`]; pass `0.0` for a flush, /// padding-less divider. Without this it follows the widget-scaling mode. pub fn pad_v( mut self, p: impl Into ) -> Self { self.pad_v = Some( p.into() ); self } /// Return the preferred `(width, height)`. Width is `max_width`; /// height is `thickness + 2 × pad_v`. pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> (f32, f32) { ( max_width, self.resolved_thickness( canvas ) + self.resolved_pad_v( canvas ) * 2.0 ) } /// Draw the divider line into `canvas` at `rect`. pub fn draw( &self, canvas: &mut Canvas, rect: Rect ) { let y = rect.y + rect.height / 2.0; let thickness = self.resolved_thickness( canvas ); canvas.draw_line( rect.x, y, rect.x + rect.width, y, self.color, thickness ); } } /// Create a default [`Separator`] (theme divider colour, widget-scaling /// default thickness unless overridden). /// /// ```rust,no_run /// # use ltk::{ column, separator, text, Element }; /// # #[ derive( Clone ) ] enum Msg {} /// # fn _ex() -> Element { /// column() /// .push( text( "Section A" ) ) /// .push( separator() ) /// .push( text( "Section B" ) ) /// .into() /// # } /// ``` pub fn separator() -> Separator { Separator::new() } impl From for Element { fn from( s: Separator ) -> Self { Element::Separator( s ) } } #[ cfg( test ) ] mod tests;