iced_native/widget/
rule.rs

1//! Display a horizontal or vertical rule for dividing content.
2use crate::layout;
3use crate::renderer;
4use crate::widget::Tree;
5use crate::{
6    Color, Element, Layout, Length, Pixels, Point, Rectangle, Size, Widget,
7};
8
9pub use iced_style::rule::{Appearance, FillMode, StyleSheet};
10
11/// Display a horizontal or vertical rule for dividing content.
12#[allow(missing_debug_implementations)]
13pub struct Rule<Renderer>
14where
15    Renderer: crate::Renderer,
16    Renderer::Theme: StyleSheet,
17{
18    width: Length,
19    height: Length,
20    is_horizontal: bool,
21    style: <Renderer::Theme as StyleSheet>::Style,
22}
23
24impl<Renderer> Rule<Renderer>
25where
26    Renderer: crate::Renderer,
27    Renderer::Theme: StyleSheet,
28{
29    /// Creates a horizontal [`Rule`] with the given height.
30    pub fn horizontal(height: impl Into<Pixels>) -> Self {
31        Rule {
32            width: Length::Fill,
33            height: Length::Fixed(height.into().0),
34            is_horizontal: true,
35            style: Default::default(),
36        }
37    }
38
39    /// Creates a vertical [`Rule`] with the given width.
40    pub fn vertical(width: impl Into<Pixels>) -> Self {
41        Rule {
42            width: Length::Fixed(width.into().0),
43            height: Length::Fill,
44            is_horizontal: false,
45            style: Default::default(),
46        }
47    }
48
49    /// Sets the style of the [`Rule`].
50    pub fn style(
51        mut self,
52        style: impl Into<<Renderer::Theme as StyleSheet>::Style>,
53    ) -> Self {
54        self.style = style.into();
55        self
56    }
57}
58
59impl<Message, Renderer> Widget<Message, Renderer> for Rule<Renderer>
60where
61    Renderer: crate::Renderer,
62    Renderer::Theme: StyleSheet,
63{
64    fn width(&self) -> Length {
65        self.width
66    }
67
68    fn height(&self) -> Length {
69        self.height
70    }
71
72    fn layout(
73        &self,
74        _renderer: &Renderer,
75        limits: &layout::Limits,
76    ) -> layout::Node {
77        let limits = limits.width(self.width).height(self.height);
78
79        layout::Node::new(limits.resolve(Size::ZERO))
80    }
81
82    fn draw(
83        &self,
84        _state: &Tree,
85        renderer: &mut Renderer,
86        theme: &Renderer::Theme,
87        _style: &renderer::Style,
88        layout: Layout<'_>,
89        _cursor_position: Point,
90        _viewport: &Rectangle,
91    ) {
92        let bounds = layout.bounds();
93        let style = theme.appearance(&self.style);
94
95        let bounds = if self.is_horizontal {
96            let line_y = (bounds.y + (bounds.height / 2.0)
97                - (style.width as f32 / 2.0))
98                .round();
99
100            let (offset, line_width) = style.fill_mode.fill(bounds.width);
101            let line_x = bounds.x + offset;
102
103            Rectangle {
104                x: line_x,
105                y: line_y,
106                width: line_width,
107                height: style.width as f32,
108            }
109        } else {
110            let line_x = (bounds.x + (bounds.width / 2.0)
111                - (style.width as f32 / 2.0))
112                .round();
113
114            let (offset, line_height) = style.fill_mode.fill(bounds.height);
115            let line_y = bounds.y + offset;
116
117            Rectangle {
118                x: line_x,
119                y: line_y,
120                width: style.width as f32,
121                height: line_height,
122            }
123        };
124
125        renderer.fill_quad(
126            renderer::Quad {
127                bounds,
128                border_radius: style.radius.into(),
129                border_width: 0.0,
130                border_color: Color::TRANSPARENT,
131            },
132            style.color,
133        );
134    }
135}
136
137impl<'a, Message, Renderer> From<Rule<Renderer>>
138    for Element<'a, Message, Renderer>
139where
140    Message: 'a,
141    Renderer: 'a + crate::Renderer,
142    Renderer::Theme: StyleSheet,
143{
144    fn from(rule: Rule<Renderer>) -> Element<'a, Message, Renderer> {
145        Element::new(rule)
146    }
147}