diff --git a/imgsrc/srv/auto-scroll.svg b/imgsrc/srv/auto-scroll.svg new file mode 100644 index 0000000000..1cc6e77f70 --- /dev/null +++ b/imgsrc/srv/auto-scroll.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pyj/read_book/flow_mode.pyj b/src/pyj/read_book/flow_mode.pyj index fc5b6d4bba..4b810a2d8c 100644 --- a/src/pyj/read_book/flow_mode.pyj +++ b/src/pyj/read_book/flow_mode.pyj @@ -141,6 +141,24 @@ def scroll_by_page(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): if sc_name is 'down': scroll_animator.start(DIRECTION.Down, False) @@ -173,10 +191,7 @@ def handle_shortcut(sc_name, evt): scroll_by_page(1) return True if sc_name is 'toggle_autoscroll': - if scroll_animator.auto and scroll_animator.is_running(): - cancel_scroll() - else: - scroll_animator.start(DIRECTION.Down, True) + toggle_autoscroll() return True 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') -def flow_auto_scroll_resume(): +def auto_scroll_resume(): scroll_animator.wait = False scroll_animator.sync() @@ -422,3 +437,17 @@ anchor_funcs = { 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() diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index 20b3ea9acd..bcb588eb8d 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -10,10 +10,10 @@ from iframe_comm import IframeClient from read_book.cfi import scroll_to as scroll_to_cfi from read_book.extract import get_elements from read_book.flow_mode import ( - anchor_funcs as flow_anchor_funcs, cancel_scroll as flow_cancel_auto_scroll, - flow_auto_scroll_resume, flow_onwheel, flow_to_scroll_fraction, - handle_gesture as flow_handle_gesture, handle_shortcut as flow_handle_shortcut, - layout as flow_layout, scroll_by_page as flow_scroll_by_page + anchor_funcs as flow_anchor_funcs, auto_scroll_action as flow_auto_scroll_action, + flow_onwheel, flow_to_scroll_fraction, handle_gesture as flow_handle_gesture, + handle_shortcut as flow_handle_shortcut, layout as flow_layout, + scroll_by_page as flow_scroll_by_page ) from read_book.footnotes import is_footnote_link from read_book.globals import ( @@ -22,10 +22,11 @@ from read_book.globals import ( ) from read_book.mathjax import apply_mathjax from read_book.paged_mode import ( - anchor_funcs as paged_anchor_funcs, calc_columns_per_screen, current_cfi, - handle_gesture as paged_handle_gesture, handle_shortcut as paged_handle_shortcut, - jump_to_cfi as paged_jump_to_cfi, layout as paged_layout, - onwheel as paged_onwheel, paged_auto_scroll_resume, + anchor_funcs as paged_anchor_funcs, + auto_scroll_action as paged_auto_scroll_action, calc_columns_per_screen, + current_cfi, handle_gesture as paged_handle_gesture, + 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, reset_paged_mode_globals, resize_done as paged_resize_done, 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_frac': self.on_scroll_to_frac, 'scroll_to_ref': self.on_scroll_to_ref, - 'set_forward_keypresses': self.set_forward_keypresses, 'set_reference_mode': self.set_reference_mode, + 'toggle_autoscroll': self.toggle_autoscroll, 'wheel_from_margin': self.wheel_from_margin, '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.last_window_ypos = 0 self.length_before = None - def on_overlay_shown(self): - if current_layout_mode() is 'flow': - flow_cancel_auto_scroll() + def on_overlay_visibility_changed(self, data): + if data.visible: + 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): sel = window.getSelection() sel.modify('extend', data.direction, data.granularity) - def set_forward_keypresses(self, data): - self.forward_keypresses = data.forward - def initialize(self, data): scroll_viewport.update_window_size(data.width, data.height) window.addEventListener('error', self.onerror) @@ -188,7 +194,7 @@ class IframeBoss: self.to_scroll_fraction = flow_to_scroll_fraction self.jump_to_cfi = scroll_to_cfi self.anchor_funcs = flow_anchor_funcs - self.auto_scroll_resume = flow_auto_scroll_resume + self.auto_scroll_action = flow_auto_scroll_action else: self.do_layout = paged_layout self.handle_wheel = paged_onwheel @@ -197,7 +203,7 @@ class IframeBoss: self.jump_to_cfi = paged_jump_to_cfi self._handle_gesture = paged_handle_gesture 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) self.keyboard_shortcut_map = create_shortcut_map(data.settings.keyboard_shortcuts) set_current_spine_item({ @@ -217,6 +223,9 @@ class IframeBoss: def on_scroll_to_frac(self, data): self.to_scroll_fraction(data.frac, False) + def toggle_autoscroll(self): + self.auto_scroll_action('toggle') + def handle_gesture(self, gesture): if gesture.type is 'show-chrome': self.send_message('show_chrome') @@ -317,7 +326,7 @@ class IframeBoss: self.onscroll() self.send_message('content_loaded', progress_frac=self.calculate_progress_frac(), file_progress_frac=progress_frac()) self.last_cfi = None - self.auto_scroll_resume() + self.auto_scroll_action('resume') window.setTimeout(self.update_cfi, 0) window.setTimeout(self.update_toc_position, 0) diff --git a/src/pyj/read_book/overlay.pyj b/src/pyj/read_book/overlay.pyj index 30f05e6c56..d3687701bd 100644 --- a/src/pyj/read_book/overlay.pyj +++ b/src/pyj/read_book/overlay.pyj @@ -6,6 +6,7 @@ from elementmaker import E from gettext import gettext as _ 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.router import home from book_list.theme import get_color @@ -230,6 +231,7 @@ class MainOverlay: # {{{ def show(self, container): self.container_id = container.getAttribute('id') icon_size = '3.5ex' + sd = get_session_data() def ac(text, tooltip, action, icon, is_text_button): if is_text_button: @@ -296,6 +298,14 @@ class MainOverlay: # {{{ full_screen_actions.push( 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: actions_div.appendChild(E.ul(*full_screen_actions)) @@ -510,7 +520,6 @@ class Overlay: c.style.color = get_color('window-foreground') if c.style.display is not 'block': c.style.display = 'block' - self.view.overlay_visibility_changed(True) return c @property diff --git a/src/pyj/read_book/paged_mode.pyj b/src/pyj/read_book/paged_mode.pyj index be026b56f0..35d94cf804 100644 --- a/src/pyj/read_book/paged_mode.pyj +++ b/src/pyj/read_book/paged_mode.pyj @@ -563,10 +563,7 @@ def handle_shortcut(sc_name, evt): scroll_by_page(False, True) return True if sc_name is 'toggle_autoscroll': - 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') - ) + auto_scroll_action('toggle') return True return False @@ -655,5 +652,10 @@ def resize_done(): resize_manager.end_resize() -def paged_auto_scroll_resume(): - pass +def auto_scroll_action(action): + 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 diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index e003c4b59e..e976d58667 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -201,6 +201,9 @@ class View: ), ) handlers = { + 'autoscroll_state_changed': def(data): + self.autoscroll_active = v'!!data.running' + , 'bump_font_size': self.bump_font_size, 'content_loaded': self.on_content_loaded, 'error': self.on_iframe_error, @@ -339,9 +342,7 @@ class View: def overlay_visibility_changed(self, visible): if self.iframe_wrapper.send_message: - if visible: - self.iframe_wrapper.send_message('overlay_shown') - self.iframe_wrapper.send_message('set_forward_keypresses', forward=v'!!visible') + self.iframe_wrapper.send_message('overlay_visibility_changed', visible=visible) if ui_operations.overlay_visibility_changed: ui_operations.overlay_visibility_changed(visible) @@ -429,6 +430,9 @@ class View: sd.set('read_mode', new_mode) ui_operations.redisplay_book() + def toggle_autoscroll(self): + self.iframe_wrapper.send_message('toggle_autoscroll') + def toggle_toolbar(self): sd = get_session_data() misc = sd.get('standalone_misc_settings')