1
0
Fork 0

Move BoolParam to its own module

This commit is contained in:
Robbert van der Helm 2022-02-14 14:27:40 +01:00
parent 287576d064
commit 5a26756765
2 changed files with 171 additions and 163 deletions

View file

@ -3,17 +3,18 @@
//! example. //! example.
use std::fmt::Display; use std::fmt::Display;
use std::sync::Arc;
use self::range::Range; use self::range::Range;
// Parameter types // Parameter types
mod boolean;
mod plain; mod plain;
pub mod internals; pub mod internals;
pub mod range; pub mod range;
pub mod smoothing; pub mod smoothing;
pub use boolean::BoolParam;
pub use plain::{FloatParam, IntParam}; pub use plain::{FloatParam, IntParam};
// Re-export for the [EnumParam] // Re-export for the [EnumParam]
@ -75,28 +76,6 @@ pub trait Param: Display {
fn as_ptr(&self) -> internals::ParamPtr; fn as_ptr(&self) -> internals::ParamPtr;
} }
/// A simple boolean parmaeter.
#[repr(C, align(4))]
pub struct BoolParam {
/// The field's current, normalized value. Should be initialized with the default value.
pub value: bool,
/// Optional callback for listening to value changes. The argument passed to this function is
/// the parameter's new value. This should not do anything expensive as it may be called
/// multiple times in rapid succession, and it can be run from both the GUI and the audio
/// thread.
pub value_changed: Option<Arc<dyn Fn(bool) + Send + Sync>>,
/// The parameter's human readable display name.
pub name: &'static str,
/// Optional custom conversion function from a boolean value to a string.
pub value_to_string: Option<Arc<dyn Fn(bool) -> String + Send + Sync>>,
/// Optional custom conversion function from a string to a boolean value. If the string cannot
/// be parsed, then this should return a `None`. If this happens while the parameter is being
/// updated then the update will be canceled.
pub string_to_value: Option<Arc<dyn Fn(&str) -> Option<bool> + Send + Sync>>,
}
/// An [IntParam]-backed categorical parameter that allows convenient conversion to and from a /// An [IntParam]-backed categorical parameter that allows convenient conversion to and from a
/// simple enum. This enum must derive the re-exported [EnumIter] and [EnumMessage] and [Display] /// simple enum. This enum must derive the re-exported [EnumIter] and [EnumMessage] and [Display]
/// traits. You can use the `#[strum(message = "Foo Bar")]` to override the name of the variant. /// traits. You can use the `#[strum(message = "Foo Bar")]` to override the name of the variant.
@ -112,19 +91,6 @@ pub struct EnumParam<T: EnumIter + EnumMessage + Eq + Copy + Display> {
variants: Vec<(T, String)>, variants: Vec<(T, String)>,
} }
#[allow(clippy::derivable_impls)]
impl Default for BoolParam {
fn default() -> Self {
Self {
value: false,
value_changed: None,
name: "",
value_to_string: None,
string_to_value: None,
}
}
}
impl<T: EnumIter + EnumMessage + Eq + Copy + Display + Default> Default for EnumParam<T> { impl<T: EnumIter + EnumMessage + Eq + Copy + Display + Default> Default for EnumParam<T> {
fn default() -> Self { fn default() -> Self {
let variants: Vec<_> = Self::build_variants(); let variants: Vec<_> = Self::build_variants();
@ -147,82 +113,6 @@ impl<T: EnumIter + EnumMessage + Eq + Copy + Display + Default> Default for Enum
} }
} }
impl Param for BoolParam {
type Plain = bool;
fn update_smoother(&mut self, _sample_rate: f32, _init: bool) {
// Can't really smooth a binary parameter now can you
}
fn set_from_string(&mut self, string: &str) -> bool {
let value = match &self.string_to_value {
Some(f) => f(string),
None => Some(string.eq_ignore_ascii_case("true") || string.eq_ignore_ascii_case("on")),
};
match value {
Some(plain) => {
self.set_plain_value(plain);
true
}
None => false,
}
}
fn plain_value(&self) -> Self::Plain {
self.value
}
fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain;
if let Some(f) = &self.value_changed {
f(plain);
}
}
fn normalized_value(&self) -> f32 {
self.preview_normalized(self.value)
}
fn set_normalized_value(&mut self, normalized: f32) {
self.set_plain_value(self.preview_plain(normalized));
}
fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String {
let value = self.preview_plain(normalized);
match (value, &self.value_to_string) {
(v, Some(f)) => f(v),
(true, None) => String::from("On"),
(false, None) => String::from("Off"),
}
}
fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
let value = match &self.string_to_value {
Some(f) => f(string),
None => Some(string.eq_ignore_ascii_case("true") || string.eq_ignore_ascii_case("on")),
}?;
Some(self.preview_normalized(value))
}
fn preview_normalized(&self, plain: Self::Plain) -> f32 {
if plain {
1.0
} else {
0.0
}
}
fn preview_plain(&self, normalized: f32) -> Self::Plain {
normalized > 0.5
}
fn as_ptr(&self) -> internals::ParamPtr {
internals::ParamPtr::BoolParam(self as *const BoolParam as *mut BoolParam)
}
}
impl<T: EnumIter + EnumMessage + Eq + Copy + Display> Param for EnumParam<T> { impl<T: EnumIter + EnumMessage + Eq + Copy + Display> Param for EnumParam<T> {
type Plain = T; type Plain = T;
@ -287,63 +177,12 @@ impl<T: EnumIter + EnumMessage + Eq + Copy + Display> Param for EnumParam<T> {
} }
} }
impl Display for BoolParam {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (self.value, &self.value_to_string) {
(v, Some(func)) => write!(f, "{}", func(v)),
(true, None) => write!(f, "On"),
(false, None) => write!(f, "Off"),
}
}
}
impl<T: EnumIter + EnumMessage + Eq + Copy + Display> Display for EnumParam<T> { impl<T: EnumIter + EnumMessage + Eq + Copy + Display> Display for EnumParam<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.variants[self.inner.plain_value() as usize].1) write!(f, "{}", self.variants[self.inner.plain_value() as usize].1)
} }
} }
impl BoolParam {
/// Build a new [Self]. Use the other associated functions to modify the behavior of the
/// parameter.
pub fn new(name: &'static str, default: bool) -> Self {
Self {
value: default,
name,
..Default::default()
}
}
/// Run a callback whenever this parameter's value changes. The argument passed to this function
/// is the parameter's new value. This should not do anything expensive as it may be called
/// multiple times in rapid succession, and it can be run from both the GUI and the audio
/// thread.
pub fn with_callback(mut self, callback: Arc<dyn Fn(bool) + Send + Sync>) -> Self {
self.value_changed = Some(callback);
self
}
/// Use a custom conversion function to convert the boolean value to a string.
pub fn with_value_to_string(
mut self,
callback: Arc<dyn Fn(bool) -> String + Send + Sync>,
) -> Self {
self.value_to_string = Some(callback);
self
}
/// Use a custom conversion function to convert from a string to a boolean value. If the string
/// cannot be parsed, then this should return a `None`. If this happens while the parameter is
/// being updated then the update will be canceled.
pub fn with_string_to_value(
mut self,
callback: Arc<dyn Fn(&str) -> Option<bool> + Send + Sync>,
) -> Self {
self.string_to_value = Some(callback);
self
}
}
impl<T: EnumIter + EnumMessage + Eq + Copy + Display> EnumParam<T> { impl<T: EnumIter + EnumMessage + Eq + Copy + Display> EnumParam<T> {
/// Build a new [Self]. Use the other associated functions to modify the behavior of the /// Build a new [Self]. Use the other associated functions to modify the behavior of the
/// parameter. /// parameter.

169
src/param/boolean.rs Normal file
View file

@ -0,0 +1,169 @@
//! Simple boolean parameters.
use std::fmt::Display;
use std::sync::Arc;
use super::internals::ParamPtr;
use super::Param;
/// A simple boolean parmaeter.
#[repr(C, align(4))]
pub struct BoolParam {
/// The field's current, normalized value. Should be initialized with the default value.
pub value: bool,
/// Optional callback for listening to value changes. The argument passed to this function is
/// the parameter's new value. This should not do anything expensive as it may be called
/// multiple times in rapid succession, and it can be run from both the GUI and the audio
/// thread.
pub value_changed: Option<Arc<dyn Fn(bool) + Send + Sync>>,
/// The parameter's human readable display name.
pub name: &'static str,
/// Optional custom conversion function from a boolean value to a string.
pub value_to_string: Option<Arc<dyn Fn(bool) -> String + Send + Sync>>,
/// Optional custom conversion function from a string to a boolean value. If the string cannot
/// be parsed, then this should return a `None`. If this happens while the parameter is being
/// updated then the update will be canceled.
pub string_to_value: Option<Arc<dyn Fn(&str) -> Option<bool> + Send + Sync>>,
}
#[allow(clippy::derivable_impls)]
impl Default for BoolParam {
fn default() -> Self {
Self {
value: false,
value_changed: None,
name: "",
value_to_string: None,
string_to_value: None,
}
}
}
impl Display for BoolParam {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (self.value, &self.value_to_string) {
(v, Some(func)) => write!(f, "{}", func(v)),
(true, None) => write!(f, "On"),
(false, None) => write!(f, "Off"),
}
}
}
impl Param for BoolParam {
type Plain = bool;
fn update_smoother(&mut self, _sample_rate: f32, _init: bool) {
// Can't really smooth a binary parameter now can you
}
fn set_from_string(&mut self, string: &str) -> bool {
let value = match &self.string_to_value {
Some(f) => f(string),
None => Some(string.eq_ignore_ascii_case("true") || string.eq_ignore_ascii_case("on")),
};
match value {
Some(plain) => {
self.set_plain_value(plain);
true
}
None => false,
}
}
fn plain_value(&self) -> Self::Plain {
self.value
}
fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain;
if let Some(f) = &self.value_changed {
f(plain);
}
}
fn normalized_value(&self) -> f32 {
self.preview_normalized(self.value)
}
fn set_normalized_value(&mut self, normalized: f32) {
self.set_plain_value(self.preview_plain(normalized));
}
fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String {
let value = self.preview_plain(normalized);
match (value, &self.value_to_string) {
(v, Some(f)) => f(v),
(true, None) => String::from("On"),
(false, None) => String::from("Off"),
}
}
fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
let value = match &self.string_to_value {
Some(f) => f(string),
None => Some(string.eq_ignore_ascii_case("true") || string.eq_ignore_ascii_case("on")),
}?;
Some(self.preview_normalized(value))
}
fn preview_normalized(&self, plain: Self::Plain) -> f32 {
if plain {
1.0
} else {
0.0
}
}
fn preview_plain(&self, normalized: f32) -> Self::Plain {
normalized > 0.5
}
fn as_ptr(&self) -> ParamPtr {
ParamPtr::BoolParam(self as *const BoolParam as *mut BoolParam)
}
}
impl BoolParam {
/// Build a new [Self]. Use the other associated functions to modify the behavior of the
/// parameter.
pub fn new(name: &'static str, default: bool) -> Self {
Self {
value: default,
name,
..Default::default()
}
}
/// Run a callback whenever this parameter's value changes. The argument passed to this function
/// is the parameter's new value. This should not do anything expensive as it may be called
/// multiple times in rapid succession, and it can be run from both the GUI and the audio
/// thread.
pub fn with_callback(mut self, callback: Arc<dyn Fn(bool) + Send + Sync>) -> Self {
self.value_changed = Some(callback);
self
}
/// Use a custom conversion function to convert the boolean value to a string.
pub fn with_value_to_string(
mut self,
callback: Arc<dyn Fn(bool) -> String + Send + Sync>,
) -> Self {
self.value_to_string = Some(callback);
self
}
/// Use a custom conversion function to convert from a string to a boolean value. If the string
/// cannot be parsed, then this should return a `None`. If this happens while the parameter is
/// being updated then the update will be canceled.
pub fn with_string_to_value(
mut self,
callback: Arc<dyn Fn(&str) -> Option<bool> + Send + Sync>,
) -> Self {
self.string_to_value = Some(callback);
self
}
}