mirror of https://github.com/wayvr-org/wayvr.git
wgui: Range sliders, fix swipe scrolling <-> slider conflict
This commit is contained in:
parent
10b14794ed
commit
45af52ddf9
|
|
@ -283,7 +283,7 @@ impl SubtabGeneralSettings {
|
||||||
// get brightness
|
// get brightness
|
||||||
let slider_brightness = state.fetch_component_as::<ComponentSlider>("slider_brightness")?;
|
let slider_brightness = state.fetch_component_as::<ComponentSlider>("slider_brightness")?;
|
||||||
if let Some(brightness) = frontend.interface.monado_brightness_get(data) {
|
if let Some(brightness) = frontend.interface.monado_brightness_get(data) {
|
||||||
slider_brightness.set_value(&mut frontend.layout.common(), brightness * 100.0);
|
slider_brightness.set_value_primary(&mut frontend.layout.common(), brightness * 100.0);
|
||||||
|
|
||||||
slider_brightness.on_value_changed({
|
slider_brightness.on_value_changed({
|
||||||
let tasks = tasks.clone();
|
let tasks = tasks.clone();
|
||||||
|
|
@ -308,11 +308,11 @@ impl SubtabGeneralSettings {
|
||||||
|
|
||||||
// set initial values
|
// set initial values
|
||||||
let (rgb, range_h, range_s, range_v) = config.chroma_key_params.get_rgb_and_hsv_ranges();
|
let (rgb, range_h, range_s, range_v) = config.chroma_key_params.get_rgb_and_hsv_ranges();
|
||||||
slider_keying_curve.set_value(&mut common, config.chroma_key_params.curve * SLIDER_MULTIPLIER);
|
slider_keying_curve.set_value_primary(&mut common, config.chroma_key_params.curve * SLIDER_MULTIPLIER);
|
||||||
slider_keying_despill.set_value(&mut common, config.chroma_key_params.despill * SLIDER_MULTIPLIER);
|
slider_keying_despill.set_value_primary(&mut common, config.chroma_key_params.despill * SLIDER_MULTIPLIER);
|
||||||
slider_keying_hue_range.set_value(&mut common, range_h * SLIDER_MULTIPLIER);
|
slider_keying_hue_range.set_value_primary(&mut common, range_h * SLIDER_MULTIPLIER);
|
||||||
slider_keying_saturation_range.set_value(&mut common, range_s * SLIDER_MULTIPLIER);
|
slider_keying_saturation_range.set_value_primary(&mut common, range_s * SLIDER_MULTIPLIER);
|
||||||
slider_keying_value_range.set_value(&mut common, range_v * SLIDER_MULTIPLIER);
|
slider_keying_value_range.set_value_primary(&mut common, range_v * SLIDER_MULTIPLIER);
|
||||||
cs_keying.set_color(&mut common, rgb);
|
cs_keying.set_color(&mut common, rgb);
|
||||||
|
|
||||||
// prepare callbacks
|
// prepare callbacks
|
||||||
|
|
@ -353,11 +353,11 @@ impl SubtabGeneralSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chroma_update(&mut self, config: &mut GeneralConfig) {
|
fn chroma_update(&mut self, config: &mut GeneralConfig) {
|
||||||
let val_curve = self.slider_keying_curve.get_value();
|
let val_curve = self.slider_keying_curve.get_value_primary();
|
||||||
let val_despill = self.slider_keying_despill.get_value();
|
let val_despill = self.slider_keying_despill.get_value_primary();
|
||||||
let val_range_h = self.slider_keying_hue_range.get_value();
|
let val_range_h = self.slider_keying_hue_range.get_value_primary();
|
||||||
let val_range_s = self.slider_keying_saturation_range.get_value();
|
let val_range_s = self.slider_keying_saturation_range.get_value_primary();
|
||||||
let val_range_v = self.slider_keying_value_range.get_value();
|
let val_range_v = self.slider_keying_value_range.get_value_primary();
|
||||||
let val_rgb = self.cs_keying.get_color();
|
let val_rgb = self.cs_keying.get_color();
|
||||||
|
|
||||||
config.chroma_key_params.despill = val_despill / SLIDER_MULTIPLIER;
|
config.chroma_key_params.despill = val_despill / SLIDER_MULTIPLIER;
|
||||||
|
|
|
||||||
|
|
@ -804,7 +804,7 @@ impl View {
|
||||||
let btn_mute = data.fetch_component_as::<ComponentButton>("btn_mute")?;
|
let btn_mute = data.fetch_component_as::<ComponentButton>("btn_mute")?;
|
||||||
let slider = data.fetch_component_as::<ComponentSlider>("slider")?;
|
let slider = data.fetch_component_as::<ComponentSlider>("slider")?;
|
||||||
|
|
||||||
slider.set_value(&mut common, params.control.on_volume_request()? / VOLUME_MULT);
|
slider.set_value_primary(&mut common, params.control.on_volume_request()? / VOLUME_MULT);
|
||||||
|
|
||||||
checkbox.set_checked(&mut common, params.checked);
|
checkbox.set_checked(&mut common, params.checked);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,11 @@
|
||||||
<CheckBox text="i'm checked by default" checked="1" />
|
<CheckBox text="i'm checked by default" checked="1" />
|
||||||
</rectangle>
|
</rectangle>
|
||||||
|
|
||||||
|
<rectangle macro="rect" flex_direction="row" gap="16">
|
||||||
|
<label text="range slider test" weight="bold" />
|
||||||
|
<Slider value="0.5" value2="1.0" min_value="-5.0" max_value="20.0" width="200" height="24"/>
|
||||||
|
</rectangle>
|
||||||
|
|
||||||
<rectangle macro="rect" flex_direction="row" align_items="start">
|
<rectangle macro="rect" flex_direction="row" align_items="start">
|
||||||
<div flex_direction="column" gap="8">
|
<div flex_direction="column" gap="8">
|
||||||
<label text="height 16" weight="bold" />
|
<label text="height 16" weight="bold" />
|
||||||
|
|
|
||||||
|
|
@ -581,7 +581,7 @@ pub fn apply_custom_command<T>(
|
||||||
.fetch_component_as::<ComponentSlider>(element)
|
.fetch_component_as::<ComponentSlider>(element)
|
||||||
{
|
{
|
||||||
let value_f32 = value_str.parse::<f32>().context("Not a valid number")?;
|
let value_f32 = value_str.parse::<f32>().context("Not a valid number")?;
|
||||||
slider.set_value(&mut com, value_f32);
|
slider.set_value_primary(&mut com, value_f32);
|
||||||
} else if let Ok(radio) = panel
|
} else if let Ok(radio) = panel
|
||||||
.parser_state
|
.parser_state
|
||||||
.fetch_component_as::<ComponentRadioGroup>(element)
|
.fetch_component_as::<ComponentRadioGroup>(element)
|
||||||
|
|
|
||||||
|
|
@ -476,17 +476,17 @@ fn reset_panel(
|
||||||
let c = panel
|
let c = panel
|
||||||
.parser_state
|
.parser_state
|
||||||
.fetch_component_as::<ComponentSlider>("lerp_slider")?;
|
.fetch_component_as::<ComponentSlider>("lerp_slider")?;
|
||||||
c.set_value(&mut com, state.positioning.get_lerp().unwrap_or(1.0));
|
c.set_value_primary(&mut com, state.positioning.get_lerp().unwrap_or(1.0));
|
||||||
|
|
||||||
let c = panel
|
let c = panel
|
||||||
.parser_state
|
.parser_state
|
||||||
.fetch_component_as::<ComponentSlider>("alpha_slider")?;
|
.fetch_component_as::<ComponentSlider>("alpha_slider")?;
|
||||||
c.set_value(&mut com, state.alpha);
|
c.set_value_primary(&mut com, state.alpha);
|
||||||
|
|
||||||
let c = panel
|
let c = panel
|
||||||
.parser_state
|
.parser_state
|
||||||
.fetch_component_as::<ComponentSlider>("curve_slider")?;
|
.fetch_component_as::<ComponentSlider>("curve_slider")?;
|
||||||
c.set_value(&mut com, state.curvature.unwrap_or(0.0));
|
c.set_value_primary(&mut com, state.curvature.unwrap_or(0.0));
|
||||||
|
|
||||||
let c = panel
|
let c = panel
|
||||||
.parser_state
|
.parser_state
|
||||||
|
|
|
||||||
|
|
@ -163,9 +163,9 @@ impl ComponentColorSelector {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut common = layout.common();
|
let mut common = layout.common();
|
||||||
slider_r.set_value(&mut common, state.color.r * 255.0);
|
slider_r.set_value_primary(&mut common, state.color.r * 255.0);
|
||||||
slider_g.set_value(&mut common, state.color.g * 255.0);
|
slider_g.set_value_primary(&mut common, state.color.g * 255.0);
|
||||||
slider_b.set_value(&mut common, state.color.b * 255.0);
|
slider_b.set_value_primary(&mut common, state.color.b * 255.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
slider_r.on_value_changed(self.gen_slider_callback(ColorIndex::Red));
|
slider_r.on_value_changed(self.gen_slider_callback(ColorIndex::Red));
|
||||||
|
|
|
||||||
|
|
@ -29,31 +29,29 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct Value(pub f32);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ValuesMinMax {
|
pub struct Limits {
|
||||||
pub value: f32,
|
|
||||||
pub min_value: f32,
|
pub min_value: f32,
|
||||||
pub max_value: f32,
|
pub max_value: f32,
|
||||||
pub step: f32,
|
pub step: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValuesMinMax {
|
impl Value {
|
||||||
fn to_normalized(&self) -> f32 {
|
pub fn get(&self) -> f32 {
|
||||||
(self.value - self.min_value) / (self.max_value - self.min_value)
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_from_normalized(&self, normalized: f32) -> f32 {
|
pub fn set(&mut self, limits: &Limits, new_value: f32) {
|
||||||
normalized * (self.max_value - self.min_value) + self.min_value
|
let span = limits.max_value - limits.min_value;
|
||||||
}
|
let clamped = new_value.max(limits.min_value).min(limits.max_value);
|
||||||
|
|
||||||
fn set_value(&mut self, new_value: f32) -> &mut Self {
|
|
||||||
let span = self.max_value - self.min_value;
|
|
||||||
let clamped = new_value.max(self.min_value).min(self.max_value);
|
|
||||||
|
|
||||||
// get the step index from min
|
// get the step index from min
|
||||||
let mut k = ((clamped - self.min_value) / self.step).round();
|
let mut k = ((clamped - limits.min_value) / limits.step).round();
|
||||||
|
|
||||||
let k_max = (span / self.step).floor();
|
let k_max = (span / limits.step).floor();
|
||||||
if k < 0.0 {
|
if k < 0.0 {
|
||||||
k = 0.0;
|
k = 0.0;
|
||||||
}
|
}
|
||||||
|
|
@ -61,25 +59,50 @@ impl ValuesMinMax {
|
||||||
k = k_max;
|
k = k_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapped = self.min_value + k * self.step;
|
let snapped = limits.min_value + k * limits.step;
|
||||||
self.value = snapped.max(self.min_value).min(self.max_value);
|
self.0 = snapped.max(limits.min_value).min(limits.max_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self
|
impl Limits {
|
||||||
|
fn to_normalized(&self, value: f32) -> f32 {
|
||||||
|
(value - self.min_value) / (self.max_value - self.min_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_from_normalized(&self, normalized: f32) -> f32 {
|
||||||
|
normalized * (self.max_value - self.min_value) + self.min_value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub style: taffy::Style,
|
pub style: taffy::Style,
|
||||||
pub values: ValuesMinMax,
|
pub limits: Limits,
|
||||||
|
pub value1: Value,
|
||||||
|
pub value2: Option<Value>, // range slider support
|
||||||
pub show_value: bool,
|
pub show_value: bool,
|
||||||
pub tooltip: Option<tooltip::TooltipInfo>,
|
pub tooltip: Option<tooltip::TooltipInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ValueIndex {
|
||||||
|
Primary,
|
||||||
|
Secondary, /* for range sliders */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DraggedBy {
|
||||||
|
index: ValueIndex,
|
||||||
|
device: DeviceBitmask,
|
||||||
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
dragged_by: Option<DeviceBitmask>,
|
dragged_by: Option<DraggedBy>,
|
||||||
hovered: bool,
|
hovered_body: bool,
|
||||||
values: ValuesMinMax,
|
hovered1: bool,
|
||||||
|
hovered2: bool,
|
||||||
|
value1: Value,
|
||||||
|
value2: Option<Value>,
|
||||||
|
limits: Limits,
|
||||||
on_value_changed: Option<SliderValueChangedCallback>,
|
on_value_changed: Option<SliderValueChangedCallback>,
|
||||||
active_tooltip: Option<Rc<ComponentTooltip>>,
|
active_tooltip: Option<Rc<ComponentTooltip>>,
|
||||||
}
|
}
|
||||||
|
|
@ -90,14 +113,20 @@ impl TooltipTrait for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SliderHandleData {
|
||||||
|
id_handle_rect: WidgetID, // Rectangle
|
||||||
|
id_text: Option<WidgetID>, // Text
|
||||||
|
id_handle: WidgetID,
|
||||||
|
}
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
body_node: taffy::NodeId,
|
body_node: taffy::NodeId,
|
||||||
slider_handle_rect_id: WidgetID, // Rectangle
|
handle1: SliderHandleData,
|
||||||
slider_text_id: Option<WidgetID>, // Text
|
handle2: Option<SliderHandleData>,
|
||||||
slider_handle_id: WidgetID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SliderValueChangedEvent {
|
pub struct SliderValueChangedEvent {
|
||||||
|
pub index: ValueIndex,
|
||||||
pub value: f32,
|
pub value: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,8 +142,13 @@ impl ComponentTrait for ComponentSlider {
|
||||||
fn refresh(&self, data: &mut RefreshData) {
|
fn refresh(&self, data: &mut RefreshData) {
|
||||||
let mut common = data.layout.common();
|
let mut common = data.layout.common();
|
||||||
let mut state = self.state.borrow_mut();
|
let mut state = self.state.borrow_mut();
|
||||||
let value = state.values.value;
|
|
||||||
state.set_value(&mut common, &self.data, value);
|
let value1 = state.value1.get();
|
||||||
|
state.set_value(&mut common, &self.data, ValueIndex::Primary, value1);
|
||||||
|
|
||||||
|
if let Some(value2) = state.value2.as_ref().map(|v| v.get()) {
|
||||||
|
state.set_value(&mut common, &self.data, ValueIndex::Secondary, value2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base(&self) -> &ComponentBase {
|
fn base(&self) -> &ComponentBase {
|
||||||
|
|
@ -127,13 +161,25 @@ impl ComponentTrait for ComponentSlider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentSlider {
|
impl ComponentSlider {
|
||||||
pub fn get_value(&self) -> f32 {
|
pub fn get_value_primary(&self) -> f32 {
|
||||||
self.state.borrow().values.value
|
self.get_value(ValueIndex::Primary).unwrap() /* safe */
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&self, common: &mut CallbackDataCommon, value: f32) {
|
pub fn get_value(&self, index: ValueIndex) -> Option<f32> {
|
||||||
|
let state = self.state.borrow();
|
||||||
|
match index {
|
||||||
|
ValueIndex::Primary => Some(state.value1.get()),
|
||||||
|
ValueIndex::Secondary => state.value2.as_ref().map(|v| v.get()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_value(&self, common: &mut CallbackDataCommon, index: ValueIndex, new_value: f32) {
|
||||||
let mut state = self.state.borrow_mut();
|
let mut state = self.state.borrow_mut();
|
||||||
state.set_value(common, &self.data, value);
|
state.set_value(common, &self.data, index, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_value_primary(&self, common: &mut CallbackDataCommon, new_value: f32) {
|
||||||
|
self.set_value(common, ValueIndex::Primary, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_value_changed(&self, func: SliderValueChangedCallback) {
|
pub fn on_value_changed(&self, func: SliderValueChangedCallback) {
|
||||||
|
|
@ -153,14 +199,15 @@ fn get_width(slider_body_node: taffy::NodeId, tree: &taffy::tree::TaffyTree<Widg
|
||||||
|
|
||||||
fn conf_handle_style(
|
fn conf_handle_style(
|
||||||
alterables: &mut EventAlterables,
|
alterables: &mut EventAlterables,
|
||||||
values: &ValuesMinMax,
|
limits: &Limits,
|
||||||
|
value: f32,
|
||||||
slider_handle_id: WidgetID,
|
slider_handle_id: WidgetID,
|
||||||
body_node: taffy::NodeId,
|
body_node: taffy::NodeId,
|
||||||
slider_handle_style: &taffy::Style,
|
slider_handle_style: &taffy::Style,
|
||||||
tree: &taffy::tree::TaffyTree<WidgetID>,
|
tree: &taffy::tree::TaffyTree<WidgetID>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
/* returns false if nothing changed */
|
/* returns false if nothing has changed */
|
||||||
let norm = values.to_normalized();
|
let norm = limits.to_normalized(value);
|
||||||
|
|
||||||
// convert normalized value to taffy percentage margin in percent
|
// convert normalized value to taffy percentage margin in percent
|
||||||
let width = get_width(body_node, tree);
|
let width = get_width(body_node, tree);
|
||||||
|
|
@ -184,11 +231,22 @@ const HANDLE_WIDTH: f32 = 32.0;
|
||||||
const HANDLE_HEIGHT: f32 = 24.0;
|
const HANDLE_HEIGHT: f32 = 24.0;
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
fn get_hovered_index(&self) -> Option<ValueIndex> {
|
||||||
|
if self.hovered1 {
|
||||||
|
Some(ValueIndex::Primary)
|
||||||
|
} else if self.hovered2 {
|
||||||
|
Some(ValueIndex::Secondary)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_value_to_mouse(
|
fn update_value_to_mouse(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_data: &event::CallbackData<'_>,
|
event_data: &event::CallbackData<'_>,
|
||||||
data: &Data,
|
data: &Data,
|
||||||
common: &mut CallbackDataCommon,
|
common: &mut CallbackDataCommon,
|
||||||
|
index: ValueIndex,
|
||||||
) {
|
) {
|
||||||
let mouse_pos = event_data
|
let mouse_pos = event_data
|
||||||
.metadata
|
.metadata
|
||||||
|
|
@ -200,10 +258,10 @@ impl State {
|
||||||
get_width(data.body_node, &common.state.tree) - HANDLE_WIDTH,
|
get_width(data.body_node, &common.state.tree) - HANDLE_WIDTH,
|
||||||
);
|
);
|
||||||
|
|
||||||
let target_value = self.values.get_from_normalized(norm);
|
let target_value = self.limits.get_from_normalized(norm);
|
||||||
let val = target_value;
|
let val = target_value;
|
||||||
|
|
||||||
self.set_value(common, data, val);
|
self.set_value(common, data, index, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_text(common: &mut CallbackDataCommon, text: &mut WidgetLabel, value: f32) {
|
fn update_text(common: &mut CallbackDataCommon, text: &mut WidgetLabel, value: f32) {
|
||||||
|
|
@ -217,23 +275,47 @@ impl State {
|
||||||
text.set_text(common, Translation::from_raw_text(&pretty));
|
text.set_text(common, Translation::from_raw_text(&pretty));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_value(&mut self, common: &mut CallbackDataCommon, data: &Data, value: f32) {
|
fn set_value(&mut self, common: &mut CallbackDataCommon, data: &Data, index: ValueIndex, new_value: f32) {
|
||||||
let before = self.values.value;
|
let val1 = self.value1.get();
|
||||||
self.values.set_value(value);
|
|
||||||
|
|
||||||
let changed = self.values.value != before;
|
let Some(value) = (match index {
|
||||||
|
ValueIndex::Primary => Some(&mut self.value1),
|
||||||
|
ValueIndex::Secondary => self.value2.as_mut(),
|
||||||
|
}) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let Some(slider_handle_node_id) = common.state.nodes.get(data.slider_handle_id) else {
|
// Slider handle widget
|
||||||
|
let Some(handle_data) = (match index {
|
||||||
|
ValueIndex::Primary => Some(&data.handle1),
|
||||||
|
ValueIndex::Secondary => data.handle2.as_ref(),
|
||||||
|
}) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
|
||||||
|
let before = value.get();
|
||||||
|
|
||||||
|
if index == ValueIndex::Secondary {
|
||||||
|
value.set(&self.limits, new_value.max(val1));
|
||||||
|
} else {
|
||||||
|
value.set(&self.limits, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let has_changed = value.get() != before;
|
||||||
|
|
||||||
|
let Some(slider_handle_node_id) = common.state.nodes.get(handle_data.id_handle) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(style) = common.state.tree.style(*slider_handle_node_id) else {
|
let Ok(style) = common.state.tree.style(*slider_handle_node_id) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !conf_handle_style(
|
if !conf_handle_style(
|
||||||
common.alterables,
|
common.alterables,
|
||||||
&self.values,
|
&self.limits,
|
||||||
data.slider_handle_id,
|
value.get(),
|
||||||
|
handle_data.id_handle,
|
||||||
data.body_node,
|
data.body_node,
|
||||||
style,
|
style,
|
||||||
&common.state.tree,
|
&common.state.tree,
|
||||||
|
|
@ -241,20 +323,21 @@ impl State {
|
||||||
return; // nothing changed visually
|
return; // nothing changed visually
|
||||||
}
|
}
|
||||||
|
|
||||||
common.alterables.mark_dirty(data.slider_handle_id);
|
common.alterables.mark_dirty(handle_data.id_handle);
|
||||||
common.alterables.mark_redraw();
|
common.alterables.mark_redraw();
|
||||||
|
|
||||||
if let Some(slider_text_id) = data.slider_text_id
|
if let Some(id_text) = handle_data.id_text
|
||||||
&& let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(slider_text_id)
|
&& let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(id_text)
|
||||||
{
|
{
|
||||||
Self::update_text(common, &mut label, self.values.value);
|
Self::update_text(common, &mut label, value.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if changed && let Some(on_value_changed) = &self.on_value_changed {
|
if has_changed && let Some(on_value_changed) = &self.on_value_changed {
|
||||||
on_value_changed(
|
on_value_changed(
|
||||||
common,
|
common,
|
||||||
SliderValueChangedEvent {
|
SliderValueChangedEvent {
|
||||||
value: self.values.value,
|
index: index,
|
||||||
|
value: value.get(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -310,18 +393,16 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID, an
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_event_mouse_enter(
|
fn register_event_mouse_enter(
|
||||||
data: Rc<Data>,
|
|
||||||
state: Rc<RefCell<State>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection,
|
listeners: &mut EventListenerCollection,
|
||||||
tooltip_info: Option<tooltip::TooltipInfo>,
|
tooltip_info: Option<tooltip::TooltipInfo>,
|
||||||
anim_mult: f32,
|
|
||||||
) -> event::EventListenerID {
|
) -> event::EventListenerID {
|
||||||
listeners.register(
|
listeners.register(
|
||||||
EventListenerKind::MouseEnter,
|
EventListenerKind::MouseEnter,
|
||||||
Box::new(move |common, event_data, (), ()| {
|
Box::new(move |common, event_data, (), ()| {
|
||||||
common.alterables.trigger_haptics();
|
common.alterables.trigger_haptics();
|
||||||
state.borrow_mut().hovered = true;
|
state.borrow_mut().hovered_body = true;
|
||||||
on_enter_anim(common, data.slider_handle_rect_id, anim_mult);
|
|
||||||
ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone());
|
ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone());
|
||||||
|
|
||||||
Ok(EventResult::Pass)
|
Ok(EventResult::Pass)
|
||||||
|
|
@ -330,10 +411,8 @@ fn register_event_mouse_enter(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_event_mouse_leave(
|
fn register_event_mouse_leave(
|
||||||
data: Rc<Data>,
|
|
||||||
state: Rc<RefCell<State>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection,
|
listeners: &mut EventListenerCollection,
|
||||||
anim_mult: f32,
|
|
||||||
) -> event::EventListenerID {
|
) -> event::EventListenerID {
|
||||||
listeners.register(
|
listeners.register(
|
||||||
EventListenerKind::MouseLeave,
|
EventListenerKind::MouseLeave,
|
||||||
|
|
@ -342,36 +421,110 @@ fn register_event_mouse_leave(
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
state.hovered = false;
|
state.hovered_body = false;
|
||||||
state.active_tooltip = None;
|
state.active_tooltip = None;
|
||||||
}
|
}
|
||||||
on_leave_anim(common, data.slider_handle_rect_id, anim_mult);
|
|
||||||
|
|
||||||
Ok(EventResult::Pass)
|
Ok(EventResult::Pass)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_handle_dist(common: &mut CallbackDataCommon, handle: &SliderHandleData, mouse_pos: Vec2) -> f32 {
|
||||||
|
let center = common.state.get_widget_boundary(handle.id_handle).center();
|
||||||
|
Vec2::distance(center, mouse_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_HOVER_DIST: f32 = 64.0;
|
||||||
|
|
||||||
|
fn update_handle_hovers(
|
||||||
|
common: &mut CallbackDataCommon,
|
||||||
|
data: &Data,
|
||||||
|
state: &mut State,
|
||||||
|
anim_mult: f32,
|
||||||
|
mouse_pos: Vec2,
|
||||||
|
) {
|
||||||
|
let hovered1_prev = state.hovered1;
|
||||||
|
let hovered2_prev = state.hovered2;
|
||||||
|
|
||||||
|
if !state.hovered_body {
|
||||||
|
state.hovered1 = false;
|
||||||
|
state.hovered2 = false;
|
||||||
|
} else {
|
||||||
|
let dist1 = get_handle_dist(common, &data.handle1, mouse_pos);
|
||||||
|
|
||||||
|
let dist2 = data
|
||||||
|
.handle2
|
||||||
|
.as_ref()
|
||||||
|
.map(|h| get_handle_dist(common, h, mouse_pos))
|
||||||
|
.unwrap_or(std::f32::MAX);
|
||||||
|
|
||||||
|
state.hovered1 = dist1 <= MAX_HOVER_DIST;
|
||||||
|
state.hovered2 = dist2 <= MAX_HOVER_DIST;
|
||||||
|
|
||||||
|
// both of them are hovered, hover the closest one
|
||||||
|
if state.hovered1 && state.hovered2 {
|
||||||
|
if dist1 < dist2 {
|
||||||
|
state.hovered2 = false;
|
||||||
|
} else {
|
||||||
|
state.hovered1 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hover state changed, run animations
|
||||||
|
if state.hovered1 != hovered1_prev {
|
||||||
|
if state.hovered1 && !hovered1_prev {
|
||||||
|
on_enter_anim(common, data.handle1.id_handle_rect, anim_mult);
|
||||||
|
} else {
|
||||||
|
on_leave_anim(common, data.handle1.id_handle_rect, anim_mult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.hovered2 != hovered2_prev
|
||||||
|
&& let Some(handle2) = data.handle2.as_ref()
|
||||||
|
{
|
||||||
|
if state.hovered2 && !hovered2_prev {
|
||||||
|
on_enter_anim(common, handle2.id_handle_rect, anim_mult);
|
||||||
|
} else {
|
||||||
|
on_leave_anim(common, handle2.id_handle_rect, anim_mult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn register_event_mouse_motion(
|
fn register_event_mouse_motion(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<State>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection,
|
listeners: &mut EventListenerCollection,
|
||||||
|
anim_mult: f32,
|
||||||
) -> event::EventListenerID {
|
) -> event::EventListenerID {
|
||||||
listeners.register(
|
listeners.register(
|
||||||
EventListenerKind::MouseMotion,
|
EventListenerKind::MouseMotion,
|
||||||
Box::new(move |common, event_data, (), ()| {
|
Box::new(move |common, event_data, (), ()| {
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
|
||||||
let CallbackMetadata::MousePosition(pos) = event_data.metadata else {
|
let Some(pos_relative) = event_data
|
||||||
|
.metadata
|
||||||
|
.get_mouse_pos_relative(&common.alterables.transform_stack)
|
||||||
|
else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
if state.dragged_by.is_some_and(|device| device == pos.device) {
|
let CallbackMetadata::MousePosition(pos) = &event_data.metadata else {
|
||||||
state.update_value_to_mouse(event_data, &data, common);
|
unreachable!();
|
||||||
Ok(EventResult::Consumed)
|
};
|
||||||
} else {
|
|
||||||
Ok(EventResult::Pass)
|
update_handle_hovers(common, &data, &mut state, anim_mult, pos_relative);
|
||||||
|
|
||||||
|
if let Some(dragged_by) = &state.dragged_by {
|
||||||
|
if dragged_by.device == pos.device {
|
||||||
|
let index = dragged_by.index;
|
||||||
|
state.update_value_to_mouse(event_data, &data, common, index);
|
||||||
|
return Ok(EventResult::Consumed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(EventResult::Pass)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -392,13 +545,18 @@ fn register_event_mouse_press(
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
if state.hovered {
|
if !state.hovered_body {
|
||||||
state.dragged_by = Some(btn.device);
|
// this slider isn't hovered at all?
|
||||||
state.update_value_to_mouse(event_data, &data, common);
|
return Ok(EventResult::Pass);
|
||||||
Ok(EventResult::Consumed)
|
|
||||||
} else {
|
|
||||||
Ok(EventResult::Pass)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hovered_index = state.get_hovered_index().unwrap_or(ValueIndex::Primary);
|
||||||
|
state.dragged_by = Some(DraggedBy {
|
||||||
|
device: btn.device,
|
||||||
|
index: hovered_index,
|
||||||
|
});
|
||||||
|
state.update_value_to_mouse(event_data, &data, common, hovered_index);
|
||||||
|
Ok(EventResult::Consumed)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -423,36 +581,11 @@ fn register_event_mouse_release(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentSlider>)> {
|
fn mount_slider_handle(
|
||||||
let mut style = params.style;
|
ess: &mut ConstructEssentials,
|
||||||
style.position = taffy::Position::Relative;
|
body_id: WidgetID,
|
||||||
style.min_size = style.size;
|
show_value: bool,
|
||||||
style.max_size = style.size;
|
) -> anyhow::Result<SliderHandleData> {
|
||||||
|
|
||||||
let (root, slider_body_node) = ess.layout.add_child(ess.parent, WidgetDiv::create(), style)?;
|
|
||||||
let body_id = root.id;
|
|
||||||
|
|
||||||
let (_background_id, _) = ess.layout.add_child(
|
|
||||||
body_id,
|
|
||||||
WidgetRectangle::create(WidgetRectangleParams {
|
|
||||||
color: BODY_COLOR,
|
|
||||||
round: WLength::Percent(1.0),
|
|
||||||
border_color: BODY_BORDER_COLOR,
|
|
||||||
border: 2.0,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
taffy::Style {
|
|
||||||
size: taffy::Size {
|
|
||||||
width: percent(1.0),
|
|
||||||
height: percent(PAD_PERCENT),
|
|
||||||
},
|
|
||||||
position: taffy::Position::Absolute,
|
|
||||||
align_self: Some(taffy::AlignItems::Center),
|
|
||||||
justify_self: Some(taffy::JustifySelf::Center),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let slider_handle_style = taffy::Style {
|
let slider_handle_style = taffy::Style {
|
||||||
size: taffy::Size {
|
size: taffy::Size {
|
||||||
width: length(0.0),
|
width: length(0.0),
|
||||||
|
|
@ -488,15 +621,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let state = State {
|
let slider_text: Option<(WidgetPair, taffy::NodeId)> = if show_value {
|
||||||
dragged_by: None,
|
|
||||||
hovered: false,
|
|
||||||
values: params.values,
|
|
||||||
on_value_changed: None,
|
|
||||||
active_tooltip: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let slider_text: Option<(WidgetPair, taffy::NodeId)> = if params.show_value {
|
|
||||||
let label = WidgetLabel::create(
|
let label = WidgetLabel::create(
|
||||||
&mut ess.layout.state,
|
&mut ess.layout.state,
|
||||||
WidgetLabelParams {
|
WidgetLabelParams {
|
||||||
|
|
@ -514,11 +639,66 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ok(SliderHandleData {
|
||||||
|
id_handle_rect: slider_handle_rect.id,
|
||||||
|
id_text: slider_text.map(|s| s.0.id),
|
||||||
|
id_handle: slider_handle.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentSlider>)> {
|
||||||
|
let mut style = params.style;
|
||||||
|
style.position = taffy::Position::Relative;
|
||||||
|
style.min_size = style.size;
|
||||||
|
style.max_size = style.size;
|
||||||
|
|
||||||
|
let (root, slider_body_node) = ess.layout.add_child(ess.parent, WidgetDiv::create(), style)?;
|
||||||
|
let body_id = root.id;
|
||||||
|
|
||||||
|
let (_background_id, _) = ess.layout.add_child(
|
||||||
|
body_id,
|
||||||
|
WidgetRectangle::create(WidgetRectangleParams {
|
||||||
|
color: BODY_COLOR,
|
||||||
|
round: WLength::Percent(1.0),
|
||||||
|
border_color: BODY_BORDER_COLOR,
|
||||||
|
border: 2.0,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
taffy::Style {
|
||||||
|
size: taffy::Size {
|
||||||
|
width: percent(1.0),
|
||||||
|
height: percent(PAD_PERCENT),
|
||||||
|
},
|
||||||
|
position: taffy::Position::Absolute,
|
||||||
|
align_self: Some(taffy::AlignItems::Center),
|
||||||
|
justify_self: Some(taffy::JustifySelf::Center),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let slider_handle1 = mount_slider_handle(ess, body_id, params.show_value)?;
|
||||||
|
let slider_handle2 = if params.value2.is_some() {
|
||||||
|
Some(mount_slider_handle(ess, body_id, params.show_value)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let state = State {
|
||||||
|
dragged_by: None,
|
||||||
|
hovered_body: false,
|
||||||
|
hovered1: false,
|
||||||
|
hovered2: false,
|
||||||
|
value1: params.value1,
|
||||||
|
value2: params.value2,
|
||||||
|
limits: params.limits,
|
||||||
|
on_value_changed: None,
|
||||||
|
active_tooltip: None,
|
||||||
|
};
|
||||||
|
|
||||||
let data = Rc::new(Data {
|
let data = Rc::new(Data {
|
||||||
slider_handle_rect_id: slider_handle_rect.id,
|
|
||||||
body_node: slider_body_node,
|
body_node: slider_body_node,
|
||||||
slider_handle_id: slider_handle.id,
|
handle1: slider_handle1,
|
||||||
slider_text_id: slider_text.map(|s| s.0.id),
|
handle2: slider_handle2,
|
||||||
});
|
});
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(state));
|
let state = Rc::new(RefCell::new(state));
|
||||||
|
|
@ -529,9 +709,9 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
let listeners = &mut root.widget.state().event_listeners;
|
let listeners = &mut root.widget.state().event_listeners;
|
||||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||||
vec![
|
vec![
|
||||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
register_event_mouse_enter(state.clone(), listeners, params.tooltip),
|
||||||
register_event_mouse_leave(data.clone(), state.clone(), listeners, anim_mult),
|
register_event_mouse_leave(state.clone(), listeners),
|
||||||
register_event_mouse_motion(data.clone(), state.clone(), listeners),
|
register_event_mouse_motion(data.clone(), state.clone(), listeners, anim_mult),
|
||||||
register_event_mouse_press(data.clone(), state.clone(), listeners),
|
register_event_mouse_press(data.clone(), state.clone(), listeners),
|
||||||
register_event_mouse_release(state.clone(), listeners),
|
register_event_mouse_release(state.clone(), listeners),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ pub fn parse_component_slider(
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut min_value = 0.0;
|
let mut min_value = 0.0;
|
||||||
let mut max_value = 1.0;
|
let mut max_value = 1.0;
|
||||||
let mut initial_value = 0.5;
|
let mut initial_value1 = 0.5;
|
||||||
|
let mut initial_value2: Option<f32> = None;
|
||||||
let mut step = 1.0;
|
let mut step = 1.0;
|
||||||
let mut show_value = 1;
|
let mut show_value = 1;
|
||||||
let mut tooltip = TooltipAttribs::default();
|
let mut tooltip = TooltipAttribs::default();
|
||||||
|
|
@ -35,7 +36,13 @@ pub fn parse_component_slider(
|
||||||
ctx.parse_check_f32(tag_name, key, value, &mut max_value);
|
ctx.parse_check_f32(tag_name, key, value, &mut max_value);
|
||||||
}
|
}
|
||||||
"value" => {
|
"value" => {
|
||||||
ctx.parse_check_f32(tag_name, key, value, &mut initial_value);
|
ctx.parse_check_f32(tag_name, key, value, &mut initial_value1);
|
||||||
|
}
|
||||||
|
"value2" => {
|
||||||
|
let mut val = 0.0;
|
||||||
|
if ctx.parse_check_f32(tag_name, key, value, &mut val) {
|
||||||
|
initial_value2 = Some(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"step" => {
|
"step" => {
|
||||||
ctx.parse_check_f32(tag_name, key, value, &mut step);
|
ctx.parse_check_f32(tag_name, key, value, &mut step);
|
||||||
|
|
@ -56,12 +63,13 @@ pub fn parse_component_slider(
|
||||||
},
|
},
|
||||||
slider::Params {
|
slider::Params {
|
||||||
style,
|
style,
|
||||||
values: slider::ValuesMinMax {
|
limits: slider::Limits {
|
||||||
min_value,
|
min_value,
|
||||||
max_value,
|
max_value,
|
||||||
value: initial_value,
|
|
||||||
step,
|
step,
|
||||||
},
|
},
|
||||||
|
value1: slider::Value(initial_value1),
|
||||||
|
value2: initial_value2.map(|v| slider::Value(v)),
|
||||||
show_value: show_value != 0,
|
show_value: show_value != 0,
|
||||||
tooltip: tooltip.get_info(),
|
tooltip: tooltip.get_info(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -568,14 +568,6 @@ impl WidgetState {
|
||||||
event: &Event,
|
event: &Event,
|
||||||
) -> anyhow::Result<EventResult> {
|
) -> anyhow::Result<EventResult> {
|
||||||
match &event {
|
match &event {
|
||||||
Event::MouseDown(e) => {
|
|
||||||
// firstly, check if this widget is scrollable at all
|
|
||||||
let (active_x, active_y) = get_scroll_active_axis(¶ms.style, ¶ms.taffy_layout);
|
|
||||||
if active_x || active_y {
|
|
||||||
self.data.press_down_start_mouse_pos = Some(e.pos);
|
|
||||||
self.data.swipe_scroll_start = self.data.scrolling_target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::MouseUp(_e) => {
|
Event::MouseUp(_e) => {
|
||||||
if self.data.swipe_running {
|
if self.data.swipe_running {
|
||||||
self.data.swipe_running = false;
|
self.data.swipe_running = false;
|
||||||
|
|
@ -654,6 +646,13 @@ impl WidgetState {
|
||||||
res = Some(self.invoke_listeners(&mut invoke_data, EventListenerKind::MouseCancel, CallbackMetadata::None)?);
|
res = Some(self.invoke_listeners(&mut invoke_data, EventListenerKind::MouseCancel, CallbackMetadata::None)?);
|
||||||
}
|
}
|
||||||
Event::MouseDown(e) => {
|
Event::MouseDown(e) => {
|
||||||
|
// firstly, check if this widget is scrollable at all
|
||||||
|
let (active_x, active_y) = get_scroll_active_axis(&invoke_data.params.style, &invoke_data.params.taffy_layout);
|
||||||
|
if active_x || active_y {
|
||||||
|
self.data.press_down_start_mouse_pos = Some(e.pos);
|
||||||
|
self.data.swipe_scroll_start = self.data.scrolling_target;
|
||||||
|
}
|
||||||
|
|
||||||
if hovered && self.data.set_device_pressed(e.device, true) {
|
if hovered && self.data.set_device_pressed(e.device, true) {
|
||||||
res = Some(self.invoke_listeners(
|
res = Some(self.invoke_listeners(
|
||||||
&mut invoke_data,
|
&mut invoke_data,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue