Merge pull request #452 from tydude001:fix/432-filter-list-scroll

This commit is contained in:
Brandon Thomas 2026-10-12 23:35:13 -04:00
commit f267530b7c
2 changed files with 64 additions and 1 deletions

View File

@ -2547,7 +2547,9 @@ fn filter_menu(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, was_open: bool)
c.1 = all_new;
}
}
egui::ScrollArea::vertical().max_height(220.0).show(ui, |ui| {
// Full width: shrunk to the longest value, the scroll bar sat mid-menu and the wheel only
// worked over the values themselves (#432).
egui::ScrollArea::vertical().max_height(220.0).auto_shrink([false, true]).show(ui, |ui| {
for (v, on) in checks.iter_mut().filter(|(v, _)| matches(v)) {
ui.checkbox(on, v.as_str());
}

View File

@ -0,0 +1,61 @@
//! The AutoFilter value list scrolls with the pointer anywhere over it, not only over the values
//! themselves (issue #432): the list takes the menu's full width, so its scroll bar and wheel area do too.
use egui::{Event, Modifiers, MouseWheelUnit, PointerButton, TouchPhase, pos2, vec2};
use egui_kittest::kittest::Queryable;
use gridcraft_engine::Session;
use gridcraft_engine::core::CellRef;
use gridcraft_ui_egui::{SheetApp, grid};
use serde_json::json;
type Harness = egui_kittest::Harness<'static, SheetApp>;
/// A1:A81 holds a header and 80 distinct values, with the AutoFilter's menu open on column A.
fn filter_menu_on_a_long_list() -> Harness {
let mut session = Session::new();
session.new_workbook();
let mut values = vec![vec![json!("Code")]];
values.extend((1..=80).map(|i| vec![json!(format!("ITEM-{i:03}"))]));
session.execute("range.setValues", json!({"range": "A1", "values": values})).unwrap();
session.execute("data.filter", json!({"range": "A1:A81"})).unwrap();
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|ui, app: &mut SheetApp| {
app.logic(ui.ctx());
app.ui(ui);
},
SheetApp::new(session, Default::default()),
);
h.run_steps(4);
let button = {
let app = h.state();
let sh = app.session.active().unwrap().wb.active().unwrap();
let geo = grid::Geo::new(sh, app.grid.rect.unwrap(), app.view().scroll);
grid::filter_button_rect(&geo, sh, CellRef::parse("A1").unwrap()).center()
};
h.input_mut().events.push(Event::PointerMoved(button));
for pressed in [true, false] {
h.input_mut().events.push(Event::PointerButton { pos: button, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE });
}
h.run_steps(4);
assert!(h.state().grid.filter_menu.is_some(), "the filter menu opens");
h
}
#[test]
fn filter_list_scrolls_with_the_pointer_right_of_the_values() {
let mut h = filter_menu_on_a_long_list();
let first = h.get_by_label("ITEM-001").rect();
// The menu is 230 points wide; the value labels end well before this point.
let pointer = pos2(first.left() + 200.0, first.center().y);
h.input_mut().events.push(Event::PointerMoved(pointer));
h.run_steps(2);
h.input_mut().events.push(Event::MouseWheel {
unit: MouseWheelUnit::Line,
delta: vec2(0.0, -3.0),
phase: TouchPhase::Move,
modifiers: Modifiers::NONE,
});
h.run_steps(20);
let now = h.query_by_label("ITEM-001").map(|n| n.rect().top());
assert!(now.is_none_or(|y| y < first.top() - 20.0), "the wheel scrolls the list: ITEM-001 was at {}, now {now:?}", first.top());
}