Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return more info from ScrollArea::show #1166

Merged
merged 1 commit into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* Replaced `Style::body_text_style` with more generic `Style::text_styles` ([#1154](https://github.com/emilk/egui/pull/1154)).
* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)).
* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)).
* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)),
* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)).
* `ScrollArea::show` now returns a `ScrollAreaOutput`, so you might need to add `.inner` after the call to it ([#1166](https://github.com/emilk/egui/pull/1166)).

### Fixed 🐛
* Context menu now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043))
Expand Down
1 change: 1 addition & 0 deletions egui/src/containers/combo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ fn combo_box_dyn<'c, R>(
ScrollArea::vertical()
.max_height(ui.spacing().combo_height)
.show(ui, menu_contents)
.inner
});

InnerResponse {
Expand Down
52 changes: 42 additions & 10 deletions egui/src/containers/scroll_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::*;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub(crate) struct State {
pub struct State {
/// Positive offset means scrolling down/right
offset: Vec2,
pub offset: Vec2,

show_scroll: [bool; 2],

Expand Down Expand Up @@ -51,6 +51,20 @@ impl State {
}
}

pub struct ScrollAreaOutput<R> {
/// What the user closure returned.
pub inner: R,

/// `Id` of the `ScrollArea`.
pub id: Id,

/// The current state of the scroll area.
pub state: State,

/// Where on the screen the content is (excludes scroll bars).
pub inner_rect: Rect,
}

/// Add vertical and/or horizontal scrolling to a contained [`Ui`].
///
/// ```
Expand Down Expand Up @@ -258,6 +272,7 @@ struct Prepared {
/// width of the vertical bar, and the height of the horizontal bar?
current_bar_use: Vec2,
always_show_scroll: bool,
/// Where on the screen the content is (excludes scroll bars).
inner_rect: Rect,
content_ui: Ui,
/// Relative coordinates: the offset and size of the view of the inner UI.
Expand Down Expand Up @@ -365,7 +380,11 @@ impl ScrollArea {
/// Show the `ScrollArea`, and add the contents to the viewport.
///
/// If the inner area can be very long, consider using [`Self::show_rows`] instead.
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> R {
pub fn show<R>(
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> ScrollAreaOutput<R> {
self.show_viewport_dyn(ui, Box::new(|ui, _viewport| add_contents(ui)))
}

Expand All @@ -391,7 +410,7 @@ impl ScrollArea {
row_height_sans_spacing: f32,
total_rows: usize,
add_contents: impl FnOnce(&mut Ui, std::ops::Range<usize>) -> R,
) -> R {
) -> ScrollAreaOutput<R> {
let spacing = ui.spacing().item_spacing;
let row_height_with_spacing = row_height_sans_spacing + spacing.y;
self.show_viewport(ui, |ui, viewport| {
Expand Down Expand Up @@ -420,24 +439,35 @@ impl ScrollArea {
///
/// `add_contents` is past the viewport, which is the relative view of the content.
/// So if the passed rect has min = zero, then show the top left content (the user has not scrolled).
pub fn show_viewport<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui, Rect) -> R) -> R {
pub fn show_viewport<R>(
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui, Rect) -> R,
) -> ScrollAreaOutput<R> {
self.show_viewport_dyn(ui, Box::new(add_contents))
}

fn show_viewport_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui, Rect) -> R + 'c>,
) -> R {
) -> ScrollAreaOutput<R> {
let mut prepared = self.begin(ui);
let ret = add_contents(&mut prepared.content_ui, prepared.viewport);
prepared.end(ui);
ret
let id = prepared.id;
let inner_rect = prepared.inner_rect;
let inner = add_contents(&mut prepared.content_ui, prepared.viewport);
let state = prepared.end(ui);
ScrollAreaOutput {
inner,
id,
state,
inner_rect,
}
}
}

impl Prepared {
fn end(self, ui: &mut Ui) {
fn end(self, ui: &mut Ui) -> State {
let Prepared {
id,
mut state,
Expand Down Expand Up @@ -747,6 +777,8 @@ impl Prepared {
state.show_scroll = show_scroll_this_frame;

state.store(ui.ctx(), id);

state
}
}

Expand Down
2 changes: 1 addition & 1 deletion egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ impl<'open> Window<'open> {
}

if scroll.has_any_bar() {
scroll.show(ui, add_contents)
scroll.show(ui, add_contents).inner
} else {
add_contents(ui)
}
Expand Down
2 changes: 2 additions & 0 deletions egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,9 @@ impl std::ops::BitOrAssign for Response {
/// ```
#[derive(Debug)]
pub struct InnerResponse<R> {
/// What the user closure returned.
pub inner: R,
/// The response of the area.
pub response: Response,
}

Expand Down
46 changes: 24 additions & 22 deletions egui_demo_lib/src/apps/demo/scrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,32 +210,34 @@ impl super::View for ScrollTo {
}

ui.separator();
let (current_scroll, max_scroll) = scroll_area.show(ui, |ui| {
if scroll_top {
ui.scroll_to_cursor(Align::TOP);
}
ui.vertical(|ui| {
for item in 1..=50 {
if track_item && item == self.track_item {
let response =
ui.colored_label(Color32::YELLOW, format!("This is item {}", item));
response.scroll_to_me(self.tack_item_align);
} else {
ui.label(format!("This is item {}", item));
}
let (current_scroll, max_scroll) = scroll_area
.show(ui, |ui| {
if scroll_top {
ui.scroll_to_cursor(Align::TOP);
}
});
ui.vertical(|ui| {
for item in 1..=50 {
if track_item && item == self.track_item {
let response =
ui.colored_label(Color32::YELLOW, format!("This is item {}", item));
response.scroll_to_me(self.tack_item_align);
} else {
ui.label(format!("This is item {}", item));
}
}
});

if scroll_bottom {
ui.scroll_to_cursor(Align::BOTTOM);
}
if scroll_bottom {
ui.scroll_to_cursor(Align::BOTTOM);
}

let margin = ui.visuals().clip_rect_margin;
let margin = ui.visuals().clip_rect_margin;

let current_scroll = ui.clip_rect().top() - ui.min_rect().top() + margin;
let max_scroll = ui.min_rect().height() - ui.clip_rect().height() + 2.0 * margin;
(current_scroll, max_scroll)
});
let current_scroll = ui.clip_rect().top() - ui.min_rect().top() + margin;
let max_scroll = ui.min_rect().height() - ui.clip_rect().height() + 2.0 * margin;
(current_scroll, max_scroll)
})
.inner;
ui.separator();

ui.label(format!(
Expand Down