feat(combobox): implement text wrap for selected text (#2272)

* feat(combobox): implement text wrap for selected text

* chore(changelog): add line to changelog

* feat(combobox-text-wrap): make wrap boolean

- specifying a wrap width didn't really make sense so now it's boolean
- the selected text will now use the maximum available width while still
  respecting the spacing and icon coming after it

* feat(combobox-text-wrap): update changelog
This commit is contained in:
Robert Walter 2022-11-16 11:57:27 +01:00 committed by GitHub
parent 0ba04184d5
commit 0ff1ee3893
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 3 deletions

View file

@ -18,6 +18,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Added `egui::gui_zoom` module with helpers for scaling the whole GUI of an app ([#2239](https://github.com/emilk/egui/pull/2239)). * Added `egui::gui_zoom` module with helpers for scaling the whole GUI of an app ([#2239](https://github.com/emilk/egui/pull/2239)).
* You can now put one interactive widget on top of another, and only one will get interaction at a time ([#2244](https://github.com/emilk/egui/pull/2244)). * You can now put one interactive widget on top of another, and only one will get interaction at a time ([#2244](https://github.com/emilk/egui/pull/2244)).
* Added `ui.centered`. * Added `ui.centered`.
* Added possibility to enable text wrap for the selected text of `egui::ComboBox` ([#2272](https://github.com/emilk/egui/pull/2244))
* Added `Area::constrain` and `Window::constrain` which constrains area to the screen bounds. ([#2270](https://github.com/emilk/egui/pull/2270)). * Added `Area::constrain` and `Window::constrain` which constrains area to the screen bounds. ([#2270](https://github.com/emilk/egui/pull/2270)).
* Added `Area::pivot` and `Window::pivot` which controls what part of the window to position. ([#2303](https://github.com/emilk/egui/pull/2303)). * Added `Area::pivot` and `Window::pivot` which controls what part of the window to position. ([#2303](https://github.com/emilk/egui/pull/2303)).

View file

@ -36,6 +36,7 @@ pub struct ComboBox {
selected_text: WidgetText, selected_text: WidgetText,
width: Option<f32>, width: Option<f32>,
icon: Option<IconPainter>, icon: Option<IconPainter>,
wrap_enabled: bool,
} }
impl ComboBox { impl ComboBox {
@ -47,6 +48,7 @@ impl ComboBox {
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
icon: None, icon: None,
wrap_enabled: false,
} }
} }
@ -59,6 +61,7 @@ impl ComboBox {
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
icon: None, icon: None,
wrap_enabled: false,
} }
} }
@ -70,6 +73,7 @@ impl ComboBox {
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
icon: None, icon: None,
wrap_enabled: false,
} }
} }
@ -124,6 +128,12 @@ impl ComboBox {
self self
} }
/// Controls whether text wrap is used for the selected text
pub fn wrap(mut self, wrap: bool) -> Self {
self.wrap_enabled = wrap;
self
}
/// Show the combo box, with the given ui code for the menu contents. /// Show the combo box, with the given ui code for the menu contents.
/// ///
/// Returns `InnerResponse { inner: None }` if the combo box is closed. /// Returns `InnerResponse { inner: None }` if the combo box is closed.
@ -146,6 +156,7 @@ impl ComboBox {
selected_text, selected_text,
width, width,
icon, icon,
wrap_enabled,
} = self; } = self;
let button_id = ui.make_persistent_id(id_source); let button_id = ui.make_persistent_id(id_source);
@ -154,7 +165,14 @@ impl ComboBox {
if let Some(width) = width { if let Some(width) = width {
ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later. ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later.
} }
let mut ir = combo_box_dyn(ui, button_id, selected_text, menu_contents, icon); let mut ir = combo_box_dyn(
ui,
button_id,
selected_text,
menu_contents,
icon,
wrap_enabled,
);
if let Some(label) = label { if let Some(label) = label {
ir.response ir.response
.widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text())); .widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text()));
@ -221,6 +239,7 @@ fn combo_box_dyn<'c, R>(
selected_text: WidgetText, selected_text: WidgetText,
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
icon: Option<IconPainter>, icon: Option<IconPainter>,
wrap_enabled: bool,
) -> InnerResponse<Option<R>> { ) -> InnerResponse<Option<R>> {
let popup_id = button_id.with("popup"); let popup_id = button_id.with("popup");
@ -244,10 +263,16 @@ fn combo_box_dyn<'c, R>(
let button_response = button_frame(ui, button_id, is_popup_open, Sense::click(), |ui| { let button_response = button_frame(ui, button_id, is_popup_open, Sense::click(), |ui| {
// We don't want to change width when user selects something new // We don't want to change width when user selects something new
let full_minimum_width = ui.spacing().slider_width; let full_minimum_width = wrap_enabled
.then(|| ui.available_width() - ui.spacing().item_spacing.x * 2.0)
.unwrap_or_else(|| ui.spacing().slider_width);
let icon_size = Vec2::splat(ui.spacing().icon_width); let icon_size = Vec2::splat(ui.spacing().icon_width);
let wrap_width = wrap_enabled
.then(|| ui.available_width() - ui.spacing().item_spacing.x - icon_size.x)
.unwrap_or(f32::INFINITY);
let galley = selected_text.into_galley(ui, Some(false), f32::INFINITY, TextStyle::Button); let galley =
selected_text.into_galley(ui, Some(wrap_enabled), wrap_width, TextStyle::Button);
let width = galley.size().x + ui.spacing().item_spacing.x + icon_size.x; let width = galley.size().x + ui.spacing().item_spacing.x + icon_size.x;
let width = width.at_least(full_minimum_width); let width = width.at_least(full_minimum_width);