move "Look & Feel/Main interface" to its own widget

This commit is contained in:
un-pogaz 2025-01-31 16:12:55 +01:00
parent d121dde02a
commit 210415fd4a
4 changed files with 557 additions and 512 deletions

View File

@ -10,16 +10,12 @@ from functools import partial
from threading import Thread from threading import Thread
from qt.core import ( from qt.core import (
QApplication,
QBrush, QBrush,
QColor, QColor,
QColorDialog, QColorDialog,
QComboBox, QComboBox,
QDialog, QDialog,
QDialogButtonBox, QDialogButtonBox,
QFont,
QFontDialog,
QFontInfo,
QFormLayout, QFormLayout,
QHeaderView, QHeaderView,
QIcon, QIcon,
@ -41,22 +37,19 @@ from qt.core import (
) )
from calibre import human_readable from calibre import human_readable
from calibre.constants import ismacos, iswindows
from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
from calibre.ebooks.metadata.sources.prefs import msprefs from calibre.ebooks.metadata.sources.prefs import msprefs
from calibre.gui2 import config, default_author_link, error_dialog, gprefs, icon_resource_manager, open_local_file, qt_app, question_dialog from calibre.gui2 import config, default_author_link, error_dialog, gprefs, open_local_file, question_dialog
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
from calibre.gui2.library.alternate_views import CM_TO_INCH, auto_height from calibre.gui2.library.alternate_views import CM_TO_INCH, auto_height
from calibre.gui2.preferences import ConfigWidgetBase, Setting, set_help_tips, test_widget from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.gui2.preferences.coloring import EditRules from calibre.gui2.preferences.coloring import EditRules
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, move_field_down, move_field_up, reset_layout
from calibre.gui2.preferences.look_feel_ui import Ui_Form from calibre.gui2.preferences.look_feel_ui import Ui_Form
from calibre.gui2.widgets import BusyCursor from calibre.gui2.widgets import BusyCursor
from calibre.gui2.widgets2 import Dialog from calibre.gui2.widgets2 import Dialog
from calibre.startup import connect_lambda from calibre.startup import connect_lambda
from calibre.utils.config import prefs
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.utils.localization import available_translations, get_lang, get_language
from calibre.utils.resources import get_path as P from calibre.utils.resources import get_path as P
from calibre.utils.resources import set_data from calibre.utils.resources import set_data
from polyglot.builtins import iteritems from polyglot.builtins import iteritems
@ -322,53 +315,21 @@ class Background(QWidget): # {{{
# }}} # }}}
class LanguageSetting(Setting):
def commit(self):
val = self.get_gui_val()
oldval = self.get_config_val()
if val != oldval:
gprefs.set('last_used_language', oldval)
return super().commit()
class ConfigWidget(ConfigWidgetBase, Ui_Form): class ConfigWidget(ConfigWidgetBase, Ui_Form):
size_calculated = pyqtSignal(object) size_calculated = pyqtSignal(object)
def genesis(self, gui): def genesis(self, gui):
self.gui = gui self.gui = gui
self.ui_style_available = True
if not ismacos and not iswindows:
self.label_widget_style.setVisible(False)
self.opt_ui_style.setVisible(False)
self.ui_style_available = False
db = gui.library_view.model().db db = gui.library_view.model().db
r = self.register r = self.register
try:
self.icon_theme_title = icon_resource_manager.user_theme_title
except Exception:
self.icon_theme_title = _('Default icons')
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
self.commit_icon_theme = None
self.icon_theme_button.clicked.connect(self.choose_icon_theme)
self.default_author_link = DefaultAuthorLink(self.default_author_link_container) self.default_author_link = DefaultAuthorLink(self.default_author_link_container)
self.default_author_link.changed_signal.connect(self.changed_signal) self.default_author_link.changed_signal.connect(self.changed_signal)
r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')])
r('book_list_tooltips', gprefs)
r('dnd_merge', gprefs)
r('wrap_toolbar_text', gprefs, restart_required=True)
r('show_layout_buttons', gprefs)
r('show_sb_all_actions_button', gprefs)
# r('show_sb_preference_button', gprefs)
r('row_numbers_in_book_list', gprefs)
r('bd_show_cover', gprefs) r('bd_show_cover', gprefs)
r('bd_overlay_cover_size', gprefs) r('bd_overlay_cover_size', gprefs)
r('cover_corner_radius', gprefs)
r('cover_corner_radius_unit', gprefs, choices=[(_('Pixels'), 'px'), (_('Percentage'), '%')])
r('cover_grid_width', gprefs) r('cover_grid_width', gprefs)
r('cover_grid_height', gprefs) r('cover_grid_height', gprefs)
r('cover_grid_cache_size_multiple', gprefs) r('cover_grid_cache_size_multiple', gprefs)
@ -379,48 +340,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('emblem_size', gprefs) r('emblem_size', gprefs)
r('emblem_position', gprefs, choices=[ r('emblem_position', gprefs, choices=[
(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')]) (_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')])
r('book_list_extra_row_spacing', gprefs)
r('booklist_grid', gprefs)
r('book_details_comments_heading_pos', gprefs, choices=[ r('book_details_comments_heading_pos', gprefs, choices=[
(_('Never'), 'hide'), (_('Above text'), 'above'), (_('Beside text'), 'side')]) (_('Never'), 'hide'), (_('Above text'), 'above'), (_('Beside text'), 'side')])
r('book_details_note_link_icon_width', gprefs) r('book_details_note_link_icon_width', gprefs)
self.id_links_button.clicked.connect(self.edit_id_link_rules) self.id_links_button.clicked.connect(self.edit_id_link_rules)
def get_esc_lang(l):
if l == 'en':
return 'English'
return get_language(l)
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()
if l != lang]
if lang != 'en':
items.append(('en', get_esc_lang('en')))
items.sort(key=lambda x: x[1].lower())
choices = [(y, x) for x, y in items]
# Default language is the autodetected one
choices = [(get_language(lang), lang)] + choices
lul = gprefs.get('last_used_language')
if lul and (lul in available_translations() or lul in ('en', 'eng')):
choices.insert(1, ((get_language(lul), lul)))
r('language', prefs, choices=choices, restart_required=True, setting=LanguageSetting)
r('disable_animations', config)
r('systray_icon', config, restart_required=True)
r('show_splash_screen', gprefs)
r('disable_tray_notification', config)
r('use_roman_numerals_for_series_number', config) r('use_roman_numerals_for_series_number', config)
choices = [(_('Off'), 'off'), (_('Small'), 'small'),
(_('Medium-small'), 'mid-small'), (_('Medium'), 'medium'), (_('Large'), 'large')]
r('toolbar_icon_size', gprefs, choices=choices)
choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'),
(_('Never'), 'never')]
r('toolbar_text', gprefs, choices=choices)
fm = db.field_metadata fm = db.field_metadata
choices = sorted(((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']), choices = sorted(((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']),
key=lambda x:sort_key(x[0])) key=lambda x:sort_key(x[0]))
@ -441,9 +367,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('edit_metadata_single_cc_label_length', gprefs) r('edit_metadata_single_cc_label_length', gprefs)
r('edit_metadata_templates_only_F2_on_booklist', gprefs) r('edit_metadata_templates_only_F2_on_booklist', gprefs)
self.current_font = self.initial_font = None
self.change_font_button.clicked.connect(self.change_font)
self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order) self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order)
self.display_model.dataChanged.connect(self.changed_signal) self.display_model.dataChanged.connect(self.changed_signal)
self.field_display_order.setModel(self.display_model) self.field_display_order.setModel(self.display_model)
@ -527,37 +450,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.sections_view.setSpacing(4) self.sections_view.setSpacing(4)
self.sections_view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.sections_view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason) self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason)
self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state)
self.opt_gui_layout.addItem(_('Wide'), 'wide')
self.opt_gui_layout.addItem(_('Narrow'), 'narrow')
self.opt_gui_layout.currentIndexChanged.connect(self.changed_signal)
set_help_tips(self.opt_gui_layout, config.help('gui_layout'))
self.button_adjust_colors.clicked.connect(self.adjust_colors)
def adjust_colors(self):
from calibre.gui2.dialogs.palette import PaletteConfig
d = PaletteConfig(self)
if d.exec() == QDialog.DialogCode.Accepted:
d.apply_settings()
self.changed_signal.emit()
def initial_tab_changed(self): def initial_tab_changed(self):
self.sections_view.setCurrentRow(self.tabWidget.currentIndex()) self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
def update_color_palette_state(self):
if self.ui_style_available:
enabled = self.opt_ui_style.currentData() == 'calibre'
self.button_adjust_colors.setEnabled(enabled)
def choose_icon_theme(self):
from calibre.gui2.icon_theme import ChooseTheme
d = ChooseTheme(self)
if d.exec() == QDialog.DialogCode.Accepted:
self.commit_icon_theme = d.commit_changes
self.icon_theme_title = d.new_theme_title or _('Default icons')
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
self.changed_signal.emit()
def edit_id_link_rules(self): def edit_id_link_rules(self):
if IdLinksEditor(self).exec() == QDialog.DialogCode.Accepted: if IdLinksEditor(self).exec() == QDialog.DialogCode.Accepted:
self.changed_signal.emit() self.changed_signal.emit()
@ -595,12 +491,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
ConfigWidgetBase.initialize(self) ConfigWidgetBase.initialize(self)
self.default_author_link.value = default_author_link() self.default_author_link.value = default_author_link()
font = gprefs['font']
if font is not None:
font = list(font)
font.append(gprefs.get('font_stretch', QFont.Stretch.Unstretched))
self.current_font = self.initial_font = font
self.update_font_display()
self.display_model.initialize() self.display_model.initialize()
self.em_display_model.initialize() self.em_display_model.initialize()
self.bd_vertical_cats_model.initialize() self.bd_vertical_cats_model.initialize()
@ -622,8 +512,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.opt_book_details_css.blockSignals(True) self.opt_book_details_css.blockSignals(True)
self.opt_book_details_css.setPlainText(P('templates/book_details.css', data=True).decode('utf-8')) self.opt_book_details_css.setPlainText(P('templates/book_details.css', data=True).decode('utf-8'))
self.opt_book_details_css.blockSignals(False) self.opt_book_details_css.blockSignals(False)
self.update_color_palette_state()
self.opt_gui_layout.setCurrentIndex(0 if self.gui.layout_container.is_wide else 1)
def open_cg_cache(self): def open_cg_cache(self):
open_local_file(self.gui.grid_view.thumbnail_cache.location) open_local_file(self.gui.grid_view.thumbnail_cache.location)
@ -659,11 +547,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
def restore_defaults(self): def restore_defaults(self):
ConfigWidgetBase.restore_defaults(self) ConfigWidgetBase.restore_defaults(self)
self.default_author_link.value = DEFAULT_AUTHOR_LINK self.default_author_link.value = DEFAULT_AUTHOR_LINK
ofont = self.current_font
self.current_font = None
if ofont is not None:
self.changed_signal.emit()
self.update_font_display()
self.display_model.restore_defaults() self.display_model.restore_defaults()
self.em_display_model.restore_defaults() self.em_display_model.restore_defaults()
self.bd_vertical_cats_model.restore_defaults() self.bd_vertical_cats_model.restore_defaults()
@ -674,7 +557,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.set_cg_color(gprefs.defaults['cover_grid_color']) self.set_cg_color(gprefs.defaults['cover_grid_color'])
self.set_cg_texture(gprefs.defaults['cover_grid_texture']) self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
self.opt_book_details_css.setPlainText(P('templates/book_details.css', allow_user_override=False, data=True).decode('utf-8')) self.opt_book_details_css.setPlainText(P('templates/book_details.css', allow_user_override=False, data=True).decode('utf-8'))
self.opt_gui_layout.setCurrentIndex(0)
def change_cover_grid_color(self): def change_cover_grid_color(self):
col = QColorDialog.getColor(self.cg_bg_widget.bcol, col = QColorDialog.getColor(self.cg_bg_widget.bcol,
@ -702,40 +584,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.set_cg_texture(gprefs.defaults['cover_grid_texture']) self.set_cg_texture(gprefs.defaults['cover_grid_texture'])
self.changed_signal.emit() self.changed_signal.emit()
def build_font_obj(self):
font_info = qt_app.original_font if self.current_font is None else self.current_font
font = QFont(*(font_info[:4]))
font.setStretch(font_info[4])
return font
def update_font_display(self):
font = self.build_font_obj()
fi = QFontInfo(font)
name = str(fi.family())
self.font_display.setFont(font)
self.font_display.setText(name + f' [{fi.pointSize()}pt]')
def change_font(self, *args):
fd = QFontDialog(self.build_font_obj(), self)
if fd.exec() == QDialog.DialogCode.Accepted:
font = fd.selectedFont()
fi = QFontInfo(font)
self.current_font = [str(fi.family()), fi.pointSize(),
fi.weight(), fi.italic(), font.stretch()]
self.update_font_display()
self.changed_signal.emit()
def commit(self, *args): def commit(self, *args):
with BusyCursor(): with BusyCursor():
rr = ConfigWidgetBase.commit(self, *args)
if self.current_font != self.initial_font:
gprefs['font'] = (self.current_font[:4] if self.current_font else
None)
gprefs['font_stretch'] = (self.current_font[4] if self.current_font
is not None else QFont.Stretch.Unstretched)
QApplication.setFont(self.font_display.font())
rr = True
self.display_model.commit() self.display_model.commit()
self.em_display_model.commit() self.em_display_model.commit()
self.bd_vertical_cats_model.commit() self.bd_vertical_cats_model.commit()
@ -744,36 +594,24 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.grid_rules.commit(self.gui.current_db.prefs) self.grid_rules.commit(self.gui.current_db.prefs)
gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3] gprefs['cover_grid_color'] = tuple(self.cg_bg_widget.bcol.getRgb())[:3]
gprefs['cover_grid_texture'] = self.cg_bg_widget.btex gprefs['cover_grid_texture'] = self.cg_bg_widget.btex
if self.commit_icon_theme is not None:
self.commit_icon_theme()
gprefs['default_author_link'] = self.default_author_link.value gprefs['default_author_link'] = self.default_author_link.value
bcss = self.opt_book_details_css.toPlainText().encode('utf-8') bcss = self.opt_book_details_css.toPlainText().encode('utf-8')
defcss = P('templates/book_details.css', data=True, allow_user_override=False) defcss = P('templates/book_details.css', data=True, allow_user_override=False)
if defcss == bcss: if defcss == bcss:
bcss = None bcss = None
set_data('templates/book_details.css', bcss) set_data('templates/book_details.css', bcss)
self.gui.layout_container.change_layout(self.gui, self.opt_gui_layout.currentIndex() == 0)
return rr
def refresh_gui(self, gui): def refresh_gui(self, gui):
gui.book_details.book_info.refresh_css() gui.book_details.book_info.refresh_css()
gui.place_layout_buttons()
m = gui.library_view.model() m = gui.library_view.model()
m.update_db_prefs_cache() m.update_db_prefs_cache()
m.beginResetModel(), m.endResetModel() m.beginResetModel(), m.endResetModel()
self.update_font_display()
gui.tags_view.model().reset_tag_browser() gui.tags_view.model().reset_tag_browser()
gui.library_view.refresh_book_details(force=True) gui.library_view.refresh_book_details(force=True)
gui.library_view.refresh_grid() gui.library_view.refresh_grid()
gui.library_view.refresh_composite_edit() gui.library_view.refresh_composite_edit()
gui.library_view.set_row_header_visibility()
for view in 'library memory card_a card_b'.split():
getattr(gui, view + '_view').set_row_header_visibility()
gui.library_view.refresh_row_sizing()
gui.grid_view.refresh_settings() gui.grid_view.refresh_settings()
gui.update_auto_scroll_timeout() gui.update_auto_scroll_timeout()
gui.sb_all_gui_actions_button.setVisible(gprefs['show_sb_all_actions_button'])
# gui.sb_preferences_button.setVisible(gprefs['show_sb_preference_button'])
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -19,7 +19,7 @@
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="main_interface_tab"> <widget class="MainInterfaceTab" name="main_interface_tab">
<attribute name="icon"> <attribute name="icon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/lt.png</normaloff>:/images/lt.png</iconset> <normaloff>:/images/lt.png</normaloff>:/images/lt.png</iconset>
@ -27,353 +27,6 @@
<attribute name="title"> <attribute name="title">
<string>&amp;Main interface</string> <string>&amp;Main interface</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="label_widget_style">
<property name="text">
<string>User interface style (&amp;needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_ui_style</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="opt_ui_style"/>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="icon_theme">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="icon_theme_button">
<property name="text">
<string>Change &amp;icon theme</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="opt_color_palette_label">
<property name="text">
<string>User interface &amp;colors:</string>
</property>
<property name="buddy">
<cstring>button_adjust_colors</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="button_adjust_colors">
<property name="text">
<string>Adjust &amp;colors</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>&amp;User interface layout:</string>
</property>
<property name="buddy">
<cstring>opt_gui_layout</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="opt_gui_layout">
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Choose &amp;language (needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_language</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="opt_language">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Round the corners of covers:</string>
</property>
<property name="buddy">
<cstring>opt_cover_corner_radius</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="opt_cover_corner_radius">
<property name="toolTip">
<string>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.</string>
</property>
<property name="specialValueText">
<string>no rounding</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="opt_cover_corner_radius_unit">
<property name="toolTip">
<string>The unit for the cover corner rounding. Either pixel values or as a percentage of the cover size.</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="opt_systray_icon">
<property name="text">
<string>Enable s&amp;ystem tray icon (needs restart)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="opt_disable_animations">
<property name="toolTip">
<string>Disable all animations. Useful if you have a slow/old computer.</string>
</property>
<property name="text">
<string>Disable &amp;animations</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="opt_disable_tray_notification">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Disable n&amp;otifications on job completion</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="opt_show_splash_screen">
<property name="text">
<string>Show the &amp;splash screen at startup</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="opt_book_list_tooltips">
<property name="text">
<string>Show &amp;tooltips in the book list</string>
</property>
</widget>
</item>
<item row="9" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Interface font:</string>
</property>
<property name="buddy">
<cstring>font_display</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="font_display">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="1">
<widget class="QPushButton" name="change_font_button">
<property name="text">
<string>Change &amp;font (needs restart)</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Toolbar</string>
</property>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="1">
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Icon si&amp;ze:</string>
</property>
<property name="buddy">
<cstring>opt_toolbar_icon_size</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="opt_toolbar_text"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Show &amp;text under icons:</string>
</property>
<property name="buddy">
<cstring>opt_toolbar_text</cstring>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="opt_wrap_toolbar_text">
<property name="text">
<string>Use t&amp;wo lines for the text under the icons (needs restart)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="10" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Status bar buttons</string>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="opt_show_layout_buttons">
<property name="toolTip">
<string>Show individual buttons to control the layout of the interface rather than a single button with a popup.</string>
</property>
<property name="text">
<string>Show &amp;layout buttons</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="opt_show_sb_all_actions_button">
<property name="toolTip">
<string>Show a button that gives quick access to all available actions with a single click.</string>
</property>
<property name="text">
<string>S&amp;how actions button</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>E&amp;xtra spacing to add between rows in the book list (can be negative):</string>
</property>
<property name="buddy">
<cstring>opt_book_list_extra_row_spacing</cstring>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="opt_book_list_extra_row_spacing">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>-20</number>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="opt_row_numbers_in_book_list">
<property name="text">
<string>Show &amp;row numbers in the book list</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="opt_booklist_grid">
<property name="text">
<string>Draw a &amp;grid in the book list</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QCheckBox" name="opt_dnd_merge">
<property name="text">
<string>Allow using &amp;drag and drop to merge books</string>
</property>
</widget>
</item>
<item row="15" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget> </widget>
<widget class="QTabWidget" name="cover_grid_tab"> <widget class="QTabWidget" name="cover_grid_tab">
<property name="currentIndex"> <property name="currentIndex">
@ -1377,6 +1030,11 @@ columns&quot;. Editing with mouse clicks and the Tab key will be disabled.&lt;/p
<extends>QWidget</extends> <extends>QWidget</extends>
<header>calibre/gui2/preferences/look_feel_tabs.h</header> <header>calibre/gui2/preferences/look_feel_tabs.h</header>
</customwidget> </customwidget>
<customwidget>
<class>MainInterfaceTab</class>
<extends>ConfigWidgetBase</extends>
<header>calibre/gui2/preferences/look_feel_tabs/main_interface.h</header>
</customwidget>
<customwidget> <customwidget>
<class>TbDisplayTab</class> <class>TbDisplayTab</class>
<extends>ConfigWidgetBase</extends> <extends>ConfigWidgetBase</extends>

View File

@ -0,0 +1,193 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2025, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from qt.core import QApplication, QDialog, QFont, QFontDialog, QFontInfo
from calibre.constants import ismacos, iswindows
from calibre.gui2 import config, gprefs, icon_resource_manager, qt_app
from calibre.gui2.preferences import LazyConfigWidgetBase, Setting, set_help_tips
from calibre.gui2.preferences.look_feel_tabs.main_interface_ui import Ui_Form
from calibre.gui2.widgets import BusyCursor
from calibre.utils.config import prefs
from calibre.utils.localization import available_translations, get_lang, get_language
class LanguageSetting(Setting):
def commit(self):
val = self.get_gui_val()
oldval = self.get_config_val()
if val != oldval:
gprefs.set('last_used_language', oldval)
return super().commit()
class MainInterfaceTab(LazyConfigWidgetBase, Ui_Form):
def genesis(self, gui):
self.gui = gui
self.ui_style_available = True
if not ismacos and not iswindows:
self.label_widget_style.setVisible(False)
self.opt_ui_style.setVisible(False)
self.ui_style_available = False
r = self.register
try:
self.icon_theme_title = icon_resource_manager.user_theme_title
except Exception:
self.icon_theme_title = _('Default icons')
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
self.commit_icon_theme = None
self.icon_theme_button.clicked.connect(self.choose_icon_theme)
r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')])
r('book_list_tooltips', gprefs)
r('dnd_merge', gprefs)
r('wrap_toolbar_text', gprefs, restart_required=True)
r('show_layout_buttons', gprefs)
r('show_sb_all_actions_button', gprefs)
# r('show_sb_preference_button', gprefs)
r('row_numbers_in_book_list', gprefs)
r('cover_corner_radius', gprefs)
r('cover_corner_radius_unit', gprefs, choices=[(_('Pixels'), 'px'), (_('Percentage'), '%')])
r('book_list_extra_row_spacing', gprefs)
r('booklist_grid', gprefs)
def get_esc_lang(l):
if l == 'en':
return 'English'
return get_language(l)
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()
if l != lang]
if lang != 'en':
items.append(('en', get_esc_lang('en')))
items.sort(key=lambda x: x[1].lower())
choices = [(y, x) for x, y in items]
# Default language is the autodetected one
choices = [(get_language(lang), lang)] + choices
lul = gprefs.get('last_used_language')
if lul and (lul in available_translations() or lul in ('en', 'eng')):
choices.insert(1, ((get_language(lul), lul)))
r('language', prefs, choices=choices, restart_required=True, setting=LanguageSetting)
r('disable_animations', config)
r('systray_icon', config, restart_required=True)
r('show_splash_screen', gprefs)
r('disable_tray_notification', config)
choices = [(_('Off'), 'off'), (_('Small'), 'small'),
(_('Medium-small'), 'mid-small'), (_('Medium'), 'medium'), (_('Large'), 'large')]
r('toolbar_icon_size', gprefs, choices=choices)
choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'),
(_('Never'), 'never')]
r('toolbar_text', gprefs, choices=choices)
self.current_font = self.initial_font = None
self.change_font_button.clicked.connect(self.change_font)
self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state)
self.opt_gui_layout.addItem(_('Wide'), 'wide')
self.opt_gui_layout.addItem(_('Narrow'), 'narrow')
self.opt_gui_layout.currentIndexChanged.connect(self.changed_signal)
set_help_tips(self.opt_gui_layout, config.help('gui_layout'))
self.button_adjust_colors.clicked.connect(self.adjust_colors)
def lazy_initialize(self):
font = gprefs['font']
if font is not None:
font = list(font)
font.append(gprefs.get('font_stretch', QFont.Stretch.Unstretched))
self.current_font = self.initial_font = font
self.update_font_display()
self.update_color_palette_state()
self.opt_gui_layout.setCurrentIndex(0 if self.gui.layout_container.is_wide else 1)
def adjust_colors(self):
from calibre.gui2.dialogs.palette import PaletteConfig
d = PaletteConfig(self)
if d.exec() == QDialog.DialogCode.Accepted:
d.apply_settings()
self.changed_signal.emit()
def update_color_palette_state(self):
if self.ui_style_available:
enabled = self.opt_ui_style.currentData() == 'calibre'
self.button_adjust_colors.setEnabled(enabled)
def choose_icon_theme(self):
from calibre.gui2.icon_theme import ChooseTheme
d = ChooseTheme(self)
if d.exec() == QDialog.DialogCode.Accepted:
self.commit_icon_theme = d.commit_changes
self.icon_theme_title = d.new_theme_title or _('Default icons')
self.icon_theme.setText(_('Icon theme: <b>%s</b>') % self.icon_theme_title)
self.changed_signal.emit()
def build_font_obj(self):
font_info = qt_app.original_font if self.current_font is None else self.current_font
font = QFont(*(font_info[:4]))
font.setStretch(font_info[4])
return font
def change_font(self, *args):
fd = QFontDialog(self.build_font_obj(), self)
if fd.exec() == QDialog.DialogCode.Accepted:
font = fd.selectedFont()
fi = QFontInfo(font)
self.current_font = [str(fi.family()), fi.pointSize(),
fi.weight(), fi.italic(), font.stretch()]
self.update_font_display()
self.changed_signal.emit()
def update_font_display(self):
font = self.build_font_obj()
fi = QFontInfo(font)
name = str(fi.family())
self.font_display.setFont(font)
self.font_display.setText(name + f' [{fi.pointSize()}pt]')
def commit(self):
rr = LazyConfigWidgetBase.commit(self)
with BusyCursor():
if self.current_font != self.initial_font:
gprefs['font'] = (self.current_font[:4] if self.current_font else None)
gprefs['font_stretch'] = (self.current_font[4] if self.current_font
is not None else QFont.Stretch.Unstretched)
QApplication.setFont(self.font_display.font())
rr = True
if self.commit_icon_theme is not None:
self.commit_icon_theme()
self.gui.layout_container.change_layout(self.gui, self.opt_gui_layout.currentIndex() == 0)
return rr
def restore_defaults(self):
LazyConfigWidgetBase.restore_defaults(self)
ofont = self.current_font
self.current_font = None
if ofont is not None:
self.changed_signal.emit()
self.main_interface_tab.update_font_display()
self.opt_gui_layout.setCurrentIndex(0)
self.changed_signal.emit()
def refresh_gui(self, gui):
gui.place_layout_buttons()
self.update_font_display()
gui.library_view.set_row_header_visibility()
for view in 'library memory card_a card_b'.split():
getattr(gui, view + '_view').set_row_header_visibility()
gui.library_view.refresh_row_sizing()
gui.sb_all_gui_actions_button.setVisible(gprefs['show_sb_all_actions_button'])
# gui.sb_preferences_button.setVisible(gprefs['show_sb_preference_button'])

