1
0
Fork 0

Snap Diopser frequency to notes with Alt+drag

This commit is contained in:
Robbert van der Helm 2022-11-18 16:11:54 +01:00
parent 4dbc0c1a87
commit 11f8b242c5

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use nih_plug::prelude::Param;
use nih_plug::prelude::{FloatRange, Param};
use nih_plug_vizia::vizia::prelude::*;
use nih_plug_vizia::widgets::param_base::ParamWidgetBase;
use nih_plug_vizia::widgets::util::{self, ModifiersExt};
@ -37,6 +37,11 @@ pub struct XyPad {
x_param_base: ParamWidgetBase,
y_param_base: ParamWidgetBase,
/// The same range as that used by the filter frequency parameter. This is used to snap to
/// frequencies when holding Alt while dragging.
/// NOTE: This is hardcoded to work with the filter frequency parameter.
frequency_range: FloatRange,
/// Will be set to `true` if we're dragging the parameter. Resetting the parameter or entering a
/// text value should not initiate a drag.
drag_active: bool,
@ -93,6 +98,8 @@ impl XyPad {
x_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_x_param),
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param),
frequency_range: crate::filter_frequency_range(),
drag_active: false,
granular_drag_status: None,
@ -210,16 +217,25 @@ impl XyPad {
&self,
cx: &mut EventContext,
(x_pos, y_pos): (f32, f32),
snap_to_whole_notes: bool,
) {
self.set_normalized_values(
cx,
(
util::remap_current_entity_x_coordinate(cx, x_pos),
// We want the top of the widget to be 1.0 and the bottom to be 0.0,
// this is the opposite of how the y-coordinate works
1.0 - util::remap_current_entity_y_coordinate(cx, y_pos),
),
);
// When snapping to whole notes, we'll transform the normalized value back to unnormalized
// (this is hardcoded for the filter frequency parameter)
let mut x_value = util::remap_current_entity_x_coordinate(cx, x_pos);
if snap_to_whole_notes {
let x_freq = self.frequency_range.unnormalize(x_value);
let fractional_note = nih_plug::util::freq_to_midi_note(x_freq);
let note = fractional_note.round();
let note_freq = nih_plug::util::f32_midi_note_to_freq(note);
x_value = self.frequency_range.normalize(note_freq);
}
// We want the top of the widget to be 1.0 and the bottom to be 0.0, this is the opposite of
// how the y-coordinate works
let y_value = 1.0 - util::remap_current_entity_y_coordinate(cx, y_pos);
self.set_normalized_values(cx, (x_value, y_value));
}
/// Should be called at the end of a drag operation.
@ -329,6 +345,7 @@ impl View for XyPad {
self.set_normalized_values_for_mouse_pos(
cx,
(cx.mouse.cursorx, cx.mouse.cursory),
false,
);
}
}
@ -364,10 +381,10 @@ impl View for XyPad {
if self.drag_active {
let dpi_scale = cx.style.dpi_factor as f32;
if cx.modifiers.shift() {
// If shift is being held then the drag should be more granular instead of
// absolute
// TODO: Mouse warping is really needed here, but it's not exposed right now
if cx.modifiers.shift() {
let granular_drag_status =
*self
.granular_drag_status
@ -401,13 +418,17 @@ impl View for XyPad {
* GRANULAR_DRAG_MULTIPLIER)
* dpi_scale;
// This also takes the Alt+drag note snapping into account
self.set_normalized_values_for_mouse_pos(
cx,
(start_x + delta_x, start_y + delta_y),
cx.modifiers.alt(),
);
} else {
// When alt is pressed _while_ dragging, the frequency parameter on the
// X-axis snaps to whole notes
self.granular_drag_status = None;
self.set_normalized_values_for_mouse_pos(cx, (*x, *y));
self.set_normalized_values_for_mouse_pos(cx, (*x, *y), cx.modifiers.alt());
}
}
}
@ -415,10 +436,13 @@ impl View for XyPad {
// If this happens while dragging, snap back to reality uh I mean the current screen
// position
if self.drag_active && self.granular_drag_status.is_some() {
// When alt is pressed _while_ dragging, the frequency parameter on the X-axis
// snaps to whole notes
self.granular_drag_status = None;
self.set_normalized_values_for_mouse_pos(
cx,
(cx.mouse.cursorx, cx.mouse.cursory),
cx.modifiers.alt(),
);
}
}