diff --git a/Cargo.lock b/Cargo.lock index 7f3ad236..a5685377 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3498,7 +3498,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vizia" version = "0.1.0" -source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#656a7ee5bc720c6eea23b46c8480ecc9ee826da9" +source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#163ae29c603c51371a8a98cca3f4434f7bf38d37" dependencies = [ "vizia_baseview", "vizia_core", @@ -3507,7 +3507,7 @@ dependencies = [ [[package]] name = "vizia_baseview" version = "0.1.0" -source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#656a7ee5bc720c6eea23b46c8480ecc9ee826da9" +source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#163ae29c603c51371a8a98cca3f4434f7bf38d37" dependencies = [ "baseview 0.1.0 (git+https://github.com/robbert-vdh/baseview.git?branch=feature/resize)", "femtovg", @@ -3519,7 +3519,7 @@ dependencies = [ [[package]] name = "vizia_core" version = "0.1.0" -source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#656a7ee5bc720c6eea23b46c8480ecc9ee826da9" +source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#163ae29c603c51371a8a98cca3f4434f7bf38d37" dependencies = [ "bitflags", "copypasta", @@ -3544,7 +3544,7 @@ dependencies = [ [[package]] name = "vizia_derive" version = "0.1.0" -source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#656a7ee5bc720c6eea23b46c8480ecc9ee826da9" +source = "git+https://github.com/robbert-vdh/vizia.git?branch=patched#163ae29c603c51371a8a98cca3f4434f7bf38d37" dependencies = [ "proc-macro2", "quote", diff --git a/nih_plug_vizia/src/widgets.rs b/nih_plug_vizia/src/widgets.rs index c07b1f7b..eeca46d9 100644 --- a/nih_plug_vizia/src/widgets.rs +++ b/nih_plug_vizia/src/widgets.rs @@ -77,54 +77,52 @@ pub(crate) struct WindowModel { impl Model for ParamModel { fn event(&mut self, _cx: &mut vizia::Context, event: &mut vizia::Event) { - if let Some(param_event) = event.message.downcast() { - // `ParamEvent` gets downcast into `NormalizedParamEvent` by the `Message` - // implementation below - match *param_event { - RawParamEvent::BeginSetParameter(p) => unsafe { - self.context.raw_begin_set_parameter(p) - }, - RawParamEvent::SetParameterNormalized(p, v) => unsafe { - self.context.raw_set_parameter_normalized(p, v) - }, - RawParamEvent::EndSetParameter(p) => unsafe { - self.context.raw_end_set_parameter(p) - }, - } - } + // `ParamEvent` gets downcast into `NormalizedParamEvent` by the `Message` + // implementation below + event.map(|param_event, _| match *param_event { + RawParamEvent::BeginSetParameter(p) => unsafe { + self.context.raw_begin_set_parameter(p) + }, + RawParamEvent::SetParameterNormalized(p, v) => unsafe { + self.context.raw_set_parameter_normalized(p, v) + }, + RawParamEvent::EndSetParameter(p) => unsafe { self.context.raw_end_set_parameter(p) }, + }); } } impl Model for WindowModel { fn event(&mut self, cx: &mut vizia::Context, event: &mut vizia::Event) { // This gets fired whenever the inner window gets resized - if let Some(WindowEvent::WindowResize) = event.message.downcast() { - let logical_size = (cx.window_size.width, cx.window_size.height); - let old_logical_size @ (old_logical_width, old_logical_height) = - self.vizia_state.size.load(); - let scale_factor = cx.user_scale_factor; - let old_user_scale_factor = self.vizia_state.scale_factor.load(); + event.map(|window_event, _| { + if let WindowEvent::WindowResize = window_event { + let logical_size = (cx.window_size.width, cx.window_size.height); + let old_logical_size @ (old_logical_width, old_logical_height) = + self.vizia_state.size.load(); + let scale_factor = cx.user_scale_factor; + let old_user_scale_factor = self.vizia_state.scale_factor.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_logical_size && scale_factor == old_user_scale_factor { - return; + // 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_logical_size && scale_factor == old_user_scale_factor { + 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); + self.vizia_state.scale_factor.store(scale_factor); + if !self.context.request_resize() { + self.vizia_state.size.store(old_logical_size); + self.vizia_state.scale_factor.store(old_user_scale_factor); + + // This will cause the window's size to be reverted on the next event loop + cx.window_size.width = old_logical_width; + cx.window_size.height = old_logical_height; + cx.user_scale_factor = old_user_scale_factor; + } } - - // 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); - self.vizia_state.scale_factor.store(scale_factor); - if !self.context.request_resize() { - self.vizia_state.size.store(old_logical_size); - self.vizia_state.scale_factor.store(old_user_scale_factor); - - // This will cause the window's size to be reverted on the next event loop - cx.window_size.width = old_logical_width; - cx.window_size.height = old_logical_height; - cx.user_scale_factor = old_user_scale_factor; - } - } + }); } } diff --git a/nih_plug_vizia/src/widgets/param_slider.rs b/nih_plug_vizia/src/widgets/param_slider.rs index 17cfd131..1ea49729 100644 --- a/nih_plug_vizia/src/widgets/param_slider.rs +++ b/nih_plug_vizia/src/widgets/param_slider.rs @@ -78,16 +78,16 @@ enum ParamSliderInternalEvent { impl Model for ParamSliderInternal { fn event(&mut self, _cx: &mut Context, event: &mut Event) { - if let Some(param_slider_internal_event) = event.message.downcast() { - match param_slider_internal_event { + event.map( + |param_slider_internal_event, _| match param_slider_internal_event { ParamSliderInternalEvent::SetStyle(style) => self.style = *style, ParamSliderInternalEvent::SetTextInputActive(active) => { // When this gets set to `true` the textbox widget will be created, and when it // gets created we'll focus it and select all text self.text_input_active = *active; } - } - } + }, + ); } } @@ -350,128 +350,123 @@ impl View for ParamSlider { } fn event(&mut self, cx: &mut Context, event: &mut Event) { - if let Some(param_slider_event) = event.message.downcast() { - match param_slider_event { - ParamSliderEvent::CancelTextInput => { - cx.emit(ParamSliderInternalEvent::SetTextInputActive(false)); - cx.current.set_active(cx, false); - } - ParamSliderEvent::TextInput(string) => { - if let Some(normalized_value) = - unsafe { self.param_ptr.string_to_normalized_value(string) } - { - cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); - self.set_normalized_value(cx, normalized_value); - cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); - } - - cx.emit(ParamSliderInternalEvent::SetTextInputActive(false)); - } + event.map(|param_slider_event, _| match param_slider_event { + ParamSliderEvent::CancelTextInput => { + cx.emit(ParamSliderInternalEvent::SetTextInputActive(false)); + cx.current.set_active(cx, false); } - } + ParamSliderEvent::TextInput(string) => { + if let Some(normalized_value) = + unsafe { self.param_ptr.string_to_normalized_value(string) } + { + cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); + self.set_normalized_value(cx, normalized_value); + cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); + } - if let Some(window_event) = event.message.downcast() { - match window_event { - WindowEvent::MouseDown(MouseButton::Left) => { - if cx.modifiers.alt() { - // ALt+Click brings up a text entry dialog - cx.emit(ParamSliderInternalEvent::SetTextInputActive(true)); - cx.current.set_active(cx, true); - } else if cx.modifiers.command() || self.is_double_click { - // Ctrl+Click and double click should reset the parameter instead of initiating - // a drag operation - cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); - cx.emit(RawParamEvent::SetParameterNormalized( - self.param_ptr, - unsafe { self.param_ptr.default_normalized_value() }, - )); - cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); + cx.emit(ParamSliderInternalEvent::SetTextInputActive(false)); + } + }); + + event.map(|window_event, _| match window_event { + WindowEvent::MouseDown(MouseButton::Left) => { + if cx.modifiers.alt() { + // ALt+Click brings up a text entry dialog + cx.emit(ParamSliderInternalEvent::SetTextInputActive(true)); + cx.current.set_active(cx, true); + } else if cx.modifiers.command() || self.is_double_click { + // Ctrl+Click and double click should reset the parameter instead of initiating + // a drag operation + cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); + cx.emit(RawParamEvent::SetParameterNormalized( + self.param_ptr, + unsafe { self.param_ptr.default_normalized_value() }, + )); + cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); + } else { + self.drag_active = true; + cx.capture(); + // NOTE: Otherwise we don't get key up events + cx.focused = cx.current; + cx.current.set_active(cx, true); + + // When holding down shift while clicking on a parameter we want to granuarly + // edit the parameter without jumping to a new value + cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); + if cx.modifiers.shift() { + self.granular_drag_start_x_value = Some((cx.mouse.cursorx, unsafe { + self.param_ptr.normalized_value() + })); } else { - self.drag_active = true; - cx.capture(); - // NOTE: Otherwise we don't get key up events - cx.focused = cx.current; - cx.current.set_active(cx, true); - - // When holding down shift while clicking on a parameter we want to - // granuarly edit the parameter without jumping to a new value - cx.emit(RawParamEvent::BeginSetParameter(self.param_ptr)); - if cx.modifiers.shift() { - self.granular_drag_start_x_value = Some((cx.mouse.cursorx, unsafe { - self.param_ptr.normalized_value() - })); - } else { - self.granular_drag_start_x_value = None; - self.set_normalized_value_drag( - cx, - util::remap_current_entity_x_coordinate(cx, cx.mouse.cursorx), - ); - } - } - - // We'll set this here because weird things like Alt+double click should not - // cause the next click to become a reset - self.is_double_click = false; - } - WindowEvent::MouseDoubleClick(MouseButton::Left) => { - // Vizia will send a regular mouse down after this, so we'll handle the reset - // there - self.is_double_click = true; - } - WindowEvent::MouseUp(MouseButton::Left) => { - if self.drag_active { - self.drag_active = false; - cx.release(); - cx.current.set_active(cx, false); - - cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); - } - } - WindowEvent::MouseMove(x, _y) => { - if self.drag_active { - // If shift is being held then the drag should be more granular instead of - // absolute - if cx.modifiers.shift() { - let (drag_start_x, drag_start_value) = - *self.granular_drag_start_x_value.get_or_insert_with(|| { - (cx.mouse.cursorx, unsafe { - self.param_ptr.normalized_value() - }) - }); - - self.set_normalized_value_drag( - cx, - util::remap_current_entity_x_coordinate( - cx, - // This can be optimized a bit - util::remap_current_entity_x_t(cx, drag_start_value) - + (*x - drag_start_x) * GRANULAR_DRAG_MULTIPLIER, - ), - ); - } else { - self.granular_drag_start_x_value = None; - - self.set_normalized_value_drag( - cx, - util::remap_current_entity_x_coordinate(cx, *x), - ); - } - } - } - WindowEvent::KeyUp(_, Some(Key::Shift)) => { - // If this happens while dragging, snap back to reality uh I mean the current screen - // position - if self.drag_active && self.granular_drag_start_x_value.is_some() { self.granular_drag_start_x_value = None; - self.set_normalized_value( + self.set_normalized_value_drag( cx, util::remap_current_entity_x_coordinate(cx, cx.mouse.cursorx), ); } } - _ => {} + + // We'll set this here because weird things like Alt+double click should not cause + // the next click to become a reset + self.is_double_click = false; } - } + WindowEvent::MouseDoubleClick(MouseButton::Left) => { + // Vizia will send a regular mouse down after this, so we'll handle the reset there + self.is_double_click = true; + } + WindowEvent::MouseUp(MouseButton::Left) => { + if self.drag_active { + self.drag_active = false; + cx.release(); + cx.current.set_active(cx, false); + + cx.emit(RawParamEvent::EndSetParameter(self.param_ptr)); + } + } + WindowEvent::MouseMove(x, _y) => { + if self.drag_active { + // If shift is being held then the drag should be more granular instead of + // absolute + if cx.modifiers.shift() { + let (drag_start_x, drag_start_value) = + *self.granular_drag_start_x_value.get_or_insert_with(|| { + (cx.mouse.cursorx, unsafe { + self.param_ptr.normalized_value() + }) + }); + + self.set_normalized_value_drag( + cx, + util::remap_current_entity_x_coordinate( + cx, + // This can be optimized a bit + util::remap_current_entity_x_t(cx, drag_start_value) + + (*x - drag_start_x) * GRANULAR_DRAG_MULTIPLIER, + ), + ); + } else { + self.granular_drag_start_x_value = None; + + self.set_normalized_value_drag( + cx, + util::remap_current_entity_x_coordinate(cx, *x), + ); + } + } + } + WindowEvent::KeyUp(_, Some(Key::Shift)) => { + // If this happens while dragging, snap back to reality uh I mean the current screen + // position + if self.drag_active && self.granular_drag_start_x_value.is_some() { + self.granular_drag_start_x_value = None; + self.set_normalized_value( + cx, + util::remap_current_entity_x_coordinate(cx, cx.mouse.cursorx), + ); + } + } + _ => {} + }); } } diff --git a/nih_plug_vizia/src/widgets/resize_handle.rs b/nih_plug_vizia/src/widgets/resize_handle.rs index 5876ed23..93f3b7c6 100644 --- a/nih_plug_vizia/src/widgets/resize_handle.rs +++ b/nih_plug_vizia/src/widgets/resize_handle.rs @@ -35,70 +35,69 @@ impl View for ResizeHandle { } fn event(&mut self, cx: &mut Context, event: &mut Event) { - if let Some(window_event) = event.message.downcast() { - match *window_event { - WindowEvent::MouseDown(MouseButton::Left) => { - // The handle is a triangle, so we should also interac twith it as if it was a - // triangle - if intersects_triangle( - cx.cache.get_bounds(cx.current), - (cx.mouse.cursorx, cx.mouse.cursory), - ) { - cx.capture(); - cx.current.set_active(cx, true); + event.map(|window_event, meta| match *window_event { + WindowEvent::MouseDown(MouseButton::Left) => { + // The handle is a triangle, so we should also interac twith it as if it was a + // triangle + if intersects_triangle( + cx.cache.get_bounds(cx.current), + (cx.mouse.cursorx, cx.mouse.cursory), + ) { + cx.capture(); + cx.current.set_active(cx, true); - self.drag_active = true; - self.start_scale_factor = cx.user_scale_factor; - self.start_physical_coordinates = ( - cx.mouse.cursorx * cx.style.dpi_factor as f32, - cx.mouse.cursory * cx.style.dpi_factor as f32, - ); - - event.consume(); - } else { - // TODO: The click should be forwarded to the element behind the triangle - } - } - WindowEvent::MouseUp(MouseButton::Left) => { - if self.drag_active { - cx.release(); - cx.current.set_active(cx, false); - - self.drag_active = false; - } - } - WindowEvent::MouseMove(x, y) => { - cx.current.set_hover( - cx, - intersects_triangle(cx.cache.get_bounds(cx.current), (x, y)), + self.drag_active = true; + self.start_scale_factor = cx.user_scale_factor; + self.start_physical_coordinates = ( + cx.mouse.cursorx * cx.style.dpi_factor as f32, + cx.mouse.cursory * cx.style.dpi_factor as f32, ); - if self.drag_active { - // We need to convert our measurements into physical pixels relative to the - // initial drag to be able to keep a consistent ratio. This 'relative to the - // start' bit is important because otherwise we would be comparing the - // position to the same absoltue screen spotion. - // TODO: This may start doing fun things when the window grows so large that - // it gets pushed upwards or leftwards - let (compensated_physical_x, compensated_physical_y) = ( - x * self.start_scale_factor as f32, - y * self.start_scale_factor as f32, - ); - let (start_physical_x, start_physical_y) = self.start_physical_coordinates; - let new_scale_factor = (self.start_scale_factor - * (compensated_physical_x / start_physical_x) - .max(compensated_physical_y / start_physical_y) - as f64) - // Prevent approaching zero here because uh - .max(0.25); - - // If this is different then the window will automatically be resized at the end of the frame - cx.user_scale_factor = new_scale_factor; - } + meta.consume(); + } else { + // TODO: The click should be forwarded to the element behind the triangle } - _ => {} } - } + WindowEvent::MouseUp(MouseButton::Left) => { + if self.drag_active { + cx.release(); + cx.current.set_active(cx, false); + + self.drag_active = false; + } + } + WindowEvent::MouseMove(x, y) => { + cx.current.set_hover( + cx, + intersects_triangle(cx.cache.get_bounds(cx.current), (x, y)), + ); + + if self.drag_active { + // We need to convert our measurements into physical pixels relative to the + // initial drag to be able to keep a consistent ratio. This 'relative to the + // start' bit is important because otherwise we would be comparing the position + // to the same absoltue screen spotion. + // TODO: This may start doing fun things when the window grows so large that it + // gets pushed upwards or leftwards + let (compensated_physical_x, compensated_physical_y) = ( + x * self.start_scale_factor as f32, + y * self.start_scale_factor as f32, + ); + let (start_physical_x, start_physical_y) = self.start_physical_coordinates; + let new_scale_factor = (self.start_scale_factor + * (compensated_physical_x / start_physical_x) + .max(compensated_physical_y / start_physical_y) + as f64) + // Prevent approaching zero here because uh + .max(0.25); + + // If this is different then the window will automatically be resized at the end + // of the frame + cx.user_scale_factor = new_scale_factor; + } + } + _ => {} + }); } fn draw(&self, cx: &mut DrawContext, canvas: &mut Canvas) {