feat: Make Arrays collapsible; make collapsible sections optional

This commit is contained in:
Riccardo Zaglia 2023-09-11 18:44:02 +08:00
parent a417a841eb
commit a3ce7c1364
11 changed files with 236 additions and 151 deletions

106
Cargo.lock generated
View File

@ -690,7 +690,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -712,7 +712,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -729,7 +729,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -812,9 +812,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.3"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64ct"
@ -870,7 +870,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.31",
"syn 2.0.32",
"which",
]
@ -973,7 +973,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -1060,9 +1060,9 @@ dependencies = [
[[package]]
name = "cfg-expr"
version = "0.15.4"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9"
checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3"
dependencies = [
"smallvec",
"target-lexicon",
@ -1390,7 +1390,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -1401,7 +1401,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -1619,7 +1619,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -1879,7 +1879,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -2285,7 +2285,7 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
dependencies = [
"base64 0.21.3",
"base64 0.21.4",
"bytes",
"headers-core",
"http",
@ -2579,7 +2579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix 0.38.11",
"rustix 0.38.13",
"windows-sys 0.48.0",
]
@ -2774,9 +2774,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
[[package]]
name = "local-ip-address"
@ -3250,7 +3250,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -3262,7 +3262,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -3411,7 +3411,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -3596,7 +3596,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -3654,12 +3654,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8832c0f9be7e3cae60727e6256cfd2cd3c3e2b6cd5dad4190ecb2fd658c9030b"
checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
dependencies = [
"proc-macro2",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -3824,7 +3824,7 @@ version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"base64 0.21.3",
"base64 0.21.4",
"bytes",
"encoding_rs",
"futures-core",
@ -3963,14 +3963,14 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.11"
version = "0.38.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
dependencies = [
"bitflags 2.4.0",
"errno 0.3.3",
"libc",
"linux-raw-sys 0.4.5",
"linux-raw-sys 0.4.7",
"windows-sys 0.48.0",
]
@ -3992,7 +3992,7 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
dependencies = [
"base64 0.21.3",
"base64 0.21.4",
]
[[package]]
@ -4132,14 +4132,14 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
name = "serde_json"
version = "1.0.105"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2"
dependencies = [
"itoa",
"ryu",
@ -4154,7 +4154,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -4181,7 +4181,7 @@ dependencies = [
[[package]]
name = "settings-schema"
version = "0.2.0"
source = "git+https://github.com/alvr-org/settings-schema-rs?rev=b565cf6#b565cf6aafa7e01d5edd29be8564dffec5f051f0"
source = "git+https://github.com/alvr-org/settings-schema-rs?rev=676185f#676185f35869f05a90fcc81f66a4bbd9d86f9c12"
dependencies = [
"serde",
"serde_json",
@ -4191,12 +4191,12 @@ dependencies = [
[[package]]
name = "settings-schema-derive"
version = "0.2.0"
source = "git+https://github.com/alvr-org/settings-schema-rs?rev=b565cf6#b565cf6aafa7e01d5edd29be8564dffec5f051f0"
source = "git+https://github.com/alvr-org/settings-schema-rs?rev=676185f#676185f35869f05a90fcc81f66a4bbd9d86f9c12"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -4471,9 +4471,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.31"
version = "2.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
dependencies = [
"proc-macro2",
"quote",
@ -4503,7 +4503,7 @@ dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml 0.7.6",
"toml 0.7.8",
"version-compare",
]
@ -4522,7 +4522,7 @@ dependencies = [
"cfg-if",
"fastrand 2.0.0",
"redox_syscall 0.3.5",
"rustix 0.38.11",
"rustix 0.38.13",
"windows-sys 0.48.0",
]
@ -4552,7 +4552,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -4638,7 +4638,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -4710,9 +4710,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.7.6"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
dependencies = [
"serde",
"serde_spanned",
@ -4731,9 +4731,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.19.14"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap 2.0.0",
"serde",
@ -4768,7 +4768,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
]
[[package]]
@ -4891,7 +4891,7 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
dependencies = [
"base64 0.21.3",
"base64 0.21.4",
"flate2",
"log",
"once_cell",
@ -4996,7 +4996,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
"wasm-bindgen-shared",
]
@ -5030,7 +5030,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.32",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -5301,7 +5301,7 @@ dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.11",
"rustix 0.38.13",
]
[[package]]
@ -5691,9 +5691,9 @@ checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
[[package]]
name = "xml-rs"
version = "0.8.17"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1eee6bf5926be7cf998d7381a9a23d833fd493f6a8034658a9505a4dc4b20444"
checksum = "bab77e97b50aee93da431f2cee7cd0f43b4d1da3c408042f2d7d164187774f0a"
[[package]]
name = "xshell"

View File

@ -18,7 +18,7 @@ once_cell = "1"
parking_lot = "0.12"
semver = { version = "1", features = ["serde"] }
serde = { version = "1", features = ["derive"] }
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "b565cf6" }
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "676185f" }
# settings-schema = { path = "../../../../settings-schema-rs/settings-schema" }
[target.'cfg(not(target_os = "android"))'.dependencies]

View File

@ -21,7 +21,7 @@ env_logger = "0.10"
ico = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "b565cf6" }
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "676185f" }
statrs = "0.16"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

View File

@ -44,13 +44,11 @@ impl SettingsTab {
let schema = Settings::schema(alvr_session::session_settings_default());
// Top level node must be a section
let schema_entries = if let SchemaNode::Section(entries) = schema {
entries
} else {
let SchemaNode::Section { entries, .. } = schema else {
unreachable!();
};
let top_level_entries = schema_entries
let top_level_entries = entries
.into_iter()
.map(|entry| {
let id = entry.name;

View File

@ -5,6 +5,7 @@ use eframe::egui::Ui;
use serde_json as json;
pub struct Control {
nesting_info: NestingInfo,
controls: Vec<SettingControl>,
}
@ -15,13 +16,17 @@ impl Control {
.enumerate()
.map(|(idx, schema)| {
let mut nesting_info = nesting_info.clone();
nesting_info.path.push("content".into());
nesting_info.path.push(idx.into());
SettingControl::new(nesting_info, schema)
})
.collect();
Self { controls }
Self {
nesting_info,
controls,
}
}
pub fn ui(
@ -32,19 +37,32 @@ impl Control {
) -> Option<PathValuePair> {
super::grid_flow_inline(ui, allow_inline);
let session_array_mut = session_fragment.as_array_mut().unwrap();
let count = self.controls.len();
let json::Value::Bool(collapsed_state_mut) = &mut session_fragment["gui_collapsed"] else {
unreachable!()
};
let mut request = None;
for (idx, control) in self.controls.iter_mut().enumerate() {
let allow_inline = idx == 0;
request = control
.ui(ui, &mut session_array_mut[idx], allow_inline)
.or(request);
if idx != count - 1 {
if (*collapsed_state_mut && ui.small_button("Expand").clicked())
|| (!*collapsed_state_mut && ui.small_button("Collapse").clicked())
{
*collapsed_state_mut = !*collapsed_state_mut;
request = super::set_single_value(
&self.nesting_info,
"gui_collapsed".into(),
json::Value::Bool(*collapsed_state_mut),
);
}
if !*collapsed_state_mut {
let session_array_mut = session_fragment["content"].as_array_mut().unwrap();
for (idx, control) in self.controls.iter_mut().enumerate() {
ui.end_row();
request = control
.ui(ui, &mut session_array_mut[idx], false)
.or(request);
}
}

View File

@ -71,9 +71,14 @@ pub enum SettingControl {
impl SettingControl {
pub fn new(nesting_info: NestingInfo, schema: SchemaNode) -> Self {
match schema {
SchemaNode::Section(entries) => {
Self::Section(section::Control::new(nesting_info, entries))
}
SchemaNode::Section {
entries,
gui_collapsible,
} => Self::Section(section::Control::new(
nesting_info,
entries,
gui_collapsible,
)),
SchemaNode::Choice {
default,
variants,

View File

@ -23,12 +23,14 @@ struct Entry {
pub struct Control {
nesting_info: NestingInfo,
entries: Vec<Entry>,
gui_collapsible: bool,
}
impl Control {
pub fn new(
mut nesting_info: NestingInfo,
schema_entries: Vec<SchemaEntry<SchemaNode>>,
gui_collapsible: bool,
) -> Self {
nesting_info.indentation_level += 1;
@ -59,6 +61,7 @@ impl Control {
Self {
nesting_info,
entries,
gui_collapsible,
}
}
@ -68,35 +71,42 @@ impl Control {
session_fragment: &mut json::Value,
allow_inline: bool,
) -> Option<PathValuePair> {
super::grid_flow_inline(ui, allow_inline);
let session_fragments_mut = session_fragment.as_object_mut().unwrap();
let json::Value::Bool(state_mut) = &mut session_fragments_mut["gui_collapsed"] else {
unreachable!()
};
let entries_count = self.entries.len();
fn get_request(nesting_info: &NestingInfo, collapsed: bool) -> Option<PathValuePair> {
super::set_single_value(
nesting_info,
"gui_collapsed".into(),
json::Value::Bool(collapsed),
)
}
let mut request = None;
let mut response = None;
if (*state_mut && ui.small_button("Expand").clicked())
|| (!*state_mut && ui.small_button("Collapse").clicked())
{
*state_mut = !*state_mut;
response = get_request(&self.nesting_info, *state_mut);
}
let collapsed = if self.gui_collapsible {
super::grid_flow_inline(ui, allow_inline);
if !*state_mut {
ui.end_row();
let json::Value::Bool(state_mut) = &mut session_fragment["gui_collapsed"] else {
unreachable!()
};
if (*state_mut && ui.small_button("Expand").clicked())
|| (!*state_mut && ui.small_button("Collapse").clicked())
{
*state_mut = !*state_mut;
request = super::set_single_value(
&self.nesting_info,
"gui_collapsed".into(),
json::Value::Bool(*state_mut),
);
}
if !*state_mut {
ui.end_row();
}
*state_mut
} else {
if allow_inline {
ui.end_row();
}
false
};
if !collapsed {
for (i, entry) in self.entries.iter_mut().enumerate() {
ui.horizontal(|ui| {
ui.add_space(INDENTATION_STEP * self.nesting_info.indentation_level as f32);
@ -131,10 +141,10 @@ impl Control {
);
}
});
response = entry
request = entry
.control
.ui(ui, &mut session_fragments_mut[&entry.id.id], true)
.or(response);
.ui(ui, &mut session_fragment[&entry.id.id], true)
.or(request);
if i != entries_count - 1 {
ui.end_row();
@ -142,6 +152,6 @@ impl Control {
}
}
response
request
}
}

View File

@ -12,7 +12,7 @@ alvr_common.workspace = true
bytemuck = { version = "1", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "b565cf6" }
settings-schema = { git = "https://github.com/alvr-org/settings-schema-rs", rev = "676185f" }
[build-dependencies]
regex = "1"

View File

@ -107,7 +107,13 @@ static OPENVR_PROPS_DEFAULT: alvr_common::once_cell::sync::Lazy<OpenvrPropertyDe
"Uint64" => "0",
"Float" => "0.0",
"String" => "String::new()",
"Vector3" => "[0.0, 0.0, 0.0]",
"Vector3" => {
r"ArrayDefault {
gui_collapsed: false,
content: [0.0, 0.0, 0.0],
}"
}
_ => "()",
};

View File

@ -242,7 +242,10 @@ fn extrapolate_session_settings_from_session_settings(
schema: &SchemaNode,
) -> json::Value {
match schema {
SchemaNode::Section(entries) => json::Value::Object({
SchemaNode::Section {
entries,
gui_collapsible,
} => json::Value::Object({
let mut entries: json::Map<String, json::Value> = entries
.iter()
.map(|named_entry| {
@ -260,17 +263,19 @@ fn extrapolate_session_settings_from_session_settings(
})
.collect();
let collapsed_state = new_session_settings
.get("gui_collapsed")
.and_then(|val| val.as_bool())
.unwrap_or_else(|| {
old_session_settings
.get("gui_collapsed")
.unwrap()
.as_bool()
.unwrap()
});
entries.insert("gui_collapsed".into(), json::Value::Bool(collapsed_state));
if *gui_collapsible {
let collapsed_state = new_session_settings
.get("gui_collapsed")
.and_then(|val| val.as_bool())
.unwrap_or_else(|| {
old_session_settings
.get("gui_collapsed")
.unwrap()
.as_bool()
.unwrap()
});
entries.insert("gui_collapsed".into(), json::Value::Bool(collapsed_state));
}
entries
}),
@ -392,6 +397,12 @@ fn extrapolate_session_settings_from_session_settings(
}
SchemaNode::Array(array_schema) => {
let gui_collapsed = new_session_settings
.get("gui_collapsed")
.cloned()
.filter(|new_key| new_key.is_string())
.unwrap_or_else(|| old_session_settings["gui_collapsed"].clone());
let array_vec = (0..array_schema.len())
.map(|idx| {
new_session_settings
@ -399,13 +410,23 @@ fn extrapolate_session_settings_from_session_settings(
.cloned()
.unwrap_or_else(|| old_session_settings[idx].clone())
})
.collect();
json::Value::Array(array_vec)
.collect::<Vec<_>>();
json::json!({
"gui_collapsed": gui_collapsed,
"content": array_vec
})
}
SchemaNode::Vector {
default_element, ..
} => {
let gui_collapsed = new_session_settings
.get("gui_collapsed")
.cloned()
.filter(|new_key| new_key.is_string())
.unwrap_or_else(|| old_session_settings["gui_collapsed"].clone());
let element_json = new_session_settings
.get("element")
.map(|new_element_json| {
@ -427,12 +448,19 @@ fn extrapolate_session_settings_from_session_settings(
.unwrap_or_else(|| old_session_settings["content"].clone());
json::json!({
"gui_collapsed": gui_collapsed,
"element": element_json,
"content": content_json
})
}
SchemaNode::Dictionary { default_value, .. } => {
let gui_collapsed = new_session_settings
.get("gui_collapsed")
.cloned()
.filter(|new_key| new_key.is_string())
.unwrap_or_else(|| old_session_settings["gui_collapsed"].clone());
let key_json = new_session_settings
.get("key")
.cloned()
@ -457,6 +485,7 @@ fn extrapolate_session_settings_from_session_settings(
.unwrap_or_else(|| old_session_settings["content"].clone());
json::json!({
"gui_collapsed": gui_collapsed,
"key": key_json,
"value": value_json,
"content": content_json
@ -472,7 +501,7 @@ fn json_session_settings_to_settings(
schema: &SchemaNode,
) -> json::Value {
match schema {
SchemaNode::Section(entries) => json::Value::Object(
SchemaNode::Section { entries, .. } => json::Value::Object(
entries
.iter()
.map(|named_entry| {
@ -531,7 +560,10 @@ fn json_session_settings_to_settings(
.iter()
.enumerate()
.map(|(idx, element_schema)| {
json_session_settings_to_settings(&session_settings[idx], element_schema)
json_session_settings_to_settings(
&session_settings["content"][idx],
element_schema,
)
})
.collect(),
),
@ -600,7 +632,6 @@ mod tests {
fn test_session_extrapolation_diff() {
let input_json_string = r#"{
"session_settings": {
"gui_collapsed": false,
"fjdshfks": false,
"video": {
"preferred_fps": 60.0

View File

@ -2,7 +2,8 @@ use alvr_common::{LogSeverity, LogSeverityDefault, LogSeverityDefaultVariant};
use bytemuck::{Pod, Zeroable};
use serde::{Deserialize, Serialize};
use settings_schema::{
DictionaryDefault, OptionalDefault, SettingsSchema, Switch, SwitchDefault, VectorDefault,
ArrayDefault, DictionaryDefault, OptionalDefault, SettingsSchema, Switch, SwitchDefault,
VectorDefault,
};
include!(concat!(env!("OUT_DIR"), "/openvr_property_keys.rs"));
@ -11,6 +12,7 @@ include!(concat!(env!("OUT_DIR"), "/openvr_property_keys.rs"));
#[schema(gui = "button_group")]
pub enum FrameSize {
Scale(#[schema(gui(slider(min = 0.25, max = 2.0, step = 0.01)))] f32),
Absolute {
#[schema(gui(slider(min = 32, max = 0x1000, step = 32)))]
width: u32,
@ -87,6 +89,7 @@ pub enum EntropyCoding {
/// Except for preset, the value of these fields is not applied if == -1 (flag)
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct NvencConfig {
#[schema(strings(
help = "P1 is the fastest preset and P7 is the preset that produces better quality. P6 and P7 are too slow to be usable."
@ -137,6 +140,7 @@ Temporal: Helps improve overall encoding quality, very small trade-off in speed.
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct AmfConfig {
#[schema(flag = "steamvr-restart")]
pub quality_preset: EncoderQualityPresetAmd,
@ -167,7 +171,7 @@ pub struct SoftwareEncodingConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct EncoderConfig {
#[schema(strings(help = r#"CBR: Constant BitRate mode. This is recommended.
VBR: Variable BitRate mode. Not commended because it may throw off the adaptive bitrate algorithm. This is only supported on Windows and only with AMD/Nvidia GPUs"#))]
@ -222,6 +226,7 @@ pub struct EncoderLatencyLimiter {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone, PartialEq)]
#[schema(collapsible)]
pub struct DecoderLatencyLimiter {
#[schema(strings(
display_name = "Maximum decoder latency",
@ -252,6 +257,8 @@ pub struct DecoderLatencyLimiter {
pub enum BitrateMode {
#[schema(strings(display_name = "Constant"))]
ConstantMbps(#[schema(gui(slider(min = 5, max = 1000, logarithmic)), suffix = "Mbps")] u64),
#[schema(collapsible)]
Adaptive {
#[schema(strings(
help = "Percentage of network bandwidth to allocate for video transmission"
@ -298,6 +305,7 @@ pub struct BitrateAdaptiveFramerateConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone, PartialEq)]
#[schema(collapsible)]
pub struct BitrateConfig {
#[schema(flag = "real-time")]
pub mode: BitrateMode,
@ -334,6 +342,7 @@ pub enum ClientsideFoveationMode {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct ClientsideFoveation {
pub mode: ClientsideFoveationMode,
@ -343,6 +352,7 @@ pub struct ClientsideFoveation {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct FoveatedRenderingConfig {
#[schema(strings(display_name = "Center region width"))]
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
@ -377,6 +387,7 @@ pub struct FoveatedRenderingConfig {
#[repr(C)]
#[derive(SettingsSchema, Clone, Copy, Serialize, Deserialize, Pod, Zeroable)]
#[schema(collapsible)]
pub struct ColorCorrectionConfig {
#[schema(gui(slider(min = -1.0, max = 1.0, step = 0.01)))]
#[schema(flag = "steamvr-restart")]
@ -410,6 +421,7 @@ pub enum CodecType {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct VideoConfig {
#[schema(strings(help = "You probably don't want to change this"))]
#[schema(flag = "steamvr-restart")]
@ -492,6 +504,7 @@ pub enum CustomAudioDeviceConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct AudioBufferingConfig {
#[schema(strings(display_name = "Average buffering"))]
#[schema(gui(slider(min = 0, max = 200)), suffix = "ms")]
@ -503,6 +516,7 @@ pub struct AudioBufferingConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct GameAudioConfig {
pub device: Option<CustomAudioDeviceConfig>,
pub mute_when_streaming: bool,
@ -531,12 +545,14 @@ pub enum MicrophoneDevicesConfig {
// Note: sample rate is a free parameter for microphone, because both server and client supports
// resampling. In contrary, for game audio, the server does not support resampling.
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct MicrophoneConfig {
pub devices: MicrophoneDevicesConfig,
pub buffering: AudioBufferingConfig,
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct AudioConfig {
#[schema(strings(help = "ALSA is recommended for most PulseAudio or PipeWire-based setups"))]
pub linux_backend: LinuxAudioBackend,
@ -576,6 +592,7 @@ pub enum FaceTrackingSinkConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct FaceTrackingConfig {
pub sources: FaceTrackingSources,
pub sink: FaceTrackingSinkConfig,
@ -602,6 +619,7 @@ pub struct HysteresisThreshold {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct AutomaticButtonMappingConfig {
pub click_threshold: HysteresisThreshold,
pub touch_threshold: HysteresisThreshold,
@ -609,6 +627,7 @@ pub struct AutomaticButtonMappingConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct HapticsConfig {
#[schema(flag = "real-time")]
#[schema(gui(slider(min = 0.0, max = 5.0, step = 0.1)))]
@ -625,6 +644,7 @@ pub struct HapticsConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct ControllersConfig {
#[schema(strings(
help = "Turning this off will make the controllers appear powered off. Reconnect HMD to apply."
@ -698,6 +718,7 @@ pub enum RotationRecenteringMode {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct HeadsetConfig {
#[schema(flag = "steamvr-restart")]
pub emulation_mode: HeadsetEmulationMode,
@ -758,6 +779,7 @@ pub enum SocketBufferSize {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct ConnectionConfig {
#[schema(strings(
help = r#"UDP: Faster, but less stable than TCP. Try this if your network is well optimized and free of interference.
@ -826,6 +848,7 @@ pub struct RawEventsConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct LoggingConfig {
pub client_log_report_level: Switch<LogSeverity>,
#[schema(strings(help = "Write logs into the session_log.txt file."))]
@ -854,6 +877,7 @@ pub enum DriverLaunchAction {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct SteamvrLauncher {
#[schema(strings(
help = r#"This controls the driver registration operations while launching SteamVR.
@ -875,6 +899,7 @@ pub struct RollingVideoFilesConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct CaptureConfig {
#[schema(strings(display_name = "Start video recording at client connection"))]
pub startup_video_recording: bool,
@ -886,6 +911,7 @@ pub struct CaptureConfig {
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
#[schema(collapsible)]
pub struct Patches {
#[schema(strings(help = "AMD users should keep this on. Must be off for Nvidia GPUs!",))]
#[schema(flag = "steamvr-restart")]
@ -910,7 +936,6 @@ pub fn session_settings_default() -> SettingsDefault {
variant: FrameSizeDefaultVariant::Absolute,
Scale: 1.0,
Absolute: FrameSizeAbsoluteDefault {
gui_collapsed: false,
width: 2144,
height: OptionalDefault {
set: false,
@ -924,6 +949,7 @@ pub fn session_settings_default() -> SettingsDefault {
variant: CustomAudioDeviceConfigDefaultVariant::NameSubstring,
};
let default_custom_openvr_props = VectorDefault {
gui_collapsed: true,
element: OPENVR_PROPS_DEFAULT.clone(),
content: vec![],
};
@ -933,7 +959,6 @@ pub fn session_settings_default() -> SettingsDefault {
};
SettingsDefault {
gui_collapsed: false,
video: VideoConfigDefault {
gui_collapsed: false,
adapter_index: 0,
@ -965,7 +990,6 @@ pub fn session_settings_default() -> SettingsDefault {
encoder_latency_limiter: SwitchDefault {
enabled: true,
content: EncoderLatencyLimiterDefault {
gui_collapsed: true,
max_saturation_multiplier: 0.9,
},
},
@ -984,7 +1008,6 @@ pub fn session_settings_default() -> SettingsDefault {
adapt_to_framerate: SwitchDefault {
enabled: true,
content: BitrateAdaptiveFramerateConfigDefault {
gui_collapsed: true,
framerate_reset_threshold_multiplier: 2.0,
},
},
@ -1044,7 +1067,6 @@ pub fn session_settings_default() -> SettingsDefault {
preproc_tor: 7,
},
software: SoftwareEncodingConfigDefault {
gui_collapsed: true,
force_software_encoding: false,
thread_count: 0,
},
@ -1060,6 +1082,7 @@ pub fn session_settings_default() -> SettingsDefault {
}
}
DictionaryDefault {
gui_collapsed: true,
key: "".into(),
value: int32_default(0),
content: vec![
@ -1093,13 +1116,11 @@ pub fn session_settings_default() -> SettingsDefault {
gui_collapsed: true,
mode: ClientsideFoveationModeDefault {
Static: ClientsideFoveationModeStaticDefault {
gui_collapsed: false,
level: ClientsideFoveationLevelDefault {
variant: ClientsideFoveationLevelDefaultVariant::High,
},
},
Dynamic: ClientsideFoveationModeDynamicDefault {
gui_collapsed: false,
max_level: ClientsideFoveationLevelDefault {
variant: ClientsideFoveationLevelDefaultVariant::High,
},
@ -1149,7 +1170,6 @@ pub fn session_settings_default() -> SettingsDefault {
gui_collapsed: true,
devices: MicrophoneDevicesConfigDefault {
Custom: MicrophoneDevicesConfigCustomDefault {
gui_collapsed: false,
source: default_custom_audio_device.clone(),
sink: default_custom_audio_device,
},
@ -1167,7 +1187,6 @@ pub fn session_settings_default() -> SettingsDefault {
gui_collapsed: false,
emulation_mode: HeadsetEmulationModeDefault {
Custom: HeadsetEmulationModeCustomDefault {
gui_collapsed: false,
serial_number: "Unknown".into(),
props: default_custom_openvr_props.clone(),
},
@ -1181,17 +1200,13 @@ pub fn session_settings_default() -> SettingsDefault {
content: FaceTrackingConfigDefault {
gui_collapsed: true,
sources: FaceTrackingSourcesDefault {
gui_collapsed: true,
eye_tracking_fb: true,
face_tracking_fb: true,
eye_expressions_htc: true,
lip_expressions_htc: true,
},
sink: FaceTrackingSinkConfigDefault {
VrchatEyeOsc: FaceTrackingSinkConfigVrchatEyeOscDefault {
gui_collapsed: false,
port: 9000,
},
VrchatEyeOsc: FaceTrackingSinkConfigVrchatEyeOscDefault { port: 9000 },
variant: FaceTrackingSinkConfigDefaultVariant::VrchatEyeOsc,
},
},
@ -1208,12 +1223,10 @@ pub fn session_settings_default() -> SettingsDefault {
button_mapping_config: AutomaticButtonMappingConfigDefault {
gui_collapsed: true,
click_threshold: HysteresisThresholdDefault {
gui_collapsed: false,
value: 0.5,
deviation: 0.05,
},
touch_threshold: HysteresisThresholdDefault {
gui_collapsed: false,
value: 0.1,
deviation: 0.05,
},
@ -1222,10 +1235,22 @@ pub fn session_settings_default() -> SettingsDefault {
steamvr_pipeline_frames: 3.0,
linear_velocity_cutoff: 0.05,
angular_velocity_cutoff: 10.0,
left_controller_position_offset: [0.0, 0.0, -0.11],
left_controller_rotation_offset: [-20.0, 0.0, 0.0],
left_hand_tracking_position_offset: [0.04, -0.02, -0.13],
left_hand_tracking_rotation_offset: [0.0, -45.0, -90.0],
left_controller_position_offset: ArrayDefault {
gui_collapsed: true,
content: [0.0, 0.0, -0.11],
},
left_controller_rotation_offset: ArrayDefault {
gui_collapsed: true,
content: [-20.0, 0.0, 0.0],
},
left_hand_tracking_position_offset: ArrayDefault {
gui_collapsed: true,
content: [0.04, -0.02, -0.13],
},
left_hand_tracking_rotation_offset: ArrayDefault {
gui_collapsed: true,
content: [0.0, -45.0, -90.0],
},
haptics: SwitchDefault {
enabled: true,
content: HapticsConfigDefault {
@ -1238,10 +1263,7 @@ pub fn session_settings_default() -> SettingsDefault {
},
},
position_recentering_mode: PositionRecenteringModeDefault {
Local: PositionRecenteringModeLocalDefault {
gui_collapsed: false,
view_height: 1.5,
},
Local: PositionRecenteringModeLocalDefault { view_height: 1.5 },
variant: PositionRecenteringModeDefaultVariant::LocalFloor,
},
rotation_recentering_mode: RotationRecenteringModeDefault {
@ -1256,7 +1278,6 @@ pub fn session_settings_default() -> SettingsDefault {
client_discovery: SwitchDefault {
enabled: true,
content: DiscoveryConfigDefault {
gui_collapsed: true,
auto_trust_clients: cfg!(debug_assertions),
},
},
@ -1297,7 +1318,6 @@ pub fn session_settings_default() -> SettingsDefault {
show_raw_events: SwitchDefault {
enabled: false,
content: RawEventsConfigDefault {
gui_collapsed: true,
hide_spammy_events: false,
},
},
@ -1315,10 +1335,7 @@ pub fn session_settings_default() -> SettingsDefault {
startup_video_recording: false,
rolling_video_files: SwitchDefault {
enabled: false,
content: RollingVideoFilesConfigDefault {
gui_collapsed: false,
duration_s: 5,
},
content: RollingVideoFilesConfigDefault { duration_s: 5 },
},
capture_frame_dir: if !cfg!(target_os = "linux") {
"/tmp".into()