From 0541a118e6eac6f680d89d7ad76251366d05ce36 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 2 Aug 2013 16:23:24 +0530 Subject: [PATCH] Make the cover grid customizable --- src/calibre/gui2/__init__.py | 4 + src/calibre/gui2/library/alternate_views.py | 56 +++++- src/calibre/gui2/preferences/look_feel.py | 31 +++- src/calibre/gui2/preferences/look_feel.ui | 178 ++++++++++++++++++++ 4 files changed, 255 insertions(+), 14 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 157ade7020..9c28b0ebe9 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -111,6 +111,10 @@ defs['tags_browser_category_icons'] = {} defs['cover_browser_reflections'] = True defs['extra_row_spacing'] = 0 defs['refresh_book_list_on_bulk_edit'] = True +defs['cover_grid_width'] = 0 +defs['cover_grid_height'] = 0 +defs['cover_grid_color'] = (80, 80, 80) +defs['cover_grid_cache_size'] = 200 del defs # }}} diff --git a/src/calibre/gui2/library/alternate_views.py b/src/calibre/gui2/library/alternate_views.py index 6e6912c9eb..f43abb58cb 100644 --- a/src/calibre/gui2/library/alternate_views.py +++ b/src/calibre/gui2/library/alternate_views.py @@ -20,8 +20,11 @@ from PyQt4.Qt import ( QUrl, QDrag, QPoint, QPainter, QRect) from calibre import fit_image +from calibre.gui2 import gprefs from calibre.utils.config import prefs +CM_TO_INCH = 0.393701 + # Drag 'n Drop {{{ def dragMoveEvent(self, event): event.acceptProposedAction() @@ -305,15 +308,39 @@ class CoverCache(dict): def __hash__(self): return id(self) + def set_limit(self, limit): + with self.lock: + self.limit = limit + if len(self.items) > self.limit: + extra = len(self.items) - self.limit + remove = tuple(self.iterkeys())[:extra] + for k in remove: + del self.items[k] + class CoverDelegate(QStyledItemDelegate): - def __init__(self, parent, width, height): + def __init__(self, parent): super(CoverDelegate, self).__init__(parent) + self.set_dimensions() + self.cover_cache = CoverCache(limit=gprefs['cover_grid_cache_size']) + self.render_queue = Queue() + + def set_dimensions(self): + width = self.original_width = gprefs['cover_grid_width'] + height = self.original_height = gprefs['cover_grid_height'] + + if height < 0.1: + height = max(185, QApplication.instance().desktop().availableGeometry(self.parent()).height() / 5.0) + else: + height *= self.parent().logicalDpiY() * CM_TO_INCH + + if width < 0.1: + width = 0.75 * height + else: + width *= self.parent().logicalDpiX() * CM_TO_INCH self.cover_size = QSize(width, height) self.item_size = self.cover_size + QSize(8, 8) self.spacing = max(10, min(50, int(0.1 * width))) - self.cover_cache = CoverCache() - self.render_queue = Queue() def sizeHint(self, option, index): return self.item_size @@ -366,11 +393,7 @@ class GridView(QListView): def __init__(self, parent): QListView.__init__(self, parent) setup_dnd_interface(self) - pal = QPalette(self.palette()) - r = g = b = 0x50 - pal.setColor(pal.Base, QColor(r, g, b)) - pal.setColor(pal.Text, QColor(Qt.white if (r + g + b)/3.0 < 128 else Qt.black)) - self.setPalette(pal) + self.set_color() self.setUniformItemSizes(True) self.setWrapping(True) self.setFlow(self.LeftToRight) @@ -380,7 +403,7 @@ class GridView(QListView): self.setResizeMode(self.Adjust) self.setSelectionMode(self.ExtendedSelection) self.setVerticalScrollMode(self.ScrollPerPixel) - self.delegate = CoverDelegate(self, 135, 180) + self.delegate = CoverDelegate(self) self.setItemDelegate(self.delegate) self.setSpacing(self.delegate.spacing) self.ignore_render_requests = Event() @@ -390,6 +413,21 @@ class GridView(QListView): self.gui = parent self.context_menu = None + def set_color(self): + r, g, b = gprefs['cover_grid_color'] + pal = QPalette() + pal.setColor(pal.Base, QColor(r, g, b)) + pal.setColor(pal.Text, QColor(Qt.white if (r + g + b)/3.0 < 128 else Qt.black)) + self.setPalette(pal) + + def refresh_settings(self): + if gprefs['cover_grid_width'] != self.delegate.original_width or gprefs['cover_grid_height'] != self.delegate.original_height: + self.delegate.set_dimensions() + self.setSpacing(self.delegate.spacing) + self.delegate.cover_cache.clear() + self.set_color() + self.delegate.cover_cache.set_limit(gprefs['cover_grid_cache_size']) + def shown(self): if self.render_thread is None: self.render_thread = Thread(target=self.render_covers) diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index b3021cf446..114f44d181 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -5,8 +5,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt4.Qt import (QApplication, QFont, QFontInfo, QFontDialog, - QAbstractListModel, Qt, QIcon, QKeySequence) +from PyQt4.Qt import (QApplication, QFont, QFontInfo, QFontDialog, QColorDialog, + QAbstractListModel, Qt, QIcon, QKeySequence, QPalette, QColor) from calibre.gui2.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList from calibre.gui2.preferences.look_feel_ui import Ui_Form @@ -18,7 +18,7 @@ from calibre.utils.icu import sort_key from calibre.gui2.book_details import get_field_list from calibre.gui2.preferences.coloring import EditRules -class DisplayedFields(QAbstractListModel): # {{{ +class DisplayedFields(QAbstractListModel): # {{{ def __init__(self, db, parent=None): QAbstractListModel.__init__(self, parent) @@ -110,6 +110,9 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('tag_browser_old_look', gprefs, restart_required=True) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) + r('cover_grid_width', gprefs) + r('cover_grid_height', gprefs) + r('cover_grid_cache_size', gprefs) r('cover_flow_queue_length', config, restart_required=True) r('cover_browser_reflections', gprefs) @@ -123,7 +126,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): lang = get_lang() if lang is None or lang not in available_translations(): lang = 'en' - items = [(l, get_esc_lang(l)) for l in available_translations() \ + items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) @@ -170,7 +173,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('categories_using_hierarchy', db.prefs, setting=CommaSeparatedList, choices=sorted(list(choices), key=sort_key)) - self.current_font = self.initial_font = None self.change_font_button.clicked.connect(self.change_font) @@ -197,6 +199,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): keys = [unicode(x.toString(QKeySequence.NativeText)) for x in keys] self.fs_help_msg.setText(unicode(self.fs_help_msg.text())%( _(' or ').join(keys))) + self.cover_grid_color_button.clicked.connect(self.change_cover_grid_color) def initialize(self): ConfigWidgetBase.initialize(self) @@ -215,6 +218,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): mi=None self.edit_rules.initialize(db.field_metadata, db.prefs, mi, 'column_color_rules') self.icon_rules.initialize(db.field_metadata, db.prefs, mi, 'column_icon_rules') + self.set_cg_color(gprefs['cover_grid_color']) + + def set_cg_color(self, val): + pal = QPalette() + pal.setColor(QPalette.Window, QColor(*val)) + self.cover_grid_color_label.setPalette(pal) def restore_defaults(self): ConfigWidgetBase.restore_defaults(self) @@ -227,6 +236,15 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.edit_rules.clear() self.icon_rules.clear() self.changed_signal.emit() + self.set_cg_color(gprefs.defaults['cover_grid_color']) + + def change_cover_grid_color(self): + col = QColorDialog.getColor(self.cover_grid_color_label.palette().color(QPalette.Window), + self.gui, _('Choose background color for cover grid')) + if col.isValid(): + col = tuple(col.getRgb())[:3] + self.set_cg_color(col) + self.changed_signal.emit() def build_font_obj(self): font_info = self.current_font @@ -286,6 +304,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.display_model.commit() self.edit_rules.commit(self.gui.current_db.prefs) self.icon_rules.commit(self.gui.current_db.prefs) + gprefs['cover_grid_color'] = tuple(self.cover_grid_color_label.palette().color(QPalette.Window).getRgb())[:3] return rr def refresh_gui(self, gui): @@ -296,9 +315,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): if hasattr(gui.cover_flow, 'setShowReflections'): gui.cover_flow.setShowReflections(gprefs['cover_browser_reflections']) gui.library_view.refresh_row_sizing() + gui.grid_view.refresh_settings() if __name__ == '__main__': from calibre.gui2 import Application app = Application([]) test_widget('Interface', 'Look & Feel') + diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 086c012e17..d962dad0eb 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -223,6 +223,184 @@ + + + + :/images/grid.png:/images/grid.png + + + Cover Grid + + + + + + + + Cover &Width: + + + opt_cover_grid_width + + + + + + + The width of displayed covers + + + cm + + + 1 + + + + + + + Cover &Height: + + + opt_cover_grid_height + + + + + + + The height of displayed covers + + + cm + + + 1 + + + + + + + A value of zero means set automatically based on screen size + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Background color for the cover grid: + + + + + + + + 50 + 50 + + + + true + + + + + + + + + + Change &color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Number of covers to cache in &memory: + + + opt_cover_grid_cache_size + + + + + + + 3000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 355 + + + + + +