use std::collections::HashMap;
use std::sync::Arc;
use truce_core::editor::{PluginContext, PluginContextReadF64};
use truce_params::Params;
pub struct ParamCache<P: Params + ?Sized> {
params: Arc<P>,
ids: Vec<u32>,
values: HashMap<u32, f64>,
labels: HashMap<u32, String>,
meters: HashMap<u32, f32>,
font: iced::Font,
}
impl<P: Params + ?Sized> ParamCache<P> {
pub fn new(params: Arc<P>) -> Self {
let infos = params.param_infos();
let ids: Vec<u32> = infos.iter().map(|i| i.id).collect();
let mut values = HashMap::with_capacity(ids.len());
let mut labels = HashMap::with_capacity(ids.len());
for info in &infos {
if let Some(v) = params.get_normalized(info.id) {
values.insert(info.id, v);
}
let plain = params.get_plain(info.id).unwrap_or(0.0);
if let Some(label) = params.format_value(info.id, plain) {
labels.insert(info.id, label);
}
}
Self {
params,
ids,
values,
labels,
meters: HashMap::new(),
font: iced::Font::DEFAULT,
}
}
pub fn get(&self, id: impl Into<u32>) -> f64 {
self.values.get(&id.into()).copied().unwrap_or(0.0)
}
pub fn get_plain(&self, id: impl Into<u32>) -> f64 {
self.params.get_plain(id.into()).unwrap_or(0.0)
}
pub fn label(&self, id: impl Into<u32>) -> &str {
self.labels
.get(&id.into())
.map_or("", std::string::String::as_str)
}
pub fn meter(&self, id: impl Into<u32>) -> f32 {
self.meters.get(&id.into()).copied().unwrap_or(0.0)
}
#[must_use]
pub fn font(&self) -> iced::Font {
self.font
}
pub fn set_font(&mut self, font: iced::Font) {
self.font = font;
}
#[must_use]
pub fn params(&self) -> &P {
&self.params
}
pub(crate) fn sync<Q: ?Sized>(&mut self, ctx: &PluginContext<Q>) -> Vec<u32> {
let mut changed = Vec::new();
for &id in &self.ids {
let new_val = ctx.get_param(id);
let old_val = self.values.get(&id).copied().unwrap_or(-1.0);
if (new_val - old_val).abs() > 1e-10 {
self.values.insert(id, new_val);
let slot = self.labels.entry(id).or_default();
ctx.format_param_into(id, slot);
changed.push(id);
}
}
changed
}
pub(crate) fn sync_meters<Q: ?Sized>(&mut self, ctx: &PluginContext<Q>, meter_ids: &[u32]) {
for &id in meter_ids {
self.meters.insert(id, ctx.get_meter(id));
}
}
}