From 55589a130855818b9f2754910f40baa11cc21ef3 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 10:58:12 +0100 Subject: [PATCH 1/8] Add Separator::grow and Separator::shrink --- crates/egui/src/widgets/separator.rs | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/egui/src/widgets/separator.rs b/crates/egui/src/widgets/separator.rs index 7855611acb4..1c0ee1dfede 100644 --- a/crates/egui/src/widgets/separator.rs +++ b/crates/egui/src/widgets/separator.rs @@ -14,6 +14,7 @@ use crate::*; #[must_use = "You should put this widget in an ui with `ui.add(widget);`"] pub struct Separator { spacing: f32, + grow: f32, is_horizontal_line: Option, } @@ -21,6 +22,7 @@ impl Default for Separator { fn default() -> Self { Self { spacing: 6.0, + grow: 0.0, is_horizontal_line: None, } } @@ -28,12 +30,19 @@ impl Default for Separator { impl Separator { /// How much space we take up. The line is painted in the middle of this. + /// + /// In a vertical layout, with a horizontal Separator, + /// this is the height of the separator widget. + /// + /// In a horizontal layout, with a vertical Separator, + /// this is the width of the separator widget. pub fn spacing(mut self, spacing: f32) -> Self { self.spacing = spacing; self } /// Explicitly ask for a horizontal line. + /// /// By default you will get a horizontal line in vertical layouts, /// and a vertical line in horizontal layouts. pub fn horizontal(mut self) -> Self { @@ -42,18 +51,40 @@ impl Separator { } /// Explicitly ask for a vertical line. + /// /// By default you will get a horizontal line in vertical layouts, /// and a vertical line in horizontal layouts. pub fn vertical(mut self) -> Self { self.is_horizontal_line = Some(false); self } + + /// Extend each end of the separator line by this much. + /// + /// The default is to take up the available width/height of the parent. + /// + /// This will make the line extend outside the parent ui. + pub fn grow(mut self, extra: f32) -> Self { + self.grow += extra; + self + } + + /// Contract each end of the separator line by this much. + /// + /// The default is to take up the available width/height of the parent. + /// + /// This effectively adds margins to the line. + pub fn shrink(mut self, shrink: f32) -> Self { + self.grow -= shrink; + self + } } impl Widget for Separator { fn ui(self, ui: &mut Ui) -> Response { let Separator { spacing, + grow, is_horizontal_line, } = self; @@ -75,14 +106,14 @@ impl Widget for Separator { let painter = ui.painter(); if is_horizontal_line { painter.hline( - rect.x_range(), + (rect.left() - grow)..=(rect.right() + grow), painter.round_to_pixel(rect.center().y), stroke, ); } else { painter.vline( painter.round_to_pixel(rect.center().x), - rect.y_range(), + (rect.top() - grow)..=(rect.bottom() + grow), stroke, ); } From 63c2a0199989b44f8baeb0803d58420d42ea1255 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 10:58:35 +0100 Subject: [PATCH 2/8] Be more conservative with the clipping in ScrollArea:s --- crates/egui/src/containers/scroll_area.rs | 25 ++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 80158f52d30..8fa86c58619 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -426,15 +426,26 @@ impl ScrollArea { let content_max_rect = Rect::from_min_size(inner_rect.min - state.offset, content_max_size); let mut content_ui = ui.child_ui(content_max_rect, *ui.layout()); - let mut content_clip_rect = inner_rect.expand(ui.visuals().clip_rect_margin); - content_clip_rect = content_clip_rect.intersect(ui.clip_rect()); - // Nice handling of forced resizing beyond the possible: - for d in 0..2 { - if !has_bar[d] { - content_clip_rect.max[d] = ui.clip_rect().max[d] - current_bar_use[d]; + + { + // Clip the content, but only when we really need to: + let clip_rect_margin = ui.visuals().clip_rect_margin; + let mut content_clip_rect = ui.clip_rect(); + for d in 0..2 { + if has_bar[d] { + if state.content_is_too_large[d] { + content_clip_rect.min[d] = inner_rect.min[d] - clip_rect_margin; + content_clip_rect.max[d] = inner_rect.max[d] + clip_rect_margin; + } + + if state.show_scroll[d] { + // Make sure content doesn't cover scroll bars: + content_clip_rect.max[1 - d] = inner_rect.max[1 - d] + clip_rect_margin; + } + } } + content_ui.set_clip_rect(content_clip_rect); } - content_ui.set_clip_rect(content_clip_rect); let viewport = Rect::from_min_size(Pos2::ZERO + state.offset, inner_size); From 25c3244f4b76187826bacd05dc2456cfcc906a30 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 10:58:49 +0100 Subject: [PATCH 3/8] Add test of the growing separator --- crates/egui_demo_lib/src/demo/window_with_panels.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/egui_demo_lib/src/demo/window_with_panels.rs b/crates/egui_demo_lib/src/demo/window_with_panels.rs index 4d5f1140251..5518f218aed 100644 --- a/crates/egui_demo_lib/src/demo/window_with_panels.rs +++ b/crates/egui_demo_lib/src/demo/window_with_panels.rs @@ -85,6 +85,8 @@ fn lorem_ipsum(ui: &mut egui::Ui) { egui::Layout::top_down(egui::Align::LEFT).with_cross_justify(true), |ui| { ui.label(egui::RichText::new(crate::LOREM_IPSUM_LONG).small().weak()); + ui.add(egui::Separator::default().grow(8.0)); + ui.label(egui::RichText::new(crate::LOREM_IPSUM_LONG).small().weak()); }, ); } From 8aede5fb0c561d01815ac2f5b7397c4afa7baa49 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 11:09:06 +0100 Subject: [PATCH 4/8] Improve test output --- crates/egui_demo_lib/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/egui_demo_lib/src/lib.rs b/crates/egui_demo_lib/src/lib.rs index e4c53cb9346..c061b1aa87e 100644 --- a/crates/egui_demo_lib/src/lib.rs +++ b/crates/egui_demo_lib/src/lib.rs @@ -92,7 +92,8 @@ fn test_egui_zero_window_size() { let clipped_primitives = ctx.tessellate(full_output.shapes); assert!( clipped_primitives.is_empty(), - "There should be nothing to show" + "There should be nothing to show, has at least one primitive with clip_rect: {:?}", + clipped_primitives[0].clip_rect ); } } From e7baa3e6e5d9aee6ec3d37cc781bf52235532a2f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 11:10:31 +0100 Subject: [PATCH 5/8] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 156d88acaf4..0ae6e23812a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,12 +25,14 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG * Add `Context::screen_rect` and `Context::set_cursor_icon` ([#2625](https://github.com/emilk/egui/pull/2625)). * You can turn off the vertical line left of indented regions with `Visuals::indent_has_left_vline` ([#2636](https://github.com/emilk/egui/pull/2636)). * Add `Response.highlight` to highlight a widget ([#2632](https://github.com/emilk/egui/pull/2632)). +* Add `Separator::grow` and `Separator::shrink` ([#2665](https://github.com/emilk/egui/pull/2665)). ### Changed 🔧 * Improved plot grid appearance ([#2412](https://github.com/emilk/egui/pull/2412)). * Improved the algorithm for picking the number of decimals to show when hovering values in the `Plot`. * Default `ComboBox` is now controlled with `Spacing::combo_width` ([#2621](https://github.com/emilk/egui/pull/2621)). * `DragValue` and `Slider` now use the proportional font ([#2638](https://github.com/emilk/egui/pull/2638)). +* `ScrollArea` is less aggressive about clipping its contents ([#2665](https://github.com/emilk/egui/pull/2665)). ### Fixed 🐛 * Trigger `PointerEvent::Released` for drags ([#2507](https://github.com/emilk/egui/pull/2507)). From bc661ddce4423ee85b2fc941a8cd6cddc5226b3c Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 11:19:35 +0100 Subject: [PATCH 6/8] Add back a little bit more clipping --- crates/egui/src/containers/scroll_area.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 8fa86c58619..f2532c6ff72 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -442,6 +442,9 @@ impl ScrollArea { // Make sure content doesn't cover scroll bars: content_clip_rect.max[1 - d] = inner_rect.max[1 - d] + clip_rect_margin; } + } else { + // Nice handling of forced resizing beyond the possible: + content_clip_rect.max[d] = ui.clip_rect().max[d] - current_bar_use[d]; } } content_ui.set_clip_rect(content_clip_rect); From a2b8697af31a12aaecdcb031ee36c6dae21ef481 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 11:32:08 +0100 Subject: [PATCH 7/8] Make the minimum scroll handle length a bit longer --- crates/egui/src/containers/scroll_area.rs | 2 +- crates/egui/src/style.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index f2532c6ff72..559ccb51edb 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -836,7 +836,7 @@ impl Prepared { ), ) }; - let min_handle_size = ui.spacing().scroll_bar_width; + let min_handle_size = ui.spacing().scroll_handle_min_length; if handle_rect.size()[d] < min_handle_size { handle_rect = Rect::from_center_size( handle_rect.center(), diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index ee84144204a..a7a3128769d 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -300,6 +300,9 @@ pub struct Spacing { pub scroll_bar_width: f32, + /// Make sure the scroll handle is at least this big + pub scroll_handle_min_length: f32, + /// Margin between contents and scroll bar. pub scroll_bar_inner_margin: f32, /// Margin between scroll bar and the outer container (e.g. right of a vertical scroll bar). @@ -713,6 +716,7 @@ impl Default for Spacing { tooltip_width: 600.0, combo_height: 200.0, scroll_bar_width: 8.0, + scroll_handle_min_length: 12.0, scroll_bar_inner_margin: 4.0, scroll_bar_outer_margin: 0.0, indent_ends_with_horizontal_line: false, @@ -1040,6 +1044,7 @@ impl Spacing { indent_ends_with_horizontal_line, combo_height, scroll_bar_width, + scroll_handle_min_length, scroll_bar_inner_margin, scroll_bar_outer_margin, } = self; @@ -1072,6 +1077,10 @@ impl Spacing { ui.add(DragValue::new(scroll_bar_width).clamp_range(0.0..=32.0)); ui.label("Scroll-bar width"); }); + ui.horizontal(|ui| { + ui.add(DragValue::new(scroll_handle_min_length).clamp_range(0.0..=32.0)); + ui.label("Scroll-bar handle min length"); + }); ui.horizontal(|ui| { ui.add(DragValue::new(scroll_bar_inner_margin).clamp_range(0.0..=32.0)); ui.label("Scroll-bar inner margin"); From 4fd3b90c9645a241888d01555cba8ba0819ad2c0 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 3 Feb 2023 12:59:39 +0100 Subject: [PATCH 8/8] More clip rect tweaks --- crates/egui/src/containers/scroll_area.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 559ccb51edb..6d929b28773 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -430,6 +430,7 @@ impl ScrollArea { { // Clip the content, but only when we really need to: let clip_rect_margin = ui.visuals().clip_rect_margin; + let scroll_bar_inner_margin = ui.spacing().scroll_bar_inner_margin; let mut content_clip_rect = ui.clip_rect(); for d in 0..2 { if has_bar[d] { @@ -439,14 +440,18 @@ impl ScrollArea { } if state.show_scroll[d] { - // Make sure content doesn't cover scroll bars: - content_clip_rect.max[1 - d] = inner_rect.max[1 - d] + clip_rect_margin; + // Make sure content doesn't cover scroll bars + let tiny_gap = 1.0; + content_clip_rect.max[1 - d] = + inner_rect.max[1 - d] + scroll_bar_inner_margin - tiny_gap; } } else { // Nice handling of forced resizing beyond the possible: content_clip_rect.max[d] = ui.clip_rect().max[d] - current_bar_use[d]; } } + // Make sure we din't accidentally expand the clip rect + content_clip_rect = content_clip_rect.intersect(ui.clip_rect()); content_ui.set_clip_rect(content_clip_rect); }