mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement a vertical toolbar
This commit is contained in:
parent
a82a2724ce
commit
78d048c809
@ -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()
|
||||
|
||||
|
130
src/calibre/gui2/viewer/toolbars.py
Normal file
130
src/calibre/gui2/viewer/toolbars.py
Normal 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))
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user