// Ardura 2023 - Changing the toggle switch from egui demo to work with BoolParams for nih-plug // https://github.com/emilk/egui/blob/master/crates/egui_demo_lib/src/demo/toggle_switch.rs use nih_plug::prelude::{Param, ParamSetter}; use nih_plug_egui::egui::{self, style::WidgetVisuals, Rect, Response, Ui, Widget}; struct SliderRegion<'a, P: Param> { param: &'a P, param_setter: &'a ParamSetter<'a>, } impl<'a, P: Param> SliderRegion<'a, P> { fn new(param: &'a P, param_setter: &'a ParamSetter) -> Self { SliderRegion { param, param_setter, } } // Handle the input for a given response. Returns an f32 containing the normalized value of // the parameter. fn handle_response(&self, ui: &Ui, response: &Response, rect: Rect) -> f32 { let mut value = self.param.modulated_normalized_value(); let how_on; let visuals: WidgetVisuals; // Check if our button is clicked if response.clicked() { if value == 0.0 { self.param_setter.set_parameter_normalized(self.param, 1.0); how_on = ui.ctx().animate_bool(response.id, true); visuals = ui.style().interact_selectable(&response, true); value = 1.0; } else { self.param_setter.set_parameter_normalized(self.param, 0.0); how_on = ui.ctx().animate_bool(response.id, false); visuals = ui.style().interact_selectable(&response, false); value = 0.0; } } else { let temp: bool = if value > 0.0 { true } else { false }; how_on = ui.ctx().animate_bool(response.id, temp); visuals = ui.style().interact_selectable(&response, temp); } // DRAWING let rect = rect.expand(visuals.expansion); let radius = 0.5 * rect.height(); ui.painter() .rect(rect, radius, visuals.bg_fill, visuals.bg_stroke); // Paint the circle, animating it from left to right with `how_on`: let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on); let center = egui::pos2(circle_x, rect.center().y); ui.painter() .circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke); value } } pub struct ToggleSwitch<'a, P: Param> { slider_region: SliderRegion<'a, P>, } impl<'a, P: Param> ToggleSwitch<'a, P> { pub fn for_param(param: &'a P, param_setter: &'a ParamSetter) -> Self { ToggleSwitch { slider_region: SliderRegion::new(param, param_setter), } } } impl<'a, P: Param> Widget for ToggleSwitch<'a, P> { fn ui(self, ui: &mut Ui) -> Response { // Figure out the size to reserve on screen for widget let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0); let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click()); self.slider_region.handle_response(&ui, &response, rect); response } }