diff --git a/src/pyj/read_book/flow_mode.pyj b/src/pyj/read_book/flow_mode.pyj index 9059e790fe..22671bc943 100644 --- a/src/pyj/read_book/flow_mode.pyj +++ b/src/pyj/read_book/flow_mode.pyj @@ -6,6 +6,7 @@ from select import word_at_point from dom import set_css from read_book.globals import current_spine_item, get_boss +from read_book.settings import opts from read_book.viewport import scroll_viewport from utils import document_height, viewport_to_document @@ -167,7 +168,6 @@ def layout(is_single_page): DIRECTION = {'Up': -1, 'Down': 1} class ScrollAnimator: DURATION = 100 # milliseconds - SCROLL_SPEED = 30 # lines/sec TODO: This will be configurable def __init__(self): self.animation_id = None @@ -187,7 +187,7 @@ class ScrollAnimator: duration = (self.end_time - self.start_time) progress = max(0, min(1, (ts - self.start_time) / duration)) # max/min to account for jitter scroll_target = self.start_offset - scroll_target += Math.trunc(self.direction * progress * duration * line_height() * self.SCROLL_SPEED) / 1000 + scroll_target += Math.trunc(self.direction * progress * duration * line_height() * opts.lines_per_sec_smooth) / 1000 window.scrollTo(0, scroll_target) @@ -196,7 +196,7 @@ class ScrollAnimator: else: self.animation_id = None amt = window.pageYOffset - self.start_offset - if abs(amt) < 3 and duration is self.DURATION: + if abs(amt) < 3 and duration is self.DURATION and !(0 <= scroll_target <= document_height() - window.innerHeight): get_boss().send_message('next_spine_item', previous=self.direction is DIRECTION.Up) else: report_human_scroll(amt) diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index 02bb34276b..0b16865ff3 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -93,6 +93,7 @@ class IframeBoss: handlers = { 'change_color_scheme': self.change_color_scheme, 'change_font_size': self.change_font_size, + 'change_scroll_speed': self.change_scroll_speed, 'display': self.display, 'find': self.find, 'gesture_from_margin': self.gesture_from_margin, @@ -243,6 +244,10 @@ class IframeBoss: opts.base_font_size = data.base_font_size apply_font_size() + def change_scroll_speed(self, data): + if data.lines_per_sec_smooth?: + opts.lines_per_sec_smooth = data.lines_per_sec_smooth + def change_stylesheet(self, data): opts.user_stylesheet = data.sheet or '' apply_stylesheet() diff --git a/src/pyj/read_book/prefs/scrolling.pyj b/src/pyj/read_book/prefs/scrolling.pyj index 96eebe56e6..8fdd1263a6 100644 --- a/src/pyj/read_book/prefs/scrolling.pyj +++ b/src/pyj/read_book/prefs/scrolling.pyj @@ -11,6 +11,8 @@ from read_book.prefs.utils import create_button_box from session import defaults CONTAINER = unique_id('standalone-scrolling-settings') +MIN_SCROLL_SPEED = 0.5 +MAX_SCROLL_SPEED = 50 def restore_defaults(): @@ -23,6 +25,15 @@ def get_container(): return document.getElementById(CONTAINER) +def change_scroll_speed(amt): + sd = get_session_data() + lps = sd.get('lines_per_sec_smooth') + nlps = max(MIN_SCROLL_SPEED, min(lps + amt, MAX_SCROLL_SPEED)) + if nlps != lps: + sd.set('lines_per_sec_smooth', nlps) + return nlps + + def create_scrolling_panel(container, apply_func, cancel_func): container.appendChild(E.div(id=CONTAINER, style='margin: 1rem')) container = container.lastChild diff --git a/src/pyj/read_book/settings.pyj b/src/pyj/read_book/settings.pyj index e0892e75cd..4126ddc62f 100644 --- a/src/pyj/read_book/settings.pyj +++ b/src/pyj/read_book/settings.pyj @@ -17,6 +17,7 @@ def update_settings(settings): opts.cover_preserve_aspect_ratio = v'!!settings.cover_preserve_aspect_ratio' opts.hide_tooltips = settings.hide_tooltips opts.is_dark_theme = v'!!settings.is_dark_theme' + opts.lines_per_sec_smooth = settings.lines_per_sec_smooth opts.margin_left = max(0, settings.margin_left) opts.margin_right = max(0, settings.margin_right) opts.override_book_colors = settings.override_book_colors diff --git a/src/pyj/read_book/shortcuts.pyj b/src/pyj/read_book/shortcuts.pyj index 99f3cb1937..f2827fb0ae 100644 --- a/src/pyj/read_book/shortcuts.pyj +++ b/src/pyj/read_book/shortcuts.pyj @@ -270,6 +270,18 @@ def shortcuts_definition(): _('Go to a specified book location or position'), ), + 'scrollspeed_increase': desc( + "Alt+ArrowUp", + 'scroll', + _('Smooth scroll faster'), + ), + + 'scrollspeed_decrease': desc( + "Alt+ArrowDown", + 'scroll', + _('Smooth scroll slower'), + ), + } return ans diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 6b4dabbf44..2335debba1 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -23,6 +23,7 @@ from read_book.overlay import Overlay from read_book.prefs.colors import resolve_color_scheme from read_book.prefs.font_size import change_font_size_by from read_book.prefs.head_foot import render_head_foot +from read_book.prefs.scrolling import change_scroll_speed, MIN_SCROLL_SPEED as SCROLL_SPEED_STEP from read_book.resources import load_resources from read_book.search import SearchOverlay, find_in_spine from read_book.shortcuts import create_shortcut_map @@ -409,6 +410,10 @@ class View: self.iframe_wrapper.send_message('modify_selection', direction='backward', granularity='word') elif data.name is 'extend_selection_by_word': self.iframe_wrapper.send_message('modify_selection', direction='forward', granularity='word') + elif data.name is 'scrollspeed_increase': + self.update_scroll_speed(SCROLL_SPEED_STEP) + elif data.name is 'scrollspeed_decrease': + self.update_scroll_speed(-SCROLL_SPEED_STEP) def on_selection_change(self, data): self.currently_showing.selected_text = data.text @@ -703,6 +708,7 @@ class View: 'hide_tooltips': sd.get('hide_tooltips'), 'cover_preserve_aspect_ratio': sd.get('cover_preserve_aspect_ratio'), 'paged_wheel_scrolls_by_screen': sd.get('paged_wheel_scrolls_by_screen'), + 'lines_per_sec_smooth': sd.get('lines_per_sec_smooth'), } def show_name(self, name, initial_position=None): @@ -993,6 +999,9 @@ class View: def update_font_size(self): self.iframe_wrapper.send_message('change_font_size', base_font_size=get_session_data().get('base_font_size')) + def update_scroll_speed(self, amt): + self.iframe_wrapper.send_message('change_scroll_speed', lines_per_sec_smooth=change_scroll_speed(amt)) + def update_color_scheme(self): cs = self.get_color_scheme(True) self.iframe_wrapper.send_message('change_color_scheme', color_scheme=cs) diff --git a/src/pyj/session.pyj b/src/pyj/session.pyj index d8a79d9679..c224e3463d 100644 --- a/src/pyj/session.pyj +++ b/src/pyj/session.pyj @@ -37,6 +37,7 @@ defaults = { 'header': {}, 'hide_tooltips': False, 'keyboard_shortcuts': {}, + 'lines_per_sec_smooth': 30, 'margin_bottom': 20, 'margin_left': 20, 'margin_right': 20, @@ -63,6 +64,7 @@ is_local_setting = { 'columns_per_screen': True, 'controls_help_shown_count': True, 'current_color_scheme': True, + 'lines_per_sec_smooth': True, 'margin_bottom': True, 'margin_left': True, 'margin_right': True,