Add a way to rescale and resize the UI from VIZIA
With some additional VIZIA patches. This currently causes the layout to do weird things, so it's not usable yet. On the baseview side this has also only been implemented for Linux. Once the vizia quirks are gone we can add a widget that you can add to your GUI to make it scaleable.
This commit is contained in:
parent
f9db59f4bc
commit
a39eea1fe9
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -327,6 +327,24 @@ dependencies = [
|
||||||
"xcb-util",
|
"xcb-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "baseview"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/robbert-vdh/baseview.git?branch=feature/resize#b5d0751c82c3fd0301366f1f31c07f3cd53aa52f"
|
||||||
|
dependencies = [
|
||||||
|
"cocoa",
|
||||||
|
"core-foundation",
|
||||||
|
"keyboard-types",
|
||||||
|
"nix",
|
||||||
|
"objc",
|
||||||
|
"raw-window-handle",
|
||||||
|
"uuid",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
"x11",
|
||||||
|
"xcb 0.9.0",
|
||||||
|
"xcb-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -884,7 +902,7 @@ name = "egui-baseview"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://github.com/robbert-vdh/egui-baseview.git?branch=fix/update-dependencies#afde9c661809ee08d69864caa899246592d93f8c"
|
source = "git+https://github.com/robbert-vdh/egui-baseview.git?branch=fix/update-dependencies#afde9c661809ee08d69864caa899246592d93f8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers)",
|
||||||
"copypasta",
|
"copypasta",
|
||||||
"egui",
|
"egui",
|
||||||
"gl",
|
"gl",
|
||||||
|
@ -1558,7 +1576,7 @@ name = "iced_baseview"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
source = "git+https://github.com/robbert-vdh/iced_baseview.git?branch=feature/update-baseview#116e9043779946c9b2a1b4d2a06bf46752930919"
|
source = "git+https://github.com/robbert-vdh/iced_baseview.git?branch=feature/update-baseview#116e9043779946c9b2a1b4d2a06bf46752930919"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers)",
|
||||||
"copypasta",
|
"copypasta",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
@ -2165,7 +2183,7 @@ dependencies = [
|
||||||
name = "nih_plug_egui"
|
name = "nih_plug_egui"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers)",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"egui",
|
"egui",
|
||||||
"egui-baseview",
|
"egui-baseview",
|
||||||
|
@ -2179,7 +2197,7 @@ name = "nih_plug_iced"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic_refcell",
|
"atomic_refcell",
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers)",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"iced_baseview",
|
"iced_baseview",
|
||||||
"nih_plug",
|
"nih_plug",
|
||||||
|
@ -2190,7 +2208,7 @@ dependencies = [
|
||||||
name = "nih_plug_vizia"
|
name = "nih_plug_vizia"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/resize)",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"femtovg",
|
"femtovg",
|
||||||
"nih_plug",
|
"nih_plug",
|
||||||
|
@ -3607,7 +3625,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vizia"
|
name = "vizia"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#c671d86063e5f7754b90fca3c92350efa6d9fc0c"
|
source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#6c9844125ee68537842a025657cbd51734a2589d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vizia_baseview",
|
"vizia_baseview",
|
||||||
"vizia_core",
|
"vizia_core",
|
||||||
|
@ -3616,9 +3634,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vizia_baseview"
|
name = "vizia_baseview"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#c671d86063e5f7754b90fca3c92350efa6d9fc0c"
|
source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#6c9844125ee68537842a025657cbd51734a2589d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"baseview",
|
"baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/resize)",
|
||||||
"femtovg",
|
"femtovg",
|
||||||
"keyboard-types",
|
"keyboard-types",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
|
@ -3628,7 +3646,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vizia_core"
|
name = "vizia_core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#c671d86063e5f7754b90fca3c92350efa6d9fc0c"
|
source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#6c9844125ee68537842a025657cbd51734a2589d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"copypasta",
|
"copypasta",
|
||||||
|
@ -3651,7 +3669,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vizia_derive"
|
name = "vizia_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#c671d86063e5f7754b90fca3c92350efa6d9fc0c"
|
source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#6c9844125ee68537842a025657cbd51734a2589d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -11,10 +11,10 @@ description = "An adapter to use VIZIA GUIs with NIH-plug"
|
||||||
nih_plug = { path = ".." }
|
nih_plug = { path = ".." }
|
||||||
nih_plug_assets = { git = "https://github.com/robbert-vdh/nih_plug_assets.git" }
|
nih_plug_assets = { git = "https://github.com/robbert-vdh/nih_plug_assets.git" }
|
||||||
|
|
||||||
baseview = { git = "https://github.com/robbert-vdh/baseview.git", branch = "feature/mouse-event-modifiers" }
|
baseview = { git = "https://github.com/robbert-vdh/baseview.git", branch = "feature/resize" }
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
# Vizia doesn't re-export this, we will
|
# Vizia doesn't re-export this, we will
|
||||||
femtovg = { version = "0.3.0", default-features = false, features = ["image-loading"] }
|
femtovg = { version = "0.3.0", default-features = false, features = ["image-loading"] }
|
||||||
# This fork contains changed for better keyboard modifier handling and DPI
|
# This fork contains changed for better keyboard modifier handling and DPI
|
||||||
# scaling
|
# scaling, window scaling, and a lot more fixes and improvements
|
||||||
vizia = { git = "https://github.com/robbert-vdh/vizia.git", branch = "feature/baseview-modifiers", default_features = false, features = ["baseview", "clipboard"] }
|
vizia = { git = "https://github.com/robbert-vdh/vizia.git", branch = "patched", default_features = false, features = ["baseview", "clipboard"] }
|
||||||
|
|
|
@ -55,28 +55,67 @@ where
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Once we add resizing, we may want to be able to remember the GUI size. In that case we need
|
/// State for a `nih_plug_vizia` editor. The scale factor can be manipulated at runtime by emitting
|
||||||
// to make this serializable (only restoring the size of course) so it can be persisted.
|
/// [`WindowEvent::SetScale`][vizia::WindowEvent::SetScale] events.
|
||||||
|
///
|
||||||
|
/// # TODO
|
||||||
|
///
|
||||||
|
/// Make this serializable so it can be persisted.
|
||||||
pub struct ViziaState {
|
pub struct ViziaState {
|
||||||
|
/// The window's size in logical pixels before applying `scale_factor`.
|
||||||
size: AtomicCell<(u32, u32)>,
|
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.
|
||||||
|
scale_factor: AtomicCell<f64>,
|
||||||
open: AtomicBool,
|
open: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViziaState {
|
impl ViziaState {
|
||||||
/// Initialize the GUI's state. This value can be passed to [`create_vizia_editor()`]. The window
|
/// Initialize the GUI's state. This value can be passed to [`create_vizia_editor()`]. The
|
||||||
/// size is in logical pixels, so before it is multiplied by the DPI scaling factor.
|
/// window size is in logical pixels, so before it is multiplied by the DPI scaling factor.
|
||||||
pub fn from_size(width: u32, height: u32) -> Arc<ViziaState> {
|
pub fn from_size(width: u32, height: u32) -> Arc<ViziaState> {
|
||||||
Arc::new(ViziaState {
|
Arc::new(ViziaState {
|
||||||
size: AtomicCell::new((width, height)),
|
size: AtomicCell::new((width, height)),
|
||||||
|
scale_factor: AtomicCell::new(1.0),
|
||||||
open: AtomicBool::new(false),
|
open: AtomicBool::new(false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a `(width, height)` pair for the current size of the GUI in logical pixels.
|
/// The same as [`from_size()`][Self::from_size()], but with a separate initial scale factor.
|
||||||
pub fn size(&self) -> (u32, u32) {
|
/// This scale factor gets applied on top of any HiDPI scaling, and it can be modified at
|
||||||
|
/// runtime by emitting [`WindowEvent::SetScale`][vizia::WindowEvent::SetScale] events.
|
||||||
|
pub fn from_size_with_scale(width: u32, height: u32, scale_factor: f64) -> Arc<ViziaState> {
|
||||||
|
Arc::new(ViziaState {
|
||||||
|
size: AtomicCell::new((width, height)),
|
||||||
|
scale_factor: AtomicCell::new(scale_factor),
|
||||||
|
open: AtomicBool::new(false),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a `(width, height)` pair for the current size of the GUI in logical pixels, after
|
||||||
|
/// applying the user scale factor.
|
||||||
|
pub fn scaled_logical_size(&self) -> (u32, u32) {
|
||||||
|
let (logical_width, logical_height) = self.size.load();
|
||||||
|
let scale_factor = self.scale_factor.load();
|
||||||
|
|
||||||
|
(
|
||||||
|
(logical_width as f64 * scale_factor).round() as u32,
|
||||||
|
(logical_height as f64 * scale_factor).round() as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a `(width, height)` pair for the current size of the GUI in logical pixels before
|
||||||
|
/// applying the user scale factor.
|
||||||
|
pub fn inner_logical_size(&self) -> (u32, u32) {
|
||||||
self.size.load()
|
self.size.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the non-DPI related uniform scaling factor the GUI's size will be multiplied with. This
|
||||||
|
/// can be changed by emitting [`WindowEvent::SetScale`][vizia::WindowEvent::SetScale] events.
|
||||||
|
pub fn user_scale_factor(&self) -> f64 {
|
||||||
|
self.scale_factor.load()
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the GUI is currently visible.
|
/// Whether the GUI is currently visible.
|
||||||
// Called `is_open()` instead of `open()` to avoid the ambiguity.
|
// Called `is_open()` instead of `open()` to avoid the ambiguity.
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
|
@ -105,12 +144,15 @@ impl Editor for ViziaEditor {
|
||||||
context: Arc<dyn GuiContext>,
|
context: Arc<dyn GuiContext>,
|
||||||
) -> Box<dyn std::any::Any + Send + Sync> {
|
) -> Box<dyn std::any::Any + Send + Sync> {
|
||||||
let app = self.app.clone();
|
let app = self.app.clone();
|
||||||
|
let vizia_state = self.vizia_state.clone();
|
||||||
let apply_theming = self.apply_theming;
|
let apply_theming = self.apply_theming;
|
||||||
|
|
||||||
let (unscaled_width, unscaled_height) = self.vizia_state.size();
|
let (unscaled_width, unscaled_height) = vizia_state.inner_logical_size();
|
||||||
let scaling_factor = self.scaling_factor.load();
|
let system_scaling_factor = self.scaling_factor.load();
|
||||||
let window_description =
|
let user_scale_factor = vizia_state.user_scale_factor();
|
||||||
WindowDescription::new().with_inner_size(unscaled_width, unscaled_height);
|
let window_description = WindowDescription::new()
|
||||||
|
.with_inner_size(unscaled_width, unscaled_height)
|
||||||
|
.with_scale_factor(user_scale_factor);
|
||||||
|
|
||||||
let window = Application::new(window_description, move |cx| {
|
let window = Application::new(window_description, move |cx| {
|
||||||
// Set some default styles to match the iced integration
|
// Set some default styles to match the iced integration
|
||||||
|
@ -136,10 +178,18 @@ impl Editor for ViziaEditor {
|
||||||
}
|
}
|
||||||
.build(cx);
|
.build(cx);
|
||||||
|
|
||||||
|
// And we'll link `WindowEvent::ResizeWindow` and `WindowEvent::SetScale` events to our
|
||||||
|
// `ViziaState`. We'll notify the host when any of these change.
|
||||||
|
widgets::WindowModel {
|
||||||
|
context: context.clone(),
|
||||||
|
vizia_state: vizia_state.clone(),
|
||||||
|
}
|
||||||
|
.build(cx);
|
||||||
|
|
||||||
app(cx)
|
app(cx)
|
||||||
})
|
})
|
||||||
.with_scale_policy(
|
.with_scale_policy(
|
||||||
scaling_factor
|
system_scaling_factor
|
||||||
.map(|factor| WindowScalePolicy::ScaleFactor(factor as f64))
|
.map(|factor| WindowScalePolicy::ScaleFactor(factor as f64))
|
||||||
.unwrap_or(WindowScalePolicy::SystemScaleFactor),
|
.unwrap_or(WindowScalePolicy::SystemScaleFactor),
|
||||||
)
|
)
|
||||||
|
@ -153,16 +203,21 @@ impl Editor for ViziaEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> (u32, u32) {
|
fn size(&self) -> (u32, u32) {
|
||||||
self.vizia_state.size()
|
// This includes the user scale factor if set, but not any HiDPI scaling
|
||||||
|
self.vizia_state.scaled_logical_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scale_factor(&self, factor: f32) -> bool {
|
fn set_scale_factor(&self, factor: f32) -> bool {
|
||||||
|
// We're making things a bit more complicated by having both a system scale factor, which is
|
||||||
|
// used for HiDPI and also known to the host, and a user scale factor that the user can use
|
||||||
|
// to arbitrarily resize the GUI
|
||||||
self.scaling_factor.store(Some(factor));
|
self.scaling_factor.store(Some(factor));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_values_changed(&self) {
|
fn param_values_changed(&self) {
|
||||||
// TODO: Update the GUI when this happens
|
// TODO: Update the GUI when this happens, right now this happens automatically as a result
|
||||||
|
// of of the reactivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
use nih_plug::prelude::{GuiContext, Param, ParamPtr};
|
use nih_plug::prelude::{GuiContext, Param, ParamPtr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use vizia::{Context, Model};
|
use vizia::{Context, Model, WindowEvent};
|
||||||
|
|
||||||
|
use super::ViziaState;
|
||||||
|
|
||||||
mod generic_ui;
|
mod generic_ui;
|
||||||
mod param_slider;
|
mod param_slider;
|
||||||
|
@ -63,6 +65,13 @@ pub(crate) struct ParamModel {
|
||||||
pub context: Arc<dyn GuiContext>,
|
pub context: Arc<dyn GuiContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles interactions through `WindowEvent` for VIZIA GUIs by updating the `ViziaState`.
|
||||||
|
/// Registered in [`ViziaEditor::spawn()`][super::ViziaEditor::spawn()].
|
||||||
|
pub(crate) struct WindowModel {
|
||||||
|
pub context: Arc<dyn GuiContext>,
|
||||||
|
pub vizia_state: Arc<ViziaState>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Model for ParamModel {
|
impl Model for ParamModel {
|
||||||
fn event(&mut self, _cx: &mut vizia::Context, event: &mut vizia::Event) {
|
fn event(&mut self, _cx: &mut vizia::Context, event: &mut vizia::Event) {
|
||||||
if let Some(param_event) = event.message.downcast() {
|
if let Some(param_event) = event.message.downcast() {
|
||||||
|
@ -83,6 +92,56 @@ impl Model for ParamModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Model for WindowModel {
|
||||||
|
fn event(&mut self, cx: &mut vizia::Context, event: &mut vizia::Event) {
|
||||||
|
if let Some(window_event) = event.message.downcast() {
|
||||||
|
match *window_event {
|
||||||
|
WindowEvent::ResizeWindow(logical_width, logical_height) => {
|
||||||
|
let logical_size =
|
||||||
|
(logical_width.round() as u32, logical_height.round() as u32);
|
||||||
|
let old_size @ (old_logical_width, old_logical_height) =
|
||||||
|
self.vizia_state.size.load();
|
||||||
|
|
||||||
|
// Don't do anything if the current size already matches the new size, this
|
||||||
|
// could otherwise also cause a feedback loop on resize failure
|
||||||
|
if logical_size == old_size {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our embedded baseview window will have already been resized. If the host does
|
||||||
|
// not accept our new size, then we'll try to undo that
|
||||||
|
self.vizia_state.size.store(logical_size);
|
||||||
|
if !self.context.request_resize() {
|
||||||
|
self.vizia_state.size.store(old_size);
|
||||||
|
cx.emit(WindowEvent::ResizeWindow(
|
||||||
|
old_logical_width as f32,
|
||||||
|
old_logical_height as f32,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowEvent::SetScale(user_scale_factor) => {
|
||||||
|
let old_user_scale_factor = self.vizia_state.scale_factor.load();
|
||||||
|
|
||||||
|
// Don't do anything if the current scale already matches the new scale
|
||||||
|
if user_scale_factor == old_user_scale_factor {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This works the same as the `ResizeWindow` handler. The actual window size
|
||||||
|
// reported to the host gets calculated from a combination of the window's
|
||||||
|
// logical size (before user scaling) and the user scale factor.
|
||||||
|
self.vizia_state.scale_factor.store(user_scale_factor);
|
||||||
|
if !self.context.request_resize() {
|
||||||
|
self.vizia_state.scale_factor.store(old_user_scale_factor);
|
||||||
|
cx.emit(WindowEvent::SetScale(old_user_scale_factor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<P: Param> From<ParamEvent<'_, P>> for RawParamEvent {
|
impl<P: Param> From<ParamEvent<'_, P>> for RawParamEvent {
|
||||||
fn from(event: ParamEvent<'_, P>) -> Self {
|
fn from(event: ParamEvent<'_, P>) -> Self {
|
||||||
match event {
|
match event {
|
||||||
|
|
Loading…
Reference in a new issue