Bookshelf: Add an optional second line to the spine controllable by a template

This commit is contained in:
Kovid Goyal 2026-01-04 20:55:36 +05:30
parent 797b3cf114
commit 934bb4e14a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 194 additions and 152 deletions

View File

@ -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

View File

@ -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())

View File

@ -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(

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>607</width>
<height>336</height>
<height>423</height>
</rect>
</property>
<property name="currentIndex">
@ -17,10 +17,7 @@
<attribute name="title">
<string>&amp;Layout</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@ -49,151 +46,6 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_bookshelf_thumbnail">
<property name="text">
<string>Cover &amp;thumbnail on the spines:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_thumbnail</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="opt_bookshelf_thumbnail"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_title">
<property name="text">
<string>Template for spine &amp;title:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_title_template</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="opt_bookshelf_title_template">
<property name="toolTip">
<string>&lt;p&gt;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.&lt;/p&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="template_title_button">
<property name="text">
<string>Template &amp;editor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_pages">
<property name="text">
<string>Template for spine &amp;width:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_spine_size_template</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="opt_bookshelf_spine_size_template">
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="template_pages_button">
<property name="text">
<string>Template &amp;editor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="use_pages_button">
<property name="text">
<string>Use a custom &amp;pages column</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_fade_time">
<property name="text">
<string>Duration of hover &amp;animation</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_fade_time</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="opt_bookshelf_fade_time">
<property name="specialValueText">
<string>Disable</string>
</property>
<property name="suffix">
<string> milliseconds</string>
</property>
<property name="maximum">
<number>2000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_hover_interact">
<property name="text">
<string>&amp;Expand the hovered cover:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_hover</cstring>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="opt_bookshelf_hover">
<property name="toolTip">
<string>Control what happens when the mouse hovers over the spine of a book.</string>
</property>
</widget>
</item>
<item row="9" column="0">
<spacer name="vertical_spacer_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0" colspan="2">
<widget class="QPushButton" name="recount_button">
<property name="toolTip">
<string>Have calibre re-count the pages in all books in the current library.</string>
</property>
<property name="text">
<string>&amp;Recount pages</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
@ -223,6 +75,179 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_bookshelf_thumbnail">
<property name="text">
<string>Cover &amp;thumbnail on the spines:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_thumbnail</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="opt_bookshelf_thumbnail"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_title">
<property name="text">
<string>Template for spine &amp;title:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_title_template</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="opt_bookshelf_title_template">
<property name="toolTip">
<string>&lt;p&gt;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.&lt;/p&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="template_title_button">
<property name="text">
<string>Template &amp;editor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Template for spine a&amp;uthor::</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_author_template</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLineEdit" name="opt_bookshelf_author_template">
<property name="toolTip">
<string>&lt;p&gt;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.&lt;/p&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="template_title_button_2">
<property name="text">
<string>Template &amp;editor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_pages">
<property name="text">
<string>Template for spine &amp;width:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_spine_size_template</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="opt_bookshelf_spine_size_template">
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="template_pages_button">
<property name="text">
<string>Template &amp;editor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="use_pages_button">
<property name="text">
<string>Use a custom &amp;pages column</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_fade_time">
<property name="text">
<string>Duration of hover &amp;animation</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_fade_time</cstring>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="opt_bookshelf_fade_time">
<property name="specialValueText">
<string>Disable</string>
</property>
<property name="suffix">
<string> milliseconds</string>
</property>
<property name="maximum">
<number>2000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_hover_interact">
<property name="text">
<string>&amp;Expand the hovered cover:</string>
</property>
<property name="buddy">
<cstring>opt_bookshelf_hover</cstring>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="opt_bookshelf_hover">
<property name="toolTip">
<string>Control what happens when the mouse hovers over the spine of a book.</string>
</property>
</widget>
</item>
<item row="10" column="0">
<spacer name="vertical_spacer_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0" colspan="2">
<widget class="QPushButton" name="recount_button">
<property name="toolTip">
<string>Have calibre re-count the pages in all books in the current library.</string>
</property>
<property name="text">
<string>&amp;Recount pages</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="CoverCacheConfig" name="config_cache">