diff --git a/src/param.rs b/src/param.rs index 82cb459e..e1dea1ec 100644 --- a/src/param.rs +++ b/src/param.rs @@ -30,9 +30,22 @@ pub trait Param: Display { /// Get the unit label for this parameter, if any. 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; + /// 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. fn plain_value(&self) -> Self::Plain; diff --git a/src/param/boolean.rs b/src/param/boolean.rs index 6fd08302..0a354c45 100644 --- a/src/param/boolean.rs +++ b/src/param/boolean.rs @@ -66,6 +66,14 @@ impl Param for BoolParam { 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 { self.value } diff --git a/src/param/enums.rs b/src/param/enums.rs index e3120634..4e184f20 100644 --- a/src/param/enums.rs +++ b/src/param/enums.rs @@ -113,6 +113,14 @@ impl Param for EnumParam { 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 { T::from_index(self.inner.plain_value() as usize) } @@ -174,6 +182,14 @@ impl Param for EnumParamInner { 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 { self.inner.plain_value() } diff --git a/src/param/float.rs b/src/param/float.rs index 43127485..3e27feeb 100644 --- a/src/param/float.rs +++ b/src/param/float.rs @@ -107,6 +107,29 @@ impl Param for FloatParam { 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 { self.value } diff --git a/src/param/integer.rs b/src/param/integer.rs index a2f8237a..d7e913c3 100644 --- a/src/param/integer.rs +++ b/src/param/integer.rs @@ -95,7 +95,15 @@ impl Param for IntParam { } fn step_count(&self) -> Option { - 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 { diff --git a/src/param/range.rs b/src/param/range.rs index d09cc546..91a17142 100644 --- a/src/param/range.rs +++ b/src/param/range.rs @@ -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. pub fn snap_to_step(&self, value: f32, step_size: f32) -> f32 { 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. - pub fn step_count(&self) -> Option { + /// The minimum value in this range. + pub fn min(&self) -> i32 { 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, } } }