1
0
Fork 0

Update the Diopser XY pad

The translation can now be done from the stylesheet, in percentages.
This commit is contained in:
Robbert van der Helm 2023-11-14 23:40:26 +01:00
parent 669edc1df5
commit 762844f8f6
2 changed files with 38 additions and 47 deletions

View file

@ -83,8 +83,11 @@ xy-pad .xy-pad__value-entry .selection {
xy-pad__handle { xy-pad__handle {
background-color: #e5e5e5; background-color: #e5e5e5;
border-color: #0a0a0a; border-color: #0a0a0a;
border-width: 1px;
border-radius: 50%; border-radius: 50%;
border-width: 1px;
height: 20px;
translate: -50% -50%;
width: 20px;
} }
.xy-pad__handle--modulated { .xy-pad__handle--modulated {
background-color: #a4eafc69; background-color: #a4eafc69;

View file

@ -25,10 +25,6 @@ use crate::params;
/// normalized parameter. /// normalized parameter.
const GRANULAR_DRAG_MULTIPLIER: f32 = 0.1; const GRANULAR_DRAG_MULTIPLIER: f32 = 0.1;
// TODO: Vizia doesn't let you do this -50% translation programmatically yet, so this is hardcoded
// for now
const HANDLE_WIDTH_PX: f32 = 20.0;
/// An X-Y pad that controlers two parameters at the same time by binding them to one of the two /// An X-Y pad that controlers two parameters at the same time by binding them to one of the two
/// axes. This specific implementation has a tooltip for the X-axis parameter and allows /// axes. This specific implementation has a tooltip for the X-axis parameter and allows
/// Alt+clicking to enter a specific value. /// Alt+clicking to enter a specific value.
@ -123,8 +119,8 @@ impl XyPad {
FMap2: Fn(&Params) -> &P2 + Copy + 'static, FMap2: Fn(&Params) -> &P2 + Copy + 'static,
{ {
Self { Self {
x_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_x_param), x_param_base: ParamWidgetBase::new(cx, params, params_to_x_param),
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param), y_param_base: ParamWidgetBase::new(cx, params, params_to_y_param),
frequency_range: params::filter_frequency_range(), frequency_range: params::filter_frequency_range(),
x_renormalize_display: Box::new(x_renormalize_display.clone()), x_renormalize_display: Box::new(x_renormalize_display.clone()),
@ -143,7 +139,7 @@ impl XyPad {
// We need to create lenses for both the x-parameter's values and the y-parameter's // We need to create lenses for both the x-parameter's values and the y-parameter's
// values // values
ParamWidgetBase::build_view( ParamWidgetBase::build_view(
params.clone(), params,
params_to_x_param, params_to_x_param,
move |cx, x_param_data| { move |cx, x_param_data| {
ParamWidgetBase::view( ParamWidgetBase::view(
@ -200,19 +196,19 @@ impl XyPad {
XyPad::text_input_active, XyPad::text_input_active,
move |cx, text_input_active| { move |cx, text_input_active| {
if text_input_active.get(cx) { if text_input_active.get(cx) {
Self::text_input_view(cx, x_display_value_lens.clone()); Self::text_input_view(cx, x_display_value_lens);
} else { } else {
Self::xy_pad_modulation_handle_view( Self::xy_pad_modulation_handle_view(
cx, cx,
modulated_x_position_lens.clone(), modulated_x_position_lens,
modulated_y_position_lens.clone(), modulated_y_position_lens,
); );
Self::xy_pad_handle_view( Self::xy_pad_handle_view(
cx, cx,
x_position_lens.clone(), x_position_lens,
y_position_lens.clone(), y_position_lens,
x_display_value_lens.clone(), x_display_value_lens,
y_display_value_lens.clone(), y_display_value_lens,
); );
} }
}, },
@ -255,11 +251,6 @@ impl XyPad {
.position_type(PositionType::SelfDirected) .position_type(PositionType::SelfDirected)
.top(y_position_lens) .top(y_position_lens)
.left(x_position_lens) .left(x_position_lens)
// TODO: It would be much nicer if this could be set in the
// stylesheet, but Vizia doesn't support that right now
.translate((-(HANDLE_WIDTH_PX / 2.0), -(HANDLE_WIDTH_PX / 2.0)))
.width(Pixels(HANDLE_WIDTH_PX))
.height(Pixels(HANDLE_WIDTH_PX))
.hoverable(false); .hoverable(false);
// The stylesheet makes the tooltip visible when hovering over the X-Y // The stylesheet makes the tooltip visible when hovering over the X-Y
@ -282,7 +273,7 @@ impl XyPad {
// When a new parameter value causes the width of the tooltip to // When a new parameter value causes the width of the tooltip to
// change, we must recompute its position so it stays anchored to // change, we must recompute its position so it stays anchored to
// the mouse cursor // the mouse cursor
if change_flags.intersects(GeometryChanged::WIDTH_CHANGED) { if change_flags.intersects(GeoChanged::WIDTH_CHANGED) {
cx.emit(XyPadEvent::TooltipWidthChanged); cx.emit(XyPadEvent::TooltipWidthChanged);
} }
}) })
@ -301,9 +292,6 @@ impl XyPad {
.position_type(PositionType::SelfDirected) .position_type(PositionType::SelfDirected)
.top(modulated_y_position_lens) .top(modulated_y_position_lens)
.left(modulated_x_position_lens) .left(modulated_x_position_lens)
.translate((-(HANDLE_WIDTH_PX / 2.0), -(HANDLE_WIDTH_PX / 2.0)))
.width(Pixels(HANDLE_WIDTH_PX))
.height(Pixels(HANDLE_WIDTH_PX))
.hoverable(false); .hoverable(false);
} }
@ -370,23 +358,19 @@ impl XyPad {
/// space there, the tooltip will be pushed to the left or the right of the cursor. /// space there, the tooltip will be pushed to the left or the right of the cursor.
fn update_tooltip_pos(&mut self, cx: &mut EventContext) { fn update_tooltip_pos(&mut self, cx: &mut EventContext) {
let bounds = cx.cache.get_bounds(cx.current()); let bounds = cx.cache.get_bounds(cx.current());
let relative_x = cx.mouse.cursorx - bounds.x; let relative_x = cx.mouse().cursorx - bounds.x;
let relative_y = cx.mouse.cursory - bounds.y; let relative_y = cx.mouse().cursory - bounds.y;
// These positions need to take DPI scaling into account // These positions need to take DPI scaling into account
let dpi_scale = cx.style.dpi_factor as f32; let dpi_scale = cx.scale_factor();
let padding = 2.0 * dpi_scale; let padding = 2.0 * dpi_scale;
// If there's not enough space at the top right, we'll move the tooltip to the // If there's not enough space at the top right, we'll move the tooltip to the
// bottom and/or the left // bottom and/or the left
// NOTE: This is hardcoded to find the tooltip. The Binding also counts as a child. // NOTE: This is hardcoded to find the tooltip. The Binding also counts as a child.
let binding_entity = cx let binding_entity = cx.last_child().expect("Missing child view in X-Y pad");
.tree
.get_last_child(cx.current())
.expect("Missing child view in X-Y pad");
let tooltip_entity = cx let tooltip_entity = cx
.tree .with_current(binding_entity, |cx| cx.last_child())
.get_last_child(binding_entity)
.expect("Missing child view in X-Y pad binding"); .expect("Missing child view in X-Y pad binding");
let tooltip_bounds = cx.cache.get_bounds(tooltip_entity); let tooltip_bounds = cx.cache.get_bounds(tooltip_entity);
// NOTE: The width can vary drastically depending on the frequency value, so we'll // NOTE: The width can vary drastically depending on the frequency value, so we'll
@ -463,11 +447,11 @@ impl View for XyPad {
event.map(|window_event, meta| match window_event { event.map(|window_event, meta| match window_event {
WindowEvent::MouseDown(MouseButton::Left) WindowEvent::MouseDown(MouseButton::Left)
| WindowEvent::MouseTripleClick(MouseButton::Left) => { | WindowEvent::MouseTripleClick(MouseButton::Left) => {
if cx.modifiers.alt() { if cx.modifiers().alt() {
// ALt+Click brings up a text entry dialog // ALt+Click brings up a text entry dialog
self.text_input_active = true; self.text_input_active = true;
cx.set_active(true); cx.set_active(true);
} else if cx.modifiers.command() { } else if cx.modifiers().command() {
// Ctrl+Click, double click, and right clicks should reset the parameter instead // Ctrl+Click, double click, and right clicks should reset the parameter instead
// of initiating a drag operation // of initiating a drag operation
self.begin_set_parameters(cx); self.begin_set_parameters(cx);
@ -483,18 +467,18 @@ impl View for XyPad {
// When holding down shift while clicking on the X-Y pad we want to granuarly // When holding down shift while clicking on the X-Y pad we want to granuarly
// edit the parameter without jumping to a new value // edit the parameter without jumping to a new value
self.begin_set_parameters(cx); self.begin_set_parameters(cx);
if cx.modifiers.shift() { if cx.modifiers().shift() {
self.granular_drag_status = Some(GranularDragStatus { self.granular_drag_status = Some(GranularDragStatus {
starting_x_coordinate: cx.mouse.cursorx, starting_x_coordinate: cx.mouse().cursorx,
x_starting_value: self.x_param_base.unmodulated_normalized_value(), x_starting_value: self.x_param_base.unmodulated_normalized_value(),
starting_y_coordinate: cx.mouse.cursory, starting_y_coordinate: cx.mouse().cursory,
y_starting_value: self.y_param_base.unmodulated_normalized_value(), y_starting_value: self.y_param_base.unmodulated_normalized_value(),
}); });
} else { } else {
self.granular_drag_status = None; self.granular_drag_status = None;
self.set_normalized_values_for_mouse_pos( self.set_normalized_values_for_mouse_pos(
cx, cx,
(cx.mouse.cursorx, cx.mouse.cursory), (cx.mouse().cursorx, cx.mouse().cursory),
false, false,
); );
} }
@ -532,9 +516,9 @@ impl View for XyPad {
self.update_tooltip_pos(cx); self.update_tooltip_pos(cx);
if self.drag_active { if self.drag_active {
let dpi_scale = cx.style.dpi_factor as f32; let dpi_scale = cx.scale_factor();
if cx.modifiers.shift() { if cx.modifiers().shift() {
// If shift is being held then the drag should be more granular instead of // If shift is being held then the drag should be more granular instead of
// absolute // absolute
// TODO: Mouse warping is really needed here, but it's not exposed right now // TODO: Mouse warping is really needed here, but it's not exposed right now
@ -577,13 +561,17 @@ impl View for XyPad {
self.set_normalized_values_for_mouse_pos( self.set_normalized_values_for_mouse_pos(
cx, cx,
(start_x + delta_x, start_y + delta_y), (start_x + delta_x, start_y + delta_y),
cx.modifiers.alt(), cx.modifiers().alt(),
); );
} else { } else {
// When alt is pressed _while_ dragging, the frequency parameter on the // When alt is pressed _while_ dragging, the frequency parameter on the
// X-axis snaps to whole notes // X-axis snaps to whole notes
self.granular_drag_status = None; self.granular_drag_status = None;
self.set_normalized_values_for_mouse_pos(cx, (*x, *y), cx.modifiers.alt()); self.set_normalized_values_for_mouse_pos(
cx,
(*x, *y),
cx.modifiers().alt(),
);
} }
} }
} }
@ -596,8 +584,8 @@ impl View for XyPad {
self.granular_drag_status = None; self.granular_drag_status = None;
self.set_normalized_values_for_mouse_pos( self.set_normalized_values_for_mouse_pos(
cx, cx,
(cx.mouse.cursorx, cx.mouse.cursory), (cx.mouse().cursorx, cx.mouse().cursory),
cx.modifiers.alt(), cx.modifiers().alt(),
); );
} }
} }
@ -613,7 +601,7 @@ impl View for XyPad {
|value| (self.x_renormalize_event)((self.x_renormalize_display)(value)); |value| (self.x_renormalize_event)((self.x_renormalize_display)(value));
if remaining_scroll_x.abs() >= 1.0 { if remaining_scroll_x.abs() >= 1.0 {
let use_finer_steps = cx.modifiers.shift(); let use_finer_steps = cx.modifiers().shift();
// Scrolling while dragging needs to be taken into account here // Scrolling while dragging needs to be taken into account here
if !self.drag_active { if !self.drag_active {
@ -646,7 +634,7 @@ impl View for XyPad {
} }
if remaining_scroll_y.abs() >= 1.0 { if remaining_scroll_y.abs() >= 1.0 {
let use_finer_steps = cx.modifiers.shift(); let use_finer_steps = cx.modifiers().shift();
// Scrolling while dragging needs to be taken into account here // Scrolling while dragging needs to be taken into account here
if !self.drag_active { if !self.drag_active {