Implement a vertical toolbar

This commit is contained in:
Kovid Goyal 2019-10-31 15:29:59 +05:30
parent a82a2724ce
commit 78d048c809
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 184 additions and 0 deletions

View File

@ -15,6 +15,15 @@ def get_main_window_for(widget):
p = p.parent() p = p.parent()
def index_to_key_sequence(idx):
mods = []
for i, x in enumerate(('ALT', 'CTRL', 'META', 'SHIFT')):
if idx[i] == 'y':
mods.append(x.capitalize())
mods.append(idx[4:])
return QKeySequence('+'.join(mods))
def key_to_text(key): def key_to_text(key):
return QKeySequence(key).toString(QKeySequence.PortableText).lower() return QKeySequence(key).toString(QKeySequence.PortableText).lower()

View File

@ -0,0 +1,130 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import os
from collections import defaultdict
from functools import partial
from PyQt5.Qt import QAction, QIcon, QKeySequence, QMenu, Qt, QToolBar, pyqtSignal
from PyQt5.QtWebEngineWidgets import QWebEnginePage
from calibre.gui2 import elided_text
from calibre.gui2.viewer.shortcuts import index_to_key_sequence
from calibre.gui2.viewer.web_view import get_session_pref, set_book_path
from polyglot.builtins import iteritems
class VerticalToolBar(QToolBar):
action_triggered = pyqtSignal(object)
open_book_at_path = pyqtSignal(object)
def __init__(self, parent=None):
QToolBar.__init__(self, parent)
self.setObjectName('vertical_toolbar')
self.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea)
self.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.setOrientation(Qt.Vertical)
def initialize(self, web_view):
self.action_triggered.connect(web_view.trigger_shortcut)
page = web_view.page()
web_view.shortcuts_changed.connect(self.set_tooltips)
web_view.paged_mode_changed.connect(self.update_mode_action)
self.shortcut_actions = {}
self.back_action = page.action(QWebEnginePage.Back)
self.back_action.setIcon(QIcon(I('back.png')))
self.back_action.setText(_('Back'))
self.addAction(self.back_action)
self.forward_action = page.action(QWebEnginePage.Forward)
self.forward_action.setIcon(QIcon(I('forward.png')))
self.forward_action.setText(_('Forward'))
self.addAction(self.forward_action)
self.addSeparator()
def shortcut_action(icon, text, sc):
a = QAction(QIcon(I(icon)), text, self)
self.addAction(a)
connect_lambda(a.triggered, self, lambda self: self.action_triggered.emit(sc))
self.shortcut_actions[sc] = a
return a
self.open_action = a = QAction(QIcon(I('document_open.png')), _('Open e-book'), self)
self.open_menu = m = QMenu(self)
a.setMenu(m)
m.aboutToShow.connect(self.populate_open_menu)
connect_lambda(a.triggered, self, lambda self: self.open_book_at_path.emit(None))
self.addAction(a)
self.copy_action = a = page.action(QWebEnginePage.Copy)
a.setIcon(QIcon(I('edit-copy.png'))), a.setText(_('Copy to clipboard'))
self.addAction(a)
self.increase_font_size_action = shortcut_action('font_size_larger.png', _('Increase font size'), 'increase_font_size')
self.decrease_font_size_action = shortcut_action('font_size_smaller.png', _('Decrease font size'), 'decrease_font_size')
self.fullscreen_action = shortcut_action('page.png', _('Toggle full screen'), 'toggle_full_screen')
self.addSeparator()
self.next_action = shortcut_action('next.png', _('Next page'), 'next')
self.previous_action = shortcut_action('previous.png', _('Previous page'), 'previous')
self.addSeparator()
self.toc_action = shortcut_action('toc.png', _('Table of Contents'), 'toggle_toc')
self.bookmarks_action = shortcut_action('bookmarks.png', _('Bookmarks'), 'toggle_bookmarks')
self.lookup_action = shortcut_action('search.png', _('Lookup words'), 'toggle_lookup')
self.chrome_action = shortcut_action('tweaks.png', _('Show viewer controls'), 'show_chrome')
self.addSeparator()
self.mode_action = a = shortcut_action('scroll.png', _('Toggle paged mode'), 'toggle_paged_mode')
a.setCheckable(True)
self.print_action = shortcut_action('print.png', _('Print book'), 'print')
self.preferences_action = shortcut_action('config.png', _('Preferences'), 'preferences')
self.metadata_action = shortcut_action('metadata.png', _('Show book metadata'), 'metadata')
self.update_mode_action()
self.addSeparator()
def update_mode_action(self):
mode = get_session_pref('read_mode', default='paged', group=None)
a = self.mode_action
if mode == 'paged':
a.setChecked(False)
a.setToolTip(_('Switch to flow mode — where the text is not broken into pages'))
else:
a.setChecked(True)
a.setToolTip(_('Switch to paged mode — where the text is broken into pages'))
def set_tooltips(self, smap):
rmap = defaultdict(list)
for k, v in iteritems(smap):
rmap[v].append(k)
for sc, a in iteritems(self.shortcut_actions):
if a.isCheckable():
continue
x = rmap.get(sc)
if x is not None:
def as_text(idx):
return index_to_key_sequence(idx).toString(QKeySequence.NativeText)
keys = sorted(filter(None, map(as_text, x)))
if keys:
a.setToolTip('{} [{}]'.format(a.text(), ', '.join(keys)))
def populate_open_menu(self):
m = self.open_menu
m.clear()
recent = get_session_pref('standalone_recently_opened', group=None, default=())
if recent:
for entry in recent:
try:
path = os.path.abspath(entry['pathtoebook'])
except Exception:
continue
if path == os.path.abspath(set_book_path.pathtoebook):
continue
m.addAction('{}\t {}'.format(
elided_text(entry['title'], pos='right', width=250),
elided_text(os.path.basename(path), width=250))).triggered.connect(partial(
self.open_book_at_path.emit, path))

