diff --git a/src/launcher/forms/configuration_edit_dialog.ui b/src/launcher/forms/configuration_edit_dialog.ui index a6b381967..18d220947 100644 --- a/src/launcher/forms/configuration_edit_dialog.ui +++ b/src/launcher/forms/configuration_edit_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 560 - 450 + 760 + 620 @@ -17,363 +17,278 @@ + + 8 + + + 8 + - - - QFrame::StyledPanel + + + 8 - - - QFormLayout::AllNonFixedFieldsGrow - - - - - QFrame::StyledPanel - - - - - - Enable Vulkan validation layers - - - Vulkan validation - - - true - - - - - - - Validate SPIR-V binary - - - Shader validation - - - true - - - - - - - Dump command buffers - - - Command buffer dump - - - - - - - Enable RenderDoc capture - - - RenderDoc capture - - - - - - - Run in borderless desktop fullscreen - - - Fullscreen - - - - - - - Helps prevent crashes in some games on Windows - - - Windows SysV red zone crash protection (Experimental) - - - - - - - - - - User name: - - - - - - - Local user name exposed to games - - - true - - - - - - - User ID: - - - - - - - Local user ID exposed to games - - - 2147483647 - - - - - - - Screen resolution: - - - - - - - Window resolution - - - - - - - Present mode: - - - - - - - Vulkan swapchain presentation mode - - - - - - - Vblank frequency: - - - - - - - Virtual display refresh rate used for frame pacing - - - 30 - - - 360 - - - 60 - - - - - - - Console language: - - - - - - - Language - - - - - - - Shader optimization type: - - - - - - - Optimize shaders for code size or performance - - - - - - - Shader log direction: - - - - - - - Dump shaders to file or console window. If enabled may decrease emulator performance - - - - - - - Shader log folder: - - - - - - - Specify directory to dump shaders - - - true - - - - - - - Command buffer dump folder: - - - - - - - Specify directory to dump command buffers - - - true - - - - - - - Printf direction: - - - - - - - Print logs to file or console window. If enabled may decrease emulator performance - - - - - - - Printf output file: - - - - - - - Specify file to dump logs - - - true - - - - - - - Profiler direction: - - - - - - - Enable or disable profiler. If enabled may decrease emulator performance - - - - - - - - - - - - - 80 - 25 - - - - Save - - - true + + 8 + + + + + User profile + + + QFormLayout::AllNonFixedFieldsGrow + + + + User name: + + + + + Local user name exposed to games + true + + + + + User ID: + + + + + Local user ID exposed to games + 2147483647 + + + + + Console language: + + + + + Language + + + + + + + Graphics && display + + + + QFormLayout::AllNonFixedFieldsGrow + + + + Screen resolution: + + + + + Window resolution + + + + + Present mode: + + + + + Vulkan swapchain presentation mode + + + + + Vblank frequency: + + + + + Virtual display refresh rate used for frame pacing + 30 + 360 + 60 + + + + + Shader optimization: + + + + + Optimize shaders for code size or performance + + + + + Run in borderless desktop fullscreen + Fullscreen + + + + + + + + + Debugging && logs + + + 8 + 6 + + + Enable Vulkan validation layers + Vulkan validation + true + + + + + Validate SPIR-V binary + Shader validation + true + + + + + Enable RenderDoc capture + RenderDoc capture + + + + + Dump command buffers + Command buffer dump + + + + + Shader logging: + + + + + Dump shaders to file or console window. If enabled may decrease emulator performance + + + + + Shader log folder: + + + + + Specify directory to dump shaders + true + + + + + Printf output: + + + + + Print logs to file or console window. If enabled may decrease emulator performance + + + + + Printf output file: + + + + + Specify file to dump logs + true + + + + + Profiler: + + + + + Enable or disable profiler. If enabled may decrease emulator performance + + + + + Command buffer folder: + + + + + Specify directory to dump command buffers + true + + + + + + + + + Compatibility + + + + + Helps prevent crashes in some games on Windows + Windows SysV red zone crash protection (Experimental) + + + + + Qt::Horizontal + + 4020 + + + + + + + + + + + + + 8025 + Reset + Restore default settings + + + + + Qt::Horizontal + 4020 + + - - - 80 - 25 - - - - Cancel - + 8025 + Cancel - - - Qt::Horizontal - + + 8025 + Save + true - - - - - 80 - 25 - - - - Clear - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -392,16 +307,6 @@ clicked() ConfigurationEditDialog reject() - - - 496 - 65 - - - 280 - 180 - - diff --git a/src/launcher/icons/edit-configuration.svg b/src/launcher/icons/edit-configuration.svg index 6223a1bda..5f538bc71 100644 --- a/src/launcher/icons/edit-configuration.svg +++ b/src/launcher/icons/edit-configuration.svg @@ -1,5 +1,5 @@ - + diff --git a/src/launcher/icons/global-settings.svg b/src/launcher/icons/global-settings.svg index 5f704d44d..ba3d36cf1 100644 --- a/src/launcher/icons/global-settings.svg +++ b/src/launcher/icons/global-settings.svg @@ -1,5 +1,5 @@ - + diff --git a/src/launcher/icons/input-mapping.svg b/src/launcher/icons/input-mapping.svg index 659fbdf0b..c3e16abc7 100644 --- a/src/launcher/icons/input-mapping.svg +++ b/src/launcher/icons/input-mapping.svg @@ -1,9 +1,9 @@ - + - - + + diff --git a/src/launcher/icons/remove-configuration.svg b/src/launcher/icons/remove-configuration.svg index 4a53ef64d..ba64f79ed 100644 --- a/src/launcher/icons/remove-configuration.svg +++ b/src/launcher/icons/remove-configuration.svg @@ -1,5 +1,5 @@ - + diff --git a/src/launcher/include/configurationEditDialog.h b/src/launcher/include/configurationEditDialog.h index 1ced2274b..03ff4e795 100644 --- a/src/launcher/include/configurationEditDialog.h +++ b/src/launcher/include/configurationEditDialog.h @@ -10,6 +10,7 @@ class QByteArray; class QGroupBox; class QListWidget; class QMoveEvent; +class QResizeEvent; class QToolButton; class QSettings; class QWidget; @@ -48,6 +49,7 @@ protected: void AddGameDirectoryItem(const QString& dir); void moveEvent(QMoveEvent* event) override; + void resizeEvent(QResizeEvent* event) override; static QByteArray g_last_geometry; diff --git a/src/launcher/include/configurationListWidget.h b/src/launcher/include/configurationListWidget.h index ca0061170..f6dccda0e 100644 --- a/src/launcher/include/configurationListWidget.h +++ b/src/launcher/include/configurationListWidget.h @@ -11,6 +11,7 @@ class ConfigurationItem; class CompatibilityDatabase; +class QEvent; class QTreeWidgetItem; class QPoint; class MainDialog; @@ -52,6 +53,9 @@ signals: void Run(); void Select(); +protected: + void changeEvent(QEvent* event) override; + public slots: void WriteSettings(); void ReadSettings(); @@ -74,6 +78,7 @@ private: void ClearCustomSettings(ConfigurationItem* item); void SelectItem(QTreeWidgetItem* witem); void ApplyCompatibility(); + void UpdateToolbarIcons(); [[nodiscard]] bool HasValidGameDirectory() const; ConfigurationItem* m_selected_item = nullptr; diff --git a/src/launcher/include/gameListTreeWidget.h b/src/launcher/include/gameListTreeWidget.h index 1ef44377a..eed8f8294 100644 --- a/src/launcher/include/gameListTreeWidget.h +++ b/src/launcher/include/gameListTreeWidget.h @@ -1,7 +1,6 @@ #ifndef GAME_LIST_TREE_WIDGET_H #define GAME_LIST_TREE_WIDGET_H -#include #include #include #include @@ -44,7 +43,9 @@ protected: painter.fillRect(event->rect(), palette().brush(QPalette::Base)); } else { painter.drawPixmap(m_scaled_pos, m_scaled); - painter.fillRect(event->rect(), QColor(0, 0, 0, 115)); + auto overlay = palette().color(QPalette::Base); + overlay.setAlpha(185); + painter.fillRect(event->rect(), overlay); } } diff --git a/src/launcher/include/launcherTheme.h b/src/launcher/include/launcherTheme.h new file mode 100644 index 000000000..4f5bee4d1 --- /dev/null +++ b/src/launcher/include/launcherTheme.h @@ -0,0 +1,12 @@ +#ifndef LAUNCHER_THEME_H +#define LAUNCHER_THEME_H + +class QApplication; + +namespace LauncherTheme { + +void Initialize(QApplication& application); + +} // namespace LauncherTheme + +#endif // LAUNCHER_THEME_H diff --git a/src/launcher/resources.qrc b/src/launcher/resources.qrc index b57e0d7db..7ddfa3f0b 100644 --- a/src/launcher/resources.qrc +++ b/src/launcher/resources.qrc @@ -5,4 +5,7 @@ icons/input-mapping.svg icons/remove-configuration.svg + + styles/launcher.qss + diff --git a/src/launcher/src/configurationEditDialog.cpp b/src/launcher/src/configurationEditDialog.cpp index fc9d6d63f..43e2dcc44 100644 --- a/src/launcher/src/configurationEditDialog.cpp +++ b/src/launcher/src/configurationEditDialog.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -115,7 +116,10 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p m_ui->lineEdit_printf_file->setEnabled(log == Configuration::LogDirection::File); }); - layout()->setSizeConstraint(QLayout::SetFixedSize); + // Keep the controls at a usable minimum while allowing the settings window + // and its expanding fields to use any additional space the user gives them. + layout()->setSizeConstraint(QLayout::SetMinimumSize); + setSizeGripEnabled(true); restoreGeometry(g_last_geometry); @@ -248,7 +252,8 @@ void ConfigurationEditDialog::SetGameDirectories(const QStringList& dirs) { m_game_dirs_group->setVisible(true); update_game_directory_buttons(); - adjustSize(); + layout()->activate(); + resize(size().expandedTo(minimumSizeHint())); } QStringList ConfigurationEditDialog::GetGameDirectories() const { @@ -288,6 +293,11 @@ void ConfigurationEditDialog::moveEvent(QMoveEvent* event) { g_last_geometry = saveGeometry(); } +void ConfigurationEditDialog::resizeEvent(QResizeEvent* event) { + QDialog::resizeEvent(event); + g_last_geometry = saveGeometry(); +} + static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) { info.user_name = ui.lineEdit_user_name->text().trimmed(); info.user_id = ui.spinBox_user_id->value(); diff --git a/src/launcher/src/configurationItem.cpp b/src/launcher/src/configurationItem.cpp index d20459a5d..9836b9a9f 100644 --- a/src/launcher/src/configurationItem.cpp +++ b/src/launcher/src/configurationItem.cpp @@ -127,10 +127,12 @@ ConfigurationItem::ConfigurationItem(std::unique_ptr info, QTreeW layout->setSpacing(6); m_status_indicator = new QLabel(m_status_widget); + m_status_indicator->setObjectName(QStringLiteral("game_status_indicator")); m_status_indicator->setFixedSize(QSize(12, 12)); layout->addWidget(m_status_indicator); m_status_combo = new NoWheelComboBox(m_status_widget); + m_status_combo->setObjectName(QStringLiteral("game_status_editor")); MakeTransparent(m_status_combo); AddStatus(m_status_combo, Configuration::GameStatus::Unknown); AddStatus(m_status_combo, Configuration::GameStatus::MainMenu); @@ -139,26 +141,16 @@ ConfigurationItem::ConfigurationItem(std::unique_ptr info, QTreeW AddStatus(m_status_combo, Configuration::GameStatus::DoesntBoot); m_status_combo->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_status_combo->setFixedWidth(125); - m_status_combo->setStyleSheet(QStringLiteral( - "QComboBox { background: transparent; border: 0; color: #eef4ff; padding-left: 2px; }" - "QComboBox:focus { background: rgba(255,255,255,35); border-radius: 3px; }" - "QComboBox::drop-down { border: 0; }" - "QComboBox QAbstractItemView { background: #181c24; color: #eef4ff; " - "selection-background-color: #267bd8; }")); layout->addWidget(m_status_combo); layout->addStretch(1); parent->setItemWidget(this, StatusColumn, m_status_widget); m_comment_edit = new QLineEdit(parent); + m_comment_edit->setObjectName(QStringLiteral("game_comment_editor")); MakeTransparent(m_comment_edit); m_comment_edit->setClearButtonEnabled(true); m_comment_edit->setFrame(false); - m_comment_edit->setStyleSheet(QStringLiteral( - "QLineEdit { background: transparent; border: 0; color: #eef4ff; padding-left: 2px; " - "selection-background-color: #267bd8; }" - "QLineEdit:focus { background: rgba(255,255,255,35); " - "border: 1px solid rgba(255,255,255,90); border-radius: 3px; }")); parent->setItemWidget(this, CommentsColumn, m_comment_edit); Update(); @@ -260,8 +252,6 @@ void ConfigurationItem::UpdateIcon() { void ConfigurationItem::UpdateStatusIndicator() { m_status_indicator->setStyleSheet( - QStringLiteral( - "background-color: %1; border: 1px solid rgba(255, 255, 255, 90); border-radius: 6px;") - .arg(GetStatusColor(m_info->game_status))); + QStringLiteral("background-color: %1;").arg(GetStatusColor(m_info->game_status))); m_status_indicator->setToolTip(GetStatusText(m_info->game_status)); } diff --git a/src/launcher/src/configurationListWidget.cpp b/src/launcher/src/configurationListWidget.cpp index 55a42f033..182042125 100644 --- a/src/launcher/src/configurationListWidget.cpp +++ b/src/launcher/src/configurationListWidget.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -131,7 +133,7 @@ static QString GetPic0Path(const Configuration& info) { return QFileInfo::exists(path) ? QFileInfo(path).absoluteFilePath() : QString(); } -static void ApplyGameListStyle(Ui::ConfigurationListWidget* ui) { +static void ConfigureGameList(Ui::ConfigurationListWidget* ui) { ui->cfgs_list->setAlternatingRowColors(false); ui->cfgs_list->setAllColumnsShowFocus(true); ui->cfgs_list->setIndentation(0); @@ -142,35 +144,6 @@ static void ApplyGameListStyle(Ui::ConfigurationListWidget* ui) { ui->cfgs_list->header()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); ui->cfgs_list->header()->setHighlightSections(false); ui->cfgs_list->header()->setStretchLastSection(true); - - ui->cfgs_list->setStyleSheet(QStringLiteral( - "QTreeWidget { background: transparent; border: 1px solid rgba(255,255,255,42); " - "color: #eef4ff; outline: 0; }" - "QTreeWidget::item { background: rgba(8,10,16,92); " - "border-bottom: 1px solid rgba(255,255,255,24); padding: 4px; }" - "QTreeWidget::item:selected { background: rgba(32,118,210,150); color: #ffffff; }" - "QHeaderView::section { background: rgba(22,25,31,235); color: #dce6f6; border: 0; " - "border-right: 1px solid rgba(255,255,255,35); border-bottom: 1px solid " - "rgba(255,255,255,45); " - "padding: 5px 6px; }" - "QScrollBar:vertical { background: rgba(12,14,18,150); width: 14px; margin: 0; }" - "QScrollBar::handle:vertical { background: rgba(220,230,245,120); min-height: 36px; }" - "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; }")); - - ui->search_line_edit->setStyleSheet(QStringLiteral( - "QLineEdit { background: rgba(12,14,18,210); border: 1px solid rgba(255,255,255,42); " - "border-radius: 4px; color: #eef4ff; padding: 5px 8px; selection-background-color: " - "#267bd8; }" - "QLineEdit:focus { border-color: rgba(80,160,255,180); }")); - ui->global_settings_button->setStyleSheet(QStringLiteral( - "QToolButton { background: rgba(255,255,255,18); border: 1px solid transparent; " - "border-radius: 5px; padding: 3px; }" - "QToolButton:hover { background: rgba(255,255,255,45); border-color: rgba(255,255,255,70); " - "}" - "QToolButton:disabled { background: transparent; }")); - ui->edit_button->setStyleSheet(ui->global_settings_button->styleSheet()); - ui->delete_button->setStyleSheet(ui->global_settings_button->styleSheet()); - ui->input_mapping_button->setStyleSheet(ui->global_settings_button->styleSheet()); } static void AddSaveDataDir(QStringList* dirs, QSet* seen, const QString& root, @@ -226,14 +199,11 @@ ConfigurationListWidget::ConfigurationListWidget(QWidget* parent) m_compatibility = new CompatibilityDatabase( QCoreApplication::arguments().contains(QStringLiteral("--local")), this); m_ui->setupUi(this); - ApplyGameListStyle(m_ui); + ConfigureGameList(m_ui); - m_ui->global_settings_button->setIcon(QIcon(QStringLiteral(":/icons/global-settings.svg"))); + UpdateToolbarIcons(); m_ui->global_settings_button->setToolTip(tr("Edit global settings and game folders")); - m_ui->input_mapping_button->setIcon(QIcon(QStringLiteral(":/icons/input-mapping.svg"))); m_ui->input_mapping_button->setToolTip(tr("Edit global input mapping")); - m_ui->edit_button->setIcon(QIcon(QStringLiteral(":/icons/edit-configuration.svg"))); - m_ui->delete_button->setIcon(QIcon(QStringLiteral(":/icons/remove-configuration.svg"))); m_ui->delete_button->setEnabled(false); m_ui->edit_button->setEnabled(false); @@ -287,6 +257,30 @@ ConfigurationListWidget::~ConfigurationListWidget() { delete m_ui; } +void ConfigurationListWidget::changeEvent(QEvent* event) { + QWidget::changeEvent(event); + if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::PaletteChange) { + UpdateToolbarIcons(); + } +} + +void ConfigurationListWidget::UpdateToolbarIcons() { + const auto color = palette().color(QPalette::Window).lightness() < 128 ? QColor(Qt::white) + : QColor(Qt::black); + const auto set_icon = [&color](QToolButton* button, const QString& resource) { + auto pixmap = QIcon(resource).pixmap(button->iconSize(), button->devicePixelRatioF()); + QPainter painter(&pixmap); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(pixmap.rect(), color); + button->setIcon(QIcon(pixmap)); + }; + + set_icon(m_ui->global_settings_button, QStringLiteral(":/icons/global-settings.svg")); + set_icon(m_ui->input_mapping_button, QStringLiteral(":/icons/input-mapping.svg")); + set_icon(m_ui->edit_button, QStringLiteral(":/icons/edit-configuration.svg")); + set_icon(m_ui->delete_button, QStringLiteral(":/icons/remove-configuration.svg")); +} + void ConfigurationListWidget::WriteSettings() { QFile file = QFile(QDir(".").absoluteFilePath(CONF_FILE_NAME)); std::unique_ptr s; diff --git a/src/launcher/src/launcherTheme.cpp b/src/launcher/src/launcherTheme.cpp new file mode 100644 index 000000000..2ed0e1660 --- /dev/null +++ b/src/launcher/src/launcherTheme.cpp @@ -0,0 +1,45 @@ +#include "launcherTheme.h" + +#include +#include +#include +#include +#include + +namespace { + +class PaletteChangeFilter final: public QObject { +public: + explicit PaletteChangeFilter(QApplication& application) + : QObject(&application), m_application(application) {} + +protected: + bool eventFilter(QObject* watched, QEvent* event) override { + if (event->type() == QEvent::ApplicationPaletteChange && !m_refresh_pending) { + m_refresh_pending = true; + QTimer::singleShot(0, &m_application, [this] { + m_application.setStyleSheet(m_application.styleSheet()); + m_refresh_pending = false; + }); + } + + return QObject::eventFilter(watched, event); + } + +private: + QApplication& m_application; + bool m_refresh_pending = false; +}; + +} // namespace + +namespace LauncherTheme { + +void Initialize(QApplication& application) { + QFile style_sheet_file(QStringLiteral(":/styles/launcher.qss")); + if (style_sheet_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + application.setStyleSheet(QString::fromUtf8(style_sheet_file.readAll())); + application.installEventFilter(new PaletteChangeFilter(application)); + } +} +} // namespace LauncherTheme diff --git a/src/launcher/src/main.cpp b/src/launcher/src/main.cpp index 98128a0a5..327a10fb0 100644 --- a/src/launcher/src/main.cpp +++ b/src/launcher/src/main.cpp @@ -1,18 +1,15 @@ #include "mainDialog.h" +#include "launcherTheme.h" #include #include #include -#include - -class QStyle; int main(int argc, char* argv[]) { QApplication a(argc, argv); - MainDialog w; + LauncherTheme::Initialize(a); - QStyle* s = QStyleFactory::create("fusion"); - QApplication::setStyle(s); + MainDialog w; QObject::connect(&a, &QApplication::aboutToQuit, &w, &MainDialog::Quit); diff --git a/src/launcher/styles/launcher.qss b/src/launcher/styles/launcher.qss new file mode 100644 index 000000000..007bc58ea --- /dev/null +++ b/src/launcher/styles/launcher.qss @@ -0,0 +1,108 @@ +GameListTreeWidget#cfgs_list { + background: transparent; + border: 1px solid palette(mid); + color: palette(text); + outline: 0; +} + +GameListTreeWidget#cfgs_list::item { + background: transparent; + border-bottom: 1px solid palette(mid); + padding: 4px; +} + +GameListTreeWidget#cfgs_list::item:selected { + background: palette(highlight); + color: palette(highlighted-text); +} + +GameListTreeWidget#cfgs_list QHeaderView::section { + background: palette(button); + color: palette(button-text); + border: 0; + border-right: 1px solid palette(mid); + border-bottom: 1px solid palette(mid); + padding: 5px 6px; +} + +QLineEdit#search_line_edit { + background: palette(base); + border: 1px solid palette(mid); + border-radius: 4px; + color: palette(text); + padding: 5px 8px; + selection-background-color: palette(highlight); + selection-color: palette(highlighted-text); +} + +QLineEdit#search_line_edit:focus { + border-color: palette(highlight); +} + +QToolButton#global_settings_button, +QToolButton#input_mapping_button, +QToolButton#edit_button, +QToolButton#delete_button { + background: transparent; + border: 1px solid transparent; + border-radius: 5px; + padding: 3px; +} + +QToolButton#global_settings_button:hover, +QToolButton#input_mapping_button:hover, +QToolButton#edit_button:hover, +QToolButton#delete_button:hover { + background: palette(button); + border-color: palette(mid); +} + +QToolButton#global_settings_button:pressed, +QToolButton#input_mapping_button:pressed, +QToolButton#edit_button:pressed, +QToolButton#delete_button:pressed { + background: palette(midlight); +} + +QComboBox#game_status_editor { + background: transparent; + border: 0; + color: palette(text); + padding-left: 2px; +} + +QComboBox#game_status_editor:focus { + background: palette(button); + border-radius: 3px; +} + +QComboBox#game_status_editor::drop-down { + border: 0; +} + +QComboBox#game_status_editor QAbstractItemView { + background: palette(base); + color: palette(text); + selection-background-color: palette(highlight); + selection-color: palette(highlighted-text); +} + +QLineEdit#game_comment_editor { + background: transparent; + border: 0; + color: palette(text); + padding-left: 2px; + selection-background-color: palette(highlight); + selection-color: palette(highlighted-text); +} + +QLineEdit#game_comment_editor:focus { + background: palette(base); + border: 1px solid palette(mid); + border-radius: 3px; +} + +QLabel#game_status_indicator { + border: 1px solid palette(base); + border-radius: 6px; +}