Finish the drawing for the iced param slider
This commit is contained in:
parent
291abb8bcf
commit
4e9ee27c19
|
@ -1,4 +1,4 @@
|
||||||
//! Utilities for creating these widgets
|
//! Utilities for creating these widgets.
|
||||||
|
|
||||||
use egui::Color32;
|
use egui::Color32;
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ pub fn create_iced_editor<E: IcedEditor>(
|
||||||
/// A plugin editor using `iced`. This wraps around [`Application`] with the only change being that
|
/// A plugin editor using `iced`. This wraps around [`Application`] with the only change being that
|
||||||
/// the usual `new()` function now additionally takes a `Arc<dyn GuiContext>` that the editor can
|
/// the usual `new()` function now additionally takes a `Arc<dyn GuiContext>` that the editor can
|
||||||
/// store to interact with the parameters. The editor should have a `Pin<Arc<impl Params>>` as part
|
/// store to interact with the parameters. The editor should have a `Pin<Arc<impl Params>>` as part
|
||||||
/// of their [`Flags`][Self::Flags] so it can read the current parameter values. See [`Application`]
|
/// of their [`InitializationFlags`][Self::InitializationFlags] so it can read the current parameter
|
||||||
/// for more information.
|
/// values. See [`Application`] for more information.
|
||||||
pub trait IcedEditor: 'static + Send + Sync + Sized {
|
pub trait IcedEditor: 'static + Send + Sync + Sized {
|
||||||
/// See [`Application::Executor`]. You'll likely want to use [`crate::executor::Default`].
|
/// See [`Application::Executor`]. You'll likely want to use [`crate::executor::Default`].
|
||||||
type Executor: Executor;
|
type Executor: Executor;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use nih_plug::param::internals::ParamPtr;
|
use nih_plug::param::internals::ParamPtr;
|
||||||
|
|
||||||
mod param_slider;
|
mod param_slider;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
pub use param_slider::ParamSlider;
|
pub use param_slider::ParamSlider;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
//! A slider that integrates with NIH-plug's [`Param`] types.
|
//! A slider that integrates with NIH-plug's [`Param`] types.
|
||||||
|
|
||||||
use crate::backend;
|
use crate::{
|
||||||
use crate::event::{self, Event};
|
alignment, backend, event, layout, mouse, renderer, text, Clipboard, Color, Element, Event,
|
||||||
use crate::layout;
|
Layout, Length, Point, Rectangle, Shell, Size, Widget,
|
||||||
use crate::mouse;
|
};
|
||||||
use crate::renderer;
|
use nih_plug::prelude::{GuiContext, Param, ParamSetter};
|
||||||
use crate::text;
|
|
||||||
use crate::{Clipboard, Color, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
|
|
||||||
use nih_plug::prelude::Param;
|
|
||||||
|
|
||||||
|
use super::util;
|
||||||
use super::ParamMessage;
|
use super::ParamMessage;
|
||||||
|
|
||||||
/// A slider that integrates with NIH-plug's [`Param`] types.
|
/// A slider that integrates with NIH-plug's [`Param`] types.
|
||||||
|
@ -16,6 +14,9 @@ use super::ParamMessage;
|
||||||
/// TODO: There are currently no styling options at all
|
/// TODO: There are currently no styling options at all
|
||||||
pub struct ParamSlider<'a, P: Param, Renderer: text::Renderer> {
|
pub struct ParamSlider<'a, P: Param, Renderer: text::Renderer> {
|
||||||
param: &'a P,
|
param: &'a P,
|
||||||
|
/// We'll visualize the parameter's current value by drawing the difference between the current
|
||||||
|
/// normalized value and the default normalized value.
|
||||||
|
setter: ParamSetter<'a>,
|
||||||
|
|
||||||
height: Length,
|
height: Length,
|
||||||
width: Length,
|
width: Length,
|
||||||
|
@ -25,9 +26,13 @@ pub struct ParamSlider<'a, P: Param, Renderer: text::Renderer> {
|
||||||
|
|
||||||
impl<'a, P: Param, Renderer: text::Renderer> ParamSlider<'a, P, Renderer> {
|
impl<'a, P: Param, Renderer: text::Renderer> ParamSlider<'a, P, Renderer> {
|
||||||
/// Creates a new [`ParamSlider`] for the given parameter.
|
/// Creates a new [`ParamSlider`] for the given parameter.
|
||||||
pub fn new(param: &'a P) -> Self {
|
pub fn new(param: &'a P, context: &'a dyn GuiContext) -> Self {
|
||||||
|
let setter = ParamSetter::new(context);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
param,
|
param,
|
||||||
|
setter,
|
||||||
|
|
||||||
width: Length::Units(180),
|
width: Length::Units(180),
|
||||||
height: Length::Units(30),
|
height: Length::Units(30),
|
||||||
text_size: None,
|
text_size: None,
|
||||||
|
@ -111,17 +116,19 @@ impl<'a, P: Param, Renderer: text::Renderer> Widget<ParamMessage, Renderer>
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
_style: &renderer::Style,
|
style: &renderer::Style,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
|
const BORDER_WIDTH: f32 = 1.0;
|
||||||
|
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
let is_mouse_over = bounds.contains(cursor_position);
|
||||||
|
|
||||||
// TODO:
|
// The bar itself
|
||||||
let background_color = if is_mouse_over {
|
let background_color = if is_mouse_over {
|
||||||
Color::new(0.5, 0.5, 0.5, 0.2)
|
Color::new(0.5, 0.5, 0.5, 0.1)
|
||||||
} else {
|
} else {
|
||||||
Color::TRANSPARENT
|
Color::TRANSPARENT
|
||||||
};
|
};
|
||||||
|
@ -130,51 +137,70 @@ impl<'a, P: Param, Renderer: text::Renderer> Widget<ParamMessage, Renderer>
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
bounds,
|
bounds,
|
||||||
border_color: Color::BLACK,
|
border_color: Color::BLACK,
|
||||||
border_width: 1.0,
|
border_width: BORDER_WIDTH,
|
||||||
border_radius: 0.0,
|
border_radius: 0.0,
|
||||||
},
|
},
|
||||||
background_color,
|
background_color,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO:
|
// We'll visualize the difference between the current value and the default value
|
||||||
|
let current_value = self.param.normalized_value();
|
||||||
|
let fill_start_x = util::remap_rect_x(
|
||||||
|
&bounds,
|
||||||
|
self.setter.default_normalized_param_value(self.param),
|
||||||
|
);
|
||||||
|
let fill_end_x = util::remap_rect_x(&bounds, current_value);
|
||||||
|
|
||||||
// renderer.fill_text(Text {
|
let fill_color = Color::from_rgb8(196, 196, 196);
|
||||||
// content: &Renderer::ARROW_DOWN_ICON.to_string(),
|
let fill_rect = Rectangle {
|
||||||
// font: Renderer::ICON_FONT,
|
x: fill_start_x.min(fill_end_x),
|
||||||
// size: bounds.height * style.icon_size,
|
y: bounds.y + BORDER_WIDTH,
|
||||||
// bounds: Rectangle {
|
width: (fill_end_x - fill_start_x).abs(),
|
||||||
// x: bounds.x + bounds.width - f32::from(self.padding.horizontal()),
|
height: bounds.height - BORDER_WIDTH * 2.0,
|
||||||
// y: bounds.center_y(),
|
};
|
||||||
// ..bounds
|
renderer.fill_quad(
|
||||||
// },
|
renderer::Quad {
|
||||||
// color: style.text_color,
|
bounds: fill_rect,
|
||||||
// horizontal_alignment: alignment::Horizontal::Right,
|
border_color: Color::TRANSPARENT,
|
||||||
// vertical_alignment: alignment::Vertical::Center,
|
border_width: 0.0,
|
||||||
// });
|
border_radius: 0.0,
|
||||||
|
},
|
||||||
|
fill_color,
|
||||||
|
);
|
||||||
|
|
||||||
// if let Some(label) = self
|
// We'll overlay the label on the slider. To make it more readable (and because it looks
|
||||||
// .selected
|
// cool), the parts that overlap with the fill rect will be rendered in white while the rest
|
||||||
// .as_ref()
|
// will be rendered in black.
|
||||||
// .map(ToString::to_string)
|
let display_value = self.param.to_string();
|
||||||
// .as_ref()
|
let text_size = self.text_size.unwrap_or_else(|| renderer.default_size()) as f32;
|
||||||
// .or_else(|| self.placeholder.as_ref())
|
let text_bounds = Rectangle {
|
||||||
// {
|
x: bounds.center_x(),
|
||||||
// renderer.fill_text(Text {
|
y: bounds.center_y(),
|
||||||
// content: label,
|
..bounds
|
||||||
// size: f32::from(self.text_size.unwrap_or(renderer.default_size())),
|
};
|
||||||
// font: self.font.clone(),
|
renderer.fill_text(text::Text {
|
||||||
// color: is_selected
|
content: &display_value,
|
||||||
// .then(|| style.text_color)
|
font: self.font.clone(),
|
||||||
// .unwrap_or(style.placeholder_color),
|
size: text_size,
|
||||||
// bounds: Rectangle {
|
bounds: text_bounds,
|
||||||
// x: bounds.x + f32::from(self.padding.left),
|
color: style.text_color,
|
||||||
// y: bounds.center_y(),
|
horizontal_alignment: alignment::Horizontal::Center,
|
||||||
// ..bounds
|
vertical_alignment: alignment::Vertical::Center,
|
||||||
// },
|
});
|
||||||
// horizontal_alignment: alignment::Horizontal::Left,
|
|
||||||
// vertical_alignment: alignment::Vertical::Center,
|
// This will clip to the filled area
|
||||||
// })
|
renderer.with_layer(fill_rect, |renderer| {
|
||||||
// }
|
let filled_text_color = Color::from_rgb8(80, 80, 80);
|
||||||
|
renderer.fill_text(text::Text {
|
||||||
|
content: &display_value,
|
||||||
|
font: self.font.clone(),
|
||||||
|
size: text_size,
|
||||||
|
bounds: text_bounds,
|
||||||
|
color: filled_text_color,
|
||||||
|
horizontal_alignment: alignment::Horizontal::Center,
|
||||||
|
vertical_alignment: alignment::Vertical::Center,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
nih_plug_iced/src/widgets/util.rs
Normal file
15
nih_plug_iced/src/widgets/util.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//! Utilities for creating these widgets.
|
||||||
|
|
||||||
|
use crate::Rectangle;
|
||||||
|
|
||||||
|
/// Remap a `[0, 1]` value to an x-coordinate within this rectangle. The value will be clamped to
|
||||||
|
/// `[0, 1]` if it isn't already in that range.
|
||||||
|
pub fn remap_rect_x(rect: &Rectangle, t: f32) -> f32 {
|
||||||
|
rect.x + (rect.width * t.clamp(0.0, 1.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remap a `[0, 1]` value to a y-coordinate within this rectangle. The value will be clamped to
|
||||||
|
/// `[0, 1]` if it isn't already in that range.
|
||||||
|
pub fn remap_rect_y(rect: &Rectangle, t: f32) -> f32 {
|
||||||
|
rect.y + (rect.height * t.clamp(0.0, 1.0))
|
||||||
|
}
|
|
@ -84,7 +84,7 @@ impl IcedEditor for GainEditor {
|
||||||
.vertical_alignment(alignment::Vertical::Center),
|
.vertical_alignment(alignment::Vertical::Center),
|
||||||
)
|
)
|
||||||
.push(
|
.push(
|
||||||
ParamSlider::new(&self.params.gain).map(Message::ParamUpdate)
|
ParamSlider::new(&self.params.gain, self.context.as_ref()).map(Message::ParamUpdate)
|
||||||
// Button::new(&mut self.gain_dummy_state, Text::new("Gain"))
|
// Button::new(&mut self.gain_dummy_state, Text::new("Gain"))
|
||||||
// .height(30.into())
|
// .height(30.into())
|
||||||
// .width(180.into()),
|
// .width(180.into()),
|
||||||
|
|
Loading…
Reference in a new issue