View File

@ -0,0 +1,356 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="main_interface_tab">
<layout class="QGridLayout" name="gridLayout_main_interface">
<item row="0" column="0">
<widget class="QLabel" name="label_widget_style">
<property name="text">
<string>User interface style (&amp;needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_ui_style</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="opt_ui_style"/>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="icon_theme">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="icon_theme_button">
<property name="text">
<string>Change &amp;icon theme</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="opt_color_palette_label">
<property name="text">
<string>User interface &amp;colors:</string>
</property>
<property name="buddy">
<cstring>button_adjust_colors</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="button_adjust_colors">
<property name="text">
<string>Adjust &amp;colors</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>&amp;User interface layout:</string>
</property>
<property name="buddy">
<cstring>opt_gui_layout</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="opt_gui_layout">
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Choose &amp;language (needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_language</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="opt_language">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Round the corners of covers:</string>
</property>
<property name="buddy">
<cstring>opt_cover_corner_radius</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="opt_cover_corner_radius">
<property name="toolTip">
<string>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.</string>
</property>
<property name="specialValueText">
<string>no rounding</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="opt_cover_corner_radius_unit">
<property name="toolTip">
<string>The unit for the cover corner rounding. Either pixel values or as a percentage of the cover size.</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="opt_systray_icon">
<property name="text">
<string>Enable s&amp;ystem tray icon (needs restart)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="opt_disable_animations">
<property name="toolTip">
<string>Disable all animations. Useful if you have a slow/old computer.</string>
</property>
<property name="text">
<string>Disable &amp;animations</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="opt_disable_tray_notification">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Disable n&amp;otifications on job completion</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="opt_show_splash_screen">
<property name="text">
<string>Show the &amp;splash screen at startup</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="opt_book_list_tooltips">
<property name="text">
<string>Show &amp;tooltips in the book list</string>
</property>
</widget>
</item>
<item row="9" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Interface font:</string>
</property>
<property name="buddy">
<cstring>font_display</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="font_display">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="1">
<widget class="QPushButton" name="change_font_button">
<property name="text">
<string>Change &amp;font (needs restart)</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Toolbar</string>
</property>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="1">
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Icon si&amp;ze:</string>
</property>
<property name="buddy">
<cstring>opt_toolbar_icon_size</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="opt_toolbar_text"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Show &amp;text under icons:</string>
</property>
<property name="buddy">
<cstring>opt_toolbar_text</cstring>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="opt_wrap_toolbar_text">
<property name="text">
<string>Use t&amp;wo lines for the text under the icons (needs restart)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="10" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Status bar buttons</string>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="opt_show_layout_buttons">
<property name="toolTip">
<string>Show individual buttons to control the layout of the interface rather than a single button with a popup.</string>
</property>
<property name="text">
<string>Show &amp;layout buttons</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="opt_show_sb_all_actions_button">
<property name="toolTip">
<string>Show a button that gives quick access to all available actions with a single click.</string>
</property>
<property name="text">
<string>S&amp;how actions button</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>E&amp;xtra spacing to add between rows in the book list (can be negative):</string>
</property>
<property name="buddy">
<cstring>opt_book_list_extra_row_spacing</cstring>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="opt_book_list_extra_row_spacing">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>-20</number>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="opt_row_numbers_in_book_list">
<property name="text">
<string>Show &amp;row numbers in the book list</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="opt_booklist_grid">
<property name="text">
<string>Draw a &amp;grid in the book list</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QCheckBox" name="opt_dnd_merge">
<property name="text">
<string>Allow using &amp;drag and drop to merge books</string>
</property>
</widget>
</item>
<item row="15" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../../../../resources/images.qrc"/>
</resources>
</ui>