Snap Diopser frequency to notes with Alt+drag
This commit is contained in:
parent
4dbc0c1a87
commit
11f8b242c5
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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::vizia::prelude::*;
|
||||||
use nih_plug_vizia::widgets::param_base::ParamWidgetBase;
|
use nih_plug_vizia::widgets::param_base::ParamWidgetBase;
|
||||||
use nih_plug_vizia::widgets::util::{self, ModifiersExt};
|
use nih_plug_vizia::widgets::util::{self, ModifiersExt};
|
||||||
|
@ -37,6 +37,11 @@ pub struct XyPad {
|
||||||
x_param_base: ParamWidgetBase,
|
x_param_base: ParamWidgetBase,
|
||||||
y_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
|
/// Will be set to `true` if we're dragging the parameter. Resetting the parameter or entering a
|
||||||
/// text value should not initiate a drag.
|
/// text value should not initiate a drag.
|
||||||
drag_active: bool,
|
drag_active: bool,
|
||||||
|
@ -93,6 +98,8 @@ impl XyPad {
|
||||||
x_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_x_param),
|
x_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_x_param),
|
||||||
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param),
|
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param),
|
||||||
|
|
||||||
|
frequency_range: crate::filter_frequency_range(),
|
||||||
|
|
||||||
drag_active: false,
|
drag_active: false,
|
||||||
granular_drag_status: None,
|
granular_drag_status: None,
|
||||||
|
|
||||||
|
@ -210,16 +217,25 @@ impl XyPad {
|
||||||
&self,
|
&self,
|
||||||
cx: &mut EventContext,
|
cx: &mut EventContext,
|
||||||
(x_pos, y_pos): (f32, f32),
|
(x_pos, y_pos): (f32, f32),
|
||||||
|
snap_to_whole_notes: bool,
|
||||||
) {
|
) {
|
||||||
self.set_normalized_values(
|
// When snapping to whole notes, we'll transform the normalized value back to unnormalized
|
||||||
cx,
|
// (this is hardcoded for the filter frequency parameter)
|
||||||
(
|
let mut x_value = util::remap_current_entity_x_coordinate(cx, x_pos);
|
||||||
util::remap_current_entity_x_coordinate(cx, x_pos),
|
if snap_to_whole_notes {
|
||||||
// We want the top of the widget to be 1.0 and the bottom to be 0.0,
|
let x_freq = self.frequency_range.unnormalize(x_value);
|
||||||
// this is the opposite of how the y-coordinate works
|
let fractional_note = nih_plug::util::freq_to_midi_note(x_freq);
|
||||||
1.0 - util::remap_current_entity_y_coordinate(cx, y_pos),
|
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.
|
/// 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(
|
self.set_normalized_values_for_mouse_pos(
|
||||||
cx,
|
cx,
|
||||||
(cx.mouse.cursorx, cx.mouse.cursory),
|
(cx.mouse.cursorx, cx.mouse.cursory),
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,10 +381,10 @@ impl View for XyPad {
|
||||||
if self.drag_active {
|
if self.drag_active {
|
||||||
let dpi_scale = cx.style.dpi_factor as f32;
|
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
|
// 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
|
||||||
if cx.modifiers.shift() {
|
|
||||||
let granular_drag_status =
|
let granular_drag_status =
|
||||||
*self
|
*self
|
||||||
.granular_drag_status
|
.granular_drag_status
|
||||||
|
@ -401,13 +418,17 @@ impl View for XyPad {
|
||||||
* GRANULAR_DRAG_MULTIPLIER)
|
* GRANULAR_DRAG_MULTIPLIER)
|
||||||
* dpi_scale;
|
* dpi_scale;
|
||||||
|
|
||||||
|
// This also takes the Alt+drag note snapping into account
|
||||||
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(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// When alt is pressed _while_ dragging, the frequency parameter on the
|
||||||
|
// 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));
|
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
|
// If this happens while dragging, snap back to reality uh I mean the current screen
|
||||||
// position
|
// position
|
||||||
if self.drag_active && self.granular_drag_status.is_some() {
|
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.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(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue