egui/widgets/
image_button.rs1use crate::*;
2
3#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
5#[derive(Clone, Debug)]
6pub struct ImageButton<'a> {
7 image: Image<'a>,
8 sense: Sense,
9 frame: bool,
10 selected: bool,
11}
12
13impl<'a> ImageButton<'a> {
14 pub fn new(image: impl Into<Image<'a>>) -> Self {
15 Self {
16 image: image.into(),
17 sense: Sense::click(),
18 frame: true,
19 selected: false,
20 }
21 }
22
23 #[inline]
25 pub fn uv(mut self, uv: impl Into<Rect>) -> Self {
26 self.image = self.image.uv(uv);
27 self
28 }
29
30 #[inline]
32 pub fn tint(mut self, tint: impl Into<Color32>) -> Self {
33 self.image = self.image.tint(tint);
34 self
35 }
36
37 #[inline]
39 pub fn selected(mut self, selected: bool) -> Self {
40 self.selected = selected;
41 self
42 }
43
44 #[inline]
46 pub fn frame(mut self, frame: bool) -> Self {
47 self.frame = frame;
48 self
49 }
50
51 #[inline]
54 pub fn sense(mut self, sense: Sense) -> Self {
55 self.sense = sense;
56 self
57 }
58
59 #[inline]
63 pub fn rounding(mut self, rounding: impl Into<Rounding>) -> Self {
64 self.image = self.image.rounding(rounding.into());
65 self
66 }
67}
68
69impl<'a> Widget for ImageButton<'a> {
70 fn ui(self, ui: &mut Ui) -> Response {
71 let padding = if self.frame {
72 Vec2::splat(ui.spacing().button_padding.x)
74 } else {
75 Vec2::ZERO
76 };
77
78 let available_size_for_image = ui.available_size() - 2.0 * padding;
79 let tlr = self.image.load_for_size(ui.ctx(), available_size_for_image);
80 let original_image_size = tlr.as_ref().ok().and_then(|t| t.size());
81 let image_size = self
82 .image
83 .calc_size(available_size_for_image, original_image_size);
84
85 let padded_size = image_size + 2.0 * padding;
86 let (rect, response) = ui.allocate_exact_size(padded_size, self.sense);
87 response.widget_info(|| WidgetInfo::new(WidgetType::ImageButton));
88
89 if ui.is_rect_visible(rect) {
90 let (expansion, rounding, fill, stroke) = if self.selected {
91 let selection = ui.visuals().selection;
92 (
93 Vec2::ZERO,
94 self.image.image_options().rounding,
95 selection.bg_fill,
96 selection.stroke,
97 )
98 } else if self.frame {
99 let visuals = ui.style().interact(&response);
100 let expansion = Vec2::splat(visuals.expansion);
101 (
102 expansion,
103 self.image.image_options().rounding,
104 visuals.weak_bg_fill,
105 visuals.bg_stroke,
106 )
107 } else {
108 Default::default()
109 };
110
111 ui.painter()
113 .rect_filled(rect.expand2(expansion), rounding, fill);
114
115 let image_rect = ui
116 .layout()
117 .align_size_within_rect(image_size, rect.shrink2(padding));
118 let image_options = self.image.image_options().clone();
120
121 widgets::image::paint_texture_load_result(ui, &tlr, image_rect, None, &image_options);
122
123 ui.painter()
125 .rect_stroke(rect.expand2(expansion), rounding, stroke);
126 }
127
128 widgets::image::texture_load_result_response(&self.image.source(ui.ctx()), &tlr, response)
129 }
130}