diff --git a/qt/me/preferences_dialog.py b/qt/me/preferences_dialog.py index 4dd8b455..462e5682 100644 --- a/qt/me/preferences_dialog.py +++ b/qt/me/preferences_dialog.py @@ -76,7 +76,7 @@ class PreferencesDialog(PreferencesDialogBase): self.widgetsVLayout.addWidget(self.debugModeBox) self._setupBottomPart() - def _load(self, prefs, setchecked): + def _load(self, prefs, setchecked, section): setchecked(self.tagTrackBox, prefs.scan_tag_track) setchecked(self.tagArtistBox, prefs.scan_tag_artist) setchecked(self.tagAlbumBox, prefs.scan_tag_album) diff --git a/qt/pe/image_viewer.py b/qt/pe/image_viewer.py index 08a70db8..bf71a068 100644 --- a/qt/pe/image_viewer.py +++ b/qt/pe/image_viewer.py @@ -49,7 +49,9 @@ class ViewerToolBar(QToolBar): ( "actionZoomIn", QKeySequence.ZoomIn, - QIcon.fromTheme("zoom-in") if ISLINUX + QIcon.fromTheme("zoom-in") + if ISLINUX + and not self.parent.app.prefs.details_dialog_override_theme_icons else QIcon(QPixmap(":/" + "zoom_in")), tr("Increase zoom"), controller.zoomIn, @@ -57,7 +59,9 @@ class ViewerToolBar(QToolBar): ( "actionZoomOut", QKeySequence.ZoomOut, - QIcon.fromTheme("zoom-out") if ISLINUX + QIcon.fromTheme("zoom-out") + if ISLINUX + and not self.parent.app.prefs.details_dialog_override_theme_icons else QIcon(QPixmap(":/" + "zoom_out")), tr("Decrease zoom"), controller.zoomOut, @@ -65,7 +69,9 @@ class ViewerToolBar(QToolBar): ( "actionNormalSize", tr("Ctrl+/"), - QIcon.fromTheme("zoom-original") if ISLINUX + QIcon.fromTheme("zoom-original") + if ISLINUX + and not self.parent.app.prefs.details_dialog_override_theme_icons else QIcon(QPixmap(":/" + "zoom_original")), tr("Normal size"), controller.zoomNormalSize, @@ -73,7 +79,9 @@ class ViewerToolBar(QToolBar): ( "actionBestFit", tr("Ctrl+*"), - QIcon.fromTheme("zoom-best-fit") if ISLINUX + QIcon.fromTheme("zoom-best-fit") + if ISLINUX + and not self.parent.app.prefs.details_dialog_override_theme_icons else QIcon(QPixmap(":/" + "zoom_best_fit")), tr("Best fit"), controller.zoomBestFit, @@ -90,6 +98,7 @@ class ViewerToolBar(QToolBar): QIcon.fromTheme('view-refresh', self.style().standardIcon(QStyle.SP_BrowserReload)) if ISLINUX + and not self.parent.app.prefs.details_dialog_override_theme_icons else QIcon(QPixmap(":/" + "exchange"))) self.buttonImgSwap.setText('Swap images') self.buttonImgSwap.setToolTip('Swap images') diff --git a/qt/pe/preferences_dialog.py b/qt/pe/preferences_dialog.py index c220d317..05626582 100644 --- a/qt/pe/preferences_dialog.py +++ b/qt/pe/preferences_dialog.py @@ -45,7 +45,7 @@ class PreferencesDialog(PreferencesDialogBase): self.widgetsVLayout.addWidget(self.cacheTypeRadio) self._setupBottomPart() - def _load(self, prefs, setchecked): + def _load(self, prefs, setchecked, section): setchecked(self.matchScaledBox, prefs.match_scaled) self.cacheTypeRadio.selected_index = ( 1 if prefs.picture_cache_type == "shelve" else 0 diff --git a/qt/preferences.py b/qt/preferences.py index 39e55b1e..604a9107 100644 --- a/qt/preferences.py +++ b/qt/preferences.py @@ -5,8 +5,11 @@ # http://www.gnu.org/licenses/gpl-3.0.html from PyQt5.QtWidgets import QApplication +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QColor from hscommon import trans +from hscommon.plat import ISLINUX from core.app import AppMode from core.scanner import ScanType from qtlib.preferences import Preferences as PreferencesBase @@ -31,8 +34,20 @@ class Preferences(PreferencesBase): self.tableFontSize = get("TableFontSize", self.tableFontSize) self.reference_bold_font = get('ReferenceBoldFont', self.reference_bold_font) - self.details_dialog_titlebar_enabled = get('DetailsDialogTitleBarEnabled', self.details_dialog_titlebar_enabled) - self.details_dialog_vertical_titlebar = get('DetailsDialogVerticalTitleBar', self.details_dialog_vertical_titlebar) + self.details_dialog_titlebar_enabled = get('DetailsDialogTitleBarEnabled', + self.details_dialog_titlebar_enabled) + self.details_dialog_vertical_titlebar = get('DetailsDialogVerticalTitleBar', + self.details_dialog_vertical_titlebar) + # On Windows and MacOS, use internal icons by default + self.details_dialog_override_theme_icons =\ + get('DetailsDialogOverrideThemeIcons', + self.details_dialog_override_theme_icons) if ISLINUX else True + + self.result_table_ref_foreground_color =\ + get('ResultTableRefForegroundColor', self.result_table_ref_foreground_color) + self.result_table_delta_foreground_color =\ + get('ResultTableDeltaForegroundColor', self.result_table_delta_foreground_color) + self.resultWindowIsMaximized = get( "ResultWindowIsMaximized", self.resultWindowIsMaximized ) @@ -71,6 +86,10 @@ class Preferences(PreferencesBase): self.reference_bold_font = True self.details_dialog_titlebar_enabled = True self.details_dialog_vertical_titlebar = True + # By default use internal icons on platforms other than Linux for now + self.details_dialog_override_theme_icons = False if not ISLINUX else True + self.result_table_ref_foreground_color = QColor(Qt.blue) + self.result_table_delta_foreground_color = QColor(255, 142, 40) # orange self.resultWindowIsMaximized = False self.resultWindowRect = None self.directoriesWindowRect = None @@ -106,6 +125,9 @@ class Preferences(PreferencesBase): set_('ReferenceBoldFont', self.reference_bold_font) set_('DetailsDialogTitleBarEnabled', self.details_dialog_titlebar_enabled) set_('DetailsDialogVerticalTitleBar', self.details_dialog_vertical_titlebar) + set_('DetailsDialogOverrideThemeIcons', self.details_dialog_override_theme_icons) + set_('ResultTableRefForegroundColor', self.result_table_ref_foreground_color) + set_('ResultTableDeltaForegroundColor', self.result_table_delta_foreground_color) set_("ResultWindowIsMaximized", self.resultWindowIsMaximized) self.set_rect("ResultWindowRect", self.resultWindowRect) self.set_rect("DirectoriesWindowRect", self.directoriesWindowRect) diff --git a/qt/preferences_dialog.py b/qt/preferences_dialog.py index 95eb1b67..37736c96 100644 --- a/qt/preferences_dialog.py +++ b/qt/preferences_dialog.py @@ -4,12 +4,13 @@ # which should be included with this package. The terms are also available at # http://www.gnu.org/licenses/gpl-3.0.html -from PyQt5.QtCore import Qt, QSize +from PyQt5.QtCore import Qt, QSize, pyqtSlot from PyQt5.QtWidgets import ( QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, + QGridLayout, QLabel, QComboBox, QSlider, @@ -20,11 +21,19 @@ from PyQt5.QtWidgets import ( QMessageBox, QSpinBox, QLayout, + QTabWidget, + QWidget, + QColorDialog, + QPushButton, + QFrame, ) +from PyQt5.QtGui import QPixmap, QIcon from hscommon.trans import trget +from hscommon.plat import ISLINUX from qtlib.util import horizontalWrap from qtlib.preferences import get_langnames +from enum import Flag, auto from .preferences import Preferences @@ -50,6 +59,13 @@ SUPPORTED_LANGUAGES = [ ] +class Sections(Flag): + """Filter blocks of preferences when reset or loaded""" + GENERAL = auto() + DISPLAY = auto() + ALL = GENERAL | DISPLAY + + class PreferencesDialogBase(QDialog): def __init__(self, parent, app, **kwargs): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint @@ -111,34 +127,7 @@ class PreferencesDialogBase(QDialog): def _setupBottomPart(self): # The bottom part of the pref panel is always the same in all editions. - self.fontSizeLabel = QLabel(tr("Font size:")) - self.fontSizeSpinBox = QSpinBox() - self.fontSizeSpinBox.setMinimum(5) - self.widgetsVLayout.addLayout( - horizontalWrap([self.fontSizeLabel, self.fontSizeSpinBox, None]) - ) - self._setupAddCheckbox("reference_bold_font", - tr("Bold font for reference")) - self.widgetsVLayout.addWidget(self.reference_bold_font) - - self._setupAddCheckbox("details_dialog_titlebar_enabled", - tr("Details dialog displays a title bar and is dockable")) - self.widgetsVLayout.addWidget(self.details_dialog_titlebar_enabled) - self._setupAddCheckbox("details_dialog_vertical_titlebar", - tr("Details dialog displays a vertical title bar (Linux only)")) - self.widgetsVLayout.addWidget(self.details_dialog_vertical_titlebar) - self.details_dialog_vertical_titlebar.setEnabled( - self.details_dialog_titlebar_enabled.isChecked()) - self.details_dialog_titlebar_enabled.stateChanged.connect( - self.details_dialog_vertical_titlebar.setEnabled) - - self.languageLabel = QLabel(tr("Language:"), self) - self.languageComboBox = QComboBox(self) - for lang in self.supportedLanguages: - self.languageComboBox.addItem(get_langnames()[lang]) - self.widgetsVLayout.addLayout( - horizontalWrap([self.languageLabel, self.languageComboBox, None]) - ) + self._setupDisplayPage() self.copyMoveLabel = QLabel(self) self.copyMoveLabel.setText(tr("Copy and Move:")) self.widgetsVLayout.addWidget(self.copyMoveLabel) @@ -155,6 +144,66 @@ class PreferencesDialogBase(QDialog): self.customCommandEdit = QLineEdit(self) self.widgetsVLayout.addWidget(self.customCommandEdit) + def _setupDisplayPage(self): + self.languageLabel = QLabel(tr("Language:"), self) + self.languageComboBox = QComboBox(self) + for lang in self.supportedLanguages: + self.languageComboBox.addItem(get_langnames()[lang]) + self.displayVLayout.insertLayout( + 0, horizontalWrap([self.languageLabel, self.languageComboBox, None]) + ) + + line = QFrame(self) + line.setFrameShape(QFrame.HLine) + self.displayVLayout.addWidget(line) + + gridlayout = QGridLayout() + self.result_table_label = QLabel(tr("Result Table:")) + gridlayout.addWidget(self.result_table_label, 0, 0) + self.fontSizeLabel = QLabel(tr("Font size:")) + self.fontSizeSpinBox = QSpinBox() + self.fontSizeSpinBox.setMinimum(5) + gridlayout.addWidget(self.fontSizeLabel, 1, 0) + gridlayout.addWidget(self.fontSizeSpinBox, 1, 1, 1, 1, Qt.AlignLeft) + self._setupAddCheckbox("reference_bold_font", + tr("Bold font for reference")) + gridlayout.addWidget(self.reference_bold_font, 2, 0) + self.result_table_ref_foreground_color_label = QLabel(tr("Reference foreground color:")) + gridlayout.addWidget(self.result_table_ref_foreground_color_label, 3, 0) + self.result_table_ref_foreground_color = ColorPickerButton(self) + gridlayout.addWidget(self.result_table_ref_foreground_color, 3, 1, 1, 1, Qt.AlignLeft) + self.result_table_delta_foreground_color_label = QLabel(tr("Delta foreground color:")) + gridlayout.addWidget(self.result_table_delta_foreground_color_label, 4, 0) + self.result_table_delta_foreground_color = ColorPickerButton(self) + gridlayout.addWidget(self.result_table_delta_foreground_color, 4, 1, 1, 1, Qt.AlignLeft) + self.displayVLayout.addLayout(gridlayout) + + line = QFrame(self) + line.setFrameShape(QFrame.HLine) + self.displayVLayout.addWidget(line) + + self.details_dialog_label = QLabel(tr("Details window:")) + self.displayVLayout.addWidget(self.details_dialog_label) + self._setupAddCheckbox("details_dialog_titlebar_enabled", + tr("Show a title bar and is dockable")) + self.details_dialog_titlebar_enabled.setToolTip( + tr("Title bar can only be disabled while the window is docked")) + self.displayVLayout.addWidget(self.details_dialog_titlebar_enabled) + self._setupAddCheckbox("details_dialog_vertical_titlebar", + tr("Vertical title bar")) + self.displayVLayout.addWidget(self.details_dialog_vertical_titlebar) + self.details_dialog_vertical_titlebar.setEnabled( + self.details_dialog_titlebar_enabled.isChecked()) + self.details_dialog_titlebar_enabled.stateChanged.connect( + self.details_dialog_vertical_titlebar.setEnabled) + self._setupAddCheckbox("details_dialog_override_theme_icons", + tr("Override theme icons")) + self.details_dialog_override_theme_icons.setToolTip( + tr("Use our own internal icons instead of those provided by the theme engine")) + # Prevent changing this on platforms where themes are unpredictable + self.details_dialog_override_theme_icons.setEnabled(False if not ISLINUX else True) + self.displayVLayout.addWidget(self.details_dialog_override_theme_icons) + def _setupAddCheckbox(self, name, label, parent=None): if parent is None: parent = self @@ -171,19 +220,29 @@ class PreferencesDialogBase(QDialog): self.setSizeGripEnabled(False) self.setModal(True) self.mainVLayout = QVBoxLayout(self) + self.tabwidget = QTabWidget() + self.page_general = QWidget() + self.page_display = QWidget() self.widgetsVLayout = QVBoxLayout() + self.page_general.setLayout(self.widgetsVLayout) + self.displayVLayout = QVBoxLayout() + self.page_display.setLayout(self.displayVLayout) self._setupPreferenceWidgets() - self.mainVLayout.addLayout(self.widgetsVLayout) + # self.mainVLayout.addLayout(self.widgetsVLayout) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.RestoreDefaults ) + self.mainVLayout.addWidget(self.tabwidget) self.mainVLayout.addWidget(self.buttonBox) self.layout().setSizeConstraint(QLayout.SetFixedSize) + self.tabwidget.addTab(self.page_general, "General") + self.tabwidget.addTab(self.page_display, "Display") + self.displayVLayout.addStretch(0) - def _load(self, prefs, setchecked): + def _load(self, prefs, setchecked, section): # Edition-specific pass @@ -191,29 +250,39 @@ class PreferencesDialogBase(QDialog): # Edition-specific pass - def load(self, prefs=None): + def load(self, prefs=None, section=Sections.ALL): if prefs is None: prefs = self.app.prefs - self.filterHardnessSlider.setValue(prefs.filter_hardness) - self.filterHardnessLabel.setNum(prefs.filter_hardness) setchecked = lambda cb, b: cb.setCheckState(Qt.Checked if b else Qt.Unchecked) - setchecked(self.mixFileKindBox, prefs.mix_file_kind) - setchecked(self.useRegexpBox, prefs.use_regexp) - setchecked(self.removeEmptyFoldersBox, prefs.remove_empty_folders) - setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches) - setchecked(self.debugModeBox, prefs.debug_mode) - setchecked(self.reference_bold_font, prefs.reference_bold_font) - setchecked(self.details_dialog_titlebar_enabled , prefs.details_dialog_titlebar_enabled) - setchecked(self.details_dialog_vertical_titlebar, prefs.details_dialog_vertical_titlebar) - self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type) - self.customCommandEdit.setText(prefs.custom_command) - self.fontSizeSpinBox.setValue(prefs.tableFontSize) - try: - langindex = self.supportedLanguages.index(self.app.prefs.language) - except ValueError: - langindex = 0 - self.languageComboBox.setCurrentIndex(langindex) - self._load(prefs, setchecked) + if section & Sections.GENERAL: + self.filterHardnessSlider.setValue(prefs.filter_hardness) + self.filterHardnessLabel.setNum(prefs.filter_hardness) + setchecked(self.mixFileKindBox, prefs.mix_file_kind) + setchecked(self.useRegexpBox, prefs.use_regexp) + setchecked(self.removeEmptyFoldersBox, prefs.remove_empty_folders) + setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches) + setchecked(self.debugModeBox, prefs.debug_mode) + self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type) + self.customCommandEdit.setText(prefs.custom_command) + if section & Sections.DISPLAY: + setchecked(self.reference_bold_font, prefs.reference_bold_font) + setchecked(self.details_dialog_titlebar_enabled, + prefs.details_dialog_titlebar_enabled) + setchecked(self.details_dialog_vertical_titlebar, + prefs.details_dialog_vertical_titlebar) + self.fontSizeSpinBox.setValue(prefs.tableFontSize) + setchecked(self.details_dialog_override_theme_icons, + prefs.details_dialog_override_theme_icons) + self.result_table_ref_foreground_color.setColor( + prefs.result_table_ref_foreground_color) + self.result_table_delta_foreground_color.setColor( + prefs.result_table_delta_foreground_color) + try: + langindex = self.supportedLanguages.index(self.app.prefs.language) + except ValueError: + langindex = 0 + self.languageComboBox.setCurrentIndex(langindex) + self._load(prefs, setchecked, section) def save(self): prefs = self.app.prefs @@ -227,6 +296,9 @@ class PreferencesDialogBase(QDialog): prefs.reference_bold_font = ischecked(self.reference_bold_font) prefs.details_dialog_titlebar_enabled = ischecked(self.details_dialog_titlebar_enabled) prefs.details_dialog_vertical_titlebar = ischecked(self.details_dialog_vertical_titlebar) + prefs.details_dialog_override_theme_icons = ischecked(self.details_dialog_override_theme_icons) + prefs.result_table_ref_foreground_color = self.result_table_ref_foreground_color.color + prefs.result_table_delta_foreground_color = self.result_table_delta_foreground_color.color prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex() prefs.custom_command = str(self.customCommandEdit.text()) prefs.tableFontSize = self.fontSizeSpinBox.value() @@ -243,11 +315,45 @@ class PreferencesDialogBase(QDialog): self.app.prefs.language = lang self._save(prefs, ischecked) - def resetToDefaults(self): - self.load(Preferences()) + def resetToDefaults(self, section_to_update): + self.load(Preferences(), section_to_update) # --- Events def buttonClicked(self, button): role = self.buttonBox.buttonRole(button) if role == QDialogButtonBox.ResetRole: - self.resetToDefaults() + current_tab = self.tabwidget.currentWidget() + section_to_update = Sections.ALL + if current_tab is self.page_general: + section_to_update = Sections.GENERAL + if current_tab is self.page_display: + section_to_update = Sections.DISPLAY + self.resetToDefaults(section_to_update) + + +class ColorPickerButton(QPushButton): + def __init__(self, parent): + super().__init__(parent) + self.parent = parent + self.color = None + self.clicked.connect(self.onClicked) + + @pyqtSlot() + def onClicked(self): + color = QColorDialog.getColor( + self.color if self.color is not None else Qt.white, + self.parent) + self.setColor(color) + + def setColor(self, color): + size = QSize(1, 1) + px = QPixmap(size) + if color is None: + size.width = 0 + size.height = 0 + elif not color.isValid(): + return + else: + self.color = color + px.fill(color) + self.setIcon(QIcon(px)) diff --git a/qt/results_model.py b/qt/results_model.py index d16fcc97..b896bc92 100644 --- a/qt/results_model.py +++ b/qt/results_model.py @@ -7,7 +7,7 @@ # http://www.gnu.org/licenses/gpl-3.0.html from PyQt5.QtCore import Qt, pyqtSignal, QModelIndex -from PyQt5.QtGui import QBrush, QFont, QFontMetrics, QColor +from PyQt5.QtGui import QBrush, QFont, QFontMetrics from PyQt5.QtWidgets import QTableView from qtlib.table import Table @@ -37,9 +37,9 @@ class ResultsModel(Table): return data[column.name] elif role == Qt.ForegroundRole: if row.isref: - return QBrush(Qt.blue) + return QBrush(self.prefs.result_table_ref_foreground_color) elif row.is_cell_delta(column.name): - return QBrush(QColor(255, 142, 40)) # orange + return QBrush(self.prefs.result_table_delta_foreground_color) elif role == Qt.FontRole: font = QFont(self.view.font()) if self.prefs.reference_bold_font: diff --git a/qt/se/preferences_dialog.py b/qt/se/preferences_dialog.py index 994e8b54..0424afcc 100644 --- a/qt/se/preferences_dialog.py +++ b/qt/se/preferences_dialog.py @@ -85,7 +85,7 @@ class PreferencesDialog(PreferencesDialogBase): self.widgetsVLayout.addWidget(self.widget) self._setupBottomPart() - def _load(self, prefs, setchecked): + def _load(self, prefs, setchecked, section): setchecked(self.matchSimilarBox, prefs.match_similar) setchecked(self.wordWeightingBox, prefs.word_weighting) setchecked(self.ignoreSmallFilesBox, prefs.ignore_small_files)