Skip to content

Commit 7a28124

Browse files
kjkclaude
andcommitted
add MouseWheelTurnsPage, fix wheel page turn at page edge (fixes #5069)
Two mouse-wheel problems on a page zoomed past the window. RememberViewOffsetOnPageTurn applied to the page turn the wheel does when it runs off the bottom of a page. That offset is the bottom - that is how you got there - so the next page opened at its bottom, skipping its top, and since the view was still at the bottom every further notch flipped another page (pages 2 to 8 in six notches, showing only a sliver of each). Reaching a page edge by scrolling now opens the next page at its top: DisplayModel::GoToNextPage(bool keepViewOffset), false from the wheel. Explicit page turns (N / P, click-to-turn, toolbar) are unchanged, as is the up direction, which already went to the bottom of the previous page. MouseWheelTurnsPage (default false) makes one notch a page turn instead of a scroll, even when the page needs scrolling. It goes through the same GoToNextPage / GoToPrevPage as N / P, so it composes with RememberViewOffsetOnPageTurn: the view stays parked on the part of the page you are reading and the pages move under it. Alt + wheel still scrolls so the rest of the page is reachable; Shift + wheel and Ctrl + wheel are unchanged. Deltas accumulate against WHEEL_DELTA so a precision touchpad doesn't fly through the document. Toggle it without editing settings with the existing CmdToggleBoolSetting MouseWheelTurnsPage, documented in Commands.md and Scrolling-and-zooming.md with a Key + ToolbarText shortcut example. prompt: analyze issue 5069 and decide what the mouse wheel should do when RememberViewOffsetOnPageTurn is on, then implement it, documenting the existing CmdToggleBoolSetting instead of adding a new toggle command Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent de283d4 commit 7a28124

11 files changed

Lines changed: 393 additions & 77 deletions

‎cmd/gen-settings.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,14 @@ const globalPrefs: Field[] = [
11721172
"if true, next/previous page keeps the same view position on the page " +
11731173
"instead of jumping to the top (useful when zoomed in on similarly sized pages)",
11741174
).ver("3.7"),
1175+
field(
1176+
"MouseWheelTurnsPage",
1177+
Bool,
1178+
false,
1179+
"if true, one mouse-wheel notch goes to the next / previous page instead of scrolling; " +
1180+
"combine with RememberViewOffsetOnPageTurn to read zoomed-in pages without touching the keyboard. " +
1181+
"Alt + wheel still scrolls, Shift + wheel scrolls horizontally and Ctrl + wheel zooms",
1182+
).ver("3.7"),
11751183
field(
11761184
"ShowDocumentFocusIndicator",
11771185
Bool,

‎docs/md/Advanced-options-settings.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ DisableLinks = false
178178
; (introduced in version 3.7)
179179
RememberViewOffsetOnPageTurn = false
180180
181+
; if true, one mouse-wheel notch goes to the next / previous page instead of
182+
; scrolling; combine with RememberViewOffsetOnPageTurn to read zoomed-in pages
183+
; without touching the keyboard. Alt + wheel still scrolls, Shift + wheel
184+
; scrolls horizontally and Ctrl + wheel zooms (introduced in version 3.7)
185+
MouseWheelTurnsPage = false
186+
181187
; if true, draw a focus ring around the document when it has keyboard focus (Tab
182188
; to the page area) (introduced in version 3.7)
183189
ShowDocumentFocusIndicator = false

‎docs/md/Commands.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,21 @@ Shortcuts [
537537
]
538538
```
539539

540+
Add `ToolbarText` to the same entry to also get a toolbar button for it. Example: turn the reading mode of [`MouseWheelTurnsPage`](Advanced-options-settings.md) on and off with `w` or from the toolbar:
541+
542+
```
543+
Shortcuts [
544+
[
545+
Cmd = CmdToggleBoolSetting MouseWheelTurnsPage
546+
Key = w
547+
Name = Wheel Turns Page
548+
ToolbarText = Wheel Turns Page
549+
]
550+
]
551+
```
552+
553+
The same works for any other boolean advanced setting, e.g. `CmdToggleBoolSetting RememberViewOffsetOnPageTurn` or `CmdToggleBoolSetting ClickEdgeToTurnPage`.
554+
540555
## `CmdZoomCustom`
541556

542557
**Ver 3.6+**

‎docs/md/Scrolling-and-zooming.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ There are many ways to navigate around the document.
2323
- press `Alt` while scrolling : scrolls faster (by half page instead of by line)
2424
- mouse over scrollbar : scrolls faster (by half page instead of by line)
2525

26+
## Reading zoomed-in pages without the keyboard
27+
28+
When a page is zoomed past the window you usually care about one band of it — the music staves, the text inside wide scan margins — and want the next page to open at that same place. Two advanced settings do that:
29+
30+
- `RememberViewOffsetOnPageTurn = true` : next / previous page keeps the view where it is instead of jumping to the top of the new page. It applies to page turns you ask for (`n` / `p`, click-to-turn, the toolbar arrows). Wheeling off the bottom of a page still opens the next page at its top, since that is you reading on, not turning a page.
31+
- `MouseWheelTurnsPage = true` : one wheel notch is a page turn rather than a scroll. `Alt + wheel` still scrolls, so you can always reach the rest of the page; `Shift + wheel` (horizontal) and `Ctrl + wheel` (zoom) are unchanged.
32+
33+
Turn on both and the wheel becomes a page turner while the view stays parked where you put it. To switch the mode on and off without editing the settings file, bind it to a key or a toolbar button with [`CmdToggleBoolSetting`](Commands.md#cmdtoggleboolsetting):
34+
35+
```
36+
Shortcuts [
37+
[
38+
Cmd = CmdToggleBoolSetting MouseWheelTurnsPage
39+
Key = w
40+
Name = Wheel Turns Page
41+
ToolbarText = Wheel Turns Page
42+
]
43+
]
44+
```
45+
2646
# Zooming and changing view
2747

2848
## With keyboard

‎docs/md/Version-history.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Available in [pre-release](https://www.sumatrapdfreader.org/prerelease) builds.
2828
- PDF bookmark / link destinations now apply Adobe-style view modes (`/Fit`, `/FitH`, `/FitV`, `/FitB`, `/FitBH`, `/FitBV`, `/XYZ` zoom) instead of only jumping to the page (fixes #5828)
2929
- add `IgnoreDestinationZoom` advanced setting: when true, clicking a bookmark or a link inside the document keeps the zoom you are reading at instead of switching to the zoom the destination asks for; it still goes to the page and the position on it. The same option Adobe Reader and Foxit call "forbid the change of the current Zoom factor during execution of 'Go to Destination' actions"; off by default (discussion #5938)
3030
- add `DisableLinks` advanced setting (default **false**): when true, document links are ignored so you can select and read without accidentally following them — useful for drawings and schematics with many links. Toggle it from the command palette. The existing **Toggle Show Links** only draws a blue outline around links; it does not disable them (fixes #5939)
31-
- add `RememberViewOffsetOnPageTurn` advanced setting (default **false**): next/previous page keeps the same view position on the new page instead of jumping to the top, so zoomed-in pages of similar size stay lined up (fixes #5069)
31+
- add `RememberViewOffsetOnPageTurn` advanced setting (default **false**): next/previous page keeps the same view position on the new page instead of jumping to the top, so zoomed-in pages of similar size stay lined up. It applies to explicit page turns (`N` / `P`, click-to-turn, the toolbar arrows); wheeling off the bottom of a page still opens the next page at its top, because there you are continuing to read rather than turning a page (fixes #5069)
32+
- add `MouseWheelTurnsPage` advanced setting (default **false**): one wheel notch goes to the next / previous page instead of scrolling, even when the page is zoomed past the window. Together with `RememberViewOffsetOnPageTurn` the view stays parked on the part of the page you are reading and the pages move under it, which is how sheet music and scans with wide margins are read without touching the keyboard. `Alt + wheel` still scrolls, so the rest of the page stays reachable, and `Shift + wheel` (horizontal) and `Ctrl + wheel` (zoom) are unchanged. Bind it to a key or a toolbar button with `CmdToggleBoolSetting MouseWheelTurnsPage` (fixes #5069)
3233
- `EBookUI` and `ComicBookUI` each have their own `DefaultDisplayMode` so ebooks and comics can open in a different layout than PDFs (empty keeps the global `DefaultDisplayMode`) (fixes #2588)
3334
- `ComicBookUI.DefaultZoom` sets the first-open zoom for comic archives (`.cbz`, `.cbr`, …); empty keeps the global `DefaultZoom`. Use `fit width` so new comics fill the window while PDFs stay at Fit Page (fixes #5946)
3435
- add `EBookUI.FontName` advanced setting: the font family for ebooks (EPUB, MOBI, FB2, …), e.g. `Segoe UI` or `Microsoft YaHei`. Empty (the default) keeps the engine serif. When set, it overrides the document's own `font-family` so you can read in a sans-serif or a CJK UI font without editing the file (fixes #3138)

‎src/Canvas.cpp‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3507,6 +3507,25 @@ static LRESULT CanvasOnMouseWheel(MainWindow* win, UINT msg, WPARAM wp, LPARAM l
35073507
scrollIntent.armed = true;
35083508
}
35093509

3510+
// MouseWheelTurnsPage: a wheel notch is a page turn, not a scroll, even when
3511+
// the page is zoomed past the window. Pairs with RememberViewOffsetOnPageTurn
3512+
// for reading zoomed-in pages (sheet music, scans with wide margins) without
3513+
// the keyboard. Alt + wheel still scrolls, so the rest of the page is
3514+
// reachable; Shift + wheel and Ctrl + wheel are unchanged
3515+
if (vScroll && !isAlt && gGlobalPrefs->mouseWheelTurnsPage) {
3516+
win->wheelAccumDelta += delta;
3517+
if (win->wheelAccumDelta >= WHEEL_DELTA) {
3518+
win->ctrl->GoToPrevPage();
3519+
win->wheelAccumDelta -= WHEEL_DELTA;
3520+
ReadAloudOnUserViewChanged(win);
3521+
} else if (win->wheelAccumDelta <= -WHEEL_DELTA) {
3522+
win->ctrl->GoToNextPage();
3523+
win->wheelAccumDelta += WHEEL_DELTA;
3524+
ReadAloudOnUserViewChanged(win);
3525+
}
3526+
return 0;
3527+
}
3528+
35103529
// fit content: flip page on wheel, regardless of scrollbar state
35113530
if (vScroll && dm && FitContentWheelFlipsPage(dm) && IsSingle(dm->GetDisplayMode())) {
35123531
win->wheelAccumDelta += delta;
@@ -3700,6 +3719,11 @@ static LRESULT CanvasOnMouseWheel(MainWindow* win, UINT msg, WPARAM wp, LPARAM l
37003719
// logf(" flip page: delta: %d, accumDelta: %d\n", (int)delta, (int)win->wheelAccumDelta);
37013720
if (delta > 0) {
37023721
win->ctrl->GoToPrevPage(true);
3722+
} else if (dm) {
3723+
// this page turn continues a scroll, so start the new page at its top
3724+
// even with RememberViewOffsetOnPageTurn on - we're at the bottom of the
3725+
// old page only because we scrolled there (see GoToNextPage(bool))
3726+
dm->GoToNextPage(false);
37033727
} else {
37043728
win->ctrl->GoToNextPage();
37053729
}

‎src/DisplayModel.cpp‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,16 @@ static void GetRememberedViewOffset(DisplayModel* dm, int pageNo, int* scrollXOu
19891989
Returns true if advanced to the next page or false if couldn't advance
19901990
(e.g. because already was at the last page) */
19911991
bool DisplayModel::GoToNextPage() {
1992+
return GoToNextPage(gGlobalPrefs->rememberViewOffsetOnPageTurn);
1993+
}
1994+
1995+
// keepViewOffset: land on the new page at the same offset we're at now
1996+
// (RememberViewOffsetOnPageTurn) instead of at its top. It's false when the
1997+
// page turn is the continuation of a scroll (wheeling past the bottom of a
1998+
// page), because then "where we are now" is the bottom - keeping it would skip
1999+
// the top of the new page and, since we'd still be at the bottom, every further
2000+
// notch would flip another page
2001+
bool DisplayModel::GoToNextPage(bool keepViewOffset) {
19922002
int columns = ColumnsFromDisplayMode(GetDisplayMode());
19932003
int currPageNo = CurrentPageNo();
19942004
// Fully display the current page, if the previous page is still visible
@@ -2004,7 +2014,7 @@ bool DisplayModel::GoToNextPage() {
20042014
}
20052015
int scrollY = 0;
20062016
int scrollX = -1;
2007-
if (gGlobalPrefs->rememberViewOffsetOnPageTurn) {
2017+
if (keepViewOffset) {
20082018
GetRememberedViewOffset(this, currPageNo, &scrollX, &scrollY);
20092019
}
20102020
GoToPage(firstPageInNewRow, scrollY, false, scrollX);

‎src/DisplayModel.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ struct DisplayModel : DocController {
227227
RectF GetContentBox(int pageNo) const;
228228
void CalcZoomReal(float zoomVirtual);
229229
void GoToPage(int pageNo, int scrollY, bool addNavPt = false, int scrollX = -1);
230+
bool GoToNextPage(bool keepViewOffset);
230231
bool GoToPrevPage(int scrollY);
231232
int GetPageNextToPoint(Point pt) const;
232233

0 commit comments

Comments
 (0)