1
0
Fork 0

Fix text entry for vizia ParamSlider

With a couple new vizia commits that add the required behavior through
events and a new callback.
This commit is contained in:
Robbert van der Helm 2022-03-21 15:58:12 +01:00
parent a1cb362dda
commit 6f264bad85
2 changed files with 136 additions and 117 deletions

8
Cargo.lock generated
View file

@ -3605,7 +3605,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "vizia" name = "vizia"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#8247518a4d74d741ad27334fc48ba961f43134ff" source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#066ada3af33add684193ce77c6d9512288cc6d28"
dependencies = [ dependencies = [
"vizia_baseview", "vizia_baseview",
"vizia_core", "vizia_core",
@ -3614,7 +3614,7 @@ dependencies = [
[[package]] [[package]]
name = "vizia_baseview" name = "vizia_baseview"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#8247518a4d74d741ad27334fc48ba961f43134ff" source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#066ada3af33add684193ce77c6d9512288cc6d28"
dependencies = [ dependencies = [
"baseview", "baseview",
"femtovg", "femtovg",
@ -3626,7 +3626,7 @@ dependencies = [
[[package]] [[package]]
name = "vizia_core" name = "vizia_core"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#8247518a4d74d741ad27334fc48ba961f43134ff" source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#066ada3af33add684193ce77c6d9512288cc6d28"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"copypasta", "copypasta",
@ -3649,7 +3649,7 @@ dependencies = [
[[package]] [[package]]
name = "vizia_derive" name = "vizia_derive"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#8247518a4d74d741ad27334fc48ba961f43134ff" source = "git+https://github.com/robbert-vdh/vizia.git?branch=feature/baseview-modifiers#066ada3af33add684193ce77c6d9512288cc6d28"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -16,7 +16,6 @@ const GRANULAR_DRAG_MULTIPLIER: f32 = 0.1;
/// TODO: Handle scrolling for steps (and shift+scroll for smaller steps?) /// TODO: Handle scrolling for steps (and shift+scroll for smaller steps?)
/// TODO: We may want to add a couple dedicated event handlers if it seems like those would be /// TODO: We may want to add a couple dedicated event handlers if it seems like those would be
/// useful, having a completely self contained widget is perfectly fine for now though /// useful, having a completely self contained widget is perfectly fine for now though
/// TODO: Text entry doesn't work correctly yet because vizia's still missing some functionality
pub struct ParamSlider { pub struct ParamSlider {
// We're not allowed to store a reference to the parameter internally, at least not in the // We're not allowed to store a reference to the parameter internally, at least not in the
// struct that implements [`View`] // struct that implements [`View`]
@ -81,10 +80,9 @@ impl Model for ParamSliderInternal {
match param_slider_internal_event { match param_slider_internal_event {
ParamSliderInternalEvent::SetStyle(style) => self.style = *style, ParamSliderInternalEvent::SetStyle(style) => self.style = *style,
ParamSliderInternalEvent::SetTextInputActive(active) => { ParamSliderInternalEvent::SetTextInputActive(active) => {
// When this gets set to `true` the textbox widget will be created, and when it
// gets created we'll focus it and select all text
self.text_input_active = *active; self.text_input_active = *active;
if *active {
// TODO: Interact with the Textbox widget
}
} }
} }
} }
@ -146,113 +144,140 @@ impl ParamSlider {
&& step_count.is_none() && step_count.is_none()
&& (0.45..=0.55).contains(&default_value); && (0.45..=0.55).contains(&default_value);
let param_display_value_lens =
params.map(move |params| params_to_param(params).to_string());
let param_preview_display_value_lens = |normalized_value| {
params.map(move |params| {
params_to_param(params).normalized_value_to_string(normalized_value, true)
})
};
let normalized_param_value_lens =
params.map(move |params| params_to_param(params).normalized_value());
// Only draw the text input widget when it gets focussed. Otherwise, overlay the // Only draw the text input widget when it gets focussed. Otherwise, overlay the
// label with the slider. We need to always include the text input widget in the // label with the slider. Creating the textbox based on
// tree because using a `Binding` here would cause the text box to get recreated // `ParamSliderInternal::text_input_active` lets us focus the textbox when it gets
// whenever `ParamSliderInternal::text_input_active` changes. // created.
Textbox::new(cx, param_display_value_lens.clone()) Binding::new(
.class("value-entry") cx,
.on_submit(|cx, string| cx.emit(ParamSliderEvent::TextInput(string))) ParamSliderInternal::text_input_active,
.on_focus_out(|cx| cx.emit(ParamSliderEvent::CancelTextInput)) move |cx, text_input_active| {
.display(ParamSliderInternal::text_input_active) let param_display_value_lens =
.child_space(Stretch(1.0)) params.map(move |params| params_to_param(params).to_string());
.height(Stretch(1.0)) let param_preview_display_value_lens = |normalized_value| {
.width(Stretch(1.0)); params.map(move |params| {
params_to_param(params)
// This only gets shown when the text box isn't active .normalized_value_to_string(normalized_value, true)
ZStack::new(cx, move |cx| { })
// The filled bar portion. This can be visualized in a couple different };
// ways depending on the current style property. See let normalized_param_value_lens =
// [`ParamSliderStyle`]. params.map(move |params| params_to_param(params).normalized_value());
Element::new(cx)
.class("fill") if *text_input_active.get(cx) {
.height(Stretch(1.0)) Textbox::new(cx, param_display_value_lens)
.bind(normalized_param_value_lens, move |handle, value| { .class("value-entry")
let current_value = *value.get(handle.cx); .on_submit(|cx, string| {
let (start_t, delta) = match style { // FIXME: Remove
ParamSliderStyle::Centered if draw_fill_from_default => { eprintln!("on_submit");
let delta = (default_value - current_value).abs(); cx.emit(ParamSliderEvent::TextInput(string))
( })
default_value.min(current_value), .on_edit_end(|cx| {
// Don't draw the filled portion at all if it could have been a // FIXME: Remove
// rounding error since those slivers just look weird eprintln!("on_edit_end");
if delta >= 1e-3 { delta } else { 0.0 }, cx.emit(ParamSliderEvent::CancelTextInput);
) })
} .on_build(|cx| {
ParamSliderStyle::Centered | ParamSliderStyle::FromLeft => { // FIXME: Remove
(0.0, current_value) eprintln!("on_build");
} cx.emit(TextEvent::StartEdit);
ParamSliderStyle::CurrentStep cx.emit(TextEvent::SelectAll);
| ParamSliderStyle::CurrentStepLabeled => { })
let previous_step = unsafe { .child_space(Stretch(1.0))
param_ptr.previous_normalized_step(current_value) .height(Stretch(1.0))
}; .width(Stretch(1.0));
let next_step = } else {
unsafe { param_ptr.next_normalized_step(current_value) }; ZStack::new(cx, move |cx| {
( // The filled bar portion. This can be visualized in a couple
(previous_step + current_value) / 2.0, // different ways depending on the current style property. See
(next_step + current_value) / 2.0, // [`ParamSliderStyle`].
) Element::new(cx)
} .class("fill")
}; .height(Stretch(1.0))
.bind(normalized_param_value_lens, move |handle, value| {
handle let current_value = *value.get(handle.cx);
.left(Percentage(start_t * 100.0)) let (start_t, delta) = match style {
.width(Percentage(delta * 100.0)); ParamSliderStyle::Centered
}) if draw_fill_from_default =>
// Hovering is handled on the param slider as a whole, this should {
// not affect that let delta = (default_value - current_value).abs();
.hoverable(false); (
default_value.min(current_value),
// Either display the current value, or display all values over the // Don't draw the filled portion at all if it
// parameter's steps // could have been a rounding error since those
// TODO: Do the same thing as in the iced widget where we draw the // slivers just look weird
// text overlapping the fill area slightly differently. We can if delta >= 1e-3 { delta } else { 0.0 },
// set the cip region directly in vizia. )
match (style, step_count) { }
(ParamSliderStyle::CurrentStepLabeled, Some(step_count)) => { ParamSliderStyle::Centered
HStack::new(cx, |cx| { | ParamSliderStyle::FromLeft => (0.0, current_value),
// There are step_count + 1 possible values for a ParamSliderStyle::CurrentStep
// discrete parameter | ParamSliderStyle::CurrentStepLabeled => {
for value in 0..step_count + 1 { let previous_step = unsafe {
let normalized_value = value as f32 / step_count as f32; param_ptr
Label::new( .previous_normalized_step(current_value)
cx, };
param_preview_display_value_lens(normalized_value), let next_step = unsafe {
) param_ptr.next_normalized_step(current_value)
.class("value") };
.class("value--multiple") (
.height(Stretch(1.0)) (previous_step + current_value) / 2.0,
.width(Stretch(1.0)) (next_step + current_value) / 2.0,
.hoverable(false); )
} }
};
handle
.left(Percentage(start_t * 100.0))
.width(Percentage(delta * 100.0));
})
// Hovering is handled on the param slider as a whole, this
// should not affect that
.hoverable(false);
// Either display the current value, or display all values over the
// parameter's steps
// TODO: Do the same thing as in the iced widget where we draw the
// text overlapping the fill area slightly differently. We can
// set the cip region directly in vizia.
match (style, step_count) {
(ParamSliderStyle::CurrentStepLabeled, Some(step_count)) => {
HStack::new(cx, |cx| {
// There are step_count + 1 possible values for a
// discrete parameter
for value in 0..step_count + 1 {
let normalized_value =
value as f32 / step_count as f32;
Label::new(
cx,
param_preview_display_value_lens(
normalized_value,
),
)
.class("value")
.class("value--multiple")
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false);
}
})
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false);
}
_ => {
Label::new(cx, param_display_value_lens)
.class("value")
.class("value--single")
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false);
}
};
}) })
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false); .hoverable(false);
} }
_ => { },
Label::new(cx, param_display_value_lens) );
.class("value")
.class("value--single")
.height(Stretch(1.0))
.width(Stretch(1.0))
.hoverable(false);
}
};
})
.display(ParamSliderInternal::text_input_active.map(|active| !active))
.hoverable(false);
}); });
}) })
} }
@ -310,12 +335,6 @@ impl View for ParamSlider {
// ALt+Click brings up a text entry dialog // ALt+Click brings up a text entry dialog
cx.emit(ParamSliderInternalEvent::SetTextInputActive(true)); cx.emit(ParamSliderInternalEvent::SetTextInputActive(true));
cx.current.set_active(cx, true); cx.current.set_active(cx, true);
// TODO: Once vizia implements it: (and probably do this from
// `SetTextInputActive`)
// - Focus the text box
// - Select all text
// - Move the caret to the end
} else if cx.modifiers.command() || self.is_double_click { } else if cx.modifiers.command() || self.is_double_click {
// Ctrl+Click and double click should reset the parameter instead of initiating // Ctrl+Click and double click should reset the parameter instead of initiating
// a drag operation // a drag operation