From 934bb4e14a14b8da25dfe8dbc00ee097f9bae22e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jan 2026 20:55:36 +0530 Subject: [PATCH] Bookshelf: Add an optional second line to the spine controllable by a template --- src/calibre/db/backend.py | 1 + src/calibre/gui2/library/bookshelf_view.py | 19 +- .../look_feel_tabs/bookshelf_view.py | 1 + .../look_feel_tabs/bookshelf_view.ui | 325 ++++++++++-------- 4 files changed, 194 insertions(+), 152 deletions(-) diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index 14280076f7..3da1a65754 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -639,6 +639,7 @@ class DB: defs['column_tooltip_templates'] = {} defs['bookshelf_grouping_mode'] = '' defs['bookshelf_title_template'] = '{title}' + defs['bookshelf_author_template'] = '' defs['bookshelf_spine_size_template'] = '{pages}' # Migrate the beta bookshelf_grouping_mode diff --git a/src/calibre/gui2/library/bookshelf_view.py b/src/calibre/gui2/library/bookshelf_view.py index 313f983e3c..8c1ff3cf27 100644 --- a/src/calibre/gui2/library/bookshelf_view.py +++ b/src/calibre/gui2/library/bookshelf_view.py @@ -1407,8 +1407,10 @@ class BookshelfView(MomentumScrollMixin, QAbstractScrollArea): self.template_cache = {} self.template_title = db_pref('bookshelf_title_template') or '' + self.template_author = db_pref('bookshelf_author_template') or '' self.template_title_is_title = self.template_title == '{title}' self.template_title_is_empty = not self.template_title.strip() + self.template_author_is_empty = not self.template_author.strip() self.template_inited = True def render_template_title(self, book_id: int) -> str: @@ -1423,6 +1425,19 @@ class BookshelfView(MomentumScrollMixin, QAbstractScrollArea): self.template_title, mi, TEMPLATE_ERROR, mi, column_name='title', template_cache=self.template_cache) return rslt or _('Unknown') + def render_author_template(self, book_id: int) -> str: + '''Return the title generate for this book.''' + self.init_template(self.dbref()) + if self.template_author_is_empty: + return '' + match self.template_author: + case '{author_sort}': + return self.dbref().new_api.field_for('author_sort', book_id) + mi = self.dbref().get_proxy_metadata(book_id) + rslt = mi.formatter.safe_format( + self.template_title, mi, TEMPLATE_ERROR, mi, column_name='authors', template_cache=self.template_cache) + return rslt or _('Unknown') + # Miscellaneous methods def refresh_settings(self): @@ -1851,7 +1866,7 @@ class BookshelfView(MomentumScrollMixin, QAbstractScrollArea): def draw_spine_title(self, painter: QPainter, rect: QRect, spine_color: QColor, book_id: int) -> None: '''Draw vertically the title on the spine.''' first_line = self.render_template_title(book_id) - second_line = '' + second_line = self.render_author_template(book_id) margin = 6 if second_line: first_rect = QRect(rect.left(), rect.top() + margin, rect.width() // 2, rect.height() - margin) @@ -1859,7 +1874,7 @@ class BookshelfView(MomentumScrollMixin, QAbstractScrollArea): else: first_rect = QRect(rect.left(), rect.top() + margin, rect.width(), rect.height() - margin) nfl, nsl, font = self.get_text_metrics(first_line, second_line, first_rect.transposed().size()) - if not nfl and not nsl: + if not nfl and not nsl: # two lines dont fit second_line = '' first_rect = QRect(rect.left(), rect.top() + margin, rect.width(), rect.height() - margin) nfl, nsl, font = self.get_text_metrics(first_line, second_line, first_rect.transposed().size()) diff --git a/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.py b/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.py index 588535698b..a5b928b958 100644 --- a/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.py +++ b/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.py @@ -53,6 +53,7 @@ class BookshelfTab(QTabWidget, LazyConfigWidgetBase, Ui_Form): ]) r('bookshelf_title_template', db.prefs) + r('bookshelf_author_template', db.prefs) r('bookshelf_spine_size_template', db.prefs) self.config_cache.link( diff --git a/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.ui b/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.ui index fbb23c9a70..3a9f11b954 100644 --- a/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.ui +++ b/src/calibre/gui2/preferences/look_feel_tabs/bookshelf_view.ui @@ -7,7 +7,7 @@ 0 0 607 - 336 + 423 @@ -17,10 +17,7 @@ &Layout - - - QFormLayout::ExpandingFieldsGrow - + @@ -49,151 +46,6 @@ - - - - Cover &thumbnail on the spines: - - - opt_bookshelf_thumbnail - - - - - - - - - - Template for spine &title: - - - opt_bookshelf_title_template - - - - - - - - - <p>The template used to generate the text on the spine. This template uses the same syntax as save templates. Defaults to just the book title. Note that this setting is per-library, which means that you have to set it again for every different calibre library you use.</p> - - - - - - - Template &editor - - - - - - - - - Template for spine &width: - - - opt_bookshelf_spine_size_template - - - - - - - - - - - - - - - - Template &editor - - - - - - - - - Use a custom &pages column - - - - - - - Duration of hover &animation - - - opt_bookshelf_fade_time - - - - - - - Disable - - - milliseconds - - - 2000 - - - 100 - - - 200 - - - - - - - &Expand the hovered cover: - - - opt_bookshelf_hover - - - - - - - Control what happens when the mouse hovers over the spine of a book. - - - - - - - Qt::Vertical - - - - 20 - 20 - - - - - - - - Have calibre re-count the pages in all books in the current library. - - - &Recount pages - - - @@ -223,6 +75,179 @@ + + + + Cover &thumbnail on the spines: + + + opt_bookshelf_thumbnail + + + + + + + + + + Template for spine &title: + + + opt_bookshelf_title_template + + + + + + + + + <p>The template used to generate the main text on the spine. This template uses the same syntax as save templates. Defaults to just the book title. Note that this setting is per-library, which means that you have to set it again for every different calibre library you use.</p> + + + + + + + Template &editor + + + + + + + + + Template for spine a&uthor:: + + + opt_bookshelf_author_template + + + + + + + + + <p>The template used to generate an optional second line of text on the spine. This template uses the same syntax as save templates. Defaults to no second line. For very narrow books, this will be skipped when there isnt space for a second line. Note that this setting is per-library, which means that you have to set it again for every different calibre library you use.</p> + + + + + + + Template &editor + + + + + + + + + Template for spine &width: + + + opt_bookshelf_spine_size_template + + + + + + + + + + + + + + + + Template &editor + + + + + + + + + Use a custom &pages column + + + + + + + Duration of hover &animation + + + opt_bookshelf_fade_time + + + + + + + Disable + + + milliseconds + + + 2000 + + + 100 + + + 200 + + + + + + + &Expand the hovered cover: + + + opt_bookshelf_hover + + + + + + + Control what happens when the mouse hovers over the spine of a book. + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + Have calibre re-count the pages in all books in the current library. + + + &Recount pages + + +