Browse Source

`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)
pull/4574/head
Emil Ernerfeldt 5 months ago
committed by GitHub
parent
commit
ffbc63e147
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      crates/egui/src/containers/popup.rs
  2. 2
      crates/egui_demo_lib/src/demo/widget_gallery.rs
  3. 23
      tests/test_size_pass/src/main.rs

11
crates/egui/src/containers/popup.rs

@ -307,7 +307,7 @@ pub fn popup_below_widget<R>(
///
/// 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<R>(
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

2
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");

23
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],
);
});
})
}

Loading…
Cancel
Save