mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 20:43:12 +00:00
fix(ui): the sliver bookmark_position ignores is one physical pixel, not one point (#5636)
Page rectangles snap to whole physical pixels, so what counts as rounding scales with the display: the view keeps last frame's pixels per point and the threshold is its inverse. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3896e6c30a
commit
560acae86e
2 files changed
+26
-5
No files matched your search
@@ -382,6 +382,8 @@ pub struct DocView {
|
||||
/// Screen rects of the pages drawn last frame (hit-testing, tests, automation).
|
||||
screen_rects: Vec<(usize, Rect)>,
|
||||
screen_xforms: Vec<(usize, PageXform)>,
|
||||
/// Pixels per point last frame, for telling a rounding sliver of a page from a visible one.
|
||||
screen_ppp: f32,
|
||||
/// The scroll viewport on screen last frame.
|
||||
viewport_screen: Rect,
|
||||
/// Pending zoom anchor: page, fractional position (also in gutters), and viewport offset.
|
||||
@@ -669,6 +671,7 @@ impl DocView {
|
||||
page_heights: info.pages.iter().map(|p| p.height).collect(),
|
||||
screen_rects: Vec::new(),
|
||||
screen_xforms: Vec::new(),
|
||||
screen_ppp: 1.0,
|
||||
viewport_screen: Rect::NOTHING,
|
||||
zoom_anchor: None,
|
||||
shown: false,
|
||||
@@ -2010,6 +2013,7 @@ fn draw_pages(
|
||||
let origin = resp_rect.min - vec2(0.0, y_shift);
|
||||
let visible = viewport.translate(resp_rect.min.to_vec2());
|
||||
view.screen_rects.clear();
|
||||
view.screen_ppp = ui.ctx().pixels_per_point();
|
||||
view.screen_xforms.clear();
|
||||
// The pointer as the pages see it: nothing over them (a dialog from the frame it opens),
|
||||
// or a press they hold. The page modules read it rather than egui's raw pointer state.
|
||||
|
||||
@@ -32,7 +32,7 @@ impl DocView {
|
||||
// of pages of different heights, whose shorter page can start below it), else the
|
||||
// nearest one below.
|
||||
let top = self.viewport_screen.top();
|
||||
// A page showing less than SLIVER is rounding, not what the reader is looking at: a jump
|
||||
// A page showing less than a pixel is rounding, not what the reader is looking at: a jump
|
||||
// to the next page leaves the previous one's bottom edge within a pixel of the top. Such a
|
||||
// sliver still counts when nothing else shows (the last page at the very end).
|
||||
let pick = |slack: f32| {
|
||||
@@ -42,7 +42,7 @@ impl DocView {
|
||||
.min_by_key(|(p, _)| *p)
|
||||
.or_else(|| showing().min_by(|a, b| a.1.rect.top().total_cmp(&b.1.rect.top()).then(a.0.cmp(&b.0))))
|
||||
};
|
||||
let (page, xf) = pick(SLIVER).or_else(|| pick(0.0))?;
|
||||
let (page, xf) = pick(sliver(self.screen_ppp)).or_else(|| pick(0.0))?;
|
||||
let p = info.pages.get(*page)?;
|
||||
// Above the page (in the gap before it) is the page's own top. The window's vertical is
|
||||
// the view's y, or its x when the view is turned a quarter.
|
||||
@@ -460,6 +460,23 @@ pub fn shortcuts(view: &mut DocView, ctx: &egui::Context, speed: crate::scroll_s
|
||||
/// How far ↓ / ↑ scroll at Normal speed (Scroll speed halves or doubles it). Page Down / Page Up
|
||||
/// keep this much of the previous screen in view.
|
||||
const KEY_SCROLL_LINE: f32 = 40.0;
|
||||
/// How much of a page must show at the window's top edge to count as the page there, in points: less
|
||||
/// is rounding, since page rectangles snap to whole pixels.
|
||||
const SLIVER: f32 = 1.0;
|
||||
/// How much of a page must show at the window's top edge to count as the page there, in points: one
|
||||
/// physical pixel, since page rectangles snap to whole pixels and less is rounding.
|
||||
fn sliver(pixels_per_point: f32) -> f32 {
|
||||
if pixels_per_point.is_finite() && pixels_per_point > 0.0 { 1.0 / pixels_per_point } else { 1.0 }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::sliver;
|
||||
|
||||
#[test]
|
||||
fn a_sliver_is_one_physical_pixel() {
|
||||
assert_eq!(sliver(1.0), 1.0);
|
||||
assert_eq!(sliver(2.0), 0.5);
|
||||
assert_eq!(sliver(0.5), 2.0);
|
||||
for bad in [0.0, -1.0, f32::NAN, f32::INFINITY] {
|
||||
assert_eq!(sliver(bad), 1.0, "{bad}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user