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
* - :kbd:`Ctrl+Q`
- Quit calibre
* - :kbd:`X`
- Toggle autoscroll of the book list

View File

@ -970,6 +970,12 @@ class ActionOpenFolder(InterfaceActionBase):
' 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):
name = 'Send To Device'
actual_plugin = 'calibre.gui2.actions.device:SendToDeviceAction'
@ -1115,7 +1121,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionCopyToLibrary, ActionTweakEpub, ActionUnpackBook, ActionNextMatch, ActionStore,
ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy,
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):
c[book].append(lib)
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()}
if not 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',
'Connect Share', 'Copy To Library', None,
'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
@ -198,6 +199,7 @@ def create_defs():
defs['browse_annots_restrict_to_type'] = None
defs['browse_annots_use_stemmer'] = True
defs['annots_export_format'] = 'txt'
defs['books_autoscroll_time'] = 2.0
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
'''
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.gui2 import (config, available_height, available_width, gprefs,
rating_font)
from calibre.ebooks.metadata import rating_to_stars
from calibre.gui2 import (
available_height, available_width, config, gprefs, rating_font
)
from calibre_extensions import pictureflow
@ -190,6 +194,12 @@ class CoverFlow(pictureflow.PictureFlow):
if not gprefs['cover_browser_reflections']:
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):
if for_ratings:
self.setSubtitleFont(QFont(rating_font()))
@ -295,6 +305,28 @@ class CoverFlowMixin(object):
def __init__(self, *args, **kwargs):
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):
self.cover_flow = None
self.cf_last_updated_at = None

View File

@ -1290,6 +1290,14 @@ class BooksView(QTableView): # {{{
self.set_current_row(row, select=False)
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
def next_id(self):
'''

View File

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

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
* (C) Copyright 2007 Trolltech ASA
* (C) Copyright 2007 Trolltech ASA
* All rights reserved.
**
* This is version of the Pictureflow animated image show widget modified by Trolltech ASA.
@ -77,15 +77,15 @@ signals:
class PictureFlowPrivate;
/*!
Class PictureFlow implements an image show widget with animation effect
like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form
of slides, one main slide is shown at the center with few slides on
the left and right sides of the center slide. When the next or previous
slide is brought to the front, the whole slides flow to the right or
the right with smooth animation effect; until the new slide is finally
Class PictureFlow implements an image show widget with animation effect
like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form
of slides, one main slide is shown at the center with few slides on
the left and right sides of the center slide. When the next or previous
slide is brought to the front, the whole slides flow to the right or
the right with smooth animation effect; until the new slide is finally
placed at the center.
*/
*/
class PictureFlow : public QWidget
{
Q_OBJECT
@ -98,7 +98,7 @@ Q_OBJECT
public:
/*!
Creates a new PictureFlow widget.
*/
*/
PictureFlow(QWidget* parent = 0, int queueLength = 3);
/*!
@ -110,42 +110,44 @@ public:
Set the images to be displayed by this widget.
*/
void setImages(FlowImages *images);
int count() const;
/*!
Returns the dimension of each slide (in pixels).
*/
*/
QSize slideSize() const;
/*!
Sets the dimension of each slide (in pixels). Do not use this method directly
instead use resize which automatically sets an appropriate slide size.
*/
*/
void setSlideSize(QSize size);
/*!
Returns whether aspect ration is preserved when scaling images
*/
*/
bool preserveAspectRatio() const;
/*!
Whether to preserve aspect ration when scaling images
*/
*/
void setPreserveAspectRatio(bool preserve);
/*!
Turn the reflections on/off.
*/
*/
void setShowReflections(bool show);
bool showReflections() const;
/*!
Returns the font used to render subtitles
*/
*/
QFont subtitleFont() const;
/*!
Sets the font used to render subtitles
*/
*/
void setSubtitleFont(QFont font);
@ -158,20 +160,20 @@ public:
Returns QImage of specified slide.
This function will be called only whenever necessary, e.g. the 100th slide
will not be retrived when only the first few slides are visible.
*/
*/
virtual QImage slide(int index) const;
/*!
Returns the index of slide currently shown in the middle of the viewport.
*/
*/
int currentSlide() const;
public slots:
/*!
Sets slide to be shown in the middle of the viewport. No animation
Sets slide to be shown in the middle of the viewport. No animation
effect will be produced, unlike using showSlide.
*/
*/
void setCurrentSlide(int index);
/*!
@ -194,12 +196,12 @@ public slots:
Go to specified slide using animation effect.
*/
void showSlide(int index);
/*!
Clear all caches and redraw
*/
void dataChanged();
void emitcurrentChanged(int index);
signals:
@ -221,4 +223,3 @@ private:
qreal device_pixel_ratio() const;
qreal last_device_pixel_ratio;
};

View File

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

View File

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

View File

@ -1251,6 +1251,32 @@ them to all have the same width and height</string>
</property>
</widget>
</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>
</widget>
<widget class="QWidget" name="quickview_tab">