diff --git a/Cargo.lock b/Cargo.lock index f3abdd4b..0955fda9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2445,6 +2445,7 @@ dependencies = [ "crossbeam", "nih_plug", "nih_plug_assets", + "serde", "vizia", ] diff --git a/nih_plug_vizia/Cargo.toml b/nih_plug_vizia/Cargo.toml index 468dec1a..9bd519af 100644 --- a/nih_plug_vizia/Cargo.toml +++ b/nih_plug_vizia/Cargo.toml @@ -13,6 +13,8 @@ nih_plug_assets = { git = "https://github.com/robbert-vdh/nih_plug_assets.git" } baseview = { git = "https://github.com/robbert-vdh/baseview.git", branch = "feature/resize" } crossbeam = "0.8" +# To make the state persistable +serde = { version = "1.0", features = ["derive"] } # This fork contains changed for better keyboard modifier handling and DPI # scaling, window scaling, and a lot more fixes and improvements vizia = { git = "https://github.com/robbert-vdh/vizia.git", branch = "patched", default_features = false, features = ["baseview", "clipboard", "x11"] } diff --git a/nih_plug_vizia/src/lib.rs b/nih_plug_vizia/src/lib.rs index 962d1d8b..ca2e5061 100644 --- a/nih_plug_vizia/src/lib.rs +++ b/nih_plug_vizia/src/lib.rs @@ -5,7 +5,9 @@ use baseview::{WindowHandle, WindowScalePolicy}; use crossbeam::atomic::AtomicCell; +use nih_plug::param::internals::PersistentField; use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle}; +use serde::{Deserialize, Serialize}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use vizia::prelude::*; @@ -70,21 +72,36 @@ where })) } -/// State for a `nih_plug_vizia` editor. The scale factor can be manipulated at runtime by changing +/// State for an `nih_plug_vizia` editor. The scale factor can be manipulated at runtime by changing /// `cx.user_scale_factor`. -/// -/// # TODO -/// -/// Make this serializable so it can be persisted. +#[derive(Serialize, Deserialize)] pub struct ViziaState { /// The window's size in logical pixels before applying `scale_factor`. + #[serde(with = "nih_plug::param::internals::serialize_atomic_cell")] size: AtomicCell<(u32, u32)>, /// A scale factor that should be applied to `size` separate from from any system HiDPI scaling. /// This can be used to allow GUIs to be scaled uniformly. + #[serde(with = "nih_plug::param::internals::serialize_atomic_cell")] scale_factor: AtomicCell, + /// Whether the editor's window is currently open. + #[serde(skip)] open: AtomicBool, } +impl<'a> PersistentField<'a, ViziaState> for Arc { + fn set(&self, new_value: ViziaState) { + self.size.store(new_value.size.load()); + self.scale_factor.store(new_value.scale_factor.load()); + } + + fn map(&self, f: F) -> R + where + F: Fn(&ViziaState) -> R, + { + f(self) + } +} + impl ViziaState { /// Initialize the GUI's state. This value can be passed to [`create_vizia_editor()`]. The /// window size is in logical pixels, so before it is multiplied by the DPI scaling factor. diff --git a/src/param/internals.rs b/src/param/internals.rs index bfeca153..a30c45e4 100644 --- a/src/param/internals.rs +++ b/src/param/internals.rs @@ -10,6 +10,29 @@ pub use serde_json::from_str as deserialize_field; /// Re-export for use in the [`Params`] proc-macro. pub use serde_json::to_string as serialize_field; +/// Can be used with the `#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]` +/// attribute to serialize `AtomicCell`s. +pub mod serialize_atomic_cell { + use crossbeam::atomic::AtomicCell; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(cell: &AtomicCell, serializer: S) -> Result + where + S: Serializer, + T: Serialize + Copy, + { + cell.load().serialize(serializer) + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + T: Deserialize<'de> + Copy, + { + T::deserialize(deserializer).map(AtomicCell::new) + } +} + /// Describes a struct containing parameters and other persistent fields. /// /// This trait can be derived on a struct containing [`FloatParam`][super::FloatParam] and other