[App/Settings] Add support for range input and adjust number settings impl
This commit is contained in:
parent
5735eccacf
commit
566d992f76
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<?xml-model href="settings_schema.xsd"?>
|
||||||
<Sets>
|
<Sets>
|
||||||
<Set name="General" icon="">
|
<Set name="General" icon="">
|
||||||
<Group name="General Settings">
|
<Group name="General Settings">
|
||||||
|
@ -79,6 +80,11 @@
|
||||||
<description>Enable Discord Rich Presence in Xenia</description>
|
<description>Enable Discord Rich Presence in Xenia</description>
|
||||||
<cvar>discord</cvar>
|
<cvar>discord</cvar>
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
|
<BooleanSetting>
|
||||||
|
<title>Discord Rich Presence 2</title>
|
||||||
|
<description>Enable Discord Rich Presence in Xenia</description>
|
||||||
|
<cvar>discord</cvar>
|
||||||
|
</BooleanSetting>
|
||||||
<BooleanSetting>
|
<BooleanSetting>
|
||||||
<title>Show game Icon in Taskbar</title>
|
<title>Show game Icon in Taskbar</title>
|
||||||
<description>Show the currently loaded game's icon in the Taskbar</description>
|
<description>Show the currently loaded game's icon in the Taskbar</description>
|
||||||
|
@ -136,12 +142,28 @@
|
||||||
<cvar>log_file</cvar>
|
<cvar>log_file</cvar>
|
||||||
</PathInputSetting>
|
</PathInputSetting>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group name="Test Settings">
|
||||||
|
<RangeInputSetting>
|
||||||
|
<title>Test int32</title>
|
||||||
|
<description>A test int slider</description>
|
||||||
|
<cvar>test_int</cvar>
|
||||||
|
<type>int32</type>
|
||||||
|
<min>0</min>
|
||||||
|
<max>100</max>
|
||||||
|
</RangeInputSetting>
|
||||||
|
</Group>
|
||||||
</Set>
|
</Set>
|
||||||
<Set name="CPU" icon="">
|
<Set name="CPU" icon="">
|
||||||
|
|
||||||
</Set>
|
</Set>
|
||||||
<Set name="Graphics" icon="">
|
<Set name="Graphics" icon="">
|
||||||
|
<Group name="D3D12 Settings">
|
||||||
|
<MultiChoiceSetting>
|
||||||
|
<title>Resolution scale</title>
|
||||||
|
<description>Renders the game at native resolution or higher resolutions. Very GPU intensive. May cause issues in some games.</description>
|
||||||
|
|
||||||
|
</MultiChoiceSetting>
|
||||||
|
</Group>
|
||||||
</Set>
|
</Set>
|
||||||
<Set name="Audio" icon="">
|
<Set name="Audio" icon="">
|
||||||
|
|
||||||
|
|
|
@ -1,90 +1,70 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||||
<xs:element name="Sets">
|
<xs:element name="Sets">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element maxOccurs="unbounded" ref="Set"/>
|
<xs:element maxOccurs="unbounded" name="Set">
|
||||||
</xs:sequence>
|
<xs:complexType mixed="true">
|
||||||
</xs:complexType>
|
<xs:sequence minOccurs="0">
|
||||||
</xs:element>
|
<xs:element maxOccurs="unbounded" name="Group">
|
||||||
<xs:element name="Set">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="Group"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="icon" use="required"/>
|
|
||||||
<xs:attribute name="name" use="required" type="xs:NCName"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="Group">
|
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:choice maxOccurs="unbounded">
|
<xs:choice maxOccurs="unbounded">
|
||||||
<xs:element ref="BooleanSetting"/>
|
<xs:element maxOccurs="unbounded" name="MultiChoiceSetting">
|
||||||
<xs:element ref="MultiChoiceSetting"/>
|
|
||||||
</xs:choice>
|
|
||||||
<xs:element minOccurs="0" ref="PathInputSetting"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="name" use="required"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="BooleanSetting">
|
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element ref="title"/>
|
<xs:choice maxOccurs="unbounded">
|
||||||
<xs:element ref="description"/>
|
<xs:element name="title" type="xs:string" />
|
||||||
<xs:element ref="cvar"/>
|
<xs:element name="description" type="xs:string" />
|
||||||
</xs:sequence>
|
<xs:element name="type" type="xs:string" />
|
||||||
</xs:complexType>
|
<xs:element name="cvar" type="xs:string" />
|
||||||
</xs:element>
|
|
||||||
<xs:element name="MultiChoiceSetting">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="title"/>
|
|
||||||
<xs:element ref="description"/>
|
|
||||||
<xs:element ref="type"/>
|
|
||||||
<xs:element minOccurs="0" ref="cvar"/>
|
|
||||||
<xs:element ref="options"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="type" type="xs:NCName"/>
|
|
||||||
<xs:element name="options">
|
<xs:element name="options">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element maxOccurs="unbounded" ref="option"/>
|
<xs:element maxOccurs="unbounded" name="option">
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="option">
|
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element ref="title"/>
|
<xs:element name="title" type="xs:string" />
|
||||||
<xs:element ref="value"/>
|
<xs:element name="value" type="xs:unsignedByte" />
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="value" type="xs:integer"/>
|
</xs:sequence>
|
||||||
<xs:element name="TextInputSetting">
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element maxOccurs="unbounded" name="BooleanSetting">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element ref="title"/>
|
|
||||||
<xs:element ref="description"/>
|
|
||||||
<xs:element ref="cvar"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="PathInputSetting">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="title"/>
|
|
||||||
<xs:element ref="description"/>
|
|
||||||
<xs:element ref="cvar"/>
|
|
||||||
<xs:element name="require_valid_path" type="xs:boolean" minOccurs="0" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="title" type="xs:string" />
|
<xs:element name="title" type="xs:string" />
|
||||||
<xs:element name="description" type="xs:string" />
|
<xs:element name="description" type="xs:string" />
|
||||||
<xs:element name="cvar" type="xs:NCName"/>
|
<xs:element name="cvar" type="xs:string" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element maxOccurs="unbounded" name="PathInputSetting">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="title" type="xs:string" />
|
||||||
|
<xs:element name="description" type="xs:string" />
|
||||||
|
<xs:element name="cvar" type="xs:string" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required" />
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required" />
|
||||||
|
<xs:attribute name="icon" type="xs:string" use="required" />
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
</xs:schema>
|
</xs:schema>
|
|
@ -115,9 +115,8 @@ inline int number_value_to_int(NumberValue v) {
|
||||||
|
|
||||||
template <SettingsType settings_type>
|
template <SettingsType settings_type>
|
||||||
class NumberSettingsItem : public ISettingsItem {
|
class NumberSettingsItem : public ISettingsItem {
|
||||||
public:
|
struct ValueUpdater {
|
||||||
struct ValueVisitor {
|
ValueUpdater(NumberSettingsItem* item) : item(item) {}
|
||||||
ValueVisitor(NumberSettingsItem* item) : item(item) {}
|
|
||||||
|
|
||||||
bool operator()(int8_t value) { return update(ValueType::Int8, value); }
|
bool operator()(int8_t value) { return update(ValueType::Int8, value); }
|
||||||
bool operator()(int16_t value) { return update(ValueType::Int16, value); }
|
bool operator()(int16_t value) { return update(ValueType::Int16, value); }
|
||||||
|
@ -144,6 +143,7 @@ class NumberSettingsItem : public ISettingsItem {
|
||||||
NumberSettingsItem* item;
|
NumberSettingsItem* item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
NumberSettingsItem(ValueType value_type, const std::string& title,
|
NumberSettingsItem(ValueType value_type, const std::string& title,
|
||||||
const std::string& description, IConfigVar* cvar = nullptr)
|
const std::string& description, IConfigVar* cvar = nullptr)
|
||||||
: ISettingsItem(settings_type, title, description),
|
: ISettingsItem(settings_type, title, description),
|
||||||
|
@ -154,8 +154,44 @@ class NumberSettingsItem : public ISettingsItem {
|
||||||
|
|
||||||
IConfigVar* cvar() const { return cvar_; }
|
IConfigVar* cvar() const { return cvar_; }
|
||||||
|
|
||||||
|
NumberValue current_value() const {
|
||||||
|
switch (value_type()) {
|
||||||
|
case ValueType::Int8: {
|
||||||
|
return *cvar()->as<int8_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::Int16: {
|
||||||
|
return *cvar()->as<int16_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::Int32: {
|
||||||
|
return *cvar()->as<int32_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::Int64: {
|
||||||
|
return *cvar()->as<int64_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::UInt8: {
|
||||||
|
return *cvar()->as<uint8_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::UInt16: {
|
||||||
|
return *cvar()->as<uint16_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::UInt32: {
|
||||||
|
return *cvar()->as<uint32_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::UInt64: {
|
||||||
|
return *cvar()->as<uint64_t>()->current_value();
|
||||||
|
}
|
||||||
|
case ValueType::Double: {
|
||||||
|
return *cvar()->as<double>()->current_value();
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
assert_always("Invalid number type provided");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool UpdateValue(NumberValue value) {
|
virtual bool UpdateValue(NumberValue value) {
|
||||||
auto res = std::visit(ValueVisitor(this), value);
|
auto res = std::visit(ValueUpdater(this), value);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
XELOGE("Could not update value for {0}. Incorrect value type provided",
|
XELOGE("Could not update value for {0}. Incorrect value type provided",
|
||||||
cvar_->name());
|
cvar_->name());
|
||||||
|
@ -172,9 +208,8 @@ class NumberSettingsItem : public ISettingsItem {
|
||||||
class RangeInputSettingsItem : public NumberSettingsItem<SettingsType::Range> {
|
class RangeInputSettingsItem : public NumberSettingsItem<SettingsType::Range> {
|
||||||
public:
|
public:
|
||||||
RangeInputSettingsItem(ValueType value_type, std::string title,
|
RangeInputSettingsItem(ValueType value_type, std::string title,
|
||||||
NumberValue min, NumberValue max,
|
std::string description, NumberValue min,
|
||||||
std::string description = "",
|
NumberValue max, IConfigVar* cvar = nullptr)
|
||||||
IConfigVar* cvar = nullptr)
|
|
||||||
: NumberSettingsItem(value_type, title, description, cvar),
|
: NumberSettingsItem(value_type, title, description, cvar),
|
||||||
min_(min),
|
min_(min),
|
||||||
max_(max) {}
|
max_(max) {}
|
||||||
|
@ -205,6 +240,7 @@ class IMultiChoiceSettingsItem : public ISettingsItem {
|
||||||
virtual bool UpdateIndex(int index) = 0;
|
virtual bool UpdateIndex(int index) = 0;
|
||||||
virtual std::vector<std::string> option_names() const = 0;
|
virtual std::vector<std::string> option_names() const = 0;
|
||||||
virtual int current_index() const = 0;
|
virtual int current_index() const = 0;
|
||||||
|
virtual IConfigVar* cvar() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -273,6 +309,8 @@ class MultiChoiceSettingsItem : public IMultiChoiceSettingsItem {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IConfigVar* cvar() const override { return cvar_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConfigVar<T>* cvar_;
|
ConfigVar<T>* cvar_;
|
||||||
std::vector<Option> options_;
|
std::vector<Option> options_;
|
||||||
|
|
|
@ -14,6 +14,17 @@
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/config.h"
|
#include "xenia/config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
DEFINE_bool(test_bool, false, "test bool", "General");
|
||||||
|
DEFINE_int32(test_int, 0, "test bool", "General");
|
||||||
|
DEFINE_path(test_path, "C:\\", "test path", "General");
|
||||||
|
DEFINE_string(test_string, "C:\\", "test string", "General");
|
||||||
|
DEFINE_uint64(test_uint64, 0, "test uint64", "General");
|
||||||
|
DEFINE_double(test_double, 0, "test double", "General");
|
||||||
|
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace app {
|
namespace app {
|
||||||
namespace settings {
|
namespace settings {
|
||||||
|
@ -136,6 +147,35 @@ std::unique_ptr<ISettingsItem> SettingsLoader::LoadSettingsItemFromXmlNode(
|
||||||
return LoadMultiChoiceSetting<std::string>(title, description, cvar,
|
return LoadMultiChoiceSetting<std::string>(title, description, cvar,
|
||||||
node);
|
node);
|
||||||
}
|
}
|
||||||
|
} else if (node_type == "RangeInputSetting") {
|
||||||
|
std::string_view value_type_str = node.child_value("type");
|
||||||
|
ValueType value_type;
|
||||||
|
if (value_type_str == "int8") {
|
||||||
|
value_type = ValueType::Int8;
|
||||||
|
} else if (value_type_str == "int16") {
|
||||||
|
value_type = ValueType::Int16;
|
||||||
|
} else if (value_type_str == "int32") {
|
||||||
|
value_type = ValueType::Int32;
|
||||||
|
} else if (value_type_str == "int64") {
|
||||||
|
value_type = ValueType::Int64;
|
||||||
|
} else if (value_type_str == "uint8") {
|
||||||
|
value_type = ValueType::UInt8;
|
||||||
|
} else if (value_type_str == "uint16") {
|
||||||
|
value_type = ValueType::UInt16;
|
||||||
|
} else if (value_type_str == "uint32") {
|
||||||
|
value_type = ValueType::UInt32;
|
||||||
|
} else if (value_type_str == "uint64") {
|
||||||
|
value_type = ValueType::UInt64;
|
||||||
|
} else if (value_type_str == "double") {
|
||||||
|
XELOGE("Floating point types are not supported for slider");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int min = node.child("min").text().as_int();
|
||||||
|
int max = node.child("max").text().as_int();
|
||||||
|
|
||||||
|
return std::make_unique<RangeInputSettingsItem>(
|
||||||
|
value_type, title, description, min, max, cvar);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
XELOGE("Unknown settings node type {}", node.name());
|
XELOGE("Unknown settings node type {}", node.name());
|
||||||
|
@ -251,7 +291,7 @@ void SettingsLoader::AddRangeInputSetting(std::string title,
|
||||||
NumberValue max) {
|
NumberValue max) {
|
||||||
if (cvar) {
|
if (cvar) {
|
||||||
auto setting_item = std::make_unique<RangeInputSettingsItem>(
|
auto setting_item = std::make_unique<RangeInputSettingsItem>(
|
||||||
value_type, title, min, max, description, cvar);
|
value_type, title, description, min, max, cvar);
|
||||||
AddSetting(std::move(setting_item), group, set);
|
AddSetting(std::move(setting_item), group, set);
|
||||||
} else {
|
} else {
|
||||||
XELOGE("Could not find cvar for setting with title {}", title);
|
XELOGE("Could not find cvar for setting with title {}", title);
|
||||||
|
|
Loading…
Reference in New Issue