Add an auto-scroll button to the viewer controls

This commit is contained in:
Kovid Goyal 2019-12-28 20:49:37 +05:30
parent d94c2f21e7
commit 38736d9412
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 88 additions and 34 deletions

View File

@ -0,0 +1 @@
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1395 864q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23zm0-384q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23z"/></svg>

After

Width:  |  Height:  |  Size: 414 B

View File

@ -141,6 +141,24 @@ def scroll_by_page(direction):
window.scrollBy(0, h * direction) window.scrollBy(0, h * direction)
def is_auto_scroll_active():
return scroll_animator.auto and scroll_animator.is_running()
def start_autoscroll():
scroll_animator.start(DIRECTION.Down, True)
def toggle_autoscroll():
running = False
if is_auto_scroll_active():
cancel_scroll()
else:
start_autoscroll()
running = True
get_boss().send_message('autoscroll_state_changed', running=running)
def handle_shortcut(sc_name, evt): def handle_shortcut(sc_name, evt):
if sc_name is 'down': if sc_name is 'down':
scroll_animator.start(DIRECTION.Down, False) scroll_animator.start(DIRECTION.Down, False)
@ -173,10 +191,7 @@ def handle_shortcut(sc_name, evt):
scroll_by_page(1) scroll_by_page(1)
return True return True
if sc_name is 'toggle_autoscroll': if sc_name is 'toggle_autoscroll':
if scroll_animator.auto and scroll_animator.is_running(): toggle_autoscroll()
cancel_scroll()
else:
scroll_animator.start(DIRECTION.Down, True)
return True return True
if sc_name.startsWith('scrollspeed_'): if sc_name.startsWith('scrollspeed_'):
@ -190,7 +205,7 @@ def layout(is_single_page):
set_css(document.body, margin='0', border_width='0', padding='0') set_css(document.body, margin='0', border_width='0', padding='0')
def flow_auto_scroll_resume(): def auto_scroll_resume():
scroll_animator.wait = False scroll_animator.wait = False
scroll_animator.sync() scroll_animator.sync()
@ -422,3 +437,17 @@ anchor_funcs = {
return (a[0] - b[0]) or (a[1] - b[1]) return (a[0] - b[0]) or (a[1] - b[1])
, ,
} }
def auto_scroll_action(action):
if action is 'toggle':
toggle_autoscroll()
elif action is 'start':
if not is_auto_scroll_active():
toggle_autoscroll()
elif action is 'stop':
if is_auto_scroll_active():
toggle_autoscroll()
elif action is 'resume':
auto_scroll_resume()
return is_auto_scroll_active()

View File

@ -10,10 +10,10 @@ from iframe_comm import IframeClient
from read_book.cfi import scroll_to as scroll_to_cfi from read_book.cfi import scroll_to as scroll_to_cfi
from read_book.extract import get_elements from read_book.extract import get_elements
from read_book.flow_mode import ( from read_book.flow_mode import (
anchor_funcs as flow_anchor_funcs, cancel_scroll as flow_cancel_auto_scroll, anchor_funcs as flow_anchor_funcs, auto_scroll_action as flow_auto_scroll_action,
flow_auto_scroll_resume, flow_onwheel, flow_to_scroll_fraction, flow_onwheel, flow_to_scroll_fraction, handle_gesture as flow_handle_gesture,
handle_gesture as flow_handle_gesture, handle_shortcut as flow_handle_shortcut, handle_shortcut as flow_handle_shortcut, layout as flow_layout,
layout as flow_layout, scroll_by_page as flow_scroll_by_page scroll_by_page as flow_scroll_by_page
) )
from read_book.footnotes import is_footnote_link from read_book.footnotes import is_footnote_link
from read_book.globals import ( from read_book.globals import (
@ -22,10 +22,11 @@ from read_book.globals import (
) )
from read_book.mathjax import apply_mathjax from read_book.mathjax import apply_mathjax
from read_book.paged_mode import ( from read_book.paged_mode import (
anchor_funcs as paged_anchor_funcs, calc_columns_per_screen, current_cfi, anchor_funcs as paged_anchor_funcs,
handle_gesture as paged_handle_gesture, handle_shortcut as paged_handle_shortcut, auto_scroll_action as paged_auto_scroll_action, calc_columns_per_screen,
jump_to_cfi as paged_jump_to_cfi, layout as paged_layout, current_cfi, handle_gesture as paged_handle_gesture,
onwheel as paged_onwheel, paged_auto_scroll_resume, handle_shortcut as paged_handle_shortcut, jump_to_cfi as paged_jump_to_cfi,
layout as paged_layout, onwheel as paged_onwheel,
prepare_for_resize as paged_prepare_for_resize, progress_frac, prepare_for_resize as paged_prepare_for_resize, progress_frac,
reset_paged_mode_globals, resize_done as paged_resize_done, reset_paged_mode_globals, resize_done as paged_resize_done,
scroll_by_page as paged_scroll_by_page, scroll_to_elem, scroll_by_page as paged_scroll_by_page, scroll_to_elem,
@ -106,27 +107,32 @@ class IframeBoss:
'scroll_to_anchor': self.on_scroll_to_anchor, 'scroll_to_anchor': self.on_scroll_to_anchor,
'scroll_to_frac': self.on_scroll_to_frac, 'scroll_to_frac': self.on_scroll_to_frac,
'scroll_to_ref': self.on_scroll_to_ref, 'scroll_to_ref': self.on_scroll_to_ref,
'set_forward_keypresses': self.set_forward_keypresses,
'set_reference_mode': self.set_reference_mode, 'set_reference_mode': self.set_reference_mode,
'toggle_autoscroll': self.toggle_autoscroll,
'wheel_from_margin': self.wheel_from_margin, 'wheel_from_margin': self.wheel_from_margin,
'window_size': self.received_window_size, 'window_size': self.received_window_size,
'overlay_shown': self.on_overlay_shown, 'overlay_visibility_changed': self.on_overlay_visibility_changed,
} }
self.comm = IframeClient(handlers) self.comm = IframeClient(handlers)
self.last_window_ypos = 0 self.last_window_ypos = 0
self.length_before = None self.length_before = None
def on_overlay_shown(self): def on_overlay_visibility_changed(self, data):
if current_layout_mode() is 'flow': if data.visible:
flow_cancel_auto_scroll() self.forward_keypresses = True
if self.auto_scroll_action:
self.auto_scroll_active_before_overlay = self.auto_scroll_action('is_active')
self.auto_scroll_action('stop')
else:
self.forward_keypresses = False
if self.auto_scroll_active_before_overlay:
self.auto_scroll_active_before_overlay = undefined
self.auto_scroll_action('start')
def modify_selection(self, data): def modify_selection(self, data):
sel = window.getSelection() sel = window.getSelection()
sel.modify('extend', data.direction, data.granularity) sel.modify('extend', data.direction, data.granularity)
def set_forward_keypresses(self, data):
self.forward_keypresses = data.forward
def initialize(self, data): def initialize(self, data):
scroll_viewport.update_window_size(data.width, data.height) scroll_viewport.update_window_size(data.width, data.height)
window.addEventListener('error', self.onerror) window.addEventListener('error', self.onerror)
@ -188,7 +194,7 @@ class IframeBoss:
self.to_scroll_fraction = flow_to_scroll_fraction self.to_scroll_fraction = flow_to_scroll_fraction
self.jump_to_cfi = scroll_to_cfi self.jump_to_cfi = scroll_to_cfi
self.anchor_funcs = flow_anchor_funcs self.anchor_funcs = flow_anchor_funcs
self.auto_scroll_resume = flow_auto_scroll_resume self.auto_scroll_action = flow_auto_scroll_action
else: else:
self.do_layout = paged_layout self.do_layout = paged_layout
self.handle_wheel = paged_onwheel self.handle_wheel = paged_onwheel
@ -197,7 +203,7 @@ class IframeBoss:
self.jump_to_cfi = paged_jump_to_cfi self.jump_to_cfi = paged_jump_to_cfi
self._handle_gesture = paged_handle_gesture self._handle_gesture = paged_handle_gesture
self.anchor_funcs = paged_anchor_funcs self.anchor_funcs = paged_anchor_funcs
self.auto_scroll_resume = paged_auto_scroll_resume self.auto_scroll_action = paged_auto_scroll_action
update_settings(data.settings) update_settings(data.settings)
self.keyboard_shortcut_map = create_shortcut_map(data.settings.keyboard_shortcuts) self.keyboard_shortcut_map = create_shortcut_map(data.settings.keyboard_shortcuts)
set_current_spine_item({ set_current_spine_item({
@ -217,6 +223,9 @@ class IframeBoss:
def on_scroll_to_frac(self, data): def on_scroll_to_frac(self, data):
self.to_scroll_fraction(data.frac, False) self.to_scroll_fraction(data.frac, False)
def toggle_autoscroll(self):
self.auto_scroll_action('toggle')
def handle_gesture(self, gesture): def handle_gesture(self, gesture):
if gesture.type is 'show-chrome': if gesture.type is 'show-chrome':
self.send_message('show_chrome') self.send_message('show_chrome')
@ -317,7 +326,7 @@ class IframeBoss:
self.onscroll() self.onscroll()
self.send_message('content_loaded', progress_frac=self.calculate_progress_frac(), file_progress_frac=progress_frac()) self.send_message('content_loaded', progress_frac=self.calculate_progress_frac(), file_progress_frac=progress_frac())
self.last_cfi = None self.last_cfi = None
self.auto_scroll_resume() self.auto_scroll_action('resume')
window.setTimeout(self.update_cfi, 0) window.setTimeout(self.update_cfi, 0)
window.setTimeout(self.update_toc_position, 0) window.setTimeout(self.update_toc_position, 0)

View File

@ -6,6 +6,7 @@ from elementmaker import E
from gettext import gettext as _ from gettext import gettext as _
from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata
from book_list.globals import get_session_data
from book_list.library_data import sync_library_books from book_list.library_data import sync_library_books
from book_list.router import home from book_list.router import home
from book_list.theme import get_color from book_list.theme import get_color
@ -230,6 +231,7 @@ class MainOverlay: # {{{
def show(self, container): def show(self, container):
self.container_id = container.getAttribute('id') self.container_id = container.getAttribute('id')
icon_size = '3.5ex' icon_size = '3.5ex'
sd = get_session_data()
def ac(text, tooltip, action, icon, is_text_button): def ac(text, tooltip, action, icon, is_text_button):
if is_text_button: if is_text_button:
@ -296,6 +298,14 @@ class MainOverlay: # {{{
full_screen_actions.push( full_screen_actions.push(
ac(text, _('Toggle full screen mode'), def(): self.overlay.hide(), ui_operations.toggle_full_screen();, 'full-screen') ac(text, _('Toggle full screen mode'), def(): self.overlay.hide(), ui_operations.toggle_full_screen();, 'full-screen')
) )
if sd.get('read_mode') is 'flow':
asa = self.overlay.view.autoscroll_active
full_screen_actions.append(ac(
_('Stop auto scroll') if asa else _('Auto scroll'), _('Toggle auto-scrolling'), def():
self.overlay.hide()
window.setTimeout(self.overlay.view.toggle_autoscroll, 0)
, 'auto-scroll'))
if full_screen_actions.length: if full_screen_actions.length:
actions_div.appendChild(E.ul(*full_screen_actions)) actions_div.appendChild(E.ul(*full_screen_actions))
@ -510,7 +520,6 @@ class Overlay:
c.style.color = get_color('window-foreground') c.style.color = get_color('window-foreground')
if c.style.display is not 'block': if c.style.display is not 'block':
c.style.display = 'block' c.style.display = 'block'
self.view.overlay_visibility_changed(True)
return c return c
@property @property

View File

@ -563,10 +563,7 @@ def handle_shortcut(sc_name, evt):
scroll_by_page(False, True) scroll_by_page(False, True)
return True return True
if sc_name is 'toggle_autoscroll': if sc_name is 'toggle_autoscroll':
get_boss().send_message('error', title=_('No auto scroll in paged mode'), msg=_( auto_scroll_action('toggle')
'Switch to flow mode (Viewer preferences->Page layout) to enable auto'
' scrolling')
)
return True return True
return False return False
@ -655,5 +652,10 @@ def resize_done():
resize_manager.end_resize() resize_manager.end_resize()
def paged_auto_scroll_resume(): def auto_scroll_action(action):
pass if action is 'toggle':
get_boss().send_message('error', title=_('No auto scroll in paged mode'), msg=_(
'Switch to flow mode (Viewer preferences->Page layout) to enable auto'
' scrolling')
)
return False

View File

@ -201,6 +201,9 @@ class View:
), ),
) )
handlers = { handlers = {
'autoscroll_state_changed': def(data):
self.autoscroll_active = v'!!data.running'
,
'bump_font_size': self.bump_font_size, 'bump_font_size': self.bump_font_size,
'content_loaded': self.on_content_loaded, 'content_loaded': self.on_content_loaded,
'error': self.on_iframe_error, 'error': self.on_iframe_error,
@ -339,9 +342,7 @@ class View:
def overlay_visibility_changed(self, visible): def overlay_visibility_changed(self, visible):
if self.iframe_wrapper.send_message: if self.iframe_wrapper.send_message:
if visible: self.iframe_wrapper.send_message('overlay_visibility_changed', visible=visible)
self.iframe_wrapper.send_message('overlay_shown')
self.iframe_wrapper.send_message('set_forward_keypresses', forward=v'!!visible')
if ui_operations.overlay_visibility_changed: if ui_operations.overlay_visibility_changed:
ui_operations.overlay_visibility_changed(visible) ui_operations.overlay_visibility_changed(visible)
@ -429,6 +430,9 @@ class View:
sd.set('read_mode', new_mode) sd.set('read_mode', new_mode)
ui_operations.redisplay_book() ui_operations.redisplay_book()
def toggle_autoscroll(self):
self.iframe_wrapper.send_message('toggle_autoscroll')
def toggle_toolbar(self): def toggle_toolbar(self):
sd = get_session_data() sd = get_session_data()
misc = sd.get('standalone_misc_settings') misc = sd.get('standalone_misc_settings')