mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add an auto-scroll button to the viewer controls
This commit is contained in:
parent
d94c2f21e7
commit
38736d9412
1
imgsrc/srv/auto-scroll.svg
Normal file
1
imgsrc/srv/auto-scroll.svg
Normal 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 |
@ -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()
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user