Skip to main content

nice_plug_egui/widgets/
generic_ui.rs

1//! A simple generic UI widget that renders all parameters in a [`Params`] object as a scrollable
2//! list of sliders and labels.
3
4use std::sync::Arc;
5
6use egui::{self, TextStyle, Ui, Vec2};
7use nice_plug_core::{
8    context::gui::ParamSetter,
9    params::{Param, ParamFlags, Params, internals::ParamPtr},
10};
11
12use super::ParamSlider;
13
14/// A widget that can be used to create a generic UI with. This is used in conjuction with empty
15/// structs to emulate existential types.
16pub trait ParamWidget {
17    fn add_widget<P: Param>(&self, ui: &mut Ui, param: &P, setter: &ParamSetter);
18
19    /// The same as [`add_widget()`][Self::add_widget()], but for a `ParamPtr`.
20    ///
21    /// # Safety
22    ///
23    /// Undefined behavior of the `ParamPtr` does not point to a valid parameter.
24    unsafe fn add_widget_raw(&self, ui: &mut Ui, param: &ParamPtr, setter: &ParamSetter) {
25        unsafe {
26            match param {
27                ParamPtr::FloatParam(p) => self.add_widget(ui, &**p, setter),
28                ParamPtr::IntParam(p) => self.add_widget(ui, &**p, setter),
29                ParamPtr::BoolParam(p) => self.add_widget(ui, &**p, setter),
30                ParamPtr::EnumParam(p) => self.add_widget(ui, &**p, setter),
31            }
32        }
33    }
34}
35
36/// Create a generic UI using [`ParamSlider`]s.
37pub struct GenericSlider;
38
39/// Create a scrollable generic UI using the specified widget. Takes up all the remaining vertical
40/// space.
41pub fn create(
42    ui: &mut Ui,
43    params: Arc<impl Params>,
44    setter: &ParamSetter,
45    widget: impl ParamWidget,
46) {
47    let padding = Vec2::splat(ui.text_style_height(&TextStyle::Body) * 0.2);
48    egui::containers::ScrollArea::vertical()
49        // Take up all remaining space, use a wrapper container to adjust how much space that is
50        .auto_shrink([false, false])
51        .show(ui, |ui| {
52            let mut first_widget = true;
53            for (_, param_ptr, _) in params.param_map().into_iter() {
54                let flags = unsafe { param_ptr.flags() };
55                if flags.contains(ParamFlags::HIDE_IN_GENERIC_UI) {
56                    continue;
57                }
58
59                // This list looks weird without a little padding
60                if !first_widget {
61                    ui.allocate_space(padding);
62                }
63
64                ui.label(unsafe { param_ptr.name() });
65                unsafe { widget.add_widget_raw(ui, &param_ptr, setter) };
66
67                first_widget = false;
68            }
69        });
70}
71
72impl ParamWidget for GenericSlider {
73    fn add_widget<P: Param>(&self, ui: &mut Ui, param: &P, setter: &ParamSetter) {
74        // Make these sliders a bit wider, else they look a bit odd
75        ui.add(ParamSlider::for_param(param, setter).with_width(100.0));
76    }
77}