diff --git a/CHANGELOG.md b/CHANGELOG.md index aa86e9d9..636c3886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,11 +55,11 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * Renamed `Plot::custom_label_func` to `Plot::label_formatter` ([#1235](https://github.com/emilk/egui/pull/1235)). * Tooltips that don't fit the window don't flicker anymore ([#1240](https://github.com/emilk/egui/pull/1240)). * `Areas::layer_id_at` ignores non interatable layers (i.e. Tooltips) ([#1240](https://github.com/emilk/egui/pull/1240)). +* `ScrollArea`:s will not shrink below a certain minimum size, set by `min_scrolled_width/min_scrolled_height` ([1255](https://github.com/emilk/egui/pull/1255)). ### Fixed 🐛 * Context menus now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043)). * Plot `Orientation` was not public, although fields using this type were ([#1130](https://github.com/emilk/egui/pull/1130)). -* Fixed `enable_drag` for Windows ([#1108](https://github.com/emilk/egui/pull/1108)). * Calling `Context::set_pixels_per_point` before the first frame will now work. * Tooltips that don't fit the window don't flicker anymore ([#1240](https://github.com/emilk/egui/pull/1240)). * Scroll areas now follow text cursor ([1252](https://github.com/emilk/egui/pull/1252)). diff --git a/eframe/CHANGELOG.md b/eframe/CHANGELOG.md index d2861f73..77842f5c 100644 --- a/eframe/CHANGELOG.md +++ b/eframe/CHANGELOG.md @@ -12,6 +12,7 @@ NOTE: [`egui_web`](../egui_web/CHANGELOG.md), [`egui-winit`](../egui-winit/CHANG * Fix horizontal scrolling direction on Linux. * Added `App::on_exit_event` ([#1038](https://github.com/emilk/egui/pull/1038)) * Added `NativeOptions::initial_window_pos`. +* Fixed `enable_drag` for Windows ([#1108](https://github.com/emilk/egui/pull/1108)). * Shift-scroll will now result in horizontal scrolling on all platforms ([#1136](https://github.com/emilk/egui/pull/1136)). * Log using the `tracing` crate. Log to stdout by adding `tracing_subscriber::fmt::init();` to your `main` ([#1192](https://github.com/emilk/egui/pull/1192)). * Expose all parts of the location/url in `frame.info().web_info` ([#1258](https://github.com/emilk/egui/pull/1258)). diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index e86a435c..3d9254ae 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -81,6 +81,7 @@ pub struct ScrollArea { has_bar: [bool; 2], auto_shrink: [bool; 2], max_size: Vec2, + min_scrolled_size: Vec2, always_show_scroll: bool, id_source: Option, offset_x: Option, @@ -123,6 +124,7 @@ impl ScrollArea { has_bar, auto_shrink: [true; 2], max_size: Vec2::INFINITY, + min_scrolled_size: Vec2::splat(64.0), always_show_scroll: false, id_source: None, offset_x: None, @@ -152,6 +154,28 @@ impl ScrollArea { self } + /// The minimum width of a horizontal scroll area which requires scroll bars. + /// + /// The `ScrollArea` will only become smaller than this if the content is smaller than this + /// (and so we don't require scroll bars). + /// + /// Default: `64.0`. + pub fn min_scrolled_width(mut self, min_scrolled_width: f32) -> Self { + self.min_scrolled_size.x = min_scrolled_width; + self + } + + /// The minimum height of a vertical scroll area which requires scroll bars. + /// + /// The `ScrollArea` will only become smaller than this if the content is smaller than this + /// (and so we don't require scroll bars). + /// + /// Default: `64.0`. + pub fn min_scrolled_height(mut self, min_scrolled_height: f32) -> Self { + self.min_scrolled_size.y = min_scrolled_height; + self + } + /// If `false` (default), the scroll bar will be hidden when not needed/ /// If `true`, the scroll bar will always be displayed even if not needed. pub fn always_show_scroll(mut self, always_show_scroll: bool) -> Self { @@ -288,6 +312,7 @@ impl ScrollArea { has_bar, auto_shrink, max_size, + min_scrolled_size, always_show_scroll, id_source, offset_x, @@ -329,27 +354,39 @@ impl ScrollArea { let outer_size = available_outer.size().at_most(max_size); - let inner_size = outer_size - current_bar_use; + let inner_size = { + let mut inner_size = outer_size - current_bar_use; + + // Don't go so far that we shrink to zero. + // In particular, if we put a `ScrollArea` inside of a `ScrollArea`, the inner + // one shouldn't collapse into nothingness. + // See https://github.com/emilk/egui/issues/1097 + for d in 0..2 { + if has_bar[d] { + inner_size[d] = inner_size[d].max(min_scrolled_size[d]); + } + } + inner_size + }; + let inner_rect = Rect::from_min_size(available_outer.min, inner_size); - let mut inner_child_max_size = inner_size; + let mut content_max_size = inner_size; if true { // Tell the inner Ui to *try* to fit the content without needing to scroll, - // i.e. better to wrap text than showing a horizontal scrollbar! + // i.e. better to wrap text and shrink images than showing a horizontal scrollbar! } else { // Tell the inner Ui to use as much space as possible, we can scroll to see it! for d in 0..2 { if has_bar[d] { - inner_child_max_size[d] = f32::INFINITY; + content_max_size[d] = f32::INFINITY; } } } - let mut content_ui = ui.child_ui( - Rect::from_min_size(inner_rect.min - state.offset, inner_child_max_size), - *ui.layout(), - ); + 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: