From 3ae3706c847431089389721e2873bc9a0549d6d9 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:50:25 -0400 Subject: [PATCH] shared_widget: Forward-port Citra changes Seemed like a good time to move these over. Also remove usage of std::sto{l,ll,ul,f,d} --- src/yuzu/configuration/shared_widget.cpp | 157 ++++++++++++++++++----- src/yuzu/configuration/shared_widget.h | 8 ++ 2 files changed, 134 insertions(+), 31 deletions(-) diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index d63093985..e5e071386 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -151,7 +151,7 @@ QWidget* Widget::CreateCombobox(std::function& serializer, return -1; }; - const u32 setting_value = std::stoi(setting.ToString()); + const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0); combobox->setCurrentIndex(find_index(setting_value)); serializer = [this, enumeration]() { @@ -160,7 +160,7 @@ QWidget* Widget::CreateCombobox(std::function& serializer, }; restore_func = [this, find_index]() { - const u32 global_value = std::stoi(RelevantDefault(setting)); + const u32 global_value = std::strtoul(RelevantDefault(setting).c_str(), nullptr, 0); combobox->setCurrentIndex(find_index(global_value)); }; @@ -209,7 +209,7 @@ QWidget* Widget::CreateRadioGroup(std::function& serializer, } }; - const u32 setting_value = std::stoi(setting.ToString()); + const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0); set_index(setting_value); serializer = [get_selected]() { @@ -218,7 +218,7 @@ QWidget* Widget::CreateRadioGroup(std::function& serializer, }; restore_func = [this, set_index]() { - const u32 global_value = std::stoi(RelevantDefault(setting)); + const u32 global_value = std::strtoul(RelevantDefault(setting).c_str(), nullptr, 0); set_index(global_value); }; @@ -255,6 +255,58 @@ QWidget* Widget::CreateLineEdit(std::function& serializer, return line_edit; } +static void CreateIntSlider(Settings::BasicSetting& setting, bool reversed, float multiplier, + QLabel* feedback, const QString& use_format, QSlider* slider, + std::function& serializer, + std::function& restore_func) { + int max_val = std::strtol(setting.MaxVal().c_str(), nullptr, 0); + + const auto update_feedback = [=](int value) { + int present = (reversed ? max_val - value : value) * multiplier + 0.5f; + feedback->setText(use_format.arg(QVariant::fromValue(present).value())); + }; + + QObject::connect(slider, &QAbstractSlider::valueChanged, update_feedback); + update_feedback(std::strtol(setting.ToString().c_str(), nullptr, 0)); + + slider->setMinimum(std::strtol(setting.MinVal().c_str(), nullptr, 0)); + slider->setMaximum(max_val); + slider->setValue(std::strtol(setting.ToString().c_str(), nullptr, 0)); + + serializer = [slider]() { return std::to_string(slider->value()); }; + restore_func = [slider, &setting]() { + slider->setValue(std::strtol(RelevantDefault(setting).c_str(), nullptr, 0)); + }; +} + +static void CreateFloatSlider(Settings::BasicSetting& setting, bool reversed, float multiplier, + QLabel* feedback, const QString& use_format, QSlider* slider, + std::function& serializer, + std::function& restore_func) { + float max_val = std::strtof(setting.MaxVal().c_str(), nullptr); + float min_val = std::strtof(setting.MinVal().c_str(), nullptr); + float use_multiplier = multiplier == default_multiplier ? default_float_multiplier : multiplier; + + const auto update_feedback = [=](float value) { + int present = (reversed ? max_val - value : value) + 0.5f; + feedback->setText(use_format.arg(QVariant::fromValue(present).value())); + }; + + QObject::connect(slider, &QAbstractSlider::valueChanged, update_feedback); + update_feedback(std::strtof(setting.ToString().c_str(), nullptr)); + + slider->setMinimum(min_val * use_multiplier); + slider->setMaximum(max_val * use_multiplier); + slider->setValue(std::strtof(setting.ToString().c_str(), nullptr) * use_multiplier); + + serializer = [slider, use_multiplier]() { + return std::to_string(slider->value() / use_multiplier); + }; + restore_func = [slider, &setting, use_multiplier]() { + slider->setValue(std::strtof(RelevantDefault(setting).c_str(), nullptr) * use_multiplier); + }; +} + QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& given_suffix, std::function& serializer, std::function& restore_func, @@ -278,27 +330,20 @@ QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& gi layout->setContentsMargins(0, 0, 0, 0); - int max_val = std::stoi(setting.MaxVal()); - QString suffix = given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix; const QString use_format = QStringLiteral("%1").append(suffix); - QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) { - int present = (reversed ? max_val - value : value) * multiplier + 0.5f; - feedback->setText(use_format.arg(QVariant::fromValue(present).value())); - }); - - slider->setMinimum(std::stoi(setting.MinVal())); - slider->setMaximum(max_val); - slider->setValue(std::stoi(setting.ToString())); + if (setting.IsIntegral()) { + CreateIntSlider(setting, reversed, multiplier, feedback, use_format, slider, serializer, + restore_func); + } else { + CreateFloatSlider(setting, reversed, multiplier, feedback, use_format, slider, serializer, + restore_func); + } slider->setInvertedAppearance(reversed); - slider->setInvertedControls(reversed); - - serializer = [this]() { return std::to_string(slider->value()); }; - restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); }; if (!Settings::IsConfiguringGlobal()) { QObject::connect(slider, &QAbstractSlider::actionTriggered, [touch]() { touch(); }); @@ -311,11 +356,9 @@ QWidget* Widget::CreateSpinBox(const QString& given_suffix, std::function& serializer, std::function& restore_func, const std::function& touch) { - const int min_val = - setting.Ranged() ? std::stoi(setting.MinVal()) : std::numeric_limits::min(); - const int max_val = - setting.Ranged() ? std::stoi(setting.MaxVal()) : std::numeric_limits::max(); - const int default_val = std::stoi(setting.ToString()); + const auto min_val = std::strtol(setting.MinVal().c_str(), nullptr, 0); + const auto max_val = std::strtol(setting.MaxVal().c_str(), nullptr, 0); + const auto default_val = std::strtol(setting.ToString().c_str(), nullptr, 0); QString suffix = given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix; @@ -329,13 +372,13 @@ QWidget* Widget::CreateSpinBox(const QString& given_suffix, serializer = [this]() { return std::to_string(spinbox->value()); }; restore_func = [this]() { - auto value{std::stol(RelevantDefault(setting))}; + auto value{std::strtol(RelevantDefault(setting).c_str(), nullptr, 0)}; spinbox->setValue(value); }; if (!Settings::IsConfiguringGlobal()) { QObject::connect(spinbox, QOverload::of(&QSpinBox::valueChanged), [this, touch]() { - if (spinbox->value() != std::stoi(setting.ToStringGlobal())) { + if (spinbox->value() != std::strtol(setting.ToStringGlobal().c_str(), nullptr, 0)) { touch(); } }); @@ -344,6 +387,43 @@ QWidget* Widget::CreateSpinBox(const QString& given_suffix, return spinbox; } +QWidget* Widget::CreateDoubleSpinBox(const QString& given_suffix, + std::function& serializer, + std::function& restore_func, + const std::function& touch) { + const auto min_val = std::strtod(setting.MinVal().c_str(), nullptr); + const auto max_val = std::strtod(setting.MaxVal().c_str(), nullptr); + const auto default_val = std::strtod(setting.ToString().c_str(), nullptr); + + QString suffix = + given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix; + + double_spinbox = new QDoubleSpinBox(this); + double_spinbox->setRange(min_val, max_val); + double_spinbox->setValue(default_val); + double_spinbox->setSuffix(suffix); + double_spinbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + serializer = [this]() { return fmt::format("{:f}", double_spinbox->value()); }; + + restore_func = [this]() { + auto value{std::strtod(RelevantDefault(setting).c_str(), nullptr)}; + double_spinbox->setValue(value); + }; + + if (!Settings::IsConfiguringGlobal()) { + QObject::connect(double_spinbox, QOverload::of(&QDoubleSpinBox::valueChanged), + [this, touch]() { + if (double_spinbox->value() != + std::strtod(setting.ToStringGlobal().c_str(), nullptr)) { + touch(); + } + }); + } + + return double_spinbox; +} + QWidget* Widget::CreateHexEdit(std::function& serializer, std::function& restore_func, const std::function& touch) { @@ -353,7 +433,8 @@ QWidget* Widget::CreateHexEdit(std::function& serializer, } auto to_hex = [=](const std::string& input) { - return QString::fromStdString(fmt::format("{:08x}", std::stoul(input))); + return QString::fromStdString( + fmt::format("{:08x}", std::strtoul(input.c_str(), nullptr, 0))); }; QRegularExpressionValidator* regex = new QRegularExpressionValidator( @@ -366,7 +447,7 @@ QWidget* Widget::CreateHexEdit(std::function& serializer, line_edit->setValidator(regex); auto hex_to_dec = [this]() -> std::string { - return std::to_string(std::stoul(line_edit->text().toStdString(), nullptr, 16)); + return std::to_string(std::strtoul(line_edit->text().toStdString().c_str(), nullptr, 16)); }; serializer = [hex_to_dec]() { return hex_to_dec(); }; @@ -386,7 +467,8 @@ QWidget* Widget::CreateDateTimeEdit(bool disabled, bool restrict, std::function& restore_func, const std::function& touch) { const long long current_time = QDateTime::currentSecsSinceEpoch(); - const s64 the_time = disabled ? current_time : std::stoll(setting.ToString()); + const s64 the_time = + disabled ? current_time : std::strtoll(setting.ToString().c_str(), nullptr, 0); const auto default_val = QDateTime::fromSecsSinceEpoch(the_time); date_time_edit = new QDateTimeEdit(this); @@ -399,7 +481,7 @@ QWidget* Widget::CreateDateTimeEdit(bool disabled, bool restrict, auto get_clear_val = [this, restrict, current_time]() { return QDateTime::fromSecsSinceEpoch([this, restrict, current_time]() { if (restrict && checkbox->checkState() == Qt::Checked) { - return std::stoll(RelevantDefault(setting)); + return std::strtoll(RelevantDefault(setting).c_str(), nullptr, 0); } return current_time; }()); @@ -506,8 +588,7 @@ void Widget::SetupComponent(const QString& label, std::function& load_fu } else { data_component = CreateCombobox(serializer, restore_func, touch); } - } else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) || - type == typeid(s64) || type == typeid(u8)) { + } else if (setting.IsIntegral()) { switch (request) { case RequestType::Slider: case RequestType::ReverseSlider: @@ -534,6 +615,20 @@ void Widget::SetupComponent(const QString& label, std::function& load_fu default: UNIMPLEMENTED(); } + } else if (setting.IsFloatingPoint()) { + switch (request) { + case RequestType::Default: + case RequestType::SpinBox: + data_component = CreateDoubleSpinBox(suffix, serializer, restore_func, touch); + break; + case RequestType::Slider: + case RequestType::ReverseSlider: + data_component = CreateSlider(request == RequestType::ReverseSlider, multiplier, suffix, + serializer, restore_func, touch); + break; + default: + UNIMPLEMENTED(); + } } else if (type == typeid(std::string)) { switch (request) { case RequestType::Default: diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index 5303dd898..86edaacc8 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -22,6 +22,7 @@ class QObject; class QPushButton; class QSlider; class QSpinBox; +class QDoubleSpinBox; class QRadioButton; namespace Settings { @@ -43,6 +44,9 @@ enum class RequestType { MaxEnum, }; +constexpr const float default_multiplier{1.f}; +constexpr const float default_float_multiplier{100.f}; + class Widget : public QWidget { Q_OBJECT @@ -89,6 +93,7 @@ public: QPushButton* restore_button{}; ///< Restore button for custom configurations QLineEdit* line_edit{}; ///< QLineEdit, used for LineEdit and HexEdit QSpinBox* spinbox{}; + QDoubleSpinBox* double_spinbox{}; QCheckBox* checkbox{}; QSlider* slider{}; QComboBox* combobox{}; @@ -126,6 +131,9 @@ private: const std::function& touch); QWidget* CreateSpinBox(const QString& suffix, std::function& serializer, std::function& restore_func, const std::function& touch); + QWidget* CreateDoubleSpinBox(const QString& suffix, std::function& serializer, + std::function& restore_func, + const std::function& touch); QWidget* parent; const TranslationMap& translations;