ElyTable: zoom and DPI keep the scroll in print twips; drag and zoom tests far down a sheet (R2.16)
This commit is contained in:
20 files changed
+155
-64
No files matched your search
@@ -485,29 +485,3 @@ fn enter_and_tab_move_the_cell_cursor() {
|
||||
});
|
||||
assert_eq!(right.cell.address, "G2", "Tab moves right");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_click_far_down_selects_the_cell_under_it() {
|
||||
if skip() {
|
||||
return;
|
||||
}
|
||||
let (_dir, mut worker, doc, seen) = open();
|
||||
// One painted tile fixes the kernel's scale.
|
||||
let (side, twips) = (512u32, 3840);
|
||||
let ppt = f64::from(side) / f64::from(twips);
|
||||
doc.paint_tile(&mut worker, (0, 0, twips, twips), (side, side)).expect("a tile");
|
||||
let geometry = sheet::geometry(&worker.values(&doc, sheet::GEOMETRY).expect("geometry")).expect("parsed");
|
||||
worker.run(&doc, "cell.goto", &["B4998"]).expect("B4998");
|
||||
let at = poll_until(&mut worker, &doc, &seen, SETTLE, |seen| seen.cell.address == "B4998");
|
||||
let (x, y, w, h) = at.cell.cursor.expect("the cursor");
|
||||
worker.run(&doc, "cell.goto", &["A1"]).expect("A1");
|
||||
let home = poll_until(&mut worker, &doc, &at, SETTLE, |seen| seen.cell.address == "A1");
|
||||
// The cursor is in print twips; clicks take tile twips.
|
||||
let (x, y) = (geometry.columns.tile(x + w / 2, ppt), geometry.rows.tile(y + h / 2, ppt));
|
||||
for kind in [0, 1] {
|
||||
let click = crate::Mouse { kind, x, y, count: 1, buttons: 1, modifiers: 0 };
|
||||
worker.post_mouse(&doc, click).expect("clicks");
|
||||
}
|
||||
let after = poll_until(&mut worker, &doc, &home, SETTLE, |seen| seen.cell.address != "A1");
|
||||
assert_eq!(after.cell.address, "B4998");
|
||||
}
|
||||
@@ -40,7 +40,7 @@ impl Render for LokView {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let dpi = window.scale_factor();
|
||||
if dpi != self.geom.dpi {
|
||||
self.geom.dpi = dpi;
|
||||
self.keep_scroll(|view| view.geom.dpi = dpi);
|
||||
self.retire_tiles();
|
||||
}
|
||||
self.follow_theme(cx.theme().is_dark());
|
||||
@@ -210,7 +210,7 @@ impl LokView {
|
||||
let down = self.viewport.1 * TWIPS_PER_PIXEL / h as f32;
|
||||
let zoom = (across.min(down) * MARGIN).min(4.0);
|
||||
if (zoom - self.geom.zoom).abs() > 0.001 {
|
||||
self.geom.zoom = zoom;
|
||||
self.keep_scroll(|view| view.geom.zoom = zoom);
|
||||
self.retire_tiles();
|
||||
self.failed.clear();
|
||||
}
|
||||
|
||||
@@ -49,11 +49,9 @@ impl LokView {
|
||||
self.geom.twips_of(self.viewport.0) - fx,
|
||||
self.geom.twips_of(self.viewport.1) - fy,
|
||||
);
|
||||
// Room past the target, so the clamp lets it show.
|
||||
self.reach = (
|
||||
self.reach.0.max(x + w + vw + fx),
|
||||
self.reach.1.max(y + h + vh + fy),
|
||||
);
|
||||
// Room past the target, in print twips for later zooms.
|
||||
let need = self.print_of((x + w + vw + fx, y + h + vh + fy));
|
||||
self.reach = (self.reach.0.max(need.0), self.reach.1.max(need.1));
|
||||
if x >= fx && (x < fx + self.scroll.0 || x + w > fx + self.scroll.0 + vw) {
|
||||
self.scroll.0 = x - fx - vw / 2;
|
||||
}
|
||||
@@ -104,10 +102,10 @@ impl LokView {
|
||||
if self.fit {
|
||||
return self.doc_size;
|
||||
}
|
||||
(
|
||||
self.tile_of((
|
||||
self.doc_size.0.max(self.reach.0),
|
||||
self.doc_size.1.max(self.reach.1),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// The print-twips document point under a view position (LOK-04).
|
||||
|
||||
@@ -48,6 +48,14 @@ impl LokView {
|
||||
self.tile_of(self.frozen)
|
||||
}
|
||||
|
||||
/// Rescales, keeping the scrolling pane's start in place.
|
||||
pub(super) fn keep_scroll(&mut self, change: impl FnOnce(&mut Self)) {
|
||||
let start = self.scrolled_start();
|
||||
change(self);
|
||||
let ((x, y), (fx, fy)) = (self.tile_of(start), self.frozen_tiles());
|
||||
self.scroll = (x - fx, y - fy);
|
||||
}
|
||||
|
||||
/// Where the scrolling pane starts, in print twips.
|
||||
pub fn scrolled_start(&self) -> (i32, i32) {
|
||||
let (fx, fy) = self.frozen_tiles();
|
||||
|
||||
@@ -73,6 +73,44 @@ const SHORT_ROWS: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
|
||||
</table:table></office:spreadsheet></office:body>
|
||||
</office:document>"#;
|
||||
|
||||
/// A short-row sheet at 2× DPI, scrolled to `cell`'s row.
|
||||
fn far_down(cx: &mut gpui::TestAppContext, install: &std::path::Path) -> (Entity<LokView>, crate::sheet::Geometry) {
|
||||
let (view, worker) = cx.update(|app| live_view_of(app, install, "short.fods", SHORT_ROWS));
|
||||
let json = cx.update(|app| {
|
||||
let read = view.read(app);
|
||||
worker.lock().expect("the worker lock").values(&read.doc, crate::sheet::GEOMETRY).expect("geometry")
|
||||
});
|
||||
let geometry = crate::sheet::geometry(&json).expect("parsed");
|
||||
let row = cell(&geometry, 1, 4997);
|
||||
cx.update(|app| {
|
||||
view.update(app, |view, cx| {
|
||||
view.geom.dpi = 2.0;
|
||||
view.set_geometry(geometry.clone(), cx);
|
||||
view.prepare(Bounds { origin: point(px(0.0), px(0.0)), size: size(px(800.0), px(600.0)) });
|
||||
view.show(row, cx);
|
||||
})
|
||||
});
|
||||
(view, geometry)
|
||||
}
|
||||
|
||||
/// Column `x`, row `y` in print twips.
|
||||
fn cell(geometry: &crate::sheet::Geometry, x: u32, y: u32) -> crate::Rect {
|
||||
(geometry.columns.start(x), geometry.rows.start(y), geometry.columns.size(x), geometry.rows.size(y))
|
||||
}
|
||||
|
||||
/// Waits until the kernel reports `want` as the selection.
|
||||
fn selected(view: &Entity<LokView>, cx: &mut gpui::TestAppContext, want: &str) -> String {
|
||||
let mut address = String::new();
|
||||
for _ in 0..200 {
|
||||
cx.executor().tick();
|
||||
address = cx.update(|app| view.read(app).cell().address.clone());
|
||||
if address == want {
|
||||
break;
|
||||
}
|
||||
}
|
||||
address
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_click_far_down_a_sheet_selects_the_cell_under_it() {
|
||||
let Some(install) = crate::client::tests::install() else {
|
||||
@@ -80,38 +118,59 @@ fn a_click_far_down_a_sheet_selects_the_cell_under_it() {
|
||||
return;
|
||||
};
|
||||
let mut cx = gpui::TestAppContext::single();
|
||||
let (view, worker) = cx.update(|app| live_view_of(app, &install, "short.fods", SHORT_ROWS));
|
||||
let json = cx.update(|app| {
|
||||
let read = view.read(app);
|
||||
worker.lock().expect("the worker lock").values(&read.doc, crate::sheet::GEOMETRY).expect("geometry")
|
||||
});
|
||||
let geometry = crate::sheet::geometry(&json).expect("parsed");
|
||||
let (row, column) = (4997, 1);
|
||||
let cell = (
|
||||
geometry.columns.start(column),
|
||||
geometry.rows.start(row),
|
||||
geometry.columns.size(column),
|
||||
geometry.rows.size(row),
|
||||
);
|
||||
let (view, geometry) = far_down(&mut cx, &install);
|
||||
let (x, y, w, h) = cell(&geometry, 1, 4997);
|
||||
cx.update(|app| {
|
||||
view.update(app, |view, cx| {
|
||||
view.geom.dpi = 2.0;
|
||||
view.set_geometry(geometry.clone(), cx);
|
||||
view.prepare(Bounds { origin: point(px(0.0), px(0.0)), size: size(px(800.0), px(600.0)) });
|
||||
view.show(cell, cx);
|
||||
let at = view.window_point((cell.0 + cell.2 / 2, cell.1 + cell.3 / 2));
|
||||
view.update(app, |view, _| {
|
||||
let at = view.window_point((x + w / 2, y + h / 2));
|
||||
for kind in [0, 1] {
|
||||
view.mouse(kind, at, 1, 1, &gpui::Modifiers::default());
|
||||
}
|
||||
})
|
||||
});
|
||||
let mut address = String::new();
|
||||
for _ in 0..200 {
|
||||
cx.executor().tick();
|
||||
address = cx.update(|app| view.read(app).cell().address.clone());
|
||||
if address == "B4998" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_eq!(address, "B4998");
|
||||
assert_eq!(selected(&view, &mut cx, "B4998"), "B4998");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_drag_far_down_a_sheet_selects_the_range_under_it() {
|
||||
let Some(install) = crate::client::tests::install() else {
|
||||
eprintln!("SKIP: no pinned LOK build");
|
||||
return;
|
||||
};
|
||||
let mut cx = gpui::TestAppContext::single();
|
||||
let (view, geometry) = far_down(&mut cx, &install);
|
||||
let middle = |(x, y, w, h): crate::Rect| (x + w / 2, y + h / 2);
|
||||
let (from, to) = (middle(cell(&geometry, 1, 4997)), middle(cell(&geometry, 3, 5000)));
|
||||
cx.update(|app| {
|
||||
view.update(app, |view, _| {
|
||||
let modifiers = gpui::Modifiers::default();
|
||||
view.mouse(0, view.window_point(from), 1, 1, &modifiers);
|
||||
view.mouse(2, view.window_point(((from.0 + to.0) / 2, (from.1 + to.1) / 2)), 1, 1, &modifiers);
|
||||
view.mouse(2, view.window_point(to), 1, 1, &modifiers);
|
||||
view.mouse(1, view.window_point(to), 1, 1, &modifiers);
|
||||
})
|
||||
});
|
||||
assert_eq!(selected(&view, &mut cx, "B4998:D5001"), "B4998:D5001");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zooming_far_down_a_sheet_keeps_the_rows_in_view() {
|
||||
let Some(install) = crate::client::tests::install() else {
|
||||
eprintln!("SKIP: no pinned LOK build");
|
||||
return;
|
||||
};
|
||||
let mut cx = gpui::TestAppContext::single();
|
||||
let (view, geometry) = far_down(&mut cx, &install);
|
||||
let middle = |cx: &mut gpui::TestAppContext| {
|
||||
cx.update(|app| {
|
||||
let read = view.read(app);
|
||||
let (w, h) = read.viewport();
|
||||
let at = read.origin() + point(px(w / 2.0), px(h / 2.0));
|
||||
geometry.rows.at(read.doc_point(at).1)
|
||||
})
|
||||
};
|
||||
let before = middle(&mut cx);
|
||||
cx.update(|app| view.update(app, |view, cx| view.set_zoom(0.8, cx)));
|
||||
let after = middle(&mut cx);
|
||||
assert!(before.abs_diff(after) <= 1, "row {before} became {after}");
|
||||
}
|
||||
@@ -47,13 +47,15 @@ impl LokView {
|
||||
Some(at) => (f32::from(at.x - self.origin.x), f32::from(at.y - self.origin.y)),
|
||||
None => (self.viewport.0 / 2.0, self.viewport.1 / 2.0),
|
||||
};
|
||||
let under = (self.scroll.0 + self.geom.twips_of(ax), self.scroll.1 + self.geom.twips_of(ay));
|
||||
// Anchored in print twips: tile twips change with the zoom.
|
||||
let under = self.print_of((self.scroll.0 + self.geom.twips_of(ax), self.scroll.1 + self.geom.twips_of(ay)));
|
||||
self.fit = false;
|
||||
if (zoom - self.geom.zoom).abs() > 0.0001 {
|
||||
self.geom.zoom = zoom;
|
||||
self.retire_tiles();
|
||||
self.failed.clear();
|
||||
}
|
||||
let under = self.tile_of(under);
|
||||
self.scroll = (under.0 - self.geom.twips_of(ax), under.1 - self.geom.twips_of(ay));
|
||||
self.clamp_scroll();
|
||||
log::debug!("lok: zoom {:.0}%", zoom * 100.0);
|
||||
|
||||
Reference in new issue
Block a user