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

Fix Ui::scroll_with_delta only scrolling if the ScrollArea is focused #4303

Merged
merged 7 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
55 changes: 31 additions & 24 deletions crates/egui/src/containers/scroll_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,15 +782,21 @@ impl Prepared {

let content_size = content_ui.min_size();

let scroll_delta = content_ui
.ctx()
.frame_state_mut(|state| std::mem::take(&mut state.scroll_delta));

for d in 0..2 {
let mut delta = scroll_delta[d];

// We always take both scroll targets regardless of which scroll axes are enabled. This
// is to avoid them leaking to other scroll areas.
let scroll_target = content_ui
.ctx()
.frame_state_mut(|state| state.scroll_target[d].take());

if scroll_enabled[d] {
if let Some((target_range, align)) = scroll_target {
delta += if let Some((target_range, align)) = scroll_target {
let min = content_ui.min_rect().min[d];
let clip_rect = content_ui.clip_rect();
let visible_range = min..=min + clip_rect.size()[d];
Expand All @@ -799,7 +805,7 @@ impl Prepared {
let clip_end = clip_rect.max[d];
let mut spacing = ui.spacing().item_spacing[d];

let delta = if let Some(align) = align {
if let Some(align) = align {
let center_factor = align.to_factor();

let offset =
Expand All @@ -816,31 +822,32 @@ impl Prepared {
} else {
// Ui is already in view, no need to adjust scroll.
0.0
};
}
} else {
0.0
};

if delta != 0.0 {
let target_offset = state.offset[d] + delta;
if delta != 0.0 {
let target_offset = state.offset[d] + delta;

if !animated {
state.offset[d] = target_offset;
} else if let Some(animation) = &mut state.offset_target[d] {
// For instance: the user is continuously calling `ui.scroll_to_cursor`,
// so we don't want to reset the animation, but perhaps update the target:
animation.target_offset = target_offset;
} else {
// The further we scroll, the more time we take.
// TODO(emilk): let users configure this in `Style`.
let now = ui.input(|i| i.time);
let points_per_second = 1000.0;
let animation_duration =
(delta.abs() / points_per_second).clamp(0.1, 0.3);
state.offset_target[d] = Some(ScrollTarget {
animation_time_span: (now, now + animation_duration as f64),
target_offset,
});
}
ui.ctx().request_repaint();
if !animated {
state.offset[d] = target_offset;
} else if let Some(animation) = &mut state.offset_target[d] {
// For instance: the user is continuously calling `ui.scroll_to_cursor`,
// so we don't want to reset the animation, but perhaps update the target:
animation.target_offset = target_offset;
} else {
// The further we scroll, the more time we take.
// TODO(emilk): let users configure this in `Style`.
let now = ui.input(|i| i.time);
let points_per_second = 1000.0;
let animation_duration = (delta.abs() / points_per_second).clamp(0.1, 0.3);
state.offset_target[d] = Some(ScrollTarget {
animation_time_span: (now, now + animation_duration as f64),
target_offset,
});
}
ui.ctx().request_repaint();
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion crates/egui/src/frame_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ pub(crate) struct FrameState {
/// Initialized to `None` at the start of each frame.
pub(crate) tooltip_state: Option<TooltipFrameState>,

/// horizontal, vertical
/// The current scroll area should scroll to this range (horizontal, vertical).
pub(crate) scroll_target: [Option<(Rangef, Option<Align>)>; 2],

/// The current scroll area should scroll by this much.
pub(crate) scroll_delta: Vec2,

#[cfg(feature = "accesskit")]
pub(crate) accesskit_state: Option<AccessKitFrameState>,

Expand All @@ -63,6 +66,7 @@ impl Default for FrameState {
used_by_panels: Rect::NAN,
tooltip_state: None,
scroll_target: [None, None],
scroll_delta: Vec2::default(),
#[cfg(feature = "accesskit")]
accesskit_state: None,
highlight_this_frame: Default::default(),
Expand All @@ -84,6 +88,7 @@ impl FrameState {
used_by_panels,
tooltip_state,
scroll_target,
scroll_delta,
#[cfg(feature = "accesskit")]
accesskit_state,
highlight_this_frame,
Expand All @@ -99,6 +104,7 @@ impl FrameState {
*used_by_panels = Rect::NOTHING;
*tooltip_state = None;
*scroll_target = [None, None];
*scroll_delta = Vec2::default();

#[cfg(debug_assertions)]
{
Expand Down
5 changes: 3 additions & 2 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,8 +1091,9 @@ impl Ui {
/// # });
/// ```
pub fn scroll_with_delta(&self, delta: Vec2) {
self.ctx()
.input_mut(|input| input.smooth_scroll_delta += delta);
self.ctx().frame_state_mut(|state| {
state.scroll_delta = delta;
emilk marked this conversation as resolved.
Show resolved Hide resolved
});
}
}

Expand Down
8 changes: 8 additions & 0 deletions crates/egui_demo_lib/src/demo/scrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ impl super::View for ScrollTo {
let mut go_to_scroll_offset = false;
let mut scroll_top = false;
let mut scroll_bottom = false;
let mut scroll_delta = None;

ui.horizontal(|ui| {
ui.label("Scroll to a specific item index:");
Expand Down Expand Up @@ -292,6 +293,9 @@ impl super::View for ScrollTo {
ui.horizontal(|ui| {
scroll_top |= ui.button("Scroll to top").clicked();
scroll_bottom |= ui.button("Scroll to bottom").clicked();
if ui.button("Scroll down by 64px").clicked() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nicer demo with two buttons, using ⬆⬇ arrows instead of the text (egui supports those emojis)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Like this?

Bildschirmaufnahme.2024-05-27.um.23.26.14.mov

scroll_delta = Some(Vec2::new(0.0, 64.0));
}
});

let mut scroll_area = ScrollArea::vertical().max_height(200.0).auto_shrink(false);
Expand All @@ -305,6 +309,10 @@ impl super::View for ScrollTo {
if scroll_top {
ui.scroll_to_cursor(Some(Align::TOP));
}
if let Some(scroll_delta) = scroll_delta {
ui.scroll_with_delta(scroll_delta);
}

ui.vertical(|ui| {
for item in 1..=num_items {
if track_item && item == self.track_item {
Expand Down
Loading