Viewer: Make it easier to use the bookmarks panel with only keyboard. Fixes #1847423 [[Feature] Make ebook viewer keyboard-friendly](https://bugs.launchpad.net/calibre/+bug/1847423)

This commit is contained in:
Kovid Goyal 2019-10-09 14:11:23 +05:30
parent e2ded28390
commit 21df277dc4
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 66 additions and 4 deletions

View File

@ -13,6 +13,7 @@ from PyQt5.Qt import (
from calibre.gui2 import choose_files, choose_save_file
from calibre.gui2.viewer.annotations import serialize_annotation
from calibre.gui2.viewer.shortcuts import get_shortcut_for
from calibre.srv.render_book import parse_annotation
from calibre.utils.date import EPOCH, utcnow
from calibre.utils.icu import sort_key
@ -69,6 +70,7 @@ class BookmarkManager(QWidget):
edited = pyqtSignal(object)
activated = pyqtSignal(object)
create_requested = pyqtSignal()
toggle_requested = pyqtSignal()
def __init__(self, parent):
QWidget.__init__(self, parent)
@ -102,7 +104,7 @@ class BookmarkManager(QWidget):
b.clicked.connect(self.delete_bookmark)
l.addWidget(b, l.rowCount() - 1, 1)
self.button_delete = b = QPushButton(_('Sort by &name'), self)
self.button_delete = b = QPushButton(_('Sort by na&me'), self)
b.setToolTip(_('Sort bookmarks by name'))
b.clicked.connect(self.sort_by_name)
l.addWidget(b)
@ -281,3 +283,9 @@ class BookmarkManager(QWidget):
self.set_bookmarks(bookmarks)
self.set_current_bookmark(bm)
self.edited.emit(bookmarks)
def keyPressEvent(self, ev):
if ev.key() == Qt.Key_Escape or get_shortcut_for(self, ev) == 'toggle_bookmarks':
self.toggle_requested.emit()
return
return QWidget.keyPressEvent(self, ev)

View File

@ -0,0 +1,36 @@
#!/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
from PyQt5.Qt import QKeySequence, QMainWindow, Qt
def get_main_window_for(widget):
p = widget
while p is not None:
if isinstance(p, QMainWindow):
return p
p = p.parent()
def key_to_text(key):
return QKeySequence(key).toString(QKeySequence.PortableText).lower()
def ev_to_index(ev):
m = ev.modifiers()
mods = []
for x in ('ALT', 'CTRL', 'META', 'SHIFT'):
mods.append('y' if m & getattr(Qt, x) else 'n')
return ''.join(mods) + key_to_text(ev.key())
def get_shortcut_for(widget, ev):
mw = get_main_window_for(widget)
if mw is None:
return
smap = mw.web_view.shortcut_map
idx = ev_to_index(ev)
return smap.get(idx)

View File

@ -120,8 +120,9 @@ class EbookViewer(MainWindow):
connect_lambda(
w.create_requested, self,
lambda self: self.web_view.get_current_cfi(self.bookmarks_widget.create_new_bookmark))
self.bookmarks_widget.edited.connect(self.bookmarks_edited)
self.bookmarks_widget.activated.connect(self.bookmark_activated)
w.edited.connect(self.bookmarks_edited)
w.activated.connect(self.bookmark_activated)
w.toggle_requested.connect(self.toggle_bookmarks)
self.bookmarks_dock.setWidget(w)
self.web_view = WebView(self)
@ -200,7 +201,12 @@ class EbookViewer(MainWindow):
self.toc_dock.setVisible(not self.toc_dock.isVisible())
def toggle_bookmarks(self):
self.bookmarks_dock.setVisible(not self.bookmarks_dock.isVisible())
is_visible = self.bookmarks_dock.isVisible()
self.bookmarks_dock.setVisible(not is_visible)
if is_visible:
self.web_view.setFocus(Qt.OtherFocusReason)
else:
self.bookmarks_widget.bookmarks_list.setFocus(Qt.OtherFocusReason)
def toggle_lookup(self):
self.lookup_dock.setVisible(not self.lookup_dock.isVisible())

View File

@ -235,6 +235,7 @@ class ViewerBridge(Bridge):
overlay_visibility_changed = from_js(object)
show_loading_message = from_js(object)
show_error = from_js(object, object, object)
export_shortcut_map = from_js(object)
create_view = to_js()
start_book_load = to_js()
@ -405,6 +406,8 @@ class WebView(RestartingWebEngineView):
self.bridge.overlay_visibility_changed.connect(self.overlay_visibility_changed)
self.bridge.show_loading_message.connect(self.show_loading_message)
self.bridge.show_error.connect(self.show_error)
self.bridge.export_shortcut_map.connect(self.set_shortcut_map)
self.shortcut_map = {}
self.bridge.report_cfi.connect(self.call_callback)
self.bridge.change_background_image.connect(self.change_background_image)
self.pending_bridge_ready_actions = {}
@ -416,6 +419,9 @@ class WebView(RestartingWebEngineView):
self.inspector = Inspector(parent.inspector_dock.toggleViewAction(), self)
parent.inspector_dock.setWidget(self.inspector)
def set_shortcut_map(self, smap):
self.shortcut_map = smap
def url_changed(self, url):
if url.hasFragment():
frag = url.fragment(url.FullyDecoded)

View File

@ -155,6 +155,8 @@ class View:
self.book_scrollbar = BookScrollbar(self)
sd = get_session_data()
self.keyboard_shortcut_map = create_shortcut_map(sd.get('keyboard_shortcuts'))
if ui_operations.export_shortcut_map:
ui_operations.export_shortcut_map(self.keyboard_shortcut_map)
left_margin = E.div(svgicon('caret-left'), style='width:{}px;'.format(sd.get('margin_left', 20)), class_='book-side-margin', id='book-left-margin', onclick=self.left_margin_clicked)
set_left_margin_handler(left_margin)
right_margin = E.div(svgicon('caret-right'), style='width:{}px;'.format(sd.get('margin_right', 20)), class_='book-side-margin', id='book-right-margin', onclick=self.right_margin_clicked)
@ -580,6 +582,8 @@ class View:
# redisplay_book() is called when settings are changed
sd = get_session_data()
self.keyboard_shortcut_map = create_shortcut_map(sd.get('keyboard_shortcuts'))
if ui_operations.export_shortcut_map:
ui_operations.export_shortcut_map(self.keyboard_shortcut_map)
self.book_scrollbar.apply_visibility()
self.display_book(self.book)

View File

@ -316,6 +316,8 @@ if window is window.top:
to_python.overlay_visibility_changed(visible)
ui_operations.show_loading_message = def(msg):
to_python.show_loading_message(msg)
ui_operations.export_shortcut_map = def(smap):
to_python.export_shortcut_map(smap)
document.body.appendChild(E.div(id='view'))
window.onerror = onerror