From ffbc63e14708f04a7d40ca9bf486e138ddaecab8 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 29 May 2024 11:47:10 +0200 Subject: [PATCH] `ComboBox`: fix justified layout of popup if wider than parent button (#4570) * Closes https://github.com/emilk/egui/issues/4452 The `ComboBox` popup has a justified layout to make selection of items easier. Thanks to [the new sizing pass logic](https://github.com/emilk/egui/issues/4535) we don't have to know the final width in advance: ![image](https://github.com/emilk/egui/assets/1148717/53b0dda7-14c9-43be-a073-ad49865e69a6) --- crates/egui/src/containers/popup.rs | 11 +++++---- .../egui_demo_lib/src/demo/widget_gallery.rs | 2 -- tests/test_size_pass/src/main.rs | 23 +++++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 0aca413a9ed..f0c82819728 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -307,7 +307,7 @@ pub fn popup_below_widget( /// /// Useful for drop-down menus (combo boxes) or suggestion menus under text fields. /// -/// The opened popup will have the same width as the parent. +/// The opened popup will have a minimum width matching its parent. /// /// You must open the popup with [`Memory::open_popup`] or [`Memory::toggle_popup`]. /// @@ -341,18 +341,21 @@ pub fn popup_above_or_below_widget( AboveOrBelow::Below => (widget_response.rect.left_bottom(), Align2::LEFT_TOP), }; + let frame = Frame::popup(parent_ui.style()); + let frame_margin = frame.total_margin(); + let inner_width = widget_response.rect.width() - frame_margin.sum().x; + let inner = Area::new(popup_id) .order(Order::Foreground) .constrain(true) .fixed_pos(pos) + .default_width(inner_width) .pivot(pivot) .show(parent_ui.ctx(), |ui| { - let frame = Frame::popup(parent_ui.style()); - let frame_margin = frame.total_margin(); frame .show(ui, |ui| { ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| { - ui.set_width(widget_response.rect.width() - frame_margin.sum().x); + ui.set_min_width(inner_width); add_contents(ui) }) .inner diff --git a/crates/egui_demo_lib/src/demo/widget_gallery.rs b/crates/egui_demo_lib/src/demo/widget_gallery.rs index 6f5d26f5e57..babc8dd9568 100644 --- a/crates/egui_demo_lib/src/demo/widget_gallery.rs +++ b/crates/egui_demo_lib/src/demo/widget_gallery.rs @@ -172,8 +172,6 @@ impl WidgetGallery { egui::ComboBox::from_label("Take your pick") .selected_text(format!("{radio:?}")) .show_ui(ui, |ui| { - ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); - ui.set_min_width(60.0); ui.selectable_value(radio, Enum::First, "First"); ui.selectable_value(radio, Enum::Second, "Second"); ui.selectable_value(radio, Enum::Third, "Third"); diff --git a/tests/test_size_pass/src/main.rs b/tests/test_size_pass/src/main.rs index 13b49911ffb..f841cd1d9b8 100644 --- a/tests/test_size_pass/src/main.rs +++ b/tests/test_size_pass/src/main.rs @@ -9,6 +9,12 @@ fn main() -> eframe::Result<()> { let options = eframe::NativeOptions::default(); eframe::run_simple_native("My egui App", options, move |ctx, _frame| { egui::CentralPanel::default().show(ctx, |ui| { + if ui.button("Reset egui memory").clicked() { + ctx.memory_mut(|mem| *mem = Default::default()); + } + + ui.separator(); + ui.label("The menu should be as wide as the widest button"); ui.menu_button("Click for menu", |ui| { let _ = ui.button("Narrow").clicked(); @@ -20,6 +26,23 @@ fn main() -> eframe::Result<()> { ui.label("A separator:"); ui.separator(); }); + + ui.separator(); + + let alternatives = [ + "Short", + "Min", + "Very very long text that will extend", + "Short", + ]; + let mut selected = 1; + + egui::ComboBox::from_label("ComboBox").show_index( + ui, + &mut selected, + alternatives.len(), + |i| alternatives[i], + ); }); }) }