From c8015e824c374e2f69ee0ed61cf981e27323c611 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 12 Dec 2020 09:04:22 +0530 Subject: [PATCH] E-book viewer: Add a toolbar icon for Read aloud --- imgsrc/bullhorn.svg | 85 ++++++++++++++++++++++++++++ resources/images/bullhorn.png | Bin 0 -> 2616 bytes src/calibre/gui2/viewer/toolbars.py | 10 ++++ src/calibre/gui2/viewer/web_view.py | 3 + src/pyj/read_book/read_aloud.pyj | 4 ++ src/pyj/read_book/view.pyj | 8 +++ src/pyj/viewer-main.pyj | 2 + 7 files changed, 112 insertions(+) create mode 100644 imgsrc/bullhorn.svg create mode 100644 resources/images/bullhorn.png diff --git a/imgsrc/bullhorn.svg b/imgsrc/bullhorn.svg new file mode 100644 index 0000000000..7ed591be28 --- /dev/null +++ b/imgsrc/bullhorn.svg @@ -0,0 +1,85 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/resources/images/bullhorn.png b/resources/images/bullhorn.png new file mode 100644 index 0000000000000000000000000000000000000000..f94c5f361e4fa3b1103f3a8fd6ef3664a65b3fe4 GIT binary patch literal 2616 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 literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/viewer/toolbars.py b/src/calibre/gui2/viewer/toolbars.py index 1a23ecf575..b2d81bede6 100644 --- a/src/calibre/gui2/viewer/toolbars.py +++ b/src/calibre/gui2/viewer/toolbars.py @@ -65,6 +65,7 @@ def all_actions(): 'print': Action('print.png', _('Print book'), 'print'), 'preferences': Action('config.png', _('Preferences'), 'preferences'), 'metadata': Action('metadata.png', _('Show book metadata'), 'metadata'), + 'toggle_read_aloud': Action('bullhorn.png', _('Read aloud'), 'toggle_read_aloud'), 'toggle_highlights': Action('highlight_only_on.png', _('Browse highlights in book'), 'toggle_highlights'), } all_actions.ans = Actions(amap) @@ -136,6 +137,7 @@ class ActionsToolBar(ToolBar): web_view.reference_mode_changed.connect(self.update_reference_mode_action) web_view.standalone_misc_settings_changed.connect(self.update_visibility) web_view.autoscroll_state_changed.connect(self.update_autoscroll_action) + web_view.read_aloud_state_changed.connect(self.update_read_aloud_action) web_view.customize_toolbar.connect(self.customize, type=Qt.ConnectionType.QueuedConnection) web_view.view_created.connect(self.on_view_created) @@ -171,6 +173,8 @@ class ActionsToolBar(ToolBar): a.setCheckable(True) self.toggle_highlights_action = self.highlights_action = a = shortcut_action('toggle_highlights') a.setCheckable(True) + self.toggle_read_aloud_action = a = shortcut_action('toggle_read_aloud') + a.setCheckable(True) self.lookup_action = a = shortcut_action('lookup') a.setCheckable(True) self.inspector_action = a = shortcut_action('inspector') @@ -178,6 +182,7 @@ class ActionsToolBar(ToolBar): self.autoscroll_action = a = shortcut_action('autoscroll') a.setCheckable(True) self.update_autoscroll_action(False) + self.update_read_aloud_action(False) self.chrome_action = shortcut_action('chrome') self.mode_action = a = shortcut_action('mode') @@ -223,6 +228,11 @@ class ActionsToolBar(ToolBar): self.autoscroll_action.setToolTip( _('Turn off auto-scrolling') if active else _('Turn on auto-scrolling')) + def update_read_aloud_action(self, active): + self.toggle_read_aloud_action.setChecked(active) + self.autoscroll_action.setToolTip( + _('Stop reading') if active else _('Read the text of the book aloud')) + def update_reference_mode_action(self, enabled): self.reference_action.setChecked(enabled) diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index fc8f6c30f4..694001d703 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -251,6 +251,7 @@ class ViewerBridge(Bridge): ask_for_open = from_js(object) selection_changed = from_js(object, object) autoscroll_state_changed = from_js(object) + read_aloud_state_changed = from_js(object) copy_selection = from_js(object, object) view_image = from_js(object) copy_image = from_js(object) @@ -452,6 +453,7 @@ class WebView(RestartingWebEngineView): ask_for_open = pyqtSignal(object) selection_changed = pyqtSignal(object, object) autoscroll_state_changed = pyqtSignal(object) + read_aloud_state_changed = pyqtSignal(object) view_image = pyqtSignal(object) copy_image = pyqtSignal(object) overlay_visibility_changed = pyqtSignal(object) @@ -508,6 +510,7 @@ class WebView(RestartingWebEngineView): self.bridge.ask_for_open.connect(self.ask_for_open) self.bridge.selection_changed.connect(self.selection_changed) self.bridge.autoscroll_state_changed.connect(self.autoscroll_state_changed) + self.bridge.read_aloud_state_changed.connect(self.read_aloud_state_changed) self.bridge.view_image.connect(self.view_image) self.bridge.copy_image.connect(self.copy_image) self.bridge.overlay_visibility_changed.connect(self.overlay_visibility_changed) diff --git a/src/pyj/read_book/read_aloud.pyj b/src/pyj/read_book/read_aloud.pyj index 6b5eec0b82..42185bb923 100644 --- a/src/pyj/read_book/read_aloud.pyj +++ b/src/pyj/read_book/read_aloud.pyj @@ -69,12 +69,16 @@ class ReadAloud: self.state = HIDDEN self.container.style.display = 'none' self.view.focus_iframe() + if ui_operations.read_aloud_state_changed: + ui_operations.read_aloud_state_changed(False) def show(self): if self.state is HIDDEN: self.container.style.display = 'block' self.state = STOPPED self.focus() + if ui_operations.read_aloud_state_changed: + ui_operations.read_aloud_state_changed(True) def focus(self): self.container.focus() diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 1fa6f6eb34..a964034892 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -507,6 +507,8 @@ class View: self.toggle_reference_mode() elif data.name is 'read_aloud': self.start_read_aloud() + elif data.name is 'toggle_read_aloud': + self.toggle_read_aloud() elif data.name is 'reload_book': ui_operations.reload_book() elif data.name is 'next_section': @@ -680,6 +682,12 @@ class View: if not dont_start_talking: self.read_aloud.play() + def toggle_read_aloud(self): + if self.read_aloud.is_visible: + self.read_aloud.hide() + else: + self.start_read_aloud() + def show_chrome(self, data): elements = {} if data and data.elements: diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 997d0f6fb3..6bf71ed2b8 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -394,6 +394,8 @@ if window is window.top: to_python.customize_toolbar() ui_operations.autoscroll_state_changed = def(active): to_python.autoscroll_state_changed(active) + ui_operations.read_aloud_state_changed = def(active): + to_python.read_aloud_state_changed(active) ui_operations.search_result_not_found = def(sr): to_python.search_result_not_found(sr) ui_operations.scrollbar_context_menu = def(x, y, frac):