1
0
Fork 0

Add a placeholder for a parameter slider widget

This commit is contained in:
Robbert van der Helm 2022-03-14 00:53:22 +01:00
parent 5711f77cc7
commit 291abb8bcf
6 changed files with 223 additions and 16 deletions

2
Cargo.lock generated
View file

@ -1396,7 +1396,7 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "iced_baseview"
version = "0.0.3"
source = "git+https://github.com/robbert-vdh/iced_baseview.git?branch=feature/update-dependencies#1109df27432ca3837673f6e11fa1914d33ce93f3"
source = "git+https://github.com/robbert-vdh/iced_baseview.git?branch=feature/update-dependencies#d2ab5282141790fabdeb7ad028d23848f9641ac0"
dependencies = [
"baseview",
"copypasta",

View file

@ -2,7 +2,7 @@
//!
//! TODO: Proper usage example, for now check out the gain_gui example
use baseview::{Size, WindowOpenOptions, WindowScalePolicy};
use baseview::{WindowOpenOptions, WindowScalePolicy};
use crossbeam::atomic::AtomicCell;
use crossbeam::channel;
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
@ -106,12 +106,12 @@ pub trait IcedEditor: 'static + Send + Sync + Sized {
}
/// See [`Application::renderer_settings`].
fn renderer_settings() -> iced_baseview::renderer::settings::Settings {
iced_baseview::renderer::settings::Settings {
fn renderer_settings() -> iced_baseview::backend::settings::Settings {
iced_baseview::backend::settings::Settings {
// Enable some anti-aliasing by default. Since GUIs are likely very simple and most of
// the work will be on the CPU anyways this should not affect performance much.
antialiasing: Some(iced_baseview::renderer::settings::Antialiasing::MSAAx4),
..iced_baseview::renderer::settings::Settings::default()
antialiasing: Some(iced_baseview::backend::settings::Antialiasing::MSAAx4),
..iced_baseview::backend::settings::Settings::default()
}
}
@ -196,7 +196,7 @@ impl<E: IcedEditor> Editor for IcedEditorWrapper<E> {
window: WindowOpenOptions {
title: String::from("iced window"),
// Baseview should be doing the DPI scaling for us
size: Size::new(unscaled_width as f64, unscaled_height as f64),
size: baseview::Size::new(unscaled_width as f64, unscaled_height as f64),
// NOTE: For some reason passing 1.0 here causes the UI to be scaled on macOS but
// not the mouse events.
scale: scaling_factor

View file

@ -1,7 +1,16 @@
//! Widgets and utilities for making widgets to integrate iced with NIH-plug.
//!
//! # Note
//!
//! None of these widgets are finalized, and their sizes or looks can change at any point. Feel free
//! to copy the widgets and modify them to your personal taste.
use nih_plug::param::internals::ParamPtr;
mod param_slider;
pub use param_slider::ParamSlider;
/// A message to update a parameter value. Since NIH-plug manages the parameters, interacting with
/// parameter values with iced works a little different from updating any other state. This main
/// [`IcedEditor`][super::IcedEditor] should have a [`Message`][super::IcedEditor::Message] variant

View file

@ -0,0 +1,199 @@
//! A slider that integrates with NIH-plug's [`Param`] types.
use crate::backend;
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
use crate::renderer;
use crate::text;
use crate::{Clipboard, Color, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
use nih_plug::prelude::Param;
use super::ParamMessage;
/// A slider that integrates with NIH-plug's [`Param`] types.
///
/// TODO: There are currently no styling options at all
pub struct ParamSlider<'a, P: Param, Renderer: text::Renderer> {
param: &'a P,
height: Length,
width: Length,
text_size: Option<u16>,
font: Renderer::Font,
}
impl<'a, P: Param, Renderer: text::Renderer> ParamSlider<'a, P, Renderer> {
/// Creates a new [`ParamSlider`] for the given parameter.
pub fn new(param: &'a P) -> Self {
Self {
param,
width: Length::Units(180),
height: Length::Units(30),
text_size: None,
font: Renderer::Font::default(),
}
}
/// Sets the width of the [`ParamSlider`].
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
/// Sets the height of the [`ParamSlider`].
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
/// Sets the text size of the [`ParamSlider`].
pub fn text_size(mut self, size: u16) -> Self {
self.text_size = Some(size);
self
}
/// Sets the font of the [`ParamSlider`].
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self
}
}
impl<'a, P: Param, Renderer: text::Renderer> Widget<ParamMessage, Renderer>
for ParamSlider<'a, P, Renderer>
{
fn width(&self) -> Length {
self.width
}
fn height(&self) -> Length {
self.height
}
fn layout(&self, _renderer: &Renderer, limits: &layout::Limits) -> layout::Node {
let limits = limits.width(self.width).height(self.height);
let size = limits.resolve(Size::ZERO);
layout::Node::new(size)
}
fn on_event(
&mut self,
_event: Event,
_layout: Layout<'_>,
_cursor_position: Point,
_renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
_shell: &mut Shell<'_, ParamMessage>,
) -> event::Status {
// TODO: Handle interaction
event::Status::Ignored
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
let bounds = layout.bounds();
let is_mouse_over = bounds.contains(cursor_position);
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
}
}
fn draw(
&self,
renderer: &mut Renderer,
_style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
) {
let bounds = layout.bounds();
let is_mouse_over = bounds.contains(cursor_position);
// TODO:
let background_color = if is_mouse_over {
Color::new(0.5, 0.5, 0.5, 0.2)
} else {
Color::TRANSPARENT
};
renderer.fill_quad(
renderer::Quad {
bounds,
border_color: Color::BLACK,
border_width: 1.0,
border_radius: 0.0,
},
background_color,
);
// TODO:
// renderer.fill_text(Text {
// content: &Renderer::ARROW_DOWN_ICON.to_string(),
// font: Renderer::ICON_FONT,
// size: bounds.height * style.icon_size,
// bounds: Rectangle {
// x: bounds.x + bounds.width - f32::from(self.padding.horizontal()),
// y: bounds.center_y(),
// ..bounds
// },
// color: style.text_color,
// horizontal_alignment: alignment::Horizontal::Right,
// vertical_alignment: alignment::Vertical::Center,
// });
// if let Some(label) = self
// .selected
// .as_ref()
// .map(ToString::to_string)
// .as_ref()
// .or_else(|| self.placeholder.as_ref())
// {
// renderer.fill_text(Text {
// content: label,
// size: f32::from(self.text_size.unwrap_or(renderer.default_size())),
// font: self.font.clone(),
// color: is_selected
// .then(|| style.text_color)
// .unwrap_or(style.placeholder_color),
// bounds: Rectangle {
// x: bounds.x + f32::from(self.padding.left),
// y: bounds.center_y(),
// ..bounds
// },
// horizontal_alignment: alignment::Horizontal::Left,
// vertical_alignment: alignment::Vertical::Center,
// })
// }
}
}
impl<'a, P: Param> ParamSlider<'a, P, backend::Renderer> {
/// Convert this [`ParamSlider`] into an [`Element`] with the correct message. You should have a
/// variant on your own message type that wraps around [`ParamMessage`] so you can forward those
/// messages to
/// [`IcedEditor::handle_param_message()`][crate::IcedEditor::handle_param_message()].
pub fn map<Message, F>(self, f: F) -> Element<'a, Message>
where
Message: 'static,
F: Fn(ParamMessage) -> Message + 'static,
{
Element::from(self).map(f)
}
}
impl<'a, P: Param> From<ParamSlider<'a, P, backend::Renderer>> for Element<'a, ParamMessage> {
fn from(widget: ParamSlider<'a, P, backend::Renderer>) -> Self {
Element::new(widget)
}
}

View file

@ -152,7 +152,7 @@ impl<E: IcedEditor> Application for IcedEditorWrapperApplication<E> {
}
#[inline]
fn renderer_settings() -> iced_baseview::renderer::settings::Settings {
fn renderer_settings() -> iced_baseview::backend::settings::Settings {
E::renderer_settings()
}
}

View file

@ -1,5 +1,5 @@
use nih_plug::prelude::{Editor, GuiContext};
use nih_plug_iced::widgets::ParamMessage;
use nih_plug_iced::widgets::{ParamMessage, ParamSlider};
use nih_plug_iced::*;
use std::pin::Pin;
use std::sync::Arc;
@ -22,7 +22,6 @@ struct GainEditor {
params: Pin<Arc<GainParams>>,
context: Arc<dyn GuiContext>,
gain_dummy_state: widget::button::State,
meter_dummy_state: widget::button::State,
}
@ -44,7 +43,6 @@ impl IcedEditor for GainEditor {
let editor = GainEditor {
params,
context,
gain_dummy_state: widget::button::State::new(),
meter_dummy_state: widget::button::State::new(),
};
@ -73,22 +71,23 @@ impl IcedEditor for GainEditor {
.push(
Text::new("Gain GUI")
.size(40)
.height(45.into())
.height(50.into())
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center)
.vertical_alignment(alignment::Vertical::Bottom),
)
.push(
Text::new("Gain")
.height(25.into())
.height(20.into())
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center)
.vertical_alignment(alignment::Vertical::Center),
)
.push(
Button::new(&mut self.gain_dummy_state, Text::new("Gain"))
.height(30.into())
.width(180.into()),
ParamSlider::new(&self.params.gain).map(Message::ParamUpdate)
// Button::new(&mut self.gain_dummy_state, Text::new("Gain"))
// .height(30.into())
// .width(180.into()),
)
.push(Space::with_height(10.into()))
.push(