An adapter for using Slint GUIs with nice-plug audio plugins. It uses baseview for windowing and FemtoVG (OpenGL) for rendering.
I took the liberty of creating a simple gain knob VST example project using nice-plug and Nice-Plug-Slint.
please see that here: Gain Knob
Add the dependency:
[dependencies]
nice_plug_slint = { git = "https://github.com/aidan729/nice-plug-slint" }In your plugin:
use nice_plug_slint::{SlintEditor, SlintEditorState};
use std::sync::Arc;
#[derive(Params)]
struct MyParams {
#[persist = "editor-state"]
editor_state: Arc<SlintEditorState>,
}
impl Default for MyParams {
fn default() -> Self {
Self {
editor_state: Arc::new(SlintEditorState::new(400, 300)),
}
}
}
fn editor(&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
Some(Box::new(
SlintEditor::new(params.editor_state.clone(), || gui::AppWindow::new())
.with_setup({
let params = self.params.clone();
move |handler, _window| {
let component = handler.component();
let context = handler.context().clone();
// Register UI -> plugin callbacks once when the window opens
component.on_gain_changed(move |value| {
let setter = ParamSetter::new(&*context);
setter.begin_set_parameter(¶ms.gain);
setter.set_parameter_normalized(¶ms.gain, value);
setter.end_set_parameter(¶ms.gain);
});
}
})
.with_event_loop({
let params = self.params.clone();
move |handler, _setter, _window| {
// Push parameter values to the UI each frame
handler.component().set_gain(params.gain.unmodulated_normalized_value());
}
}),
))
}Holds the window size. Construct with Arc::new(SlintEditorState::new(w, h)). It should be stored on your params struct with the #[persist] attribute to persist the state across sessions.
Created with SlintEditor::new(state, factory).
The first argument is the editor state which comes from the params struct. See SlintEditorState.
The second argument is the factory closure which is called each time the window is opened.
.with_setup(handler)- called once when the window opens, before the event loop starts. Use this to register UI → plugin callbacks..with_event_loop(handler)- called every frame. Use this to push parameter values to the UI (plugin → UI).
Passed to the event loop handler. Gives you access to:
.component()- the Slint component.window()- the Slint window.context()- nice-plug'sGuiContextfor parameter operations.resize(window, width, height)- resize the window programmatically.queue_resize(width, height)- use this from inside Slint callbacks instead of callingresizedirectly, since you won't have the&mut Windowhandy
// Resizing from a Slint callback
let pending = handler.pending_resizes().clone();
component.on_resize(move || {
pending.borrow_mut().push((800, 600));
});See docs/ARCHITECTURE.md for more detail on how the Slint/baseview bridge works internally.
ISC