Skip to main content

matrix_gui/widgets/
staticline.rs

1//! Static line widget for drawing lines.
2//!
3//! This module provides a widget that draws a static line (horizontal
4//! or vertical) within a specified region with customizable width,
5//! length, padding, and color.
6
7use crate::prelude::*;
8use core::marker::PhantomData;
9
10/// Marker type for horizontal line orientation.
11pub struct OriHorizontal;
12
13/// Marker type for vertical line orientation.
14pub struct OriVertical;
15
16/// Static line widget for drawing lines.
17///
18/// This widget draws a static line (horizontal or vertical) within a
19/// specified region. The line orientation is determined by the `ORI`
20/// type parameter. The line can have customizable width, length,
21/// padding, and color.
22///
23/// # Type Parameters
24///
25/// * `'a` - The lifetime of the region reference
26/// * `ID` - The widget ID type implementing [`WidgetId`]
27/// * `COL` - The pixel color type implementing [`PixelColor`]
28/// * `ORI` - The orientation marker type (`OriHorizontal` or `OriVertical`)
29pub struct StaticLine<'a, ID, COL: PixelColor, ORI> {
30    /// The region defining the line's position and size.
31    region: &'a Region<ID>,
32    /// The width (thickness) of the line (minimum 1).
33    width: u8,
34    /// The length of the line (0 for full region width/height).
35    length: u16,
36    /// Padding around the line (in pixels).
37    padding: u16,
38    /// Optional color for the line.
39    color: OptionColor<COL>,
40    /// Phantom data for orientation marker.
41    _ori: PhantomData<ORI>,
42}
43
44impl<'a, ID: WidgetId, COL: PixelColor, ORI> StaticLine<'a, ID, COL, ORI> {
45    pub const fn new(region: &'a Region<ID>, _ori: &ORI) -> StaticLine<'a, ID, COL, ORI> {
46        StaticLine {
47            region,
48            width: 1,
49            length: 0,
50            padding: 0,
51            color: OptionColor::none(),
52            _ori: PhantomData,
53        }
54    }
55
56    pub const fn with_width(mut self, width: u8) -> Self {
57        self.width = if width == 0 { 1 } else { width };
58        self
59    }
60
61    pub const fn with_length(mut self, length: u16) -> Self {
62        self.length = length;
63        self
64    }
65
66    pub const fn with_padding(mut self, padding: u16) -> Self {
67        self.padding = padding;
68        self
69    }
70
71    pub const fn with_color(mut self, color: COL) -> Self {
72        self.color.set_color(color);
73        self
74    }
75}
76
77impl<'a, DRAW: DrawTarget<Color = COL>, ID: WidgetId, COL: PixelColor> Widget<DRAW, COL>
78    for StaticLine<'a, ID, COL, OriHorizontal>
79{
80    fn draw(&mut self, ui: &mut Ui<DRAW, COL>) -> GuiResult<Response> {
81        let widget_state = ui.get_widget_state(self.region.id())?;
82        if widget_state.compare_set(RenderStatus::Rendered) {
83            return Ok(Response::Idle);
84        }
85
86        let default_padding = ui.style().default_padding.width;
87        let padding = matrix_utils::select(self.padding > 0, self.padding, default_padding as u16);
88
89        let mut total_length = self.region.width() as u16;
90        if self.length > 0 && self.length < total_length {
91            total_length = self.length;
92        }
93
94        let area = self.region.rectangle();
95        let draw_length = total_length - 2 * padding;
96        let top_left = area.top_left
97            + Point::new(
98                padding as i32,
99                (area.size.height as i32 - self.width as i32) / 2,
100            );
101        let line_size = Size::new(draw_length as u32, self.width as u32);
102        let style = PrimitiveStyle::with_fill(self.color.text_color(ui.style()));
103        let line_area = Rectangle::new(top_left, line_size).into_styled(style);
104
105        ui.clear_area(&area)?;
106        ui.draw(&line_area)?;
107
108        Ok(Response::Idle)
109    }
110}
111
112impl<'a, DRAW: DrawTarget<Color = COL>, ID: WidgetId, COL: PixelColor> Widget<DRAW, COL>
113    for StaticLine<'a, ID, COL, OriVertical>
114{
115    fn draw(&mut self, ui: &mut Ui<DRAW, COL>) -> GuiResult<Response> {
116        let widget_state = ui.get_widget_state(self.region.id())?;
117        if widget_state.compare_set(RenderStatus::Rendered) {
118            return Ok(Response::Idle);
119        }
120
121        let default_padding = ui.style().default_padding.height;
122        let mut total_length = self.region.height() as u16;
123        if self.length > 0 && self.length < total_length {
124            total_length = self.length;
125        }
126
127        let area = self.region.rectangle();
128        let padding = matrix_utils::select(self.padding > 0, self.padding, default_padding as u16);
129
130        let draw_length = total_length - 2 * padding;
131        let top_left = area.top_left
132            + Point::new(
133                (area.size.width as i32 - self.width as i32) / 2,
134                padding as i32,
135            );
136        let line_size = Size::new(self.width as u32, draw_length as u32);
137        let style = PrimitiveStyle::with_fill(self.color.text_color(ui.style()));
138        let line_area = Rectangle::new(top_left, line_size).into_styled(style);
139
140        ui.clear_area(&area)?;
141        ui.draw(&line_area)?;
142
143        Ok(Response::Idle)
144    }
145}