pixels_graphics_lib/ui/
icon_button.rs

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