Add support for touch screens to the main calibre book list

You can now flick to scroll, tap to select and double-tap to view books.
This commit is contained in:
Kovid Goyal 2017-07-22 14:22:49 +05:30
parent 3eade1a5f2
commit 1be4482c66
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 62 additions and 3 deletions

View File

@ -15,16 +15,17 @@ from textwrap import wrap
from PyQt5.Qt import ( from PyQt5.Qt import (
QListView, QSize, QStyledItemDelegate, QModelIndex, Qt, QImage, pyqtSignal, QListView, QSize, QStyledItemDelegate, QModelIndex, Qt, QImage, pyqtSignal,
QTimer, QPalette, QColor, QItemSelection, QPixmap, QApplication, QTimer, QPalette, QColor, QItemSelection, QPixmap, QApplication, QScroller,
QMimeData, QUrl, QDrag, QPoint, QPainter, QRect, pyqtProperty, QEvent, QMimeData, QUrl, QDrag, QPoint, QPainter, QRect, pyqtProperty, QEvent,
QPropertyAnimation, QEasingCurve, pyqtSlot, QHelpEvent, QAbstractItemView, QPropertyAnimation, QEasingCurve, pyqtSlot, QHelpEvent, QAbstractItemView,
QStyleOptionViewItem, QToolTip, QByteArray, QBuffer, QBrush, qRed, qGreen, QStyleOptionViewItem, QToolTip, QByteArray, QBuffer, QBrush, qRed, qGreen,
qBlue, QItemSelectionModel, QIcon, QFont) qBlue, QItemSelectionModel, QIcon, QFont, QMouseEvent)
from calibre import fit_image, prints, prepare_string_for_xml, human_readable from calibre import fit_image, prints, prepare_string_for_xml, human_readable
from calibre.constants import DEBUG, config_dir, islinux from calibre.constants import DEBUG, config_dir, islinux
from calibre.ebooks.metadata import fmt_sidx, rating_to_stars from calibre.ebooks.metadata import fmt_sidx, rating_to_stars
from calibre.utils import join_with_timeout from calibre.utils import join_with_timeout
from calibre.utils.monotonic import monotonic
from calibre.gui2 import gprefs, config, rating_font, empty_index from calibre.gui2 import gprefs, config, rating_font, empty_index
from calibre.gui2.library.caches import CoverCache, ThumbnailCache from calibre.gui2.library.caches import CoverCache, ThumbnailCache
from calibre.utils.config import prefs, tweaks from calibre.utils.config import prefs, tweaks
@ -624,6 +625,53 @@ class CoverDelegate(QStyledItemDelegate):
# }}} # }}}
def send_click(view, pos, button=Qt.LeftButton, double_click=False):
if double_click:
ev = QMouseEvent(QEvent.MouseButtonDblClick, pos, button, button, QApplication.keyboardModifiers())
QApplication.postEvent(view.viewport(), ev)
return
ev = QMouseEvent(QEvent.MouseButtonPress, pos, button, button, QApplication.keyboardModifiers())
QApplication.postEvent(view.viewport(), ev)
ev = QMouseEvent(QEvent.MouseButtonRelease, pos, button, button, QApplication.keyboardModifiers())
QApplication.postEvent(view.viewport(), ev)
def handle_gesture(ev, view):
tap = ev.gesture(Qt.TapGesture)
if tap and tap.state() == Qt.GestureFinished:
p, view.last_tap_at = view.last_tap_at, monotonic()
interval = QApplication.instance().doubleClickInterval() / 1000
double_click = monotonic() - p < interval
send_click(view, tap.position(), double_click=double_click)
ev.accept(Qt.TapGesture)
return True
th = ev.gesture(Qt.TapAndHoldGesture)
if th and th.state() in (Qt.GestureStarted, Qt.GestureUpdated, Qt.GestureFinished):
send_click(view, th.position(), button=Qt.RightButton)
ev.accept(Qt.TapAndHoldGesture)
return True
return True
def setup_gestures(view):
v = view.viewport()
view.scroller = QScroller.grabGesture(v, QScroller.TouchGesture)
v.grabGesture(Qt.TapGesture)
v.grabGesture(Qt.TapAndHoldGesture)
view.last_tap_at = 0
def gesture_viewport_event(view, ev):
et = ev.type()
if et in (QEvent.MouseButtonPress, QEvent.MouseMove, QEvent.MouseButtonRelease, QEvent.MouseButtonDblClick):
if ev.source() in (Qt.MouseEventSynthesizedBySystem, Qt.MouseEventSynthesizedByQt):
ev.ignore()
return False
elif et == QEvent.Gesture:
return handle_gesture(ev, view)
# The View {{{ # The View {{{
@ -635,6 +683,7 @@ class GridView(QListView):
def __init__(self, parent): def __init__(self, parent):
QListView.__init__(self, parent) QListView.__init__(self, parent)
setup_gestures(self)
setup_dnd_interface(self) setup_dnd_interface(self)
self.setUniformItemSizes(True) self.setUniformItemSizes(True)
self.setWrapping(True) self.setWrapping(True)
@ -670,6 +719,12 @@ class GridView(QListView):
t.setInterval(200), t.setSingleShot(True) t.setInterval(200), t.setSingleShot(True)
t.timeout.connect(self.update_memory_cover_cache_size) t.timeout.connect(self.update_memory_cover_cache_size)
def viewportEvent(self, ev):
ret = gesture_viewport_event(self, ev)
if ret is not None:
return ret
return QListView.viewportEvent(self, ev)
@property @property
def device_pixel_ratio(self): def device_pixel_ratio(self):
try: try:

View File

@ -21,7 +21,7 @@ from calibre.gui2.library.delegates import (RatingDelegate, PubDateDelegate,
CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcTemplateDelegate, CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcTemplateDelegate,
CcEnumDelegate, CcNumberDelegate, LanguagesDelegate) CcEnumDelegate, CcNumberDelegate, LanguagesDelegate)
from calibre.gui2.library.models import BooksModel, DeviceBooksModel from calibre.gui2.library.models import BooksModel, DeviceBooksModel
from calibre.gui2.library.alternate_views import AlternateViews, setup_dnd_interface from calibre.gui2.library.alternate_views import AlternateViews, setup_dnd_interface, setup_gestures, gesture_viewport_event
from calibre.utils.config import tweaks, prefs from calibre.utils.config import tweaks, prefs
from calibre.gui2 import error_dialog, gprefs, FunctionDispatcher from calibre.gui2 import error_dialog, gprefs, FunctionDispatcher
from calibre.gui2.library import DEFAULT_SORT from calibre.gui2.library import DEFAULT_SORT
@ -193,10 +193,14 @@ class BooksView(QTableView): # {{{
def viewportEvent(self, event): def viewportEvent(self, event):
if (event.type() == event.ToolTip and not gprefs['book_list_tooltips']): if (event.type() == event.ToolTip and not gprefs['book_list_tooltips']):
return False return False
ret = gesture_viewport_event(self, event)
if ret is not None:
return ret
return QTableView.viewportEvent(self, event) return QTableView.viewportEvent(self, event)
def __init__(self, parent, modelcls=BooksModel, use_edit_metadata_dialog=True): def __init__(self, parent, modelcls=BooksModel, use_edit_metadata_dialog=True):
QTableView.__init__(self, parent) QTableView.__init__(self, parent)
setup_gestures(self)
self.default_row_height = self.verticalHeader().defaultSectionSize() self.default_row_height = self.verticalHeader().defaultSectionSize()
self.gui = parent self.gui = parent
self.setProperty('highlight_current_item', 150) self.setProperty('highlight_current_item', 150)