Move nih_plug_iced Editor implementation to module
This commit is contained in:
parent
6ebc759706
commit
0db23e5aee
128
nih_plug_iced/src/editor.rs
Normal file
128
nih_plug_iced/src/editor.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//! And [`Editor`] implementation for iced.
|
||||||
|
|
||||||
|
use baseview::{WindowOpenOptions, WindowScalePolicy};
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
use crossbeam::channel;
|
||||||
|
pub use iced_baseview::*;
|
||||||
|
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{wrapper, IcedEditor, IcedState, ParameterUpdate};
|
||||||
|
|
||||||
|
/// An [`Editor`] implementation that renders an iced [`Application`].
|
||||||
|
pub(crate) struct IcedEditorWrapper<E: IcedEditor> {
|
||||||
|
pub(crate) iced_state: Arc<IcedState>,
|
||||||
|
pub(crate) initialization_flags: E::InitializationFlags,
|
||||||
|
|
||||||
|
/// The scaling factor reported by the host, if any. On macOS this will never be set and we
|
||||||
|
/// should use the system scaling factor instead.
|
||||||
|
pub(crate) scaling_factor: AtomicCell<Option<f32>>,
|
||||||
|
|
||||||
|
/// A subscription for sending messages about parameter updates to the `IcedEditor`.
|
||||||
|
pub(crate) parameter_updates_sender: channel::Sender<ParameterUpdate>,
|
||||||
|
pub(crate) parameter_updates_receiver: Arc<channel::Receiver<ParameterUpdate>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: IcedEditor> Editor for IcedEditorWrapper<E> {
|
||||||
|
fn spawn(
|
||||||
|
&self,
|
||||||
|
parent: ParentWindowHandle,
|
||||||
|
context: Arc<dyn GuiContext>,
|
||||||
|
) -> Box<dyn std::any::Any + Send> {
|
||||||
|
let (unscaled_width, unscaled_height) = self.iced_state.size();
|
||||||
|
let scaling_factor = self.scaling_factor.load();
|
||||||
|
|
||||||
|
// TODO: iced_baseview does not have gracefuly error handling for context creation failures.
|
||||||
|
// This will panic if the context could not be created.
|
||||||
|
let window = IcedWindow::<wrapper::IcedEditorWrapperApplication<E>>::open_parented(
|
||||||
|
&parent,
|
||||||
|
Settings {
|
||||||
|
window: WindowOpenOptions {
|
||||||
|
title: String::from("iced window"),
|
||||||
|
// Baseview should be doing the DPI scaling for us
|
||||||
|
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
|
||||||
|
.map(|factor| WindowScalePolicy::ScaleFactor(factor as f64))
|
||||||
|
.unwrap_or(WindowScalePolicy::SystemScaleFactor),
|
||||||
|
|
||||||
|
#[cfg(feature = "opengl")]
|
||||||
|
gl_config: Some(baseview::gl::GlConfig {
|
||||||
|
// FIXME: glow_glyph forgot to add an `#extension`, so this won't work under
|
||||||
|
// OpenGL 3.2 at the moment. With that change applied this should work on
|
||||||
|
// OpenGL 3.2/macOS.
|
||||||
|
version: (3, 3),
|
||||||
|
red_bits: 8,
|
||||||
|
blue_bits: 8,
|
||||||
|
green_bits: 8,
|
||||||
|
alpha_bits: 8,
|
||||||
|
depth_bits: 24,
|
||||||
|
stencil_bits: 8,
|
||||||
|
samples: None,
|
||||||
|
srgb: true,
|
||||||
|
double_buffer: true,
|
||||||
|
vsync: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
// FIXME: Rust analyzer always thinks baseview/opengl is enabled even if we
|
||||||
|
// don't explicitly enable it, so you'd get a compile error if this line
|
||||||
|
// is missing
|
||||||
|
#[cfg(not(feature = "opengl"))]
|
||||||
|
gl_config: None,
|
||||||
|
},
|
||||||
|
iced_baseview: IcedBaseviewSettings {
|
||||||
|
ignore_non_modifier_keys: false,
|
||||||
|
always_redraw: true,
|
||||||
|
},
|
||||||
|
// We use this wrapper to be able to pass the GUI context to the editor
|
||||||
|
flags: (
|
||||||
|
context,
|
||||||
|
self.parameter_updates_receiver.clone(),
|
||||||
|
self.initialization_flags.clone(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.iced_state.open.store(true, Ordering::Release);
|
||||||
|
Box::new(IcedEditorHandle {
|
||||||
|
iced_state: self.iced_state.clone(),
|
||||||
|
window,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> (u32, u32) {
|
||||||
|
self.iced_state.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_scale_factor(&self, factor: f32) -> bool {
|
||||||
|
self.scaling_factor.store(Some(factor));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param_values_changed(&self) {
|
||||||
|
if self.iced_state.is_open() {
|
||||||
|
// If there's already a paramter change notification in the channel then we don't need
|
||||||
|
// to do anything else. This avoids queueing up redundant GUI redraws.
|
||||||
|
let _ = self.parameter_updates_sender.try_send(ParameterUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The window handle used for [`IcedEditorWrapper`].
|
||||||
|
struct IcedEditorHandle<Message: 'static + Send> {
|
||||||
|
iced_state: Arc<IcedState>,
|
||||||
|
window: iced_baseview::WindowHandle<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The window handle enum stored within 'WindowHandle' contains raw pointers. Is there a way around
|
||||||
|
/// having this requirement?
|
||||||
|
unsafe impl<Message: Send> Send for IcedEditorHandle<Message> {}
|
||||||
|
|
||||||
|
impl<Message: Send> Drop for IcedEditorHandle<Message> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.iced_state.open.store(false, Ordering::Release);
|
||||||
|
self.window.close_window();
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,11 +89,11 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use baseview::{WindowOpenOptions, WindowScalePolicy};
|
use baseview::WindowScalePolicy;
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use crossbeam::channel;
|
use crossbeam::channel;
|
||||||
use nih_plug::params::persist::PersistentField;
|
use nih_plug::params::persist::PersistentField;
|
||||||
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
use nih_plug::prelude::{Editor, GuiContext};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -107,6 +107,7 @@ use crate::widgets::ParamMessage;
|
||||||
pub use iced_baseview::*;
|
pub use iced_baseview::*;
|
||||||
|
|
||||||
pub mod assets;
|
pub mod assets;
|
||||||
|
mod editor;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
mod wrapper;
|
mod wrapper;
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ pub fn create_iced_editor<E: IcedEditor>(
|
||||||
// which parameter so we'd need to redraw the entire GUI either way.
|
// which parameter so we'd need to redraw the entire GUI either way.
|
||||||
let (parameter_updates_sender, parameter_updates_receiver) = channel::bounded(1);
|
let (parameter_updates_sender, parameter_updates_receiver) = channel::bounded(1);
|
||||||
|
|
||||||
Some(Box::new(IcedEditorWrapper::<E> {
|
Some(Box::new(editor::IcedEditorWrapper::<E> {
|
||||||
iced_state,
|
iced_state,
|
||||||
initialization_flags,
|
initialization_flags,
|
||||||
|
|
||||||
|
@ -279,120 +280,3 @@ impl IcedState {
|
||||||
|
|
||||||
/// A marker struct to indicate that a parameter update has happened.
|
/// A marker struct to indicate that a parameter update has happened.
|
||||||
pub(crate) struct ParameterUpdate;
|
pub(crate) struct ParameterUpdate;
|
||||||
|
|
||||||
/// An [`Editor`] implementation that renders an iced [`Application`].
|
|
||||||
struct IcedEditorWrapper<E: IcedEditor> {
|
|
||||||
iced_state: Arc<IcedState>,
|
|
||||||
initialization_flags: E::InitializationFlags,
|
|
||||||
|
|
||||||
/// The scaling factor reported by the host, if any. On macOS this will never be set and we
|
|
||||||
/// should use the system scaling factor instead.
|
|
||||||
scaling_factor: AtomicCell<Option<f32>>,
|
|
||||||
|
|
||||||
/// A subscription for sending messages about parameter updates to the `IcedEditor`.
|
|
||||||
parameter_updates_sender: channel::Sender<ParameterUpdate>,
|
|
||||||
parameter_updates_receiver: Arc<channel::Receiver<ParameterUpdate>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: IcedEditor> Editor for IcedEditorWrapper<E> {
|
|
||||||
fn spawn(
|
|
||||||
&self,
|
|
||||||
parent: ParentWindowHandle,
|
|
||||||
context: Arc<dyn GuiContext>,
|
|
||||||
) -> Box<dyn std::any::Any + Send> {
|
|
||||||
let (unscaled_width, unscaled_height) = self.iced_state.size();
|
|
||||||
let scaling_factor = self.scaling_factor.load();
|
|
||||||
|
|
||||||
// TODO: iced_baseview does not have gracefuly error handling for context creation failures.
|
|
||||||
// This will panic if the context could not be created.
|
|
||||||
let window = IcedWindow::<wrapper::IcedEditorWrapperApplication<E>>::open_parented(
|
|
||||||
&parent,
|
|
||||||
Settings {
|
|
||||||
window: WindowOpenOptions {
|
|
||||||
title: String::from("iced window"),
|
|
||||||
// Baseview should be doing the DPI scaling for us
|
|
||||||
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
|
|
||||||
.map(|factor| WindowScalePolicy::ScaleFactor(factor as f64))
|
|
||||||
.unwrap_or(WindowScalePolicy::SystemScaleFactor),
|
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
|
||||||
gl_config: Some(baseview::gl::GlConfig {
|
|
||||||
// FIXME: glow_glyph forgot to add an `#extension`, so this won't work under
|
|
||||||
// OpenGL 3.2 at the moment. With that change applied this should work on
|
|
||||||
// OpenGL 3.2/macOS.
|
|
||||||
version: (3, 3),
|
|
||||||
red_bits: 8,
|
|
||||||
blue_bits: 8,
|
|
||||||
green_bits: 8,
|
|
||||||
alpha_bits: 8,
|
|
||||||
depth_bits: 24,
|
|
||||||
stencil_bits: 8,
|
|
||||||
samples: None,
|
|
||||||
srgb: true,
|
|
||||||
double_buffer: true,
|
|
||||||
vsync: true,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
// FIXME: Rust analyzer always thinks baseview/opengl is enabled even if we
|
|
||||||
// don't explicitly enable it, so you'd get a compile error if this line
|
|
||||||
// is missing
|
|
||||||
#[cfg(not(feature = "opengl"))]
|
|
||||||
gl_config: None,
|
|
||||||
},
|
|
||||||
iced_baseview: IcedBaseviewSettings {
|
|
||||||
ignore_non_modifier_keys: false,
|
|
||||||
always_redraw: true,
|
|
||||||
},
|
|
||||||
// We use this wrapper to be able to pass the GUI context to the editor
|
|
||||||
flags: (
|
|
||||||
context,
|
|
||||||
self.parameter_updates_receiver.clone(),
|
|
||||||
self.initialization_flags.clone(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.iced_state.open.store(true, Ordering::Release);
|
|
||||||
Box::new(IcedEditorHandle {
|
|
||||||
iced_state: self.iced_state.clone(),
|
|
||||||
window,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> (u32, u32) {
|
|
||||||
self.iced_state.size()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_scale_factor(&self, factor: f32) -> bool {
|
|
||||||
self.scaling_factor.store(Some(factor));
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn param_values_changed(&self) {
|
|
||||||
if self.iced_state.is_open() {
|
|
||||||
// If there's already a paramter change notification in the channel then we don't need
|
|
||||||
// to do anything else. This avoids queueing up redundant GUI redraws.
|
|
||||||
let _ = self.parameter_updates_sender.try_send(ParameterUpdate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The window handle used for [`IcedEditorWrapper`].
|
|
||||||
struct IcedEditorHandle<Message: 'static + Send> {
|
|
||||||
iced_state: Arc<IcedState>,
|
|
||||||
window: iced_baseview::WindowHandle<Message>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The window handle enum stored within 'WindowHandle' contains raw pointers. Is there a way around
|
|
||||||
/// having this requirement?
|
|
||||||
unsafe impl<Message: Send> Send for IcedEditorHandle<Message> {}
|
|
||||||
|
|
||||||
impl<Message: Send> Drop for IcedEditorHandle<Message> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.iced_state.open.store(false, Ordering::Release);
|
|
||||||
self.window.close_window();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::futures::FutureExt;
|
use crate::futures::FutureExt;
|
||||||
use crate::{
|
use crate::{
|
||||||
futures, subscription, Application, Color, Command, Element, IcedEditor, Subscription,
|
futures, subscription, Application, Color, Command, Element, IcedEditor, ParameterUpdate,
|
||||||
WindowQueue, WindowScalePolicy, WindowSubs,
|
Subscription, WindowQueue, WindowScalePolicy, WindowSubs,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Wraps an `iced_baseview` [`Application`] around [`IcedEditor`]. Needed to allow editors to
|
/// Wraps an `iced_baseview` [`Application`] around [`IcedEditor`]. Needed to allow editors to
|
||||||
|
@ -19,7 +19,7 @@ pub(crate) struct IcedEditorWrapperApplication<E: IcedEditor> {
|
||||||
/// We will receive notifications about parameters being changed on here. Whenever a parameter
|
/// We will receive notifications about parameters being changed on here. Whenever a parameter
|
||||||
/// update gets sent, we will trigger a [`Message::parameterUpdate`] which causes the UI to be
|
/// update gets sent, we will trigger a [`Message::parameterUpdate`] which causes the UI to be
|
||||||
/// redrawn.
|
/// redrawn.
|
||||||
parameter_updates_receiver: Arc<channel::Receiver<crate::ParameterUpdate>>,
|
parameter_updates_receiver: Arc<channel::Receiver<ParameterUpdate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This wraps around `E::Message` to add a parameter update message which can be handled directly
|
/// This wraps around `E::Message` to add a parameter update message which can be handled directly
|
||||||
|
@ -53,7 +53,7 @@ impl<E: IcedEditor> Application for IcedEditorWrapperApplication<E> {
|
||||||
type Message = Message<E>;
|
type Message = Message<E>;
|
||||||
type Flags = (
|
type Flags = (
|
||||||
Arc<dyn GuiContext>,
|
Arc<dyn GuiContext>,
|
||||||
Arc<channel::Receiver<crate::ParameterUpdate>>,
|
Arc<channel::Receiver<ParameterUpdate>>,
|
||||||
E::InitializationFlags,
|
E::InitializationFlags,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue