Skip to main content

minifb_ui/ui/
tooltip.rs

1pub struct Tooltip {
2    pub text: crate::ui::text::Text,
3    pub font_size: f32,
4
5    pub bg_color: crate::color::Color,
6    pub text_color: crate::color::Color,
7    pub border_color: crate::color::Color,
8    pub border_size: usize,
9    pub radius: usize,
10    pub padding: usize,
11
12    /// Vertical offset from target (negative = above)
13    pub offset_y: isize,
14}
15
16impl Tooltip {
17    pub fn new(text: &str, font: crate::ttf::Font, size: f32) -> Self {
18        Self {
19            text: crate::ui::text::Text::new(text, font),
20            font_size: size,
21            bg_color: crate::color::Color::new(20, 20, 30),
22            text_color: crate::color::Color::new(220, 220, 230),
23            border_color: crate::color::Color::new(70, 70, 90),
24            border_size: 1,
25            radius: 6,
26            padding: 6,
27            offset_y: -8,
28        }
29    }
30
31    pub fn bg_color(mut self, color: crate::color::Color) -> Self {
32        self.bg_color = color;
33        self
34    }
35
36    pub fn text_color(mut self, color: crate::color::Color) -> Self {
37        self.text_color = color;
38        self
39    }
40
41    pub fn border_color(mut self, color: crate::color::Color) -> Self {
42        self.border_color = color;
43        self
44    }
45
46    pub fn border(mut self, size: usize) -> Self {
47        self.border_size = size;
48        self
49    }
50
51    pub fn radius(mut self, radius: usize) -> Self {
52        self.radius = radius;
53        self
54    }
55
56    pub fn padding(mut self, padding: usize) -> Self {
57        self.padding = padding;
58        self
59    }
60
61    pub fn offset_y(mut self, offset: isize) -> Self {
62        self.offset_y = offset;
63        self
64    }
65
66    /// Draws the tooltip if the mouse is hovering over the target area
67    pub fn draw_if_hovered(
68        &self,
69        window: &mut crate::window::Window,
70        target_x: usize,
71        target_y: usize,
72        target_w: usize,
73        target_h: usize,
74    ) {
75        let mouse = window.get_mouse_state();
76        let mx = mouse.pos_x;
77        let my = mouse.pos_y;
78        let in_target = mx >= target_x as f32
79            && mx < (target_x + target_w) as f32
80            && my >= target_y as f32
81            && my < (target_y + target_h) as f32;
82
83        if !in_target {
84            return;
85        }
86
87        let text_w = self.text.get_width_precise(self.font_size);
88        let lm = self.text.font.font.horizontal_line_metrics(self.font_size).unwrap();
89        let text_h = (lm.ascent - lm.descent).ceil();
90
91        let tip_w = text_w.ceil() as usize + self.padding * 2;
92        let tip_h = text_h as usize + self.padding * 2;
93
94        // Center horizontally on target, position above/below
95        let tip_x = (target_x + target_w / 2).saturating_sub(tip_w / 2);
96        let tip_y = if self.offset_y < 0 {
97            target_y.saturating_sub(tip_h).saturating_sub((-self.offset_y) as usize)
98        } else {
99            target_y + target_h + self.offset_y as usize
100        };
101
102        // Background
103        window.draw_rect_f(tip_x, tip_y, tip_w, tip_h, self.radius, &self.bg_color, 0);
104
105        // Border
106        for i in 0..self.border_size {
107            window.draw_rect(
108                tip_x + i, tip_y + i,
109                tip_w - i * 2, tip_h - i * 2,
110                self.radius.saturating_sub(i), &self.border_color,
111            );
112        }
113
114        // Text
115        window.draw_text(
116            tip_x + self.padding,
117            tip_y + self.padding,
118            &self.text, self.font_size, &self.text_color,
119        );
120    }
121}