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()
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):
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.overlay import LoadingOverlay
from calibre.gui2.viewer.toc import TOC, TOCSearch, TOCView
from calibre.gui2.viewer.toolbars import VerticalToolBar
from calibre.gui2.viewer.web_view import (
WebView, get_path_for_name, get_session_pref, set_book_path, viewer_config_dir,
vprefs
@ -98,6 +99,10 @@ class EbookViewer(MainWindow):
self.setWindowTitle(self.base_window_title)
self.in_full_screen_mode = None
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:
os.makedirs(annotations_dir)
except EnvironmentError:
@ -156,6 +161,7 @@ class EbookViewer(MainWindow):
self.web_view.show_loading_message.connect(self.show_loading_message)
self.web_view.show_error.connect(self.show_error)
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.loading_overlay = LoadingOverlay(self)
self.restore_state()

View File

@ -265,6 +265,7 @@ class ViewerBridge(Bridge):
show_home_page = to_js()
background_image_changed = to_js()
goto_frac = to_js()
trigger_shortcut = to_js()
def apply_font_settings(page_or_view):
@ -399,6 +400,8 @@ class WebView(RestartingWebEngineView):
show_loading_message = pyqtSignal(object)
show_error = pyqtSignal(object, object, object)
print_book = pyqtSignal()
shortcuts_changed = pyqtSignal(object)
paged_mode_changed = pyqtSignal()
def __init__(self, parent=None):
self._host_widget = None
@ -447,6 +450,7 @@ class WebView(RestartingWebEngineView):
def set_shortcut_map(self, smap):
self.shortcut_map = smap
self.shortcuts_changed.emit(smap)
def url_changed(self, url):
if url.hasFragment():
@ -527,12 +531,15 @@ class WebView(RestartingWebEngineView):
if key == '*' and val is None:
vprefs['session_data'] = {}
apply_font_settings(self._page)
self.paged_mode_changed.emit()
elif key != '*':
sd = vprefs['session_data']
sd[key] = val
vprefs['session_data'] = sd
if key in ('standalone_font_settings', 'base_font_size'):
apply_font_settings(self._page)
elif key == 'read_mode':
self.paged_mode_changed.emit()
def set_local_storage(self, key, val):
if key == '*' and val is None:
@ -573,3 +580,6 @@ class WebView(RestartingWebEngineView):
def clear_history(self):
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',
_('Show the viewer controls'),
),
}
return ans
@ -288,6 +289,13 @@ def add_standalone_viewer_shortcuts():
_('Quit the viewer'),
)
sc['print'] = desc(
"Ctrl+P",
'ui',
_('Print book to PDF'),
)
def create_shortcut_map(custom_shortcuts):
ans = {}
scd = shortcuts_definition()

View File

@ -339,6 +339,8 @@ class View:
ui_operations.toggle_inspector()
elif data.name is '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':
self.toggle_paged_mode()
elif data.name is 'quit':
@ -367,6 +369,19 @@ class View:
self.on_next_section({'forward': False})
elif data.name is '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):
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()
@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):
if not error_object:
# cross domain error