View File

@ -32,6 +32,7 @@ from calibre.gui2.viewer.convert_book import prepare_book, update_book
from calibre.gui2.viewer.lookup import Lookup from calibre.gui2.viewer.lookup import Lookup
from calibre.gui2.viewer.overlay import LoadingOverlay from calibre.gui2.viewer.overlay import LoadingOverlay
from calibre.gui2.viewer.toc import TOC, TOCSearch, TOCView from calibre.gui2.viewer.toc import TOC, TOCSearch, TOCView
from calibre.gui2.viewer.toolbars import VerticalToolBar
from calibre.gui2.viewer.web_view import ( from calibre.gui2.viewer.web_view import (
WebView, get_path_for_name, get_session_pref, set_book_path, viewer_config_dir, WebView, get_path_for_name, get_session_pref, set_book_path, viewer_config_dir,
vprefs vprefs
@ -98,6 +99,10 @@ class EbookViewer(MainWindow):
self.setWindowTitle(self.base_window_title) self.setWindowTitle(self.base_window_title)
self.in_full_screen_mode = None self.in_full_screen_mode = None
self.image_popup = ImagePopup(self) self.image_popup = ImagePopup(self)
self.vertical_toolbar = vt = VerticalToolBar(self)
vt.open_book_at_path.connect(self.ask_for_open)
self.addToolBar(Qt.LeftToolBarArea, vt)
# vt.setVisible(False)
try: try:
os.makedirs(annotations_dir) os.makedirs(annotations_dir)
except EnvironmentError: except EnvironmentError:
@ -156,6 +161,7 @@ class EbookViewer(MainWindow):
self.web_view.show_loading_message.connect(self.show_loading_message) self.web_view.show_loading_message.connect(self.show_loading_message)
self.web_view.show_error.connect(self.show_error) self.web_view.show_error.connect(self.show_error)
self.web_view.print_book.connect(self.print_book, type=Qt.QueuedConnection) self.web_view.print_book.connect(self.print_book, type=Qt.QueuedConnection)
self.vertical_toolbar.initialize(self.web_view)
self.setCentralWidget(self.web_view) self.setCentralWidget(self.web_view)
self.loading_overlay = LoadingOverlay(self) self.loading_overlay = LoadingOverlay(self)
self.restore_state() self.restore_state()

View File

@ -265,6 +265,7 @@ class ViewerBridge(Bridge):
show_home_page = to_js() show_home_page = to_js()
background_image_changed = to_js() background_image_changed = to_js()
goto_frac = to_js() goto_frac = to_js()
trigger_shortcut = to_js()
def apply_font_settings(page_or_view): def apply_font_settings(page_or_view):
@ -399,6 +400,8 @@ class WebView(RestartingWebEngineView):
show_loading_message = pyqtSignal(object) show_loading_message = pyqtSignal(object)
show_error = pyqtSignal(object, object, object) show_error = pyqtSignal(object, object, object)
print_book = pyqtSignal() print_book = pyqtSignal()
shortcuts_changed = pyqtSignal(object)
paged_mode_changed = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
self._host_widget = None self._host_widget = None
@ -447,6 +450,7 @@ class WebView(RestartingWebEngineView):
def set_shortcut_map(self, smap): def set_shortcut_map(self, smap):
self.shortcut_map = smap self.shortcut_map = smap
self.shortcuts_changed.emit(smap)
def url_changed(self, url): def url_changed(self, url):
if url.hasFragment(): if url.hasFragment():
@ -527,12 +531,15 @@ class WebView(RestartingWebEngineView):
if key == '*' and val is None: if key == '*' and val is None:
vprefs['session_data'] = {} vprefs['session_data'] = {}
apply_font_settings(self._page) apply_font_settings(self._page)
self.paged_mode_changed.emit()
elif key != '*': elif key != '*':
sd = vprefs['session_data'] sd = vprefs['session_data']
sd[key] = val sd[key] = val
vprefs['session_data'] = sd vprefs['session_data'] = sd
if key in ('standalone_font_settings', 'base_font_size'): if key in ('standalone_font_settings', 'base_font_size'):
apply_font_settings(self._page) apply_font_settings(self._page)
elif key == 'read_mode':
self.paged_mode_changed.emit()
def set_local_storage(self, key, val): def set_local_storage(self, key, val):
if key == '*' and val is None: if key == '*' and val is None:
@ -573,3 +580,6 @@ class WebView(RestartingWebEngineView):
def clear_history(self): def clear_history(self):
self._page.history().clear() self._page.history().clear()
def trigger_shortcut(self, which):
self.execute_when_ready('trigger_shortcut', which)

View File

@ -245,6 +245,7 @@ def shortcuts_definition():
'ui', 'ui',
_('Show the viewer controls'), _('Show the viewer controls'),
), ),
} }
return ans return ans
@ -288,6 +289,13 @@ def add_standalone_viewer_shortcuts():
_('Quit the viewer'), _('Quit the viewer'),
) )
sc['print'] = desc(
"Ctrl+P",
'ui',
_('Print book to PDF'),
)
def create_shortcut_map(custom_shortcuts): def create_shortcut_map(custom_shortcuts):
ans = {} ans = {}
scd = shortcuts_definition() scd = shortcuts_definition()

