Add a generic UI widget for vizia
This only needs a scroll bar.
This commit is contained in:
parent
4e09491dd5
commit
10bd7f46ea
|
@ -1,5 +1,24 @@
|
||||||
/* Default styling for the widgets included in nih_plug_vizia */
|
/* Default styling for the widgets included in nih_plug_vizia */
|
||||||
|
|
||||||
|
generic-ui {
|
||||||
|
child-space: 10px;
|
||||||
|
col-between: 5px;
|
||||||
|
layout-type: column;
|
||||||
|
row-between: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
generic-ui .row {
|
||||||
|
col-between: 6px;
|
||||||
|
layout-type: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
generic-ui .label {
|
||||||
|
left: 1s;
|
||||||
|
top: 1s;
|
||||||
|
bottom: 1s;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
param-slider {
|
param-slider {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
|
|
|
@ -11,10 +11,12 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use vizia::{Context, Model};
|
use vizia::{Context, Model};
|
||||||
|
|
||||||
|
mod generic_ui;
|
||||||
mod param_slider;
|
mod param_slider;
|
||||||
mod peak_meter;
|
mod peak_meter;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
pub use generic_ui::GenericUI;
|
||||||
pub use param_slider::{ParamSlider, ParamSliderExt, ParamSliderStyle};
|
pub use param_slider::{ParamSlider, ParamSliderExt, ParamSliderStyle};
|
||||||
pub use peak_meter::PeakMeter;
|
pub use peak_meter::PeakMeter;
|
||||||
|
|
||||||
|
|
85
nih_plug_vizia/src/widgets/generic_ui.rs
Normal file
85
nih_plug_vizia/src/widgets/generic_ui.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
//! Generic UIs for NIH-plug using VIZIA.
|
||||||
|
|
||||||
|
use std::{ops::Deref, pin::Pin};
|
||||||
|
|
||||||
|
use nih_plug::param::internals::ParamPtr;
|
||||||
|
use nih_plug::prelude::Params;
|
||||||
|
use vizia::*;
|
||||||
|
|
||||||
|
use super::{ParamSlider, ParamSliderExt, ParamSliderStyle};
|
||||||
|
|
||||||
|
/// Shows a generic UI for a [`Params`] object. For additional flexibility you can either use the
|
||||||
|
/// [`new()`][`Self::new()`] method to have the generic UI decide which widget to use for your
|
||||||
|
/// parmaeters, or you can use the [`new_custom()`][`Self::new_custom()`] method to determine this
|
||||||
|
/// yourself.
|
||||||
|
pub struct GenericUI;
|
||||||
|
|
||||||
|
impl GenericUI {
|
||||||
|
/// Creates a new [`GenericUi`] for all provided parameters. Use
|
||||||
|
/// [`new_custom()`][Self::new_custom()] to decide which widget gets used for each parameter.
|
||||||
|
pub fn new<L, PsPtr, Ps>(cx: &mut Context, params: L) -> Handle<'_, GenericUI>
|
||||||
|
where
|
||||||
|
L: Lens<Target = Pin<PsPtr>> + Copy,
|
||||||
|
PsPtr: 'static + Deref<Target = Ps>,
|
||||||
|
Ps: Params,
|
||||||
|
{
|
||||||
|
// Basic styling is done in the `theme.css` style sheet
|
||||||
|
// TODO: Scrolling
|
||||||
|
Self::new_custom(cx, params, |cx, param_ptr| {
|
||||||
|
HStack::new(cx, |cx| {
|
||||||
|
// Align this on the right
|
||||||
|
Label::new(cx, unsafe { param_ptr.name() }).class("label");
|
||||||
|
|
||||||
|
// TODO: Come up with a less hacky way to iterate over the mapping like this while
|
||||||
|
// keeping the clean interface on the `ParamSlider` widget
|
||||||
|
unsafe {
|
||||||
|
match param_ptr {
|
||||||
|
ParamPtr::FloatParam(p) => ParamSlider::new(cx, params, move |_| &*p),
|
||||||
|
ParamPtr::IntParam(p) => ParamSlider::new(cx, params, move |_| &*p),
|
||||||
|
ParamPtr::BoolParam(p) => ParamSlider::new(cx, params, move |_| &*p),
|
||||||
|
ParamPtr::EnumParam(p) => ParamSlider::new(cx, params, move |_| &*p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.set_style(match unsafe { param_ptr.step_count() } {
|
||||||
|
Some(step_count) if step_count <= 3 => ParamSliderStyle::CurrentStepLabeled,
|
||||||
|
Some(step_count) if step_count <= 64 => ParamSliderStyle::CurrentStep,
|
||||||
|
Some(_) => ParamSliderStyle::FromLeft,
|
||||||
|
// This is already the default, but continuous parameters should be drawn from
|
||||||
|
// the center if the default is also centered, or from the left if it is not
|
||||||
|
None => ParamSliderStyle::Centered,
|
||||||
|
})
|
||||||
|
.class("widget");
|
||||||
|
})
|
||||||
|
.class("row");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`GenericUi`] for all provided parameters using a custom closure that receives
|
||||||
|
/// a function that should draw some widget for each parameter.
|
||||||
|
pub fn new_custom<L, PsPtr, Ps>(
|
||||||
|
cx: &mut Context,
|
||||||
|
params: L,
|
||||||
|
mut make_widget: impl FnMut(&mut Context, ParamPtr),
|
||||||
|
) -> Handle<'_, GenericUI>
|
||||||
|
where
|
||||||
|
L: Lens<Target = Pin<PsPtr>> + Copy,
|
||||||
|
PsPtr: 'static + Deref<Target = Ps>,
|
||||||
|
Ps: Params,
|
||||||
|
{
|
||||||
|
// Basic styling is done in the `theme.css` style sheet
|
||||||
|
Self.build2(cx, |cx| {
|
||||||
|
// Rust does not have existential types, otherwise we could have passed functions that
|
||||||
|
// map `params` to some `impl Param` and everything would have been a lot neater
|
||||||
|
let param_map = &*params.map(|params| params.as_ref().param_map()).get(cx);
|
||||||
|
for (_, param_ptr, _) in param_map {
|
||||||
|
make_widget(cx, *param_ptr);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for GenericUI {
|
||||||
|
fn element(&self) -> Option<String> {
|
||||||
|
Some(String::from("generic-ui"))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue