Update the Diopser XY pad
The translation can now be done from the stylesheet, in percentages.
This commit is contained in:
parent
669edc1df5
commit
762844f8f6
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue