egui/widgets/
separator.rs

1use crate::{vec2, Response, Sense, Ui, Vec2, Widget};
2
3/// A visual separator. A horizontal or vertical line (depending on [`crate::Layout`]).
4///
5/// Usually you'd use the shorter version [`Ui::separator`].
6///
7/// ```
8/// # egui::__run_test_ui(|ui| {
9/// // These are equivalent:
10/// ui.separator();
11/// ui.add(egui::Separator::default());
12/// # });
13/// ```
14#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
15pub struct Separator {
16    spacing: f32,
17    grow: f32,
18    is_horizontal_line: Option<bool>,
19}
20
21impl Default for Separator {
22    fn default() -> Self {
23        Self {
24            spacing: 6.0,
25            grow: 0.0,
26            is_horizontal_line: None,
27        }
28    }
29}
30
31impl Separator {
32    /// How much space we take up. The line is painted in the middle of this.
33    ///
34    /// In a vertical layout, with a horizontal Separator,
35    /// this is the height of the separator widget.
36    ///
37    /// In a horizontal layout, with a vertical Separator,
38    /// this is the width of the separator widget.
39    #[inline]
40    pub fn spacing(mut self, spacing: f32) -> Self {
41        self.spacing = spacing;
42        self
43    }
44
45    /// Explicitly ask for a horizontal line.
46    ///
47    /// By default you will get a horizontal line in vertical layouts,
48    /// and a vertical line in horizontal layouts.
49    #[inline]
50    pub fn horizontal(mut self) -> Self {
51        self.is_horizontal_line = Some(true);
52        self
53    }
54
55    /// Explicitly ask for a vertical line.
56    ///
57    /// By default you will get a horizontal line in vertical layouts,
58    /// and a vertical line in horizontal layouts.
59    #[inline]
60    pub fn vertical(mut self) -> Self {
61        self.is_horizontal_line = Some(false);
62        self
63    }
64
65    /// Extend each end of the separator line by this much.
66    ///
67    /// The default is to take up the available width/height of the parent.
68    ///
69    /// This will make the line extend outside the parent ui.
70    #[inline]
71    pub fn grow(mut self, extra: f32) -> Self {
72        self.grow += extra;
73        self
74    }
75
76    /// Contract each end of the separator line by this much.
77    ///
78    /// The default is to take up the available width/height of the parent.
79    ///
80    /// This effectively adds margins to the line.
81    #[inline]
82    pub fn shrink(mut self, shrink: f32) -> Self {
83        self.grow -= shrink;
84        self
85    }
86}
87
88impl Widget for Separator {
89    fn ui(self, ui: &mut Ui) -> Response {
90        let Self {
91            spacing,
92            grow,
93            is_horizontal_line,
94        } = self;
95
96        let is_horizontal_line = is_horizontal_line
97            .unwrap_or_else(|| ui.is_grid() || !ui.layout().main_dir().is_horizontal());
98
99        let available_space = if ui.is_sizing_pass() {
100            Vec2::ZERO
101        } else {
102            ui.available_size_before_wrap()
103        };
104
105        let size = if is_horizontal_line {
106            vec2(available_space.x, spacing)
107        } else {
108            vec2(spacing, available_space.y)
109        };
110
111        let (rect, response) = ui.allocate_at_least(size, Sense::hover());
112
113        if ui.is_rect_visible(response.rect) {
114            let stroke = ui.visuals().widgets.noninteractive.bg_stroke;
115            let painter = ui.painter();
116            if is_horizontal_line {
117                painter.hline(
118                    (rect.left() - grow)..=(rect.right() + grow),
119                    rect.center().y,
120                    stroke,
121                );
122            } else {
123                painter.vline(
124                    rect.center().x,
125                    (rect.top() - grow)..=(rect.bottom() + grow),
126                    stroke,
127                );
128            }
129        }
130
131        response
132    }
133}