diff --git a/CHANGELOG.md b/CHANGELOG.md index f2306c7c8fc..39a4a83ab06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * Renamed `Frame::margin` to `Frame::inner_margin`. * Renamed `AlphaImage` to `FontImage` to discourage any other use for it ([#1412](https://github.com/emilk/egui/pull/1412)). * Warnings will pe painted on screen when there is an `Id` clash for `Grid`, `Plot` or `ScrollArea` ([#1452](https://github.com/emilk/egui/pull/1452)). +* `Checkbox` and `RadioButton` with an empty label (`""`) will now take up much less space ([#1456](https://github.com/emilk/egui/pull/1456)). ### Fixed 🐛 * Fixed ComboBoxes always being rendered left-aligned ([#1304](https://github.com/emilk/egui/pull/1304)). diff --git a/egui/src/style.rs b/egui/src/style.rs index 96c3f8be0ea..84632df9e77 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -608,7 +608,7 @@ impl Default for Spacing { slider_width: 100.0, text_edit_width: 280.0, icon_width: 14.0, - icon_spacing: 0.0, + icon_spacing: 4.0, tooltip_width: 600.0, combo_height: 200.0, scroll_bar_width: 8.0, diff --git a/egui/src/widgets/button.rs b/egui/src/widgets/button.rs index 48f727d4a64..9444c676c90 100644 --- a/egui/src/widgets/button.rs +++ b/egui/src/widgets/button.rs @@ -237,15 +237,23 @@ impl<'a> Widget for Checkbox<'a> { let spacing = &ui.spacing(); let icon_width = spacing.icon_width; - let icon_spacing = ui.spacing().icon_spacing; - let button_padding = spacing.button_padding; - let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding; + let icon_spacing = spacing.icon_spacing; - let wrap_width = ui.available_width() - total_extra.x; - let text = text.into_galley(ui, None, wrap_width, TextStyle::Button); + let (text, mut desired_size) = if text.is_empty() { + (None, vec2(icon_width, 0.0)) + } else { + let total_extra = vec2(icon_width + icon_spacing, 0.0); + + let wrap_width = ui.available_width() - total_extra.x; + let text = text.into_galley(ui, None, wrap_width, TextStyle::Button); + + let mut desired_size = total_extra + text.size(); + desired_size = desired_size.at_least(spacing.interact_size); - let mut desired_size = total_extra + text.size(); - desired_size = desired_size.at_least(spacing.interact_size); + (Some(text), desired_size) + }; + + desired_size = desired_size.at_least(Vec2::splat(spacing.interact_size.y)); desired_size.y = desired_size.y.max(icon_width); let (rect, mut response) = ui.allocate_exact_size(desired_size, Sense::click()); @@ -253,15 +261,17 @@ impl<'a> Widget for Checkbox<'a> { *checked = !*checked; response.mark_changed(); } - response.widget_info(|| WidgetInfo::selected(WidgetType::Checkbox, *checked, text.text())); + response.widget_info(|| { + WidgetInfo::selected( + WidgetType::Checkbox, + *checked, + text.as_ref().map_or("", |x| x.text()), + ) + }); if ui.is_rect_visible(rect) { // let visuals = ui.style().interact_selectable(&response, *checked); // too colorful let visuals = ui.style().interact(&response); - let text_pos = pos2( - rect.min.x + button_padding.x + icon_width + icon_spacing, - rect.center().y - 0.5 * text.size().y, - ); let (small_icon_rect, big_icon_rect) = ui.spacing().icon_rectangles(rect); ui.painter().add(epaint::RectShape { rect: big_icon_rect.expand(visuals.expansion), @@ -281,8 +291,13 @@ impl<'a> Widget for Checkbox<'a> { visuals.fg_stroke, )); } - - text.paint_with_visuals(ui.painter(), text_pos, visuals); + if let Some(text) = text { + let text_pos = pos2( + rect.min.x + icon_width + icon_spacing, + rect.center().y - 0.5 * text.size().y, + ); + text.paint_with_visuals(ui.painter(), text_pos, visuals); + } } response @@ -329,27 +344,37 @@ impl Widget for RadioButton { fn ui(self, ui: &mut Ui) -> Response { let RadioButton { checked, text } = self; - let icon_width = ui.spacing().icon_width; - let icon_spacing = ui.spacing().icon_spacing; - let button_padding = ui.spacing().button_padding; - let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding; + let spacing = &ui.spacing(); + let icon_width = spacing.icon_width; + let icon_spacing = spacing.icon_spacing; + + let (text, mut desired_size) = if text.is_empty() { + (None, vec2(icon_width, 0.0)) + } else { + let total_extra = vec2(icon_width + icon_spacing, 0.0); + + let wrap_width = ui.available_width() - total_extra.x; + let text = text.into_galley(ui, None, wrap_width, TextStyle::Button); - let wrap_width = ui.available_width() - total_extra.x; - let text = text.into_galley(ui, None, wrap_width, TextStyle::Button); + let mut desired_size = total_extra + text.size(); + desired_size = desired_size.at_least(spacing.interact_size); - let mut desired_size = total_extra + text.size(); - desired_size = desired_size.at_least(ui.spacing().interact_size); + (Some(text), desired_size) + }; + + desired_size = desired_size.at_least(Vec2::splat(spacing.interact_size.y)); desired_size.y = desired_size.y.max(icon_width); let (rect, response) = ui.allocate_exact_size(desired_size, Sense::click()); - response - .widget_info(|| WidgetInfo::selected(WidgetType::RadioButton, checked, text.text())); - if ui.is_rect_visible(rect) { - let text_pos = pos2( - rect.min.x + button_padding.x + icon_width + icon_spacing, - rect.center().y - 0.5 * text.size().y, - ); + response.widget_info(|| { + WidgetInfo::selected( + WidgetType::RadioButton, + checked, + text.as_ref().map_or("", |x| x.text()), + ) + }); + if ui.is_rect_visible(rect) { // let visuals = ui.style().interact_selectable(&response, checked); // too colorful let visuals = ui.style().interact(&response); @@ -374,7 +399,13 @@ impl Widget for RadioButton { }); } - text.paint_with_visuals(ui.painter(), text_pos, visuals); + if let Some(text) = text { + let text_pos = pos2( + rect.min.x + icon_width + icon_spacing, + rect.center().y - 0.5 * text.size().y, + ); + text.paint_with_visuals(ui.painter(), text_pos, visuals); + } } response diff --git a/egui_demo_lib/src/apps/demo/misc_demo_window.rs b/egui_demo_lib/src/apps/demo/misc_demo_window.rs index 949dedc2af3..f05eda14bf8 100644 --- a/egui_demo_lib/src/apps/demo/misc_demo_window.rs +++ b/egui_demo_lib/src/apps/demo/misc_demo_window.rs @@ -16,6 +16,9 @@ pub struct MiscDemoWindow { colors: ColorWidgets, tree: Tree, box_painting: BoxPainting, + + dummy_bool: bool, + dummy_usize: usize, } impl Default for MiscDemoWindow { @@ -31,6 +34,9 @@ impl Default for MiscDemoWindow { colors: Default::default(), tree: Tree::demo(), box_painting: Default::default(), + + dummy_bool: false, + dummy_usize: 0, } } } @@ -80,6 +86,28 @@ impl View for MiscDemoWindow { .default_open(false) .show(ui, |ui| self.tree.ui(ui)); + CollapsingHeader::new("Checkboxes") + .default_open(false) + .show(ui, |ui| { + ui.label("Checkboxes with empty labels take up very little space:"); + ui.spacing_mut().item_spacing = Vec2::ZERO; + ui.horizontal_wrapped(|ui| { + for _ in 0..64 { + ui.checkbox(&mut self.dummy_bool, ""); + } + }); + ui.checkbox(&mut self.dummy_bool, "checkbox"); + + ui.label("Radiobuttons are similar:"); + ui.spacing_mut().item_spacing = Vec2::ZERO; + ui.horizontal_wrapped(|ui| { + for i in 0..64 { + ui.radio_value(&mut self.dummy_usize, i, ""); + } + }); + ui.radio_value(&mut self.dummy_usize, 64, "radio_value"); + }); + ui.collapsing("Columns", |ui| { ui.add(Slider::new(&mut self.num_columns, 1..=10).text("Columns")); ui.columns(self.num_columns, |cols| {