Allow auto scrolling through the list of books by pressing the X key. The speed of scrolling can be controlled in Preferences->Look & feel->Cover browser. Useful to have a "slideshow" of book covers

Fixes #1917634 [[Enhancement] Add slideshow capability to cover browser](https://bugs.launchpad.net/calibre/+bug/1917634)
This commit is contained in:
Kovid Goyal 2021-04-15 18:01:48 +05:30
parent 095515b6e8
commit 75333c2b54
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
12 changed files with 138 additions and 34 deletions

View File

@ -782,3 +782,5 @@ calibre has several keyboard shortcuts to save you time and mouse movement. Thes
- Re-apply the current sort - Re-apply the current sort
* - :kbd:`Ctrl+Q` * - :kbd:`Ctrl+Q`
- Quit calibre - Quit calibre
* - :kbd:`X`
- Toggle autoscroll of the book list

View File

@ -970,6 +970,12 @@ class ActionOpenFolder(InterfaceActionBase):
' calibre library') ' calibre library')
class ActionAutoscrollBooks(InterfaceActionBase):
name = 'Autoscroll Books'
actual_plugin = 'calibre.gui2.actions.auto_scroll:AutoscrollBooksAction'
description = _('Auto scroll through the list of books')
class ActionSendToDevice(InterfaceActionBase): class ActionSendToDevice(InterfaceActionBase):
name = 'Send To Device' name = 'Send To Device'
actual_plugin = 'calibre.gui2.actions.device:SendToDeviceAction' actual_plugin = 'calibre.gui2.actions.device:SendToDeviceAction'
@ -1115,7 +1121,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionCopyToLibrary, ActionTweakEpub, ActionUnpackBook, ActionNextMatch, ActionStore, ActionCopyToLibrary, ActionTweakEpub, ActionUnpackBook, ActionNextMatch, ActionStore,
ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy, ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy,
ActionMarkBooks, ActionEmbed, ActionTemplateTester, ActionTagMapper, ActionAuthorMapper, ActionMarkBooks, ActionEmbed, ActionTemplateTester, ActionTagMapper, ActionAuthorMapper,
ActionVirtualLibrary, ActionBrowseAnnotations, ActionTemplateFunctions] ActionVirtualLibrary, ActionBrowseAnnotations, ActionTemplateFunctions, ActionAutoscrollBooks]
# }}} # }}}

View File

@ -2219,7 +2219,7 @@ class Cache(object):
for book in self._search(expr, virtual_fields=virtual_fields): for book in self._search(expr, virtual_fields=virtual_fields):
c[book].append(lib) c[book].append(lib)
except Exception as e: except Exception as e:
c[book].append(_('[Error in virtual library {0}: {1}]').format(lib, str(e))) c[book].append(_('[Error in Virtual library {0}: {1}]').format(lib, str(e)))
self.vls_for_books_cache = {b:tuple(sorted(libs, key=sort_key)) for b, libs in c.items()} self.vls_for_books_cache = {b:tuple(sorted(libs, key=sort_key)) for b, libs in c.items()}
if not book_ids: if not book_ids:
book_ids = self._all_book_ids() book_ids = self._all_book_ids()

View File

@ -124,7 +124,8 @@ def create_defs():
'Edit Metadata', 'Send To Device', 'Save To Disk', 'Edit Metadata', 'Send To Device', 'Save To Disk',
'Connect Share', 'Copy To Library', None, 'Connect Share', 'Copy To Library', None,
'Convert Books', 'View', 'Open Folder', 'Show Book Details', 'Convert Books', 'View', 'Open Folder', 'Show Book Details',
'Similar Books', 'Tweak ePub', None, 'Remove Books', 'Similar Books', 'Tweak ePub', None, 'Remove Books', None,
'Autoscroll Books'
) )
defs['show_splash_screen'] = True defs['show_splash_screen'] = True
@ -198,6 +199,7 @@ def create_defs():
defs['browse_annots_restrict_to_type'] = None defs['browse_annots_restrict_to_type'] = None
defs['browse_annots_use_stemmer'] = True defs['browse_annots_use_stemmer'] = True
defs['annots_export_format'] = 'txt' defs['annots_export_format'] = 'txt'
defs['books_autoscroll_time'] = 2.0
create_defs() create_defs()

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
# License: GPLv3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
from calibre.gui2.actions import InterfaceAction
class AutoscrollBooksAction(InterfaceAction):
name = 'Autoscroll Books'
action_spec = (_('Auto scroll through the book list'), 'auto-scroll.png',
_('Auto scroll through the book list, particularly useful with the cover browser open'), _('X'))
dont_add_to = frozenset(('context-menu-device', 'menubar-device'))
action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.gui.toggle_auto_scroll)
def location_selected(self, loc):
enabled = loc == 'library'
self.qaction.setEnabled(enabled)
self.menuless_qaction.setEnabled(enabled)

View File

