1
0
Fork 0

Add stepping functions to Param

This can be useful for GUI widgets.
This commit is contained in:
Robbert van der Helm 2022-03-19 16:06:20 +01:00
parent 629619256e
commit d9330628c0
6 changed files with 105 additions and 5 deletions

View file

@ -30,9 +30,22 @@ pub trait Param: Display {
/// Get the unit label for this parameter, if any. /// Get the unit label for this parameter, if any.
fn unit(&self) -> &'static str; fn unit(&self) -> &'static str;
/// Get the number of steps for this paramter, if it is stepped. Used for the host's generic UI. /// Get the number of steps for this paramter, if it is discrete. Used for the host's generic
/// UI.
fn step_count(&self) -> Option<usize>; fn step_count(&self) -> Option<usize>;
/// Return the previous step from a specific value for this parameter. This can be the same as
/// `from` if the value is at the start of its range. This is mainly used for scroll wheel
/// interaction in plugin GUIs. When the parameter is not discrete then a step should cover one
/// hundredth of the normalized range instead.
fn previous_step(&self, from: Self::Plain) -> Self::Plain;
/// Return the next step from a specific value for this parameter. This can be the same as
/// `from` if the value is at the end of its range. This is mainly used for scroll wheel
/// interaction in plugin GUIs. When the parameter is not discrete then a step should cover one
/// hundredth of the normalized range instead.
fn next_step(&self, from: Self::Plain) -> Self::Plain;
/// Get the unnormalized value for this parameter. /// Get the unnormalized value for this parameter.
fn plain_value(&self) -> Self::Plain; fn plain_value(&self) -> Self::Plain;

View file

@ -66,6 +66,14 @@ impl Param for BoolParam {
Some(1) Some(1)
} }
fn previous_step(&self, _from: Self::Plain) -> Self::Plain {
false
}
fn next_step(&self, _from: Self::Plain) -> Self::Plain {
true
}
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
} }

View file

@ -113,6 +113,14 @@ impl<T: Enum + PartialEq> Param for EnumParam<T> {
self.inner.step_count() self.inner.step_count()
} }
fn previous_step(&self, from: Self::Plain) -> Self::Plain {
T::from_index(self.inner.previous_step(T::to_index(from) as i32) as usize)
}
fn next_step(&self, from: Self::Plain) -> Self::Plain {
T::from_index(self.inner.next_step(T::to_index(from) as i32) as usize)
}
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
T::from_index(self.inner.plain_value() as usize) T::from_index(self.inner.plain_value() as usize)
} }
@ -174,6 +182,14 @@ impl Param for EnumParamInner {
Some(self.len() - 1) Some(self.len() - 1)
} }
fn previous_step(&self, from: Self::Plain) -> Self::Plain {
self.inner.previous_step(from)
}
fn next_step(&self, from: Self::Plain) -> Self::Plain {
self.inner.next_step(from)
}
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.inner.plain_value() self.inner.plain_value()
} }

View file

@ -107,6 +107,29 @@ impl Param for FloatParam {
None None
} }
fn previous_step(&self, from: Self::Plain) -> Self::Plain {
// This one's slightly more involved. We'll split the normalized range up into 100 segments,
// but if `self.step_size` is set then we'll use that. Ideally we might want to split the
// range up into at most 100 segments, falling back to the step size if the total number of
// steps would be smaller than that, but since ranges can be nonlienar that's a bit
// difficult to pull off.
// TODO: At some point, implement the above mentioned step size quantization
match self.step_size {
Some(step_size) => from - step_size,
None => self.preview_plain(self.preview_normalized(from) - 0.01),
}
.clamp(self.range.min(), self.range.max())
}
fn next_step(&self, from: Self::Plain) -> Self::Plain {
// See above
match self.step_size {
Some(step_size) => from + step_size,
None => self.preview_plain(self.preview_normalized(from) + 0.01),
}
.clamp(self.range.min(), self.range.max())
}
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
} }

View file

@ -95,7 +95,15 @@ impl Param for IntParam {
} }
fn step_count(&self) -> Option<usize> { fn step_count(&self) -> Option<usize> {
self.range.step_count() Some(self.range.step_count())
}
fn previous_step(&self, from: Self::Plain) -> Self::Plain {
(from - 1).clamp(self.range.min(), self.range.max())
}
fn next_step(&self, from: Self::Plain) -> Self::Plain {
(from + 1).clamp(self.range.min(), self.range.max())
} }
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {

View file

@ -118,6 +118,24 @@ impl FloatRange {
} }
} }
/// The minimum value in this range.
pub fn min(&self) -> f32 {
match self {
FloatRange::Linear { min, .. }
| FloatRange::Skewed { min, .. }
| FloatRange::SymmetricalSkewed { min, .. } => *min,
}
}
/// The maximum value in this range.
pub fn max(&self) -> f32 {
match self {
FloatRange::Linear { max, .. }
| FloatRange::Skewed { max, .. }
| FloatRange::SymmetricalSkewed { max, .. } => *max,
}
}
/// Snap a vlue to a step size, clamping to the minimum and maximum value of the range. /// Snap a vlue to a step size, clamping to the minimum and maximum value of the range.
pub fn snap_to_step(&self, value: f32, step_size: f32) -> f32 { pub fn snap_to_step(&self, value: f32, step_size: f32) -> f32 {
let (min, max) = match &self { let (min, max) = match &self {
@ -149,10 +167,24 @@ impl IntRange {
} }
} }
/// The number of steps in this range, if it is stepped. Used for the host's generic UI. /// The minimum value in this range.
pub fn step_count(&self) -> Option<usize> { pub fn min(&self) -> i32 {
match self { match self {
IntRange::Linear { min, max } => Some((max - min) as usize), IntRange::Linear { min, .. } => *min,
}
}
/// The maximum value in this range.
pub fn max(&self) -> i32 {
match self {
IntRange::Linear { max, .. } => *max,
}
}
/// The number of steps in this range. Used for the host's generic UI.
pub fn step_count(&self) -> usize {
match self {
IntRange::Linear { min, max } => (max - min) as usize,
} }
} }
} }