feat(rapier_testbed): autosave testbed configuration + add support for per-example settings (#799)
* feat(rapier_testbed): autosave testbed configuration + add support for per-example parameters * feat(rapier_testbed): also save the camera position * feat(rapier_testbed): improve ergonomics of example-specific settings * chore: cargo fmt * chore(rapier_testbed): small UI ergonomics improvement * chore(rapier_testbed): clippy fixes
This commit is contained in:
106
src_testbed/settings.rs
Normal file
106
src_testbed/settings.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SettingValue {
|
||||
U32 {
|
||||
value: u32,
|
||||
range: RangeInclusive<u32>,
|
||||
},
|
||||
F32 {
|
||||
value: f32,
|
||||
range: RangeInclusive<f32>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ExampleSettings {
|
||||
values: HashMap<String, SettingValue>,
|
||||
}
|
||||
|
||||
impl ExampleSettings {
|
||||
pub fn clear(&mut self) {
|
||||
self.values.clear();
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.values.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&String, &mut SettingValue)> {
|
||||
self.values.iter_mut()
|
||||
}
|
||||
|
||||
pub fn set_u32(&mut self, key: &str, value: u32, range: RangeInclusive<u32>) {
|
||||
self.values
|
||||
.insert(key.to_string(), SettingValue::U32 { value, range });
|
||||
}
|
||||
|
||||
pub fn get_or_set_u32(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
default: u32,
|
||||
range: RangeInclusive<u32>,
|
||||
) -> u32 {
|
||||
let to_insert = SettingValue::U32 {
|
||||
value: default,
|
||||
range,
|
||||
};
|
||||
let entry = self
|
||||
.values
|
||||
.entry(key.to_string())
|
||||
.or_insert(to_insert.clone());
|
||||
match entry {
|
||||
SettingValue::U32 { value, .. } => *value,
|
||||
_ => {
|
||||
// The entry doesn’t have the right type. Overwrite with the new value.
|
||||
*entry = to_insert;
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_f32(&mut self, key: &str, value: f32, range: RangeInclusive<f32>) {
|
||||
self.values
|
||||
.insert(key.to_string(), SettingValue::F32 { value, range });
|
||||
}
|
||||
|
||||
pub fn get_or_set_f32(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: f32,
|
||||
range: RangeInclusive<f32>,
|
||||
) -> f32 {
|
||||
let to_insert = SettingValue::F32 { value, range };
|
||||
let entry = self
|
||||
.values
|
||||
.entry(key.to_string())
|
||||
.or_insert(to_insert.clone());
|
||||
match entry {
|
||||
SettingValue::F32 { value, .. } => *value,
|
||||
_ => {
|
||||
// The entry doesn’t have the right type. Overwrite with the new value.
|
||||
*entry = to_insert;
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_u32(&self, key: &'static str) -> Option<u32> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::U32 { value, .. } => Some(*value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_f32(&self, key: &'static str) -> Option<f32> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::F32 { value, .. } => Some(*value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user