View File

@ -339,6 +339,8 @@ class View:
ui_operations.toggle_inspector() ui_operations.toggle_inspector()
elif data.name is 'toggle_lookup': elif data.name is 'toggle_lookup':
ui_operations.toggle_lookup() ui_operations.toggle_lookup()
elif data.name is 'toggle_full_screen':
ui_operations.toggle_full_screen()
elif data.name is 'toggle_paged_mode': elif data.name is 'toggle_paged_mode':
self.toggle_paged_mode() self.toggle_paged_mode()
elif data.name is 'quit': elif data.name is 'quit':
@ -367,6 +369,19 @@ class View:
self.on_next_section({'forward': False}) self.on_next_section({'forward': False})
elif data.name is 'open_book': elif data.name is 'open_book':
self.overlay.open_book() self.overlay.open_book()
elif data.name is 'next':
self.iframe_wrapper.send_message(
'next_screen', backwards=False, all_pages_on_screen=get_session_data().get('paged_margin_clicks_scroll_by_screen'))
elif data.name is 'previous':
self.iframe_wrapper.send_message(
'next_screen', backwards=True, all_pages_on_screen=get_session_data().get('paged_margin_clicks_scroll_by_screen'))
elif data.name is 'print':
ui_operations.print_book()
elif data.name is 'preferences':
self.overlay.show_prefs()
elif data.name is 'metadata':
self.overlay.show_metadata()
def on_selection_change(self, data): def on_selection_change(self, data):
self.currently_showing.selected_text = data.text self.currently_showing.selected_text = data.text

View File

@ -269,6 +269,12 @@ def background_image_changed(img_id):
img.src = READER_BACKGROUND_URL + '?' + Date().getTime() img.src = READER_BACKGROUND_URL + '?' + Date().getTime()
@from_python
def trigger_shortcut(which):
if view:
view.on_handle_shortcut({'name': which})
def onerror(msg, script_url, line_number, column_number, error_object): def onerror(msg, script_url, line_number, column_number, error_object):
if not error_object: if not error_object:
# cross domain error # cross domain error