Skip to content

Commit

Permalink
Add scroll_delta to FrameState
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmerlin committed Apr 2, 2024
1 parent 46d2303 commit 74d74f9
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 43 deletions.
59 changes: 31 additions & 28 deletions crates/egui/src/containers/scroll_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,12 +768,12 @@ impl Prepared {
for d in 0..2 {
// 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());
let (scroll_target, scroll_delta) = content_ui.ctx().frame_state_mut(|state| {
(state.scroll_target[d].take(), state.scroll_delta[d].take())
});

if scroll_enabled[d] {
if let Some((target_range, align)) = scroll_target {
let mut 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 @@ -782,7 +782,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 @@ -799,29 +799,34 @@ 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 let Some(scroll_delta) = scroll_delta {
delta += scroll_delta;
}

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 delta != 0.0 {
let target_offset = state.offset[d] + delta;

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 Expand Up @@ -851,8 +856,7 @@ impl Prepared {

let max_offset = content_size - inner_rect.size();
let is_hovering_outer_rect = ui.rect_contains_pointer(outer_rect);
let force_current_scroll_area = ui.input(|i| i.force_current_scroll_area);
if scrolling_enabled && is_hovering_outer_rect || force_current_scroll_area {
if scrolling_enabled && is_hovering_outer_rect {
let always_scroll_enabled_direction = ui.style().always_scroll_the_only_direction
&& scroll_enabled[0] != scroll_enabled[1];
for d in 0..2 {
Expand Down Expand Up @@ -880,7 +884,6 @@ impl Prepared {
} else {
input.smooth_scroll_delta[d] = 0.0;
}
input.force_current_scroll_area = false;
});

state.scroll_stuck_to_end[d] = false;
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 (horizontal, vertical).
pub(crate) scroll_delta: [Option<f32>; 2],

#[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: [None, None],
#[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 = [None, None];

#[cfg(debug_assertions)]
{
Expand Down
10 changes: 0 additions & 10 deletions crates/egui/src/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ pub struct InputState {
/// at the end of the frame this will be zero if a scroll-area consumed the delta.
pub smooth_scroll_delta: Vec2,

/// Force the current scroll area to consume the [Self::smooth_scroll_delta], independent of the focus / mouse position.
/// This is used when using [crate::Ui::scroll_with_delta] to scroll the current scroll area.
pub(crate) force_current_scroll_area: bool,

/// Zoom scale factor this frame (e.g. from ctrl-scroll or pinch gesture).
///
/// * `zoom = 1`: no change.
Expand Down Expand Up @@ -158,7 +154,6 @@ impl Default for InputState {
unprocessed_scroll_delta: Vec2::ZERO,
raw_scroll_delta: Vec2::ZERO,
smooth_scroll_delta: Vec2::ZERO,
force_current_scroll_area: false,
zoom_factor_delta: 1.0,
screen_rect: Rect::from_min_size(Default::default(), vec2(10_000.0, 10_000.0)),
pixels_per_point: 1.0,
Expand Down Expand Up @@ -260,7 +255,6 @@ impl InputState {
unprocessed_scroll_delta,
raw_scroll_delta,
smooth_scroll_delta,
force_current_scroll_area: false,
zoom_factor_delta,
screen_rect,
pixels_per_point,
Expand Down Expand Up @@ -1119,7 +1113,6 @@ impl InputState {
unprocessed_scroll_delta,
raw_scroll_delta,
smooth_scroll_delta,
force_current_scroll_area,

zoom_factor_delta,
screen_rect,
Expand Down Expand Up @@ -1164,9 +1157,6 @@ impl InputState {
ui.label(format!(
"smooth_scroll_delta: {smooth_scroll_delta:?} points"
));
ui.label(format!(
"force_current_scroll_area: {force_current_scroll_area}"
));
ui.label(format!("zoom_factor_delta: {zoom_factor_delta:4.2}x"));
ui.label(format!("screen_rect: {screen_rect:?} points"));
ui.label(format!(
Expand Down
5 changes: 2 additions & 3 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,9 +1091,8 @@ impl Ui {
/// # });
/// ```
pub fn scroll_with_delta(&self, delta: Vec2) {
self.ctx().input_mut(|input| {
input.smooth_scroll_delta += delta;
input.force_current_scroll_area = true;
self.ctx().frame_state_mut(|state| {
state.scroll_delta = [Some(delta.x), Some(delta.y)];
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/egui_demo_lib/src/demo/scrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl super::View for ScrollTo {
scroll_top |= ui.button("Scroll to top").clicked();
scroll_bottom |= ui.button("Scroll to bottom").clicked();
if ui.button("Scroll down by 64px").clicked() {
scroll_delta = Some(Vec2::new(0.0, -64.0));
scroll_delta = Some(Vec2::new(0.0, 64.0));
}
});

Expand Down

0 comments on commit 74d74f9

Please sign in to comment.