Drag very granularly with Shift+Drag
This commit is contained in:
parent
5dd3cab305
commit
7eb8622736
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -533,6 +533,7 @@ dependencies = [
|
|||
"crossbeam",
|
||||
"egui",
|
||||
"egui-baseview",
|
||||
"lazy_static",
|
||||
"nih_plug",
|
||||
"parking_lot",
|
||||
]
|
||||
|
|
|
@ -15,4 +15,5 @@ crossbeam = "0.8"
|
|||
egui = "0.16"
|
||||
# Upstream doesn't work with the current baseview and egui versions
|
||||
egui-baseview = { git = "https://github.com/robbert-vdh/egui-baseview.git", branch = "fix/update-dependencies" }
|
||||
lazy_static = "1.4"
|
||||
parking_lot = "0.12"
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
use egui::{vec2, Response, Sense, Stroke, TextStyle, Ui, Widget};
|
||||
use egui::{vec2, Response, Sense, Stroke, TextStyle, Ui, Vec2, Widget};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::util;
|
||||
use nih_plug::{Param, ParamSetter};
|
||||
|
||||
/// When shift+dragging a parameter, one pixel dragged corresponds to this much change in the
|
||||
/// noramlized parameter.
|
||||
const GRANULAR_DRAG_MULTIPLIER: f32 = 0.0015;
|
||||
|
||||
lazy_static! {
|
||||
static ref DRAG_NORMALIZED_START_VALUE_MEMORY_ID: egui::Id = egui::Id::new((file!(), 0));
|
||||
static ref DRAG_AMOUNT_MEMORY_ID: egui::Id = egui::Id::new((file!(), 1));
|
||||
}
|
||||
|
||||
/// A slider widget similar to [egui::widgets::Slider] that knows about NIH-plug parameters ranges
|
||||
/// and can get values for it.
|
||||
///
|
||||
/// TODO: Vertical orientation
|
||||
/// TODO: Check below for more input methods that should be added
|
||||
/// TODO: Decouple the logic from the drawing so we can also do things like nobs without having to
|
||||
/// repeat everything
|
||||
pub struct ParamSlider<'a, P: Param> {
|
||||
param: &'a P,
|
||||
setter: &'a ParamSetter<'a>,
|
||||
|
@ -46,9 +58,51 @@ impl<'a, P: Param> ParamSlider<'a, P> {
|
|||
.set_parameter_normalized(self.param, normalized_default);
|
||||
}
|
||||
|
||||
fn granular_drag(&self, ui: &Ui, drag_delta: Vec2) {
|
||||
// Remember the intial position when we started with the granular drag. This value gets
|
||||
// reset whenever we have a normal itneraction with the slider.
|
||||
let start_value = if Self::get_drag_amount_memory(ui) == 0.0 {
|
||||
Self::set_drag_normalized_start_value_memory(ui, self.normalized_value());
|
||||
self.normalized_value()
|
||||
} else {
|
||||
Self::get_drag_normalized_start_value_memory(ui)
|
||||
};
|
||||
|
||||
let total_drag_distance = drag_delta.x + Self::get_drag_amount_memory(ui);
|
||||
Self::set_drag_amount_memory(ui, total_drag_distance);
|
||||
|
||||
self.set_normalized_value(
|
||||
(start_value + (total_drag_distance * GRANULAR_DRAG_MULTIPLIER)).clamp(0.0, 1.0),
|
||||
);
|
||||
}
|
||||
|
||||
fn end_drag(&self) {
|
||||
self.setter.end_set_parameter(self.param);
|
||||
}
|
||||
|
||||
fn get_drag_normalized_start_value_memory(ui: &Ui) -> f32 {
|
||||
ui.memory()
|
||||
.data
|
||||
.get_temp(*DRAG_NORMALIZED_START_VALUE_MEMORY_ID)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
fn set_drag_normalized_start_value_memory(ui: &Ui, amount: f32) {
|
||||
ui.memory()
|
||||
.data
|
||||
.insert_temp(*DRAG_NORMALIZED_START_VALUE_MEMORY_ID, amount);
|
||||
}
|
||||
|
||||
fn get_drag_amount_memory(ui: &Ui) -> f32 {
|
||||
ui.memory()
|
||||
.data
|
||||
.get_temp(*DRAG_AMOUNT_MEMORY_ID)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
fn set_drag_amount_memory(ui: &Ui, amount: f32) {
|
||||
ui.memory().data.insert_temp(*DRAG_AMOUNT_MEMORY_ID, amount);
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Param> Widget for ParamSlider<'_, P> {
|
||||
|
@ -82,17 +136,24 @@ impl<P: Param> Widget for ParamSlider<'_, P> {
|
|||
// TODO: Optionally add alt+click for value entry?
|
||||
// TODO: Handle shift+drag being more granular
|
||||
if response.drag_started() {
|
||||
// When beginning a drag or dragging normally, reset the memory used to keep track of
|
||||
// our granular drag
|
||||
self.begin_drag();
|
||||
Self::set_drag_amount_memory(ui, 0.0);
|
||||
}
|
||||
if let Some(click_pos) = response.interact_pointer_pos() {
|
||||
// Like double clicking, Ctrl+Click should reset the parameter
|
||||
if ui.input().modifiers.command {
|
||||
// Like double clicking, Ctrl+Click should reset the parameter
|
||||
self.reset_param();
|
||||
} else if ui.input().modifiers.shift {
|
||||
// And shift dragging should switch to a more granulra input method
|
||||
self.granular_drag(ui, response.drag_delta());
|
||||
} else {
|
||||
let proportion =
|
||||
egui::emath::remap_clamp(click_pos.x, response.rect.x_range(), 0.0..=1.0)
|
||||
as f64;
|
||||
self.set_normalized_value(proportion as f32);
|
||||
Self::set_drag_amount_memory(ui, 0.0);
|
||||
}
|
||||
}
|
||||
if response.double_clicked() {
|
||||
|
|
|
@ -125,6 +125,7 @@ impl Plugin for Gain {
|
|||
// It's not yet fully implemented, as the text is missing.
|
||||
ui.label("Gain (now linked to some random skewed int)");
|
||||
ui.add(widgets::ParamSlider::for_param(¶ms.some_int, setter));
|
||||
ui.add(widgets::ParamSlider::for_param(¶ms.gain, setter));
|
||||
|
||||
// This is a simple naieve version of a parameter slider that's not aware of how
|
||||
// the parmaeters work
|
||||
|
|
Loading…
Reference in a new issue