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:
parent
a1cb362dda
commit
6f264bad85
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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,33 +144,51 @@ impl ParamSlider {
|
||||||
&& step_count.is_none()
|
&& step_count.is_none()
|
||||||
&& (0.45..=0.55).contains(&default_value);
|
&& (0.45..=0.55).contains(&default_value);
|
||||||
|
|
||||||
|
// Only draw the text input widget when it gets focussed. Otherwise, overlay the
|
||||||
|
// label with the slider. Creating the textbox based on
|
||||||
|
// `ParamSliderInternal::text_input_active` lets us focus the textbox when it gets
|
||||||
|
// created.
|
||||||
|
Binding::new(
|
||||||
|
cx,
|
||||||
|
ParamSliderInternal::text_input_active,
|
||||||
|
move |cx, text_input_active| {
|
||||||
let param_display_value_lens =
|
let param_display_value_lens =
|
||||||
params.map(move |params| params_to_param(params).to_string());
|
params.map(move |params| params_to_param(params).to_string());
|
||||||
let param_preview_display_value_lens = |normalized_value| {
|
let param_preview_display_value_lens = |normalized_value| {
|
||||||
params.map(move |params| {
|
params.map(move |params| {
|
||||||
params_to_param(params).normalized_value_to_string(normalized_value, true)
|
params_to_param(params)
|
||||||
|
.normalized_value_to_string(normalized_value, true)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let normalized_param_value_lens =
|
let normalized_param_value_lens =
|
||||||
params.map(move |params| params_to_param(params).normalized_value());
|
params.map(move |params| params_to_param(params).normalized_value());
|
||||||
|
|
||||||
// Only draw the text input widget when it gets focussed. Otherwise, overlay the
|
if *text_input_active.get(cx) {
|
||||||
// label with the slider. We need to always include the text input widget in the
|
Textbox::new(cx, param_display_value_lens)
|
||||||
// tree because using a `Binding` here would cause the text box to get recreated
|
|
||||||
// whenever `ParamSliderInternal::text_input_active` changes.
|
|
||||||
Textbox::new(cx, param_display_value_lens.clone())
|
|
||||||
.class("value-entry")
|
.class("value-entry")
|
||||||
.on_submit(|cx, string| cx.emit(ParamSliderEvent::TextInput(string)))
|
.on_submit(|cx, string| {
|
||||||
.on_focus_out(|cx| cx.emit(ParamSliderEvent::CancelTextInput))
|
// FIXME: Remove
|
||||||
.display(ParamSliderInternal::text_input_active)
|
eprintln!("on_submit");
|
||||||
|
cx.emit(ParamSliderEvent::TextInput(string))
|
||||||
|
})
|
||||||
|
.on_edit_end(|cx| {
|
||||||
|
// FIXME: Remove
|
||||||
|
eprintln!("on_edit_end");
|
||||||
|
cx.emit(ParamSliderEvent::CancelTextInput);
|
||||||
|
})
|
||||||
|
.on_build(|cx| {
|
||||||
|
// FIXME: Remove
|
||||||
|
eprintln!("on_build");
|
||||||
|
cx.emit(TextEvent::StartEdit);
|
||||||
|
cx.emit(TextEvent::SelectAll);
|
||||||
|
})
|
||||||
.child_space(Stretch(1.0))
|
.child_space(Stretch(1.0))
|
||||||
.height(Stretch(1.0))
|
.height(Stretch(1.0))
|
||||||
.width(Stretch(1.0));
|
.width(Stretch(1.0));
|
||||||
|
} else {
|
||||||
// This only gets shown when the text box isn't active
|
|
||||||
ZStack::new(cx, move |cx| {
|
ZStack::new(cx, move |cx| {
|
||||||
// The filled bar portion. This can be visualized in a couple different
|
// The filled bar portion. This can be visualized in a couple
|
||||||
// ways depending on the current style property. See
|
// different ways depending on the current style property. See
|
||||||
// [`ParamSliderStyle`].
|
// [`ParamSliderStyle`].
|
||||||
Element::new(cx)
|
Element::new(cx)
|
||||||
.class("fill")
|
.class("fill")
|
||||||
|
@ -180,25 +196,29 @@ impl ParamSlider {
|
||||||
.bind(normalized_param_value_lens, move |handle, value| {
|
.bind(normalized_param_value_lens, move |handle, value| {
|
||||||
let current_value = *value.get(handle.cx);
|
let current_value = *value.get(handle.cx);
|
||||||
let (start_t, delta) = match style {
|
let (start_t, delta) = match style {
|
||||||
ParamSliderStyle::Centered if draw_fill_from_default => {
|
ParamSliderStyle::Centered
|
||||||
|
if draw_fill_from_default =>
|
||||||
|
{
|
||||||
let delta = (default_value - current_value).abs();
|
let delta = (default_value - current_value).abs();
|
||||||
(
|
(
|
||||||
default_value.min(current_value),
|
default_value.min(current_value),
|
||||||
// Don't draw the filled portion at all if it could have been a
|
// Don't draw the filled portion at all if it
|
||||||
// rounding error since those slivers just look weird
|
// could have been a rounding error since those
|
||||||
|
// slivers just look weird
|
||||||
if delta >= 1e-3 { delta } else { 0.0 },
|
if delta >= 1e-3 { delta } else { 0.0 },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ParamSliderStyle::Centered | ParamSliderStyle::FromLeft => {
|
ParamSliderStyle::Centered
|
||||||
(0.0, current_value)
|
| ParamSliderStyle::FromLeft => (0.0, current_value),
|
||||||
}
|
|
||||||
ParamSliderStyle::CurrentStep
|
ParamSliderStyle::CurrentStep
|
||||||
| ParamSliderStyle::CurrentStepLabeled => {
|
| ParamSliderStyle::CurrentStepLabeled => {
|
||||||
let previous_step = unsafe {
|
let previous_step = unsafe {
|
||||||
param_ptr.previous_normalized_step(current_value)
|
param_ptr
|
||||||
|
.previous_normalized_step(current_value)
|
||||||
|
};
|
||||||
|
let next_step = unsafe {
|
||||||
|
param_ptr.next_normalized_step(current_value)
|
||||||
};
|
};
|
||||||
let next_step =
|
|
||||||
unsafe { param_ptr.next_normalized_step(current_value) };
|
|
||||||
(
|
(
|
||||||
(previous_step + current_value) / 2.0,
|
(previous_step + current_value) / 2.0,
|
||||||
(next_step + current_value) / 2.0,
|
(next_step + current_value) / 2.0,
|
||||||
|
@ -210,8 +230,8 @@ impl ParamSlider {
|
||||||
.left(Percentage(start_t * 100.0))
|
.left(Percentage(start_t * 100.0))
|
||||||
.width(Percentage(delta * 100.0));
|
.width(Percentage(delta * 100.0));
|
||||||
})
|
})
|
||||||
// Hovering is handled on the param slider as a whole, this should
|
// Hovering is handled on the param slider as a whole, this
|
||||||
// not affect that
|
// should not affect that
|
||||||
.hoverable(false);
|
.hoverable(false);
|
||||||
|
|
||||||
// Either display the current value, or display all values over the
|
// Either display the current value, or display all values over the
|
||||||
|
@ -225,10 +245,13 @@ impl ParamSlider {
|
||||||
// There are step_count + 1 possible values for a
|
// There are step_count + 1 possible values for a
|
||||||
// discrete parameter
|
// discrete parameter
|
||||||
for value in 0..step_count + 1 {
|
for value in 0..step_count + 1 {
|
||||||
let normalized_value = value as f32 / step_count as f32;
|
let normalized_value =
|
||||||
|
value as f32 / step_count as f32;
|
||||||
Label::new(
|
Label::new(
|
||||||
cx,
|
cx,
|
||||||
param_preview_display_value_lens(normalized_value),
|
param_preview_display_value_lens(
|
||||||
|
normalized_value,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.class("value")
|
.class("value")
|
||||||
.class("value--multiple")
|
.class("value--multiple")
|
||||||
|
@ -251,8 +274,10 @@ impl ParamSlider {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.display(ParamSliderInternal::text_input_active.map(|active| !active))
|
|
||||||
.hoverable(false);
|
.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
|
||||||
|
|
Loading…
Reference in a new issue