From 6e59a5c5ef1b2a3aa5be3fe06f0d193c7f5f37c8 Mon Sep 17 00:00:00 2001 From: Satori Date: Sat, 26 Sep 2020 23:28:16 +0100 Subject: [PATCH] [Qt] Initial settings subsystem rework --- .../themes/Xenia/stylesheets/SettingsTab.css | 64 +++++----- src/xenia/app/xenia_main.cc | 8 +- .../ui/qt/settings/panes/general_pane.cc | 117 ++++++++---------- .../ui/qt/settings/panes/settings_pane.h | 35 +----- .../qt/settings/widgets/settings_checkbox.cc | 2 +- .../qt/settings/widgets/settings_checkbox.h | 15 +-- .../qt/settings/widgets/settings_combobox.h | 13 +- .../qt/settings/widgets/settings_groupbox.cc | 57 +++++++++ .../qt/settings/widgets/settings_groupbox.h | 52 ++++++++ .../settings/widgets/settings_radio_button.h | 17 ++- .../qt/settings/widgets/settings_text_edit.h | 21 ++-- .../ui/qt/settings/widgets/settings_widget.h | 44 +++++-- 12 files changed, 281 insertions(+), 164 deletions(-) create mode 100644 src/xenia/ui/qt/settings/widgets/settings_groupbox.cc create mode 100644 src/xenia/ui/qt/settings/widgets/settings_groupbox.h diff --git a/src/xenia/app/resources/themes/Xenia/stylesheets/SettingsTab.css b/src/xenia/app/resources/themes/Xenia/stylesheets/SettingsTab.css index b461d0650..3f2c2723b 100644 --- a/src/xenia/app/resources/themes/Xenia/stylesheets/SettingsTab.css +++ b/src/xenia/app/resources/themes/Xenia/stylesheets/SettingsTab.css @@ -1,31 +1,35 @@ QWidget#SettingsTab QLabel { - color: $primary; - } - - QWidget#SettingsTab > QScrollArea { - background: transparent; - border: none; - } - QWidget#SettingsTab > QScrollArea > QWidget > QWidget { - background: transparent; - } - - QWidget#sidebarContainer { - background: $tertiary; - min-width: 300px; - max-width: 300px; - } - - QWidget#sidebarTitleLabel { - color: $primary; - font-size: 32px; - } - - QWidget#sidebarTitle #XSeperator { - background: $dark1; - } - - QWidget#navigationContainer { - background: $dark2; - } - \ No newline at end of file + color: $primary; +} + +QWidget#SettingsTab>QScrollArea { + background: transparent; + border: none; +} + +QWidget#SettingsTab>QScrollArea>QWidget>QWidget { + background: transparent; +} + +QWidget#sidebarContainer { + background: $tertiary; + min-width: 300px; + max-width: 300px; +} + +QWidget#sidebarTitleLabel { + color: $primary; + font-size: 32px; +} + +QWidget#sidebarTitle #XSeperator { + background: $dark1; +} + +QWidget#navigationContainer { + background: $dark2; +} + +QLabel#subLabel[type="warning"] { + color: $warning; +} \ No newline at end of file diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index 8fa6db17c..8bb470ed8 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include "discord/discord_presence.h" @@ -47,6 +48,7 @@ DEFINE_path( "to use the path preferred for the OS, such as the documents folder, or " "the emulator executable directory if portable.txt is present in it.", "Storage"); + DEFINE_path( content_root, "", "Root path for guest content storage (saves, etc.), or empty to use the " @@ -126,8 +128,10 @@ int xenia_main(const std::vector& args) { main_wnd->Initialize(); main_wnd->SetIcon(QIcon(":/resources/graphics/icon.ico")); main_wnd->Resize(1280, 720); - - loop.on_quit.AddListener([](ui::UIEvent*) { + main_wnd->move(QApplication::primaryScreen()->geometry().center() - + main_wnd->rect().center()); + loop.on_quit.AddListener([](ui::UIEvent*) + { if (cvars::discord) { discord::DiscordPresence::Shutdown(); } diff --git a/src/xenia/ui/qt/settings/panes/general_pane.cc b/src/xenia/ui/qt/settings/panes/general_pane.cc index 0411119f6..fbb595505 100644 --- a/src/xenia/ui/qt/settings/panes/general_pane.cc +++ b/src/xenia/ui/qt/settings/panes/general_pane.cc @@ -4,6 +4,7 @@ #include #include "xenia/ui/qt/settings/widgets/settings_checkbox.h" +#include "xenia/ui/qt/settings/widgets/settings_groupbox.h" #include "xenia/ui/qt/widgets/combobox.h" #include "xenia/ui/qt/widgets/groupbox.h" #include "xenia/ui/qt/widgets/scroll_area.h" @@ -12,86 +13,70 @@ DECLARE_bool(show_debug_tab); DECLARE_bool(discord); DECLARE_bool(use_game_icon); - namespace xe { - namespace ui { - namespace qt { +namespace xe { +namespace ui { +namespace qt { - const QStringList game_languages = { - "English", "Japanese", "German", "French", "Spanish", - "Italian", "Korean", "Chinese", "Portuguese", "Polish", - "Russian", "Swedish", "Turkish", "Norwegian", "Dutch"}; +const QStringList game_languages = { + "English", "Japanese", "German", "French", "Spanish", + "Italian", "Korean", "Chinese", "Portuguese", "Polish", + "Russian", "Swedish", "Turkish", "Norwegian", "Dutch"}; - void GeneralPane::Build() { - QWidget* base_widget = new QWidget(); - base_widget->setSizePolicy(QSizePolicy::MinimumExpanding, - QSizePolicy::MinimumExpanding); +void GeneralPane::Build() { + QWidget* base_widget = new QWidget(); + base_widget->setSizePolicy(QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding); - // Setup scroll area for settings pane - XScrollArea* scroll_area = new XScrollArea(this); - scroll_area->setWidget(base_widget); - scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scroll_area->setWidgetResizable(true); + // Setup scroll area for settings pane + XScrollArea* scroll_area = new XScrollArea(this); + scroll_area->setWidget(base_widget); + scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll_area->setWidgetResizable(true); - QVBoxLayout* layout = new QVBoxLayout(); - base_widget->setLayout(layout); + QVBoxLayout* layout = new QVBoxLayout(); + base_widget->setLayout(layout); - layout->setSpacing(16); - layout->setContentsMargins(32, 16, 32, 16); + layout->setSpacing(16); + layout->setContentsMargins(32, 16, 32, 16); - // Add settings groupboxes to layout - layout->addWidget(CreateGeneralGroupBox()); - layout->addWidget(CreateUpdateGroupBox()); - layout->addWidget(CreateWindowGroupBox()); - layout->addWidget(CreateLogGroupBox()); - layout->addStretch(); + // Add settings groupboxes to layout + layout->addWidget(CreateGeneralGroupBox()); + layout->addWidget(CreateUpdateGroupBox()); + layout->addWidget(CreateWindowGroupBox()); + layout->addWidget(CreateLogGroupBox()); + layout->addStretch(); - set_widget(scroll_area); - } + set_widget(scroll_area); +} - XGroupBox* GeneralPane::CreateGeneralGroupBox() { - XGroupBox* groupbox = new XGroupBox("General Settings"); +XGroupBox* GeneralPane::CreateGeneralGroupBox() { + auto groupbox = new SettingsGroupBox("General Settings"); - QVBoxLayout* groupbox_layout = new QVBoxLayout(); - groupbox_layout->setContentsMargins(16, 16, 16, 16); - groupbox->setLayout(groupbox_layout); + auto& config = Config::Instance(); + auto discord_cvar = config.FindConfigVar(cvars::discord); + auto discord_checkbox = groupbox->CreateCheckBox("Discord Rich Presence", discord_cvar); - auto discord_presence_checkbox = new SettingsCheckBox(cvars::discord); - discord_presence_checkbox->setText("Discord Rich Presence"); - - groupbox_layout->addWidget(discord_presence_checkbox); + discord_checkbox->set_update_config_fn( + [discord_checkbox](bool value, cvar::ConfigVar& cvar) { + cvar.set_config_value(value); + discord_checkbox->UpdateLabel( + tr("Please restart xenia for this change to take effect.")); + }); - XCheckBox* game_icon_checkbox = new XCheckBox(); - game_icon_checkbox->setText("Show Game Icon in Taskbar"); - groupbox_layout->addWidget(game_icon_checkbox); + return groupbox; +} - QHBoxLayout* game_language_layout = new QHBoxLayout(); - game_language_layout->setContentsMargins(0, 0, 0, 0); - game_language_layout->setSpacing(16); +XGroupBox* GeneralPane::CreateUpdateGroupBox() { + return new XGroupBox("Update Settings"); +} - QLabel* game_language_label = new QLabel("Game Language"); - XComboBox* game_language_combobox = new XComboBox(); - game_language_combobox->addItems(game_languages); +XGroupBox* GeneralPane::CreateWindowGroupBox() { + return new XGroupBox("Window Settings"); +} - game_language_layout->addWidget(game_language_label); - game_language_layout->addWidget(game_language_combobox); - game_language_layout->addStretch(); - - groupbox_layout->addLayout(game_language_layout); - - return groupbox; - } - - XGroupBox* GeneralPane::CreateUpdateGroupBox() { - return new XGroupBox("Update Settings"); - } - - XGroupBox* GeneralPane::CreateWindowGroupBox() { - return new XGroupBox("Window Settings"); - } - - XGroupBox* GeneralPane::CreateLogGroupBox() { - return new XGroupBox("Log Settings"); - } +XGroupBox* GeneralPane::CreateLogGroupBox() { + return new XGroupBox("Log Settings"); +} } // namespace qt } // namespace ui diff --git a/src/xenia/ui/qt/settings/panes/settings_pane.h b/src/xenia/ui/qt/settings/panes/settings_pane.h index 0b2f66099..d1731bb68 100644 --- a/src/xenia/ui/qt/settings/panes/settings_pane.h +++ b/src/xenia/ui/qt/settings/panes/settings_pane.h @@ -7,6 +7,11 @@ #include "xenia/config.h" #include "xenia/ui/qt/themeable_widget.h" #include "xenia/config.h" +#include "xenia/ui/qt/settings/widgets/settings_widget.h" +#include "xenia/ui/qt/settings/widgets/settings_radio_button.h" +#include "xenia/ui/qt/settings/widgets/settings_combobox.h" +#include "xenia/ui/qt/settings/widgets/settings_text_edit.h" +#include "xenia/ui/qt/settings/widgets/settings_checkbox.h" namespace xe { namespace ui { @@ -33,11 +38,6 @@ class SettingsPane : public Themeable { protected: void set_widget(QWidget* widget) { widget_ = widget; } - template - bool update_config_var(cvar::ConfigVar* var, const T& value) const; - - template - bool update_config_var(cvar::ConfigVar* var, QVariant value) const; private: QChar glyph_; @@ -45,31 +45,6 @@ class SettingsPane : public Themeable { QWidget* widget_ = nullptr; }; -template -bool SettingsPane::update_config_var(cvar::ConfigVar* var, - const T& value) const { - var->SetConfigValue(value); - - Config::Instance().SaveConfig(); - - return true; -} - -template -bool SettingsPane::update_config_var(cvar::ConfigVar* var, - QVariant value) const { - // QVariant can't be converted to type T - if (!value.canConvert()) { - return false; - } - - var->SetConfigValue(value.value()); - - Config::Instance().SaveConfig(); - - return true; -} - } // namespace qt } // namespace ui } // namespace xe diff --git a/src/xenia/ui/qt/settings/widgets/settings_checkbox.cc b/src/xenia/ui/qt/settings/widgets/settings_checkbox.cc index c8e532254..76c10efa3 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_checkbox.cc +++ b/src/xenia/ui/qt/settings/widgets/settings_checkbox.cc @@ -20,7 +20,7 @@ void SettingsCheckBox::Initialize() { setChecked(*cvar_->current_value()); - connect(this, &SettingsCheckBox::stateChanged, [&](int state) { + connect(this, &SettingsCheckBox::stateChanged, [this](int state) { if (state == Qt::Checked) { UpdateValue(true); } else if (state == Qt::Unchecked) { diff --git a/src/xenia/ui/qt/settings/widgets/settings_checkbox.h b/src/xenia/ui/qt/settings/widgets/settings_checkbox.h index 2c6070a2b..bb1c1572f 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_checkbox.h +++ b/src/xenia/ui/qt/settings/widgets/settings_checkbox.h @@ -18,19 +18,14 @@ namespace xe { namespace ui { namespace qt { -using SettingsType = bool; +using SettingsCvar = cvar::ConfigVar; -class SettingsCheckBox : public SettingsWidget { +class SettingsCheckBox : public SettingsWidget { public: - explicit SettingsCheckBox(const std::string& config_name, + explicit SettingsCheckBox(const QString& text, + SettingsCvar* config_var = nullptr, QLabel* label = nullptr, QWidget* parent = nullptr) - : SettingsWidget(config_name, parent) { - Initialize(); - } - - explicit SettingsCheckBox(const SettingsType& config_var, - QWidget* parent = nullptr) - : SettingsWidget(config_var, parent) { + : SettingsWidget(config_var, label, text, parent) { Initialize(); } diff --git a/src/xenia/ui/qt/settings/widgets/settings_combobox.h b/src/xenia/ui/qt/settings/widgets/settings_combobox.h index 5b52b3978..367a2cc59 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_combobox.h +++ b/src/xenia/ui/qt/settings/widgets/settings_combobox.h @@ -1,3 +1,12 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + #ifndef XENIA_UI_QT_SETTINGS_SETTINGS_COMBOBOX_H_ #define XENIA_UI_QT_SETTINGS_SETTINGS_COMBOBOX_H_ @@ -16,4 +25,6 @@ class SettingsComboBox : SettingsWidget { } // namespace qt } // namespace ui -} // namespace xe \ No newline at end of file +} // namespace xe + +#endif \ No newline at end of file diff --git a/src/xenia/ui/qt/settings/widgets/settings_groupbox.cc b/src/xenia/ui/qt/settings/widgets/settings_groupbox.cc new file mode 100644 index 000000000..304fd8692 --- /dev/null +++ b/src/xenia/ui/qt/settings/widgets/settings_groupbox.cc @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "settings_groupbox.h" + +namespace xe { +namespace ui { +namespace qt { + +double kSubLabelSize = 6.5; + +SettingsCheckBox* SettingsGroupBox::CreateCheckBox(const QString& text, + cvar::ConfigVar* target) { + auto checkbox_layout = new QVBoxLayout(); + checkbox_layout->setContentsMargins(0, 0, 0, 0); + checkbox_layout->setSpacing(0); + + auto widget_label = new QLabel(); + widget_label->setObjectName("subLabel"); + widget_label->setProperty("type", "warning"); + auto font = widget_label->font(); + font.setPointSizeF(kSubLabelSize); + widget_label->setFont(font); + + auto checkbox = new SettingsCheckBox(text, target, widget_label); + checkbox_layout->addWidget(checkbox); + + checkbox_layout->addWidget(widget_label); + + layout_->addLayout(checkbox_layout); + + return checkbox; +} + +SettingsComboBox* SettingsGroupBox::CreateComboBox(const QString& text, + cvar::ConfigVar* target) { + return nullptr; +} + +SettingsComboBox* SettingsGroupBox::CreateComboBox( + const QString& text, cvar::ConfigVar* target) { + return nullptr; +} + +SettingsRadioButton* SettingsGroupBox::CreateRadioButton(const QString& text, + cvar::ConfigVar* target) { + return nullptr; +} +} +} // namespace ui +} // namespace xe \ No newline at end of file diff --git a/src/xenia/ui/qt/settings/widgets/settings_groupbox.h b/src/xenia/ui/qt/settings/widgets/settings_groupbox.h new file mode 100644 index 000000000..69e034c45 --- /dev/null +++ b/src/xenia/ui/qt/settings/widgets/settings_groupbox.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_QT_SETTINGS_SETTINGS_GROUPBOX_H_ +#define XENIA_UI_QT_SETTINGS_SETTINGS_GROUPBOX_H_ + +#include "settings_checkbox.h" +#include "settings_combobox.h" +#include "settings_radio_button.h" +#include "xenia/ui/qt/widgets/groupbox.h" + +namespace xe { +namespace ui { +namespace qt { + +class SettingsGroupBox : public XGroupBox { + public: + SettingsGroupBox(const QString& title, QWidget* parent = nullptr) + : XGroupBox(title, parent), layout_(nullptr) { + layout_ = new QVBoxLayout(); + this->setLayout(layout_); + } + + SettingsCheckBox* CreateCheckBox(const QString& text, + cvar::ConfigVar* target = nullptr); + SettingsComboBox* CreateComboBox(const QString& text, + cvar::ConfigVar* target = nullptr); + SettingsComboBox* CreateComboBox( + const QString& text, cvar::ConfigVar* target = nullptr); + SettingsRadioButton* CreateRadioButton( + const QString& text, cvar::ConfigVar* target = nullptr); + + template + void AddSettingsWidget(SettingsWidget* widget) { + layout_->addWidget(widget); + } + + private: + QVBoxLayout* layout_; +}; + +} // namespace qt +} // namespace ui +} // namespace xe + +#endif \ No newline at end of file diff --git a/src/xenia/ui/qt/settings/widgets/settings_radio_button.h b/src/xenia/ui/qt/settings/widgets/settings_radio_button.h index 6c2aeab1e..cadec6db9 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_radio_button.h +++ b/src/xenia/ui/qt/settings/widgets/settings_radio_button.h @@ -1,15 +1,26 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + #ifndef XENIA_UI_QT_SETTINGS_SETTINGS_RADIOBOX_H_ #define XENIA_UI_QT_SETTINGS_SETTINGS_RADIOBOX_H_ #include "settings_widget.h" -#include "xenia/ui/qt/widgets/radiobox.h" +#include "xenia/ui/qt/widgets/radio_button.h" namespace xe { namespace ui { namespace qt { -class SettingsRadioBox : SettingsWidget {}; +class SettingsRadioButton : SettingsWidget {}; } // namespace qt } // namespace ui -} // namespace xe \ No newline at end of file +} // namespace xe + +#endif \ No newline at end of file diff --git a/src/xenia/ui/qt/settings/widgets/settings_text_edit.h b/src/xenia/ui/qt/settings/widgets/settings_text_edit.h index 11ff85b48..429756de1 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_text_edit.h +++ b/src/xenia/ui/qt/settings/widgets/settings_text_edit.h @@ -1,3 +1,12 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + #ifndef XENIA_UI_QT_SETTINGS_SETTINGS_TEXT_EDIT_H_ #define XENIA_UI_QT_SETTINGS_SETTINGS_TEXT_EDIT_H_ @@ -10,14 +19,10 @@ namespace xe { namespace ui { namespace qt { -template -class SettingsTextEdit : SettingsWidget { - static_assert( - std::is_same_v || - std::is_same_v, - "Settings TextEdit must use std::string or std::filesystem::path"); -}; +class SettingsTextEdit : SettingsWidget {}; } // namespace qt } // namespace ui -} // namespace xe \ No newline at end of file +} // namespace xe + +#endif diff --git a/src/xenia/ui/qt/settings/widgets/settings_widget.h b/src/xenia/ui/qt/settings/widgets/settings_widget.h index b49892e46..bb730c4c0 100644 --- a/src/xenia/ui/qt/settings/widgets/settings_widget.h +++ b/src/xenia/ui/qt/settings/widgets/settings_widget.h @@ -10,6 +10,9 @@ #ifndef XENIA_UI_QT_SETTINGS_SETTINGS_WIDGET_H_ #define XENIA_UI_QT_SETTINGS_SETTINGS_WIDGET_H_ +#include +#include +#include #include "xenia/base/cvar.h" #include "xenia/config.h" #include "xenia/ui/qt/themeable_widget.h" @@ -18,38 +21,53 @@ namespace xe { namespace ui { namespace qt { -template +template class SettingsWidget : public Widget { + static_assert(std::is_base_of_v, + "SettingsWidget base must be a derivative of QWidget"); + public: template - SettingsWidget(const std::string& config_name, Args... args) - : Widget(args...), cvar_(nullptr) { - cvar_ = dynamic_cast*>( - Config::Instance().FindConfigVarByName(config_name)); + SettingsWidget(cvar::ConfigVar* config_var, QLabel* label = nullptr, + Args... args) + : Widget(args...), cvar_(config_var), label_(label) { + // default config update function + update_config_fn_ = [](T val, cvar::ConfigVar& cvar) { + cvar.set_config_value(val); + }; } - template - SettingsWidget(const T& config_ref, Args... args) - : Widget(args...), cvar_(nullptr) { - cvar_ = dynamic_cast*>( - Config::Instance().FindConfigVar(config_ref)); + void UpdateLabel(const QString& text) { + if (label_) { + label_->setText(text); + } + } + + cvar::ConfigVar* config_var() const { return cvar_; } + void set_config_var(cvar::ConfigVar* cvar) { cvar_ = cvar; } + + void set_update_config_fn( + const std::function&)>& fn) { + update_config_fn_ = fn; } void UpdateValue(T val) { if (cvar_) { - cvar_->set_config_value(val); + update_config_fn_(val, *cvar_); + SaveToConfig(); } - Config::Instance().SaveConfig(); } void SaveToConfig() { Config::Instance().SaveConfig(); } protected: cvar::ConfigVar* cvar_; + std::function&)> update_config_fn_; + QLabel* label_; }; } // namespace qt } // namespace ui } // namespace xe -#endif \ No newline at end of file +#endif