1use egui::{CornerRadius, Response, Sense, Stroke, Ui, Vec2, Widget, WidgetInfo, WidgetType};
4
5use crate::theme::{with_alpha, Theme};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub enum IndicatorState {
10 On,
12 Off,
14 Connecting,
16}
17
18#[derive(Debug, Clone, Copy)]
20#[must_use = "Add with `ui.add(...)`."]
21pub struct Indicator {
22 state: IndicatorState,
23 size: f32,
24}
25
26impl Indicator {
27 pub fn new(state: IndicatorState) -> Self {
29 Self { state, size: 10.0 }
30 }
31
32 pub fn size(mut self, size: f32) -> Self {
34 self.size = size;
35 self
36 }
37}
38
39impl Widget for Indicator {
40 fn ui(self, ui: &mut Ui) -> Response {
41 let theme = Theme::current(ui.ctx());
42 let p = &theme.palette;
43
44 let size = Vec2::splat(self.size);
45 let (rect, response) = ui.allocate_exact_size(size, Sense::hover());
46
47 if ui.is_rect_visible(rect) {
48 let painter = ui.painter();
49 let c = rect.center();
50 let r = self.size * 0.5;
51
52 match self.state {
53 IndicatorState::On => {
54 painter.circle_filled(c, r + 1.5, with_alpha(p.success, 70));
56 painter.circle_filled(c, r, p.success);
57 }
58 IndicatorState::Off => {
59 painter.circle_stroke(c, r - 0.5, Stroke::new(1.0, p.danger));
60 let bar_w = self.size * 0.7;
62 let bar_h = 2.0;
63 let bar = egui::Rect::from_center_size(c, Vec2::new(bar_w, bar_h));
64 painter.rect_filled(bar, CornerRadius::same(1), p.danger);
65 }
66 IndicatorState::Connecting => {
67 painter.circle_stroke(c, r - 0.5, Stroke::new(1.8, p.warning));
68 }
69 }
70 }
71
72 response.widget_info(|| {
73 WidgetInfo::labeled(
74 WidgetType::Other,
75 true,
76 match self.state {
77 IndicatorState::On => "status: on",
78 IndicatorState::Off => "status: off",
79 IndicatorState::Connecting => "status: connecting",
80 },
81 )
82 });
83 response
84 }
85}