[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-model href="settings_schema.xsd"?>
|
||||
<Sets>
|
||||
<Set name="General" icon="">
|
||||
<Group name="General Settings">
|
||||
|
@ -79,6 +80,11 @@
|
|||
<description>Enable Discord Rich Presence in Xenia</description>
|
||||
<cvar>discord</cvar>
|
||||
</BooleanSetting>
|
||||
<BooleanSetting>
|
||||
<title>Discord Rich Presence 2</title>
|
||||
<description>Enable Discord Rich Presence in Xenia</description>
|
||||
<cvar>discord</cvar>
|
||||
</BooleanSetting>
|
||||
<BooleanSetting>
|
||||
<title>Show game Icon in Taskbar</title>
|
||||
<description>Show the currently loaded game's icon in the Taskbar</description>
|
||||
|
@ -136,12 +142,28 @@
|
|||
<cvar>log_file</cvar>
|
||||
</PathInputSetting>
|
||||
</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 name="CPU" icon="">
|
||||
|
||||
</Set>
|
||||
<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 name="Audio" icon="">
|
||||
|
||||
|
|
|
@ -1,90 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="Sets">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="Set"/>
|
||||
<xs:element maxOccurs="unbounded" name="Set">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:element maxOccurs="unbounded" name="Group">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element maxOccurs="unbounded" name="MultiChoiceSetting">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="title" type="xs:string" />
|
||||
<xs:element name="description" type="xs:string" />
|
||||
<xs:element name="type" type="xs:string" />
|
||||
<xs:element name="cvar" type="xs:string" />
|
||||
<xs:element name="options">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="option">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="title" type="xs:string" />
|
||||
<xs:element name="value" type="xs:unsignedByte" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element maxOccurs="unbounded" name="BooleanSetting">
|
||||
<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: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: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:sequence>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="BooleanSetting"/>
|
||||
<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:sequence>
|
||||
<xs:element ref="title"/>
|
||||
<xs:element ref="description"/>
|
||||
<xs:element ref="cvar"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</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:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="option"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="option">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="title"/>
|
||||
<xs:element ref="value"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="value" type="xs:integer"/>
|
||||
<xs:element name="TextInputSetting">
|
||||
<xs:complexType>
|
||||
<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="description" type="xs:string"/>
|
||||
<xs:element name="cvar" type="xs:NCName"/>
|
||||
</xs:schema>
|
||||
</xs:schema>
|
|
@ -115,9 +115,8 @@ inline int number_value_to_int(NumberValue v) {
|
|||
|
||||
template <SettingsType settings_type>
|
||||
class NumberSettingsItem : public ISettingsItem {
|
||||
public:
|
||||
struct ValueVisitor {
|
||||
ValueVisitor(NumberSettingsItem* item) : item(item) {}
|
||||
struct ValueUpdater {
|
||||
ValueUpdater(NumberSettingsItem* item) : item(item) {}
|
||||
|
||||
bool operator()(int8_t value) { return update(ValueType::Int8, value); }
|
||||
bool operator()(int16_t value) { return update(ValueType::Int16, value); }
|
||||
|
@ -144,6 +143,7 @@ class NumberSettingsItem : public ISettingsItem {
|
|||
NumberSettingsItem* item;
|
||||
};
|
||||
|
||||
public:
|
||||
NumberSettingsItem(ValueType value_type, const std::string& title,
|
||||
const std::string& description, IConfigVar* cvar = nullptr)
|
||||
: ISettingsItem(settings_type, title, description),
|
||||
|
@ -154,8 +154,44 @@ class NumberSettingsItem : public ISettingsItem {
|
|||
|
||||
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) {
|
||||
auto res = std::visit(ValueVisitor(this), value);
|
||||
auto res = std::visit(ValueUpdater(this), value);
|
||||
if (!res) {
|
||||
XELOGE("Could not update value for {0}. Incorrect value type provided",
|
||||
cvar_->name());
|
||||
|
@ -172,9 +208,8 @@ class NumberSettingsItem : public ISettingsItem {
|
|||
class RangeInputSettingsItem : public NumberSettingsItem<SettingsType::Range> {
|
||||
public:
|
||||
RangeInputSettingsItem(ValueType value_type, std::string title,
|
||||
NumberValue min, NumberValue max,
|
||||
std::string description = "",
|
||||
IConfigVar* cvar = nullptr)
|
||||
std::string description, NumberValue min,
|
||||
NumberValue max, IConfigVar* cvar = nullptr)
|
||||
: NumberSettingsItem(value_type, title, description, cvar),
|
||||
min_(min),
|
||||
max_(max) {}
|
||||
|
@ -205,6 +240,7 @@ class IMultiChoiceSettingsItem : public ISettingsItem {
|
|||
virtual bool UpdateIndex(int index) = 0;
|
||||
virtual std::vector<std::string> option_names() const = 0;
|
||||
virtual int current_index() const = 0;
|
||||
virtual IConfigVar* cvar() const = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -273,6 +309,8 @@ class MultiChoiceSettingsItem : public IMultiChoiceSettingsItem {
|
|||
return names;
|
||||
}
|
||||
|
||||
IConfigVar* cvar() const override { return cvar_; }
|
||||
|
||||
private:
|
||||
ConfigVar<T>* cvar_;
|
||||
std::vector<Option> options_;
|
||||
|
|
|
@ -14,6 +14,17 @@
|
|||
#include "xenia/base/logging.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 app {
|
||||
namespace settings {
|
||||
|
@ -136,6 +147,35 @@ std::unique_ptr<ISettingsItem> SettingsLoader::LoadSettingsItemFromXmlNode(
|
|||
return LoadMultiChoiceSetting<std::string>(title, description, cvar,
|
||||
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 {
|
||||
XELOGE("Unknown settings node type {}", node.name());
|
||||
|
@ -251,7 +291,7 @@ void SettingsLoader::AddRangeInputSetting(std::string title,
|
|||
NumberValue max) {
|
||||
if (cvar) {
|
||||
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);
|
||||
} else {
|
||||
XELOGE("Could not find cvar for setting with title {}", title);
|
||||
|
|
Loading…
Reference in New Issue