@ -9,15 +9,19 @@ __docformat__ = 'restructuredtext en'
Module to implement the Cover Flow feature Module to implement the Cover Flow feature
''' '''
import sys, os, time import os
import sys
import time
from qt.core import (
QAction, QApplication, QDialog, QFont, QImage, QItemSelectionModel,
QKeySequence, QLabel, QSize, QSizePolicy, QStackedLayout, Qt, QTimer, pyqtSignal
)
from qt.core import (QImage, QSizePolicy, QTimer, QDialog, Qt, QSize, QAction,
QStackedLayout, QLabel, pyqtSignal, QKeySequence, QFont, QApplication, QItemSelectionModel)
from calibre.ebooks.metadata import rating_to_stars
from calibre.constants import islinux from calibre.constants import islinux
from calibre.gui2 import (config, available_height, available_width, gprefs, from calibre.ebooks.metadata import rating_to_stars
rating_font) from calibre.gui2 import (
available_height, available_width, config, gprefs, rating_font
)
from calibre_extensions import pictureflow from calibre_extensions import pictureflow
@ -190,6 +194,12 @@ class CoverFlow(pictureflow.PictureFlow):
if not gprefs['cover_browser_reflections']: if not gprefs['cover_browser_reflections']:
self.setShowReflections(False) self.setShowReflections(False)
def one_auto_scroll(self):
if self.currentSlide() >= self.count() - 1:
self.setCurrentSlide(0)
else:
self.showNext()
def set_subtitle_font(self, for_ratings=True): def set_subtitle_font(self, for_ratings=True):
if for_ratings: if for_ratings:
self.setSubtitleFont(QFont(rating_font())) self.setSubtitleFont(QFont(rating_font()))
@ -295,6 +305,28 @@ class CoverFlowMixin(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
pass pass
def one_auto_scroll(self):
cb_visible = self.cover_flow is not None and self.cb_splitter.button.isChecked()
if cb_visible:
self.cover_flow.one_auto_scroll()
else:
self.library_view.show_next_book()
def toggle_auto_scroll(self):
if not hasattr(self, 'auto_scroll_timer'):
self.auto_scroll_timer = t = QTimer(self)
t.timeout.connect(self.one_auto_scroll)
if self.auto_scroll_timer.isActive():
self.auto_scroll_timer.stop()
else:
self.one_auto_scroll()
self.auto_scroll_timer.start(int(1000 * gprefs['books_autoscroll_time']))
def update_auto_scroll_timeout(self):
if hasattr(self, 'auto_scroll_timer') and self.auto_scroll_timer.isActive():
self.auto_scroll_timer.stop()
self.toggle_auto_scroll()
def init_cover_flow_mixin(self): def init_cover_flow_mixin(self):
self.cover_flow = None self.cover_flow = None
self.cf_last_updated_at = None self.cf_last_updated_at = None

View File

@ -1290,6 +1290,14 @@ class BooksView(QTableView): # {{{
self.set_current_row(row, select=False) self.set_current_row(row, select=False)
break break
def show_next_book(self):
ci = self.currentIndex()
if not ci.isValid():
self.set_current_row()
return
n = (ci.row() + 1) % self.model().rowCount(QModelIndex())
self.set_current_row(n)
@property @property
def next_id(self): def next_id(self):
''' '''

View File

@ -1518,6 +1518,7 @@ void PictureFlow::timerEvent(QTimerEvent* event)
void PictureFlow::dataChanged() { d->dataChanged(); } void PictureFlow::dataChanged() { d->dataChanged(); }
void PictureFlow::emitcurrentChanged(int index) { emit currentChanged(index); } void PictureFlow::emitcurrentChanged(int index) { emit currentChanged(index); }
int PictureFlow::count() const { return d->slideCount(); }
int FlowImages::count() { return 0; } int FlowImages::count() { return 0; }
QImage FlowImages::image(int index) { Q_UNUSED(index); return QImage(); } QImage FlowImages::image(int index) { Q_UNUSED(index); return QImage(); }

View File

@ -111,6 +111,8 @@ public:
*/ */
void setImages(FlowImages *images); void setImages(FlowImages *images);
int count() const;
/*! /*!
Returns the dimension of each slide (in pixels). Returns the dimension of each slide (in pixels).
*/ */
@ -221,4 +223,3 @@ private:
qreal device_pixel_ratio() const; qreal device_pixel_ratio() const;
qreal last_device_pixel_ratio; qreal last_device_pixel_ratio;
}; };

View File

@ -35,6 +35,7 @@ public :
PictureFlow(QWidget *parent /TransferThis/ = 0, int queueLength = 3); PictureFlow(QWidget *parent /TransferThis/ = 0, int queueLength = 3);
void setImages(FlowImages *images); void setImages(FlowImages *images);
int count();
QSize slideSize() const; QSize slideSize() const;

View File

@ -425,6 +425,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('cover_grid_show_title', gprefs) r('cover_grid_show_title', gprefs)
r('tag_browser_show_counts', gprefs) r('tag_browser_show_counts', gprefs)
r('tag_browser_item_padding', gprefs) r('tag_browser_item_padding', gprefs)
r('books_autoscroll_time', gprefs)
r('qv_respects_vls', gprefs) r('qv_respects_vls', gprefs)
r('qv_dclick_changes_column', gprefs) r('qv_dclick_changes_column', gprefs)
@ -806,6 +807,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
getattr(gui, view + '_view').set_row_header_visibility() getattr(gui, view + '_view').set_row_header_visibility()
gui.library_view.refresh_row_sizing() gui.library_view.refresh_row_sizing()
gui.grid_view.refresh_settings() gui.grid_view.refresh_settings()
gui.update_auto_scroll_timeout()
qv = get_quickview_action_plugin() qv = get_quickview_action_plugin()
if qv: if qv:
qv.refill_quickview() qv.refill_quickview()

View File

@ -1251,6 +1251,32 @@ them to all have the same width and height</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Show ne&amp;xt cover during auto scroll after:</string>
</property>
<property name="buddy">
<cstring>opt_books_autoscroll_time</cstring>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="opt_books_autoscroll_time">
<property name="suffix">
<string> seconds</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>100000.000000000000000</double>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="quickview_tab"> <widget class="QWidget" name="quickview_tab">