diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 463cdf33168b..e28ed316cf7d 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -38,7 +38,9 @@ QLocale, QNetworkProxyFactory, QObject, + QPainterPath, QPalette, + QRectF, QResource, QSettings, QSocketNotifier, @@ -426,7 +428,7 @@ def create_defs(): defs['cover_grid_disk_cache_size'] = 2500 defs['cover_grid_show_title'] = False defs['cover_grid_texture'] = None - defs['cover_grid_corner_radius'] = 0 + defs['cover_corner_radius'] = 0 defs['show_vl_tabs'] = False defs['vl_tabs_closable'] = True defs['show_highlight_toggle_button'] = False @@ -1756,3 +1758,17 @@ def raise_without_focus(self: QWidget) -> None: QWidget.raise_and_focus = raise_and_focus QWidget.raise_without_focus = raise_without_focus + + +@contextmanager +def clip_border_radius(painter, rect): + painter.save() + r = gprefs['cover_corner_radius'] + if r > 0: + pp = QPainterPath() + pp.addRoundedRect(QRectF(rect), r, r) + painter.setClipPath(pp) + try: + yield + finally: + painter.restore() diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 0127098b0c9d..939e5480b17f 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -43,7 +43,18 @@ from calibre.ebooks.metadata.book.base import Metadata, field_metadata from calibre.ebooks.metadata.book.render import mi_to_html from calibre.ebooks.metadata.search_internet import all_author_searches, all_book_searches, name_for, url_for_author_search, url_for_book_search -from calibre.gui2 import NO_URL_FORMATTING, choose_save_file, config, default_author_link, gprefs, pixmap_to_data, question_dialog, rating_font, safe_open_url +from calibre.gui2 import ( + NO_URL_FORMATTING, + choose_save_file, + clip_border_radius, + config, + default_author_link, + gprefs, + pixmap_to_data, + question_dialog, + rating_font, + safe_open_url, +) from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.confirm_delete import confirm as confirm_delete from calibre.gui2.dnd import dnd_get_files, dnd_get_image, dnd_has_extension, dnd_has_image, image_extensions @@ -825,7 +836,8 @@ def paintEvent(self, event): dpr = self.devicePixelRatio() spmap = self.pixmap.scaled(target.size() * dpr, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) spmap.setDevicePixelRatio(dpr) - p.drawPixmap(target, spmap) + with clip_border_radius(p, target): + p.drawPixmap(target, spmap) if gprefs['bd_overlay_cover_size']: sztgt = target.adjusted(0, 0, 0, -4) f = p.font() diff --git a/src/calibre/gui2/library/alternate_views.py b/src/calibre/gui2/library/alternate_views.py index e56b7fe9c052..6d0f24fdc516 100644 --- a/src/calibre/gui2/library/alternate_views.py +++ b/src/calibre/gui2/library/alternate_views.py @@ -10,7 +10,6 @@ import os import weakref from collections import namedtuple -from contextlib import contextmanager from functools import wraps from io import BytesIO from textwrap import wrap @@ -37,13 +36,11 @@ QMimeData, QModelIndex, QPainter, - QPainterPath, QPalette, QPixmap, QPoint, QPropertyAnimation, QRect, - QRectF, QSize, QStyledItemDelegate, QStyleOptionViewItem, @@ -64,7 +61,7 @@ from calibre import fit_image, human_readable, prepare_string_for_xml from calibre.constants import DEBUG, config_dir, islinux from calibre.ebooks.metadata import fmt_sidx, rating_to_stars -from calibre.gui2 import config, empty_index, gprefs, rating_font +from calibre.gui2 import clip_border_radius, config, empty_index, gprefs, rating_font from calibre.gui2.dnd import path_from_qurl from calibre.gui2.gestures import GestureManager from calibre.gui2.library.caches import CoverCache, ThumbnailCache @@ -565,7 +562,7 @@ def cached_emblem(self, cache, name, raw_icon=None): return ans def paint(self, painter, option, index): - with self.clip_border_radius(painter, option.rect): + with clip_border_radius(painter, option.rect): QStyledItemDelegate.paint(self, painter, option, empty_index) # draw the hover and selection highlights m = index.model() db = m.db @@ -662,21 +659,8 @@ def paint(self, painter, option, index): finally: painter.restore() - @contextmanager - def clip_border_radius(self, painter, rect): - painter.save() - r = gprefs['cover_grid_corner_radius'] - if r > 0: - pp = QPainterPath() - pp.addRoundedRect(QRectF(rect), r, r) - painter.setClipPath(pp) - try: - yield - finally: - painter.restore() - def paint_cover(self, painter: QPainter, rect: QRect, pixmap: QPixmap): - with self.clip_border_radius(painter, rect): + with clip_border_radius(painter, rect): painter.drawPixmap(rect, pixmap) def paint_title(self, painter, rect, db, book_id): diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index b9fd91a7dad7..1ef80a7e49b9 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -625,8 +625,8 @@ def genesis(self, gui): r('tag_browser_allow_keyboard_focus', gprefs) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) + r('cover_corner_radius', gprefs) r('cover_grid_width', gprefs) - r('cover_grid_corner_radius', gprefs) r('cover_grid_height', gprefs) r('cover_grid_cache_size_multiple', gprefs) r('cover_grid_disk_cache_size', gprefs) diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index a2965fe2200e..ad6f28bbe53c 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -28,26 +28,6 @@ &Main interface - - - - Show &row numbers in the book list - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -58,44 +38,55 @@ - - + + - &User interface layout: + Show the &splash screen at startup - - opt_gui_layout + + + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + 20 - - + + - User interface style (&needs restart): + Enable s&ystem tray icon (needs restart) - - opt_ui_style + + + + + + Show &row numbers in the book list - - + + - E&xtra spacing to add between rows in the book list (can be negative): + Choose &language (needs restart): - opt_book_list_extra_row_spacing + opt_language - - + + - Enable s&ystem tray icon (needs restart) + Adjust &colors - + Disable all animations. Useful if you have a slow/old computer. @@ -105,10 +96,61 @@ - - + + + + Draw a &grid in the book list + + - + + + + + + + + + + + &User interface layout: + + + opt_gui_layout + + + + + + + + 250 + 16777215 + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + 20 + + + + + + + Show &layout buttons in the status bar + + + + + + + Change &icon theme + + + + @@ -129,28 +171,17 @@ - + Change &font (needs restart) - - - - Show &tooltips in the book list - - - - - - - - - + + - + Toolbar @@ -192,40 +223,30 @@ - - - + + + + Qt::Vertical + + - 250 - 16777215 + 20 + 40 - - QComboBox::AdjustToMinimumContentsLengthWithIcon - - - 20 - - + - - + + - Choose &language (needs restart): + User interface style (&needs restart): - opt_language - - - - - - - Change &icon theme + opt_ui_style - + px @@ -235,28 +256,14 @@ - + Allow using &drag and drop to merge books - - - - Show &layout buttons in the status bar - - - - - - - Show the &splash screen at startup - - - - + Disable popup notifications when calibre completes jobs such a conversion, sending to device etc. The notifications are sent via the operating system notification facility, if available. Note that on Windows, you have to enable the system tray icon for notifications to work. @@ -266,27 +273,43 @@ - - - - QComboBox::AdjustToMinimumContentsLengthWithIcon - - - 20 + + + + Show &tooltips in the book list - - + + - Draw a &grid in the book list + E&xtra spacing to add between rows in the book list (can be negative): + + + opt_book_list_extra_row_spacing - - + + - Adjust &colors + &Round the corners of covers: + + + opt_cover_corner_radius + + + + + + + Round the corners of covers in many places they are displayed such as the Cover grid, Book details panel, etc. Adjust the amount of rounding with this setting. A value of between 5 and 10 looks good with most covers sizes. Zero disables rounding and is the default. + + + no rounding + + + px @@ -393,6 +416,20 @@ Cover size + + + + Make the covers larger, maintaining current aspect ratio. + + + &Larger covers + + + + :/images/plus.png:/images/plus.png + + + @@ -417,20 +454,13 @@ - - - - The width of displayed covers. -A value of zero means calculate automatically. - - - Automatic - - - cm + + + + Cover &width: - - 1 + + opt_cover_grid_width @@ -451,53 +481,23 @@ A value of zero means calculate automatically. - - - - - 0 - 0 - - - - By default, calibre chooses a cover size based on your computer's screen size. You can change the cover size here: - - - true + + + + Reset size to automatic - - - - - Cover &width: - - - opt_cover_grid_width + &Reset size - + - - - - Make the covers larger, maintaining current aspect ratio. - - - &Larger covers - - - - :/images/plus.png:/images/plus.png - - - @@ -511,36 +511,36 @@ A value of zero means calculate automatically. - - + + - Reset size to automatic + The width of displayed covers. +A value of zero means calculate automatically. - - &Reset size + + Automatic - - - - - - &Round the corners: + + cm - - opt_cover_grid_corner_radius + + 1 - - - - The amount by which to round the corners of the covers when they are displayed in the Cover grid. A value of 10 looks good with typical cover sizes. Adjust to your preference. A value of zero disables rounding. + + + + + 0 + 0 + - - no rounding + + By default, calibre chooses a cover size based on your computer's screen size. You can change the cover size here: - - px + + true diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 833c586570a4..f041e372a0e0 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -15,6 +15,7 @@ QCursor, QEvent, QFont, + QGraphicsPixmapItem, QGraphicsScene, QGraphicsView, QIcon, @@ -43,7 +44,7 @@ from calibre import fit_image, force_unicode, strftime from calibre.constants import ismacos, iswindows from calibre.ebooks import BOOK_EXTENSIONS -from calibre.gui2 import error_dialog, gprefs, pixmap_to_data, warning_dialog +from calibre.gui2 import clip_border_radius, error_dialog, gprefs, pixmap_to_data, warning_dialog from calibre.gui2.dnd import DownloadDialog, dnd_get_files, dnd_get_image, dnd_get_local_image_and_pixmap, dnd_has_extension, dnd_has_image, image_extensions from calibre.gui2.filename_pattern_ui import Ui_Form from calibre.gui2.progress_indicator import ProgressIndicator as _ProgressIndicator @@ -414,7 +415,8 @@ def paintEvent(self, event): x = int(abs(cw - w)/2) y = int(abs(ch - h)/2) target = QRect(x, y, w, h) - p.drawPixmap(target, pmap) + with clip_border_radius(p, target): + p.drawPixmap(target, pmap) if self.draw_border: pen = QPen() pen.setWidth(self.BORDER_WIDTH) @@ -424,8 +426,18 @@ def paintEvent(self, event): draw_size(p, target, ow, oh) # }}} +# CoverView {{{ -class CoverView(QGraphicsView, ImageDropMixin): # {{{ +class RoundedPixmap(QGraphicsPixmapItem): + + def paint(self, painter, option, widget): + painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) + target = self.boundingRect().toAlignedRect() + with clip_border_radius(painter, target): + painter.drawPixmap(target, self.pixmap()) + + +class CoverView(QGraphicsView, ImageDropMixin): cover_changed = pyqtSignal(object) @@ -445,7 +457,7 @@ def get_pixmap(self): def set_pixmap(self, pmap): self.scene = QGraphicsScene() - self.scene.addPixmap(pmap) + self.scene.addItem(RoundedPixmap(pmap)) self.setScene(self.scene) def set_background(self, brush=None):