From 2b9935e6f4445cda15479e631752a9029479a0db Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 10 May 2025 15:03:07 -0500 Subject: [PATCH] DolphinQt: Change main settings window QTabWidget into a QListWidget and QStackedWidget. --- .../Core/DolphinQt/Config/SettingsWindow.cpp | 148 ++++++++++++++---- Source/Core/DolphinQt/Config/SettingsWindow.h | 32 +++- Source/Core/DolphinQt/Settings/AudioPane.cpp | 2 +- 3 files changed, 148 insertions(+), 34 deletions(-) diff --git a/Source/Core/DolphinQt/Config/SettingsWindow.cpp b/Source/Core/DolphinQt/Config/SettingsWindow.cpp index 1883e8562e..f3618cc810 100644 --- a/Source/Core/DolphinQt/Config/SettingsWindow.cpp +++ b/Source/Core/DolphinQt/Config/SettingsWindow.cpp @@ -4,13 +4,13 @@ #include "DolphinQt/Config/SettingsWindow.h" #include -#include -#include +#include +#include +#include #include +#include "DolphinQt/QtUtils/QtUtils.h" #include "DolphinQt/QtUtils/WrapInScrollArea.h" -#include "DolphinQt/Resources.h" -#include "DolphinQt/Settings.h" #include "DolphinQt/Settings/AdvancedPane.h" #include "DolphinQt/Settings/AudioPane.h" #include "DolphinQt/Settings/GameCubePane.h" @@ -19,45 +19,137 @@ #include "DolphinQt/Settings/PathPane.h" #include "DolphinQt/Settings/WiiPane.h" -#include "Core/Core.h" - -SettingsWindow::SettingsWindow(QWidget* parent) : QDialog(parent) +StackedSettingsWindow::StackedSettingsWindow(QWidget* parent) : QDialog{parent} { - // Set Window Properties - setWindowTitle(tr("Settings")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - // Main Layout - QVBoxLayout* layout = new QVBoxLayout; + // This eliminates the ugly line between the title bar and window contents with KDE Plasma. + setStyleSheet(QStringLiteral("QDialog { border: none; }")); - // Add content to layout before dialog buttons. - m_tab_widget = new QTabWidget(); - layout->addWidget(m_tab_widget); + auto* const layout = new QHBoxLayout{this}; - m_tab_widget->addTab(GetWrappedWidget(new GeneralPane, this, 125, 100), tr("General")); - m_tab_widget->addTab(GetWrappedWidget(new InterfacePane, this, 125, 100), tr("Interface")); - m_tab_widget->addTab(GetWrappedWidget(new AudioPane, this, 125, 100), tr("Audio")); - m_tab_widget->addTab(GetWrappedWidget(new PathPane, this, 125, 100), tr("Paths")); - m_tab_widget->addTab(GetWrappedWidget(new GameCubePane, this, 125, 100), tr("GameCube")); - m_tab_widget->addTab(GetWrappedWidget(new WiiPane, this, 125, 100), tr("Wii")); - m_tab_widget->addTab(GetWrappedWidget(new AdvancedPane, this, 125, 200), tr("Advanced")); + // Calculated value for the padding in our list items. + const int list_item_padding = layout->contentsMargins().left() / 2; - // Dialog box buttons - QDialogButtonBox* close_box = new QDialogButtonBox(QDialogButtonBox::Close); + // Eliminate padding around layouts. + layout->setContentsMargins(QMargins{}); + layout->setSpacing(0); - connect(close_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + m_navigation_list = new QListWidget; - layout->addWidget(close_box); + // Ensure list doesn't grow horizontally and is not resized smaller than its contents. + m_navigation_list->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + m_navigation_list->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - setLayout(layout); + // FYI: "base" is the window color on Windows and "alternate-base" is very high contrast on macOS. + const auto [list_background, list_hover_background] = +#if defined(_WIN32) + std::pair("palette(alternate-base)", "palette(base)"); +#else + std::pair("palette(base)", "palette(alternate-base)"); +#endif + + m_navigation_list->setStyleSheet( + QString::fromUtf8( + // Remove border around entire widget and adjust background color. + "QListWidget { border: 0; background: %1; } " + "QListWidget::item { padding: %2; " +#if defined(__linux__) + "} " +#else + // For some reason this is needed to fix inconsistent item padding on Windows and macOS, + // but it unfortunately also breaks item background color changes. + "border: 0; } " + // Restore selected item color. + "QListWidget::item:selected { background: palette(highlight); " +#if defined(_WIN32) + // Prevent text color change on focus loss on Windows. + // This seems to breaks the nice white text on macOS. + "color: palette(highlighted-text); " +#endif + "} " + // Restore hovered item color, though not really the correct color. + "QListWidget::item:hover:!selected { background: %3; } " +#endif +#if defined(_WIN32) + // Remove ugly dotted outline on selected row. + "* { outline: none; } " +#endif + ) + .arg(QString::fromUtf8(list_background)) + .arg(list_item_padding) +#if !defined(__linux__) + .arg(QString::fromUtf8(list_hover_background)) +#endif + ); + + layout->addWidget(m_navigation_list); + + auto* const right_side = new QVBoxLayout; + layout->addLayout(right_side); + + m_stacked_panes = new QStackedWidget; + + right_side->addWidget(m_stacked_panes); + + // The QFrame gives us some padding around the button. + auto* const button_frame = new QFrame; + auto* const button_layout = new QGridLayout{button_frame}; + auto* const button_box = new QDialogButtonBox(QDialogButtonBox::Close); + right_side->addWidget(button_frame); + button_layout->addWidget(button_box); + + connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + + connect(m_navigation_list, &QListWidget::currentRowChanged, m_stacked_panes, + &QStackedWidget::setCurrentIndex); +} + +void StackedSettingsWindow::OnDoneCreatingPanes() +{ + // Make sure the first item is actually selected by default. + ActivatePane(0); + // Take on the preferred size. + adjustSize(); +} + +void StackedSettingsWindow::AddPane(QWidget* widget, const QString& name) +{ + m_stacked_panes->addWidget(widget); + m_navigation_list->addItem(name); +} + +void StackedSettingsWindow::AddWrappedPane(QWidget* widget, const QString& name) +{ + AddPane(GetWrappedWidget(widget), name); +} + +void StackedSettingsWindow::ActivatePane(int index) +{ + m_navigation_list->setCurrentRow(index); +} + +SettingsWindow::SettingsWindow(QWidget* parent) : StackedSettingsWindow{parent} +{ + setWindowTitle(tr("Settings")); + + AddWrappedPane(new GeneralPane, tr("General")); + AddWrappedPane(new InterfacePane, tr("Interface")); + AddWrappedPane(new AudioPane, tr("Audio")); + AddWrappedPane(new PathPane, tr("Paths")); + AddWrappedPane(new GameCubePane, tr("GameCube")); + AddWrappedPane(new WiiPane, tr("Wii")); + AddWrappedPane(new AdvancedPane, tr("Advanced")); + + OnDoneCreatingPanes(); } void SettingsWindow::SelectAudioPane() { - m_tab_widget->setCurrentIndex(static_cast(TabIndex::Audio)); + ActivatePane(static_cast(TabIndex::Audio)); } void SettingsWindow::SelectGeneralPane() { - m_tab_widget->setCurrentIndex(static_cast(TabIndex::General)); + ActivatePane(static_cast(TabIndex::General)); } diff --git a/Source/Core/DolphinQt/Config/SettingsWindow.h b/Source/Core/DolphinQt/Config/SettingsWindow.h index 02285ed244..b1217bb41b 100644 --- a/Source/Core/DolphinQt/Config/SettingsWindow.h +++ b/Source/Core/DolphinQt/Config/SettingsWindow.h @@ -5,7 +5,31 @@ #include -class QTabWidget; +class QStackedWidget; +class QListWidget; + +// A settings window with a QListWidget to switch between panes of a QStackedWidget. +class StackedSettingsWindow : public QDialog +{ + Q_OBJECT +public: + explicit StackedSettingsWindow(QWidget* parent = nullptr); + + void ActivatePane(int index); + +protected: + void AddPane(QWidget*, const QString& name); + + // Adds a scrollable Pane. + void AddWrappedPane(QWidget*, const QString& name); + + // For derived classes to call after they create their settings panes. + void OnDoneCreatingPanes(); + +private: + QStackedWidget* m_stacked_panes; + QListWidget* m_navigation_list; +}; enum class TabIndex { @@ -13,14 +37,12 @@ enum class TabIndex Audio = 2 }; -class SettingsWindow final : public QDialog +class SettingsWindow final : public StackedSettingsWindow { Q_OBJECT public: explicit SettingsWindow(QWidget* parent = nullptr); + void SelectGeneralPane(); void SelectAudioPane(); - -private: - QTabWidget* m_tab_widget; }; diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index 70baf158ac..fe8866ddd9 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -76,7 +76,7 @@ void AudioPane::CreateWidgets() m_volume_slider->setOrientation(Qt::Vertical); m_volume_indicator->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); - m_volume_indicator->setFixedWidth(QFontMetrics(font()).boundingRect(tr("%1 %").arg(100)).width()); + m_volume_indicator->setFixedWidth(QFontMetrics(font()).boundingRect(volume_box->title()).width()); volume_layout->addWidget(m_volume_slider, 0, Qt::AlignHCenter); volume_layout->addWidget(m_volume_indicator, 0, Qt::AlignHCenter);