Add a widget for labels with Alt+click text entry
This commit is contained in:
parent
89af7e366f
commit
33263b825e
|
@ -60,6 +60,25 @@ param-button.bypass:checked {
|
||||||
transition: background-color 0.1 0;
|
transition: background-color 0.1 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
param-label {
|
||||||
|
/* These should be overridden when the widget is used */
|
||||||
|
height: 20px;
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a textbox, but we want it to appear just like the label */
|
||||||
|
param-label .value-entry {
|
||||||
|
/* Vizia doesn't support the unset value */
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
param-slider .value-entry .caret {
|
||||||
|
background-color: #0a0a0a;
|
||||||
|
}
|
||||||
|
param-slider .value-entry .selection {
|
||||||
|
background-color: #0a0a0a30;
|
||||||
|
}
|
||||||
|
|
||||||
param-slider {
|
param-slider {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use super::ViziaState;
|
||||||
mod generic_ui;
|
mod generic_ui;
|
||||||
pub mod param_base;
|
pub mod param_base;
|
||||||
mod param_button;
|
mod param_button;
|
||||||
|
mod param_label;
|
||||||
mod param_slider;
|
mod param_slider;
|
||||||
mod peak_meter;
|
mod peak_meter;
|
||||||
mod resize_handle;
|
mod resize_handle;
|
||||||
|
@ -21,6 +22,7 @@ pub mod util;
|
||||||
|
|
||||||
pub use generic_ui::GenericUi;
|
pub use generic_ui::GenericUi;
|
||||||
pub use param_button::{ParamButton, ParamButtonExt};
|
pub use param_button::{ParamButton, ParamButtonExt};
|
||||||
|
pub use param_label::ParamLabel;
|
||||||
pub use param_slider::{ParamSlider, ParamSliderExt, ParamSliderStyle};
|
pub use param_slider::{ParamSlider, ParamSliderExt, ParamSliderStyle};
|
||||||
pub use peak_meter::PeakMeter;
|
pub use peak_meter::PeakMeter;
|
||||||
pub use resize_handle::ResizeHandle;
|
pub use resize_handle::ResizeHandle;
|
||||||
|
|
141
nih_plug_vizia/src/widgets/param_label.rs
Normal file
141
nih_plug_vizia/src/widgets/param_label.rs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
//! A special label that integrates with NIH-plug's [`Param`] types.
|
||||||
|
|
||||||
|
use nih_plug::prelude::Param;
|
||||||
|
use vizia::prelude::*;
|
||||||
|
|
||||||
|
use super::param_base::ParamWidgetBase;
|
||||||
|
use super::util::ModifiersExt;
|
||||||
|
|
||||||
|
/// A special label that integrates with NIH-plug's [`Param`] types. This should only be used to
|
||||||
|
/// allow text entry for parameters with no dedicated control, like the two parameters bound to an
|
||||||
|
/// X-Y pad. Use regular [`Label`]s instead when the label accompanies a parameter widget.
|
||||||
|
#[derive(Lens)]
|
||||||
|
pub struct ParamLabel {
|
||||||
|
param_base: ParamWidgetBase,
|
||||||
|
|
||||||
|
/// Will be set to `true` when the field gets Alt+Click'ed which will replace the label with a
|
||||||
|
/// text box.
|
||||||
|
text_input_active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ParamLabelEvent {
|
||||||
|
/// Text input has been cancelled without submitting a new value.
|
||||||
|
CancelTextInput,
|
||||||
|
/// A new value has been sent by the text input dialog after pressing Enter.
|
||||||
|
TextInput(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParamLabel {
|
||||||
|
/// Creates a new [`ParamLabel`] for the given parameter. See
|
||||||
|
/// [`ParamSlider`][super::ParamSlider] for more information on this function's arguments.
|
||||||
|
///
|
||||||
|
/// To make this work, you'll need to set a fixed (non-auto) width and height on the
|
||||||
|
/// `ParamLabel`.
|
||||||
|
pub fn new<L, Params, P, FMap>(
|
||||||
|
cx: &mut Context,
|
||||||
|
params: L,
|
||||||
|
params_to_param: FMap,
|
||||||
|
) -> Handle<Self>
|
||||||
|
where
|
||||||
|
L: Lens<Target = Params> + Clone,
|
||||||
|
Params: 'static,
|
||||||
|
P: Param + 'static,
|
||||||
|
FMap: Fn(&Params) -> &P + Copy + 'static,
|
||||||
|
{
|
||||||
|
// This is in essence a super stripped down version of `ParamSlider`
|
||||||
|
Self {
|
||||||
|
param_base: ParamWidgetBase::new(cx, params.clone(), params_to_param),
|
||||||
|
|
||||||
|
text_input_active: false,
|
||||||
|
}
|
||||||
|
.build(
|
||||||
|
cx,
|
||||||
|
ParamWidgetBase::view(params, params_to_param, move |cx, param_data| {
|
||||||
|
let param_name = param_data.param().name().to_owned();
|
||||||
|
|
||||||
|
// Can't use `.to_string()` here as that would include modulation
|
||||||
|
let display_value_lens = param_data.make_lens(|param| {
|
||||||
|
param.normalized_value_to_string(param.unmodulated_normalized_value(), true)
|
||||||
|
});
|
||||||
|
|
||||||
|
Binding::new(
|
||||||
|
cx,
|
||||||
|
ParamLabel::text_input_active,
|
||||||
|
move |cx, text_input_active| {
|
||||||
|
if text_input_active.get(cx) {
|
||||||
|
Textbox::new(cx, display_value_lens.clone())
|
||||||
|
.class("value-entry")
|
||||||
|
.on_submit(|cx, string, success| {
|
||||||
|
if success {
|
||||||
|
cx.emit(ParamLabelEvent::TextInput(string))
|
||||||
|
} else {
|
||||||
|
cx.emit(ParamLabelEvent::CancelTextInput);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_build(|cx| {
|
||||||
|
cx.emit(TextEvent::StartEdit);
|
||||||
|
cx.emit(TextEvent::SelectAll);
|
||||||
|
})
|
||||||
|
.class("align_center")
|
||||||
|
.child_top(Stretch(1.0))
|
||||||
|
.child_bottom(Stretch(1.0))
|
||||||
|
.height(Stretch(1.0))
|
||||||
|
.width(Stretch(1.0));
|
||||||
|
} else {
|
||||||
|
Label::new(cx, ¶m_name)
|
||||||
|
.class("param-name")
|
||||||
|
.child_space(Stretch(1.0))
|
||||||
|
.height(Stretch(1.0))
|
||||||
|
.width(Stretch(1.0));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ParamLabel {
|
||||||
|
fn element(&self) -> Option<&'static str> {
|
||||||
|
Some("param-label")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
|
||||||
|
event.map(|param_slider_event, meta| match param_slider_event {
|
||||||
|
ParamLabelEvent::CancelTextInput => {
|
||||||
|
self.text_input_active = false;
|
||||||
|
cx.set_active(false);
|
||||||
|
|
||||||
|
meta.consume();
|
||||||
|
}
|
||||||
|
ParamLabelEvent::TextInput(string) => {
|
||||||
|
if let Some(normalized_value) = self.param_base.string_to_normalized_value(string) {
|
||||||
|
self.param_base.begin_set_parameter(cx);
|
||||||
|
self.param_base.set_normalized_value(cx, normalized_value);
|
||||||
|
self.param_base.end_set_parameter(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.text_input_active = false;
|
||||||
|
|
||||||
|
meta.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event.map(|window_event, meta| match window_event {
|
||||||
|
// We don't handle Ctrl+click/double click for reset right now, only value entry is
|
||||||
|
// supported here
|
||||||
|
WindowEvent::MouseDown(MouseButton::Left)
|
||||||
|
| WindowEvent::MouseDoubleClick(MouseButton::Left)
|
||||||
|
| WindowEvent::MouseTripleClick(MouseButton::Left) => {
|
||||||
|
if cx.modifiers.alt() {
|
||||||
|
// ALt+Click brings up a text entry dialog
|
||||||
|
self.text_input_active = true;
|
||||||
|
cx.set_active(true);
|
||||||
|
|
||||||
|
meta.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue