You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a simple egui scroll view with a bunch of rects in it, when I just make a single fast swipe on the trackpad the scroll moves in jumps/jitters (as shown in the video, it was a single scroll swipe).
To Reproduce
use eframe::egui;
const COLS: usize = 8;
const ROWS: usize = 200;
const RECT_SIZE: f32 = 60.0;
const GAP: f32 = 4.0;
struct App;
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::vertical()
.auto_shrink([false; 2])
.show(ui, |ui| {
let cell = RECT_SIZE + GAP;
let total_w = COLS as f32 * cell - GAP;
let total_h = ROWS as f32 * cell - GAP;
let (rect, _) =
ui.allocate_exact_size(egui::vec2(total_w, total_h), egui::Sense::hover());
let painter = ui.painter();
for row in 0..ROWS {
for col in 0..COLS {
let idx = row * COLS + col;
let hue = idx as f32 / (ROWS * COLS) as f32;
let color =
egui::Color32::from(egui::ecolor::Hsva::new(hue, 0.75, 0.85, 1.0));
let min = rect.min + egui::vec2(col as f32 * cell, row as f32 * cell);
let tile =
egui::Rect::from_min_size(min, egui::vec2(RECT_SIZE, RECT_SIZE));
painter.rect_filled(tile, 4.0, color);
painter.text(
tile.center(),
egui::Align2::CENTER_CENTER,
idx.to_string(),
egui::FontId::proportional(14.0),
egui::Color32::WHITE,
);
}
}
});
});
}
}
fn main() -> eframe::Result<()> {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([640.0, 480.0])
.with_title("egui scroll repro"),
..Default::default()
};
eframe::run_native("repro", options, Box::new(|_cc| Ok(Box::new(App))))
}
Run this example and scroll fast with a trackpad.
For me this is consistently reproducible.
Expected behavior
Screenshots
20260602-0645-36.5288603.mp4
Desktop (please complete the following information):
OS: Windows 11
Additional context
I tried to fix it for myself by driving the scroll offset the raw input data, but I am not sure if this is a good way of doing it.
use eframe::egui;
const COLS: usize = 8;
const ROWS: usize = 200;
const RECT_SIZE: f32 = 60.0;
const GAP: f32 = 4.0;
const EASE_RATE: f32 = 12.0;
const SNAP: f32 = 0.3;
#[derive(Default)]
struct App {
target: f32,
pos: f32,
max_off: f32,
velocity: f32,
had_scroll: bool,
}
impl eframe::App for App {
fn raw_input_hook(&mut self, _ctx: &egui::Context, raw_input: &mut egui::RawInput) {
raw_input.events.retain(|event| {
if let egui::Event::MouseWheel { unit, delta, .. } = event {
let dy = match unit {
egui::MouseWheelUnit::Point => delta.y,
egui::MouseWheelUnit::Line => delta.y * (RECT_SIZE + GAP),
egui::MouseWheelUnit::Page => delta.y * self.max_off,
};
self.target = (self.target - dy).clamp(0.0, self.max_off);
self.velocity = -dy;
self.had_scroll = true;
false
} else {
true
}
});
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
let cell = RECT_SIZE + GAP;
let total_h = ROWS as f32 * cell - GAP;
self.max_off = (total_h - ui.available_height()).max(0.0);
self.target = self.target.clamp(0.0, self.max_off);
self.pos = self.pos.clamp(0.0, self.max_off);
let had_scroll = self.had_scroll;
self.had_scroll = false;
if !had_scroll {
self.target = (self.target + self.velocity).clamp(0.0, self.max_off);
self.velocity *= 0.9;
if self.velocity.abs() < 0.5 {
self.velocity = 0.0;
}
}
let dt = ctx.input(|i| i.unstable_dt).min(0.05);
let diff = self.target - self.pos;
self.pos += diff * (1.0 - (-EASE_RATE * dt).exp());
if diff.abs() < SNAP {
self.pos = self.target;
}
egui::ScrollArea::vertical()
.vertical_scroll_offset(self.pos)
.auto_shrink(false)
.animated(false)
.show(ui, |ui| {
let total_w = COLS as f32 * cell - GAP;
let (rect, _) =
ui.allocate_exact_size(egui::vec2(total_w, total_h), egui::Sense::hover());
let painter = ui.painter();
for row in 0..ROWS {
for col in 0..COLS {
let idx = row * COLS + col;
let hue = idx as f32 / (ROWS * COLS) as f32;
let color =
egui::Color32::from(egui::ecolor::Hsva::new(hue, 0.75, 0.85, 1.0));
let min = rect.min + egui::vec2(col as f32 * cell, row as f32 * cell);
let tile =
egui::Rect::from_min_size(min, egui::vec2(RECT_SIZE, RECT_SIZE));
painter.rect_filled(tile, 4.0, color);
painter.text(
tile.center(),
egui::Align2::CENTER_CENTER,
idx.to_string(),
egui::FontId::proportional(14.0),
egui::Color32::WHITE,
);
}
}
});
});
ctx.request_repaint();
}
}
fn main() -> eframe::Result {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([640.0, 480.0])
.with_title("egui scroll repro"),
..Default::default()
};
eframe::run_native(
"repro",
options,
Box::new(|_cc| Ok(Box::new(App::default()))),
)
}
Describe the bug
I have a simple egui scroll view with a bunch of rects in it, when I just make a single fast swipe on the trackpad the scroll moves in jumps/jitters (as shown in the video, it was a single scroll swipe).
To Reproduce
Run this example and scroll fast with a trackpad.
For me this is consistently reproducible.
Expected behavior
Screenshots
20260602-0645-36.5288603.mp4
Desktop (please complete the following information):
Additional context
I tried to fix it for myself by driving the scroll offset the raw input data, but I am not sure if this is a good way of doing it.
20260602-0656-12.9729125.mp4