Skip to main content

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        .expect("Border could not be constructed, please raise an issue on Github emmabritton/pixel-graphics-lib");
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        .expect("Shadow could not be constructed, please raise an issue on Github emmabritton/pixel-graphics-lib");
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    pub fn on_mouse_click(&mut self, down: Coord, up: Coord) -> bool {
94        if self.state != ViewState::Disabled {
95            self.bounds.contains(down) && self.bounds.contains(up)
96        } else {
97            false
98        }
99    }
100}
101
102impl PixelView for IconButton {
103    fn set_position(&mut self, top_left: Coord) {
104        self.bounds = self.bounds.move_to(top_left);
105        let (icon_xy, border, shadow, tooltip) = Self::layout(
106            &self.bounds,
107            &self.style,
108            &self.tooltip_text,
109            self.tooltip_positioning,
110            (self.icon.width(), self.icon.height()),
111        );
112        self.icon_xy = icon_xy;
113        self.border = border;
114        self.shadow = shadow;
115        self.tooltip = tooltip;
116    }
117
118    fn bounds(&self) -> &Rect {
119        &self.bounds
120    }
121
122    fn render(&self, graphics: &mut Graphics, mouse: &MouseData) {
123        let (error, disabled) = self.state.get_err_dis();
124        let hovering = self.bounds.contains(mouse.xy);
125        if let Some(color) = self.style.shadow.get(hovering, error, disabled) {
126            self.shadow.with_color(color).render(graphics);
127        }
128        if let Some(color) = self.style.border.get(hovering, error, disabled) {
129            self.border.with_color(color).render(graphics);
130        }
131        graphics.draw_indexed_image(self.icon_xy, &self.icon);
132        if !disabled && hovering {
133            self.tooltip.render(graphics, mouse);
134        }
135    }
136
137    fn update(&mut self, _: &Timing) {}
138
139    #[inline]
140    fn set_state(&mut self, state: ViewState) {
141        self.state = state;
142    }
143
144    #[inline]
145    fn get_state(&self) -> ViewState {
146        self.state
147    }
148}
149
150impl LayoutView for IconButton {
151    fn set_bounds(&mut self, bounds: Rect) {
152        self.bounds = bounds.clone();
153        self.set_position(bounds.top_left());
154    }
155}