ltk/widget/separator/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::types::{ Color, Length, Rect };
use crate::render::Canvas;
use super::Element;

mod theme;

/// A horizontal divider line.
///
/// Renders a 1 px (default) 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<Msg> {
/// // 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<Length>,
	/// 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<Length>,
}

impl Separator
{
	/// Create a separator with the theme's default divider colour and
	/// 1 px thickness.
	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| l.resolve( canvas.viewport_layout(), Length::EM_BASE_DEFAULT ) )
			.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| l.resolve( canvas.viewport_layout(), Length::EM_BASE_DEFAULT ) )
			.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<Length> ) -> 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<Length> ) -> 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, 1 px thickness).
///
/// ```rust,no_run
/// # use ltk::{ column, separator, text, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() -> Element<Msg> {
/// column()
///     .push( text( "Section A" ) )
///     .push( separator() )
///     .push( text( "Section B" ) )
/// .into()
/// # }
/// ```
pub fn separator() -> Separator
{
	Separator::new()
}

impl<Msg: Clone> From<Separator> for Element<Msg>
{
	fn from( s: Separator ) -> Self
	{
		Element::Separator( s )
	}
}

#[cfg(test)]
mod tests;