use truce_core::buffer::AudioBuffer;
use truce_core::events::EventList;
use truce_core::process::{ProcessContext, ProcessStatus};
use truce_gui::interaction::WidgetRegion;
use truce_gui::render::RenderBackend;
use truce_gui::widgets::WidgetType;
pub trait PluginLogic: Send + 'static {
fn new() -> Self where Self: Sized;
fn reset(&mut self, sample_rate: f64, max_block_size: usize);
fn params_mut(&mut self) -> Option<&mut dyn truce_params::Params> { None }
fn process(
&mut self,
buffer: &mut AudioBuffer,
events: &EventList,
context: &mut ProcessContext,
) -> ProcessStatus;
fn render(&self, _backend: &mut dyn RenderBackend) {}
fn uses_custom_render(&self) -> bool { false }
fn layout(&self) -> truce_gui::layout::GridLayout {
truce_gui::layout::GridLayout::build("", "", 1, 80.0, vec![], vec![])
}
fn hit_test(&self, widgets: &[WidgetRegion], x: f32, y: f32) -> Option<usize> {
default_hit_test(widgets, x, y)
}
fn save_state(&self) -> Vec<u8> { Vec::new() }
fn load_state(&mut self, _data: &[u8]) {}
fn latency(&self) -> u32 { 0 }
fn tail(&self) -> u32 { 0 }
fn custom_editor(&self) -> Option<Box<dyn truce_core::editor::Editor>> { None }
}
pub fn default_hit_test(widgets: &[WidgetRegion], x: f32, y: f32) -> Option<usize> {
for (i, w) in widgets.iter().enumerate() {
if w.widget_type == WidgetType::Meter { continue; }
if w.widget_type == WidgetType::Knob {
let dx = x - w.cx;
let dy = y - w.cy;
if dx * dx + dy * dy <= w.radius * w.radius {
return Some(i);
}
} else if x >= w.x && x <= w.x + w.w && y >= w.y && y <= w.y + w.h {
return Some(i);
}
}
None
}