pixels_graphics_lib/ui/
toggle_icon_button.rs

1use crate::prelude::*;
2use crate::ui::prelude::LayoutView;
3use crate::ui::styles::ToggleIconButtonStyle;
4use crate::ui::tooltip::Tooltip;
5use crate::ui::{PixelView, ViewState};
6
7#[derive(Debug)]
8pub struct ToggleIconButton {
9    tooltip: Tooltip,
10    icon: IndexedImage,
11    icon_xy: Coord,
12    bounds: Rect,
13    border: Polyline,
14    shadow: Polyline,
15    style: ToggleIconButtonStyle,
16    state: ViewState,
17    selected: bool,
18    tooltip_text: String,
19    tooltip_positioning: Positioning,
20}
21
22impl ToggleIconButton {
23    pub fn new<P: Into<Coord>>(
24        xy: P,
25        tooltip_text: &str,
26        tooltip_positioning: Positioning,
27        icon: IndexedImage,
28        style: &ToggleIconButtonStyle,
29    ) -> Self {
30        let xy = xy.into();
31        let (w, h) = icon.size();
32        let bounds = Rect::new_with_size(
33            xy,
34            w as usize + style.padding + style.padding,
35            h as usize + style.padding + style.padding,
36        );
37        let (icon_xy, border, shadow, tooltip) =
38            Self::layout(&bounds, style, tooltip_text, tooltip_positioning, (w, h));
39        Self {
40            tooltip,
41            icon,
42            icon_xy,
43            bounds,
44            border,
45            shadow,
46            style: style.clone(),
47            state: ViewState::Normal,
48            selected: false,
49            tooltip_text: tooltip_text.to_string(),
50            tooltip_positioning,
51        }
52    }
53
54    fn layout(
55        bounds: &Rect,
56        style: &ToggleIconButtonStyle,
57        tooltip_text: &str,
58        tooltip_positioning: Positioning,
59        (w, h): (u8, u8),
60    ) -> (Coord, Polyline, Polyline, Tooltip) {
61        let border = Polyline::rounded_rect(
62            bounds.left(),
63            bounds.top(),
64            bounds.right(),
65            bounds.bottom(),
66            style.rounding,
67            WHITE,
68        )
69        .unwrap();
70        let shadow = Polyline::rounded_rect(
71            bounds.left() + 1,
72            bounds.top() + 1,
73            bounds.right() + 1,
74            bounds.bottom() + 1,
75            style.rounding,
76            WHITE,
77        )
78        .unwrap();
79        let tooltip = Tooltip::new(
80            bounds.top_left() + (w, h),
81            tooltip_text,
82            tooltip_positioning,
83            &style.tooltip,
84        );
85        (
86            bounds.top_left() + (style.padding, style.padding) + (1, 1),
87            border,
88            shadow,
89            tooltip,
90        )
91    }
92}
93
94impl ToggleIconButton {
95    #[must_use]
96    pub fn is_selected(&self) -> bool {
97        self.selected
98    }
99
100    pub fn set_selected(&mut self, value: bool) {
101        self.selected = value;
102    }
103
104    #[must_use]
105    pub fn on_mouse_click(&mut self, down: Coord, up: Coord) -> bool {
106        if self.state != ViewState::Disabled {
107            self.bounds.contains(down) && self.bounds.contains(up)
108        } else {
109            false
110        }
111    }
112}
113
114impl PixelView for ToggleIconButton {
115    fn set_position(&mut self, top_left: Coord) {
116        self.bounds = self.bounds.move_to(top_left);
117        let (icon_xy, border, shadow, tooltip) = Self::layout(
118            &self.bounds,
119            &self.style,
120            &self.tooltip_text,
121            self.tooltip_positioning,
122            (self.icon.width(), self.icon.height()),
123        );
124        self.icon_xy = icon_xy;
125        self.border = border;
126        self.shadow = shadow;
127        self.tooltip = tooltip;
128    }
129
130    #[must_use]
131    fn bounds(&self) -> &Rect {
132        &self.bounds
133    }
134
135    fn render(&self, graphics: &mut Graphics, mouse: &MouseData) {
136        let (error, disabled) = self.state.get_err_dis();
137        let hovering = self.bounds.contains(mouse.xy);
138        if let Some(color) = self
139            .style
140            .shadow
141            .get(hovering, self.selected, error, disabled)
142        {
143            self.shadow.with_color(color).render(graphics);
144        }
145        if let Some(color) = self
146            .style
147            .border
148            .get(hovering, self.selected, error, disabled)
149        {
150            self.border.with_color(color).render(graphics);
151        }
152        graphics.draw_indexed_image(self.icon_xy, &self.icon);
153        if !disabled && hovering {
154            self.tooltip.render(graphics, mouse);
155        }
156    }
157
158    fn update(&mut self, _: &Timing) {}
159
160    #[inline]
161    fn set_state(&mut self, state: ViewState) {
162        self.state = state;
163    }
164
165    #[inline]
166    #[must_use]
167    fn get_state(&self) -> ViewState {
168        self.state
169    }
170}
171
172impl LayoutView for ToggleIconButton {
173    fn set_bounds(&mut self, bounds: Rect) {
174        self.bounds = bounds.clone();
175        self.set_position(bounds.top_left());
176    }
177}