Add a menu button with text and image (#4748)

In order to make it possible that all buttons can have the same style
with a text and an image I created a `menu_text_image_button`.

It works the same way as all the other menu buttons.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Nicolas Bircks 2024-07-09 16:51:41 +02:00 committed by GitHub
parent aa96b25746
commit 3b8453e920
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 62 additions and 7 deletions

View File

@ -105,17 +105,35 @@ pub fn menu_button<R>(
stationary_menu_impl(ui, title, Box::new(add_contents)) stationary_menu_impl(ui, title, Box::new(add_contents))
} }
/// Construct a top level menu with a custom button in a menu bar.
///
/// Responds to primary clicks.
///
/// Returns `None` if the menu is not open.
pub fn menu_custom_button<R>(
ui: &mut Ui,
button: Button<'_>,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<Option<R>> {
stationary_menu_button_impl(ui, button, Box::new(add_contents))
}
/// Construct a top level menu with an image in a menu bar. This would be e.g. "File", "Edit" etc. /// Construct a top level menu with an image in a menu bar. This would be e.g. "File", "Edit" etc.
/// ///
/// Responds to primary clicks. /// Responds to primary clicks.
/// ///
/// Returns `None` if the menu is not open. /// Returns `None` if the menu is not open.
#[deprecated = "Use `menu_custom_button` instead"]
pub fn menu_image_button<R>( pub fn menu_image_button<R>(
ui: &mut Ui, ui: &mut Ui,
image_button: ImageButton<'_>, image_button: ImageButton<'_>,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<Option<R>> { ) -> InnerResponse<Option<R>> {
stationary_menu_image_impl(ui, image_button, Box::new(add_contents)) stationary_menu_button_impl(
ui,
Button::image(image_button.image),
Box::new(add_contents),
)
} }
/// Construct a nested sub menu in another menu. /// Construct a nested sub menu in another menu.
@ -226,15 +244,15 @@ fn stationary_menu_impl<'c, R>(
/// Build a top level menu with an image button. /// Build a top level menu with an image button.
/// ///
/// Responds to primary clicks. /// Responds to primary clicks.
fn stationary_menu_image_impl<'c, R>( fn stationary_menu_button_impl<'c, R>(
ui: &mut Ui, ui: &mut Ui,
image_button: ImageButton<'_>, button: Button<'_>,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<Option<R>> { ) -> InnerResponse<Option<R>> {
let bar_id = ui.id(); let bar_id = ui.id();
let mut bar_state = BarState::load(ui.ctx(), bar_id); let mut bar_state = BarState::load(ui.ctx(), bar_id);
let button_response = ui.add(image_button); let button_response = ui.add(button);
let inner = bar_state.bar_menu(&button_response, add_contents); let inner = bar_state.bar_menu(&button_response, add_contents);
bar_state.store(ui.ctx(), bar_id); bar_state.store(ui.ctx(), bar_id);

View File

@ -2543,16 +2543,19 @@ impl Ui {
/// If called from within a menu this will instead create a button for a sub-menu. /// If called from within a menu this will instead create a button for a sub-menu.
/// ///
/// ```ignore /// ```ignore
/// # egui::__run_test_ui(|ui| {
/// let img = egui::include_image!("../assets/ferris.png"); /// let img = egui::include_image!("../assets/ferris.png");
/// ///
/// ui.menu_image_button(img, |ui| { /// ui.menu_image_button(title, img, |ui| {
/// ui.menu_button("My sub-menu", |ui| { /// ui.menu_button("My sub-menu", |ui| {
/// if ui.button("Close the menu").clicked() { /// if ui.button("Close the menu").clicked() {
/// ui.close_menu(); /// ui.close_menu();
/// } /// }
/// }); /// });
/// }); /// });
/// # });
/// ``` /// ```
///
/// ///
/// See also: [`Self::close_menu`] and [`Response::context_menu`]. /// See also: [`Self::close_menu`] and [`Response::context_menu`].
#[inline] #[inline]
@ -2564,7 +2567,41 @@ impl Ui {
if let Some(menu_state) = self.menu_state.clone() { if let Some(menu_state) = self.menu_state.clone() {
menu::submenu_button(self, menu_state, String::new(), add_contents) menu::submenu_button(self, menu_state, String::new(), add_contents)
} else { } else {
menu::menu_image_button(self, ImageButton::new(image), add_contents) menu::menu_custom_button(self, Button::image(image), add_contents)
}
}
/// Create a menu button with an image and a text that when clicked will show the given menu.
///
/// If called from within a menu this will instead create a button for a sub-menu.
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// let img = egui::include_image!("../assets/ferris.png");
/// let title = "My Menu";
///
/// ui.menu_image_text_button(img, title, |ui| {
/// ui.menu_button("My sub-menu", |ui| {
/// if ui.button("Close the menu").clicked() {
/// ui.close_menu();
/// }
/// });
/// });
/// # });
/// ```
///
/// See also: [`Self::close_menu`] and [`Response::context_menu`].
#[inline]
pub fn menu_image_text_button<'a, R>(
&mut self,
image: impl Into<Image<'a>>,
title: impl Into<WidgetText>,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<Option<R>> {
if let Some(menu_state) = self.menu_state.clone() {
menu::submenu_button(self, menu_state, title, add_contents)
} else {
menu::menu_custom_button(self, Button::image_and_text(image, title), add_contents)
} }
} }
} }

View File

@ -4,7 +4,7 @@ use crate::*;
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"] #[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ImageButton<'a> { pub struct ImageButton<'a> {
image: Image<'a>, pub(crate) image: Image<'a>,
sense: Sense, sense: Sense,
frame: bool, frame: bool,
selected: bool, selected: bool,