Skip to main content

pfx_editor_style/widgets/
pill.rs

1use egui::{Align2, Color32, CornerRadius, Response, Sense, Stroke, StrokeKind, Ui, Vec2, Widget};
2
3use super::{place, shaped};
4use crate::theme::Theme;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Tone {
8    Neutral,
9    Ok,
10    Busy,
11    Danger,
12}
13
14impl Tone {
15    fn colours(self, theme: &Theme) -> (Color32, Color32) {
16        match self {
17            Tone::Neutral => (theme.surface, theme.text2),
18            Tone::Ok => (theme.ok_tint, theme.ok),
19            Tone::Busy => (theme.hot_dim, theme.hot),
20            Tone::Danger => (theme.error_tint, theme.error),
21        }
22    }
23}
24
25pub struct Pill<'a> {
26    text: &'a str,
27    tone: Tone,
28    active: bool,
29}
30
31impl<'a> Pill<'a> {
32    pub fn new(text: &'a str, tone: Tone) -> Pill<'a> {
33        Pill {
34            text,
35            tone,
36            active: false,
37        }
38    }
39
40    pub fn active(mut self, active: bool) -> Pill<'a> {
41        self.active = active;
42        self
43    }
44}
45
46impl Widget for Pill<'_> {
47    fn ui(self, ui: &mut Ui) -> Response {
48        let theme = Theme::of(ui.ctx());
49        let (fill, ink) = self.tone.colours(&theme);
50        let galley = shaped(
51            ui.painter(),
52            self.text,
53            theme.font(theme.size_code),
54            ink,
55            theme.labels,
56        );
57        let width = galley.size().x;
58        let size = Vec2::new((width + 22.0).round(), 16.0);
59        let (rect, response) = ui.allocate_exact_size(size, Sense::hover());
60        if !ui.is_rect_visible(rect) {
61            return response;
62        }
63        let border = if self.active { ink } else { fill };
64        let painter = ui.painter();
65        painter.rect(
66            rect,
67            CornerRadius::same(theme.radius),
68            fill,
69            Stroke::new(theme.stroke, border),
70            StrokeKind::Inside,
71        );
72        painter.circle_filled(rect.left_center() + Vec2::new(8.0, 0.0), 2.5, ink);
73        place(
74            painter,
75            rect.left_center() + Vec2::new(15.0, -0.5),
76            Align2::LEFT_CENTER,
77            galley,
78            ink,
79        );
80        response
81    }
82}