|
| 1 | +//! See [`ScrollArea`] for docs. |
| 2 | +
|
1 | 3 | #![allow(clippy::needless_range_loop)] |
2 | 4 |
|
3 | 5 | use std::ops::{Add, AddAssign, BitOr, BitOrAssign}; |
4 | 6 |
|
5 | 7 | use emath::GuiRounding as _; |
| 8 | +use epaint::Margin; |
6 | 9 |
|
7 | 10 | use crate::{ |
8 | 11 | Context, CursorIcon, Id, NumExt as _, Pos2, Rangef, Rect, Response, Sense, Ui, UiBuilder, |
@@ -258,7 +261,7 @@ impl AddAssign for ScrollSource { |
258 | 261 | /// ### Coordinate system |
259 | 262 | /// * content: size of contents (generally large; that's why we want scroll bars) |
260 | 263 | /// * outer: size of scroll area including scroll bar(s) |
261 | | -/// * inner: excluding scroll bar(s). The area we clip the contents to. |
| 264 | +/// * inner: excluding scroll bar(s). The area we clip the contents to. Includes `content_margin`. |
262 | 265 | /// |
263 | 266 | /// If the floating scroll bars settings is turned on then `inner == outer`. |
264 | 267 | /// |
@@ -294,6 +297,8 @@ pub struct ScrollArea { |
294 | 297 | scroll_source: ScrollSource, |
295 | 298 | wheel_scroll_multiplier: Vec2, |
296 | 299 |
|
| 300 | + content_margin: Option<Margin>, |
| 301 | + |
297 | 302 | /// If true for vertical or horizontal the scroll wheel will stick to the |
298 | 303 | /// end position until user manually changes position. It will become true |
299 | 304 | /// again once scroll handle makes contact with end. |
@@ -346,6 +351,7 @@ impl ScrollArea { |
346 | 351 | on_drag_cursor: None, |
347 | 352 | scroll_source: ScrollSource::default(), |
348 | 353 | wheel_scroll_multiplier: Vec2::splat(1.0), |
| 354 | + content_margin: None, |
349 | 355 | stick_to_end: Vec2b::FALSE, |
350 | 356 | animated: true, |
351 | 357 | } |
@@ -593,6 +599,18 @@ impl ScrollArea { |
593 | 599 | self.direction_enabled[0] || self.direction_enabled[1] |
594 | 600 | } |
595 | 601 |
|
| 602 | + /// Extra margin added around the contents. |
| 603 | + /// |
| 604 | + /// The scroll bars will be either on top of this margin, or outside of it, |
| 605 | + /// depending on the value of [`crate::style::ScrollStyle::floating`]. |
| 606 | + /// |
| 607 | + /// Default: [`crate::style::ScrollStyle::content_margin`]. |
| 608 | + #[inline] |
| 609 | + pub fn content_margin(mut self, margin: impl Into<Margin>) -> Self { |
| 610 | + self.content_margin = Some(margin.into()); |
| 611 | + self |
| 612 | + } |
| 613 | + |
596 | 614 | /// The scroll handle will stick to the rightmost position even while the content size |
597 | 615 | /// changes dynamically. This can be useful to simulate text scrollers coming in from right |
598 | 616 | /// hand side. The scroll handle remains stuck until user manually changes position. Once "unstuck" |
@@ -644,7 +662,7 @@ struct Prepared { |
644 | 662 | scroll_bar_visibility: ScrollBarVisibility, |
645 | 663 | scroll_bar_rect: Option<Rect>, |
646 | 664 |
|
647 | | - /// Where on the screen the content is (excludes scroll bars). |
| 665 | + /// Where on the screen the content is (excludes scroll bars; includes `content_margin`). |
648 | 666 | inner_rect: Rect, |
649 | 667 |
|
650 | 668 | content_ui: Ui, |
@@ -683,6 +701,7 @@ impl ScrollArea { |
683 | 701 | on_drag_cursor, |
684 | 702 | scroll_source, |
685 | 703 | wheel_scroll_multiplier, |
| 704 | + content_margin: _, // Used elsewhere |
686 | 705 | stick_to_end, |
687 | 706 | animated, |
688 | 707 | } = self; |
@@ -983,10 +1002,21 @@ impl ScrollArea { |
983 | 1002 | ui: &mut Ui, |
984 | 1003 | add_contents: Box<dyn FnOnce(&mut Ui, Rect) -> R + 'c>, |
985 | 1004 | ) -> ScrollAreaOutput<R> { |
| 1005 | + let margin = self |
| 1006 | + .content_margin |
| 1007 | + .unwrap_or_else(|| ui.spacing().scroll.content_margin); |
| 1008 | + |
986 | 1009 | let mut prepared = self.begin(ui); |
987 | 1010 | let id = prepared.id; |
988 | 1011 | let inner_rect = prepared.inner_rect; |
989 | | - let inner = add_contents(&mut prepared.content_ui, prepared.viewport); |
| 1012 | + |
| 1013 | + let inner = crate::Frame::NONE |
| 1014 | + .inner_margin(margin) |
| 1015 | + .show(&mut prepared.content_ui, |ui| { |
| 1016 | + add_contents(ui, prepared.viewport) |
| 1017 | + }) |
| 1018 | + .inner; |
| 1019 | + |
990 | 1020 | let (content_size, state) = prepared.end(ui); |
991 | 1021 | ScrollAreaOutput { |
992 | 1022 | inner, |
|
0 commit comments