Skip to content

Commit 90757ca

Browse files
authored
Add Button::image_and_text (#832)
* Support image button with text * Add example (`cargo run --example native_texture`)
1 parent 8896243 commit 90757ca

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

egui/src/widgets/button.rs

+47-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct Button {
2929
small: bool,
3030
frame: Option<bool>,
3131
min_size: Vec2,
32+
image: Option<widgets::Image>,
3233
}
3334

3435
impl Button {
@@ -42,6 +43,27 @@ impl Button {
4243
small: false,
4344
frame: None,
4445
min_size: Vec2::ZERO,
46+
image: None,
47+
}
48+
}
49+
50+
/// Creates a button with an image to the left of the text. The size of the image as displayed is defined by the size Vec2 provided.
51+
#[allow(clippy::needless_pass_by_value)]
52+
pub fn image_and_text(
53+
texture_id: TextureId,
54+
size: impl Into<Vec2>,
55+
text: impl Into<WidgetText>,
56+
) -> Self {
57+
Self {
58+
text: text.into(),
59+
fill: None,
60+
stroke: None,
61+
sense: Sense::click(),
62+
small: false,
63+
frame: None,
64+
wrap: None,
65+
min_size: Vec2::ZERO,
66+
image: Some(widgets::Image::new(texture_id, size)),
4567
}
4668
}
4769

@@ -123,6 +145,7 @@ impl Widget for Button {
123145
small,
124146
frame,
125147
min_size,
148+
image,
126149
} = self;
127150

128151
let frame = frame.unwrap_or_else(|| ui.visuals().button_frame);
@@ -142,15 +165,27 @@ impl Widget for Button {
142165
}
143166
desired_size = desired_size.at_least(min_size);
144167

168+
if let Some(image) = image {
169+
desired_size.x += image.size().x + ui.spacing().icon_spacing;
170+
desired_size.y = desired_size.y.max(image.size().y + 2.0 * button_padding.y);
171+
}
172+
145173
let (rect, response) = ui.allocate_at_least(desired_size, sense);
146174
response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, text.text()));
147175

148176
if ui.is_rect_visible(rect) {
149177
let visuals = ui.style().interact(&response);
150-
let text_pos = ui
151-
.layout()
152-
.align_size_within_rect(text.size(), rect.shrink2(button_padding))
153-
.min;
178+
let text_pos = if let Some(image) = image {
179+
let icon_spacing = ui.spacing().icon_spacing;
180+
pos2(
181+
rect.min.x + button_padding.x + image.size().x + icon_spacing,
182+
rect.center().y - 0.5 * text.size().y,
183+
)
184+
} else {
185+
ui.layout()
186+
.align_size_within_rect(text.size(), rect.shrink2(button_padding))
187+
.min
188+
};
154189

155190
if frame {
156191
let fill = fill.unwrap_or(visuals.bg_fill);
@@ -166,6 +201,14 @@ impl Widget for Button {
166201
text.paint_with_visuals(ui.painter(), text_pos, visuals);
167202
}
168203

204+
if let Some(image) = image {
205+
let image_rect = Rect::from_min_size(
206+
pos2(rect.min.x, rect.center().y - 0.5 - (image.size().y / 2.0)),
207+
image.size(),
208+
);
209+
image.paint_at(ui, image_rect);
210+
}
211+
169212
response
170213
}
171214
}

egui_glium/examples/native_texture.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,23 @@ fn main() {
5252
let glium_texture = std::rc::Rc::new(glium_texture);
5353
// Allocate egui's texture id for GL texture
5454
let texture_id = egui_glium.painter.register_native_texture(glium_texture);
55+
// Setup button image size for reasonable image size for button container.
56+
let button_image_size = egui::Vec2::new(32_f32, 32_f32);
5557

5658
event_loop.run(move |event, _, control_flow| {
5759
let mut redraw = || {
5860
let mut quit = false;
5961

6062
let (needs_repaint, shapes) = egui_glium.run(&display, |egui_ctx| {
6163
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
62-
if ui.button("Quit").clicked() {
64+
if ui
65+
.add(egui::Button::image_and_text(
66+
texture_id,
67+
button_image_size,
68+
"Quit",
69+
))
70+
.clicked()
71+
{
6372
quit = true;
6473
}
6574
});

0 commit comments

Comments
 (0)