From 7ac26b84b1bab86f0a358f70daf52c8d2d7fd98a Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 20 Feb 2021 17:27:55 +0100 Subject: [PATCH] DragValue: handle slowly dragging a value with limited precision --- egui/src/context.rs | 3 ++- egui/src/memory.rs | 17 ++++++++++++++--- egui/src/response.rs | 5 +++++ egui/src/widgets/drag_value.rs | 22 ++++++++++++++++------ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/egui/src/context.rs b/egui/src/context.rs index 8ca12c03..81038adc 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -533,7 +533,8 @@ impl Context { self.request_repaint(); } - self.memory().end_frame(&self.frame_state().used_ids); + self.memory() + .end_frame(&self.input, &self.frame_state().used_ids); let mut output: Output = std::mem::take(&mut self.output()); if self.repaint_requests.load(SeqCst) > 0 { diff --git a/egui/src/memory.rs b/egui/src/memory.rs index 650f88c7..ad7a30d8 100644 --- a/egui/src/memory.rs +++ b/egui/src/memory.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use crate::{ area, collapsing_header, menu, resize, scroll_area, util::Cache, widgets::text_edit, window, - Id, LayerId, Pos2, Rect, Style, Vec2, + Id, InputState, LayerId, Pos2, Rect, Style, Vec2, }; use epaint::color::{Color32, Hsva}; @@ -35,11 +35,14 @@ pub struct Memory { #[cfg_attr(feature = "persistence", serde(skip))] pub(crate) window_interaction: Option, - /// For temporary edit of e.g. a slider value. + /// For temporary edit of e.g. a `DragValue` value. /// Couples with [`Interaction::kb_focus_id`]. #[cfg_attr(feature = "persistence", serde(skip))] pub(crate) temp_edit_string: Option, + /// Value of the `DragValue` being dragged (if any). + pub(crate) drag_value: Option<(Id, f64)>, + pub(crate) areas: Areas, /// Used by color picker @@ -182,7 +185,11 @@ impl Memory { } } - pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap) { + pub(crate) fn end_frame( + &mut self, + input: &InputState, + used_ids: &epaint::ahash::AHashMap, + ) { self.areas.end_frame(); if let Some(kb_focus_id) = self.interaction.kb_focus_id { @@ -195,6 +202,10 @@ impl Memory { self.interaction.kb_focus_id = None; } } + + if input.pointer.any_pressed() || input.pointer.any_released() { + self.drag_value = Default::default(); + } } pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option { diff --git a/egui/src/response.rs b/egui/src/response.rs index 253edb0e..2d88d205 100644 --- a/egui/src/response.rs +++ b/egui/src/response.rs @@ -160,6 +160,11 @@ impl Response { self.dragged } + /// Did a drag on this widgets begin this frame? + pub fn drag_started(&self) -> bool { + self.dragged && self.ctx.input().pointer.any_pressed() + } + /// The widget was being dragged, but now it has been released. pub fn drag_released(&self) -> bool { self.drag_released diff --git a/egui/src/widgets/drag_value.rs b/egui/src/widgets/drag_value.rs index 4498f7a0..cb5e47aa 100644 --- a/egui/src/widgets/drag_value.rs +++ b/egui/src/widgets/drag_value.rs @@ -191,6 +191,7 @@ impl<'a> Widget for DragValue<'a> { value as f32, // Show full precision value on-hover. TODO: figure out f64 vs f32 suffix )); + if response.clicked() { ui.memory().request_kb_focus(kb_edit_id); ui.memory().temp_edit_string = None; // Filled in next frame @@ -199,12 +200,21 @@ impl<'a> Widget for DragValue<'a> { let delta_points = mdelta.x - mdelta.y; // Increase to the right and up let delta_value = speed * delta_points; if delta_value != 0.0 { - let new_value = value + delta_value as f64; - let new_value = emath::round_to_decimals(new_value, auto_decimals); - let new_value = clamp(new_value, clamp_range); - set(&mut value_function, new_value); - // TODO: To make use or `smart_aim` for `DragValue` we need to store some state somewhere, - // otherwise we will just keep rounding to the same value while moving the mouse. + // Since we round the value being dragged, we need to store the full precision value in memory: + let stored_value = ui + .memory() + .drag_value + .filter(|(id, _)| *id == response.id) + .map(|(_, value)| value); + let stored_value = stored_value.unwrap_or(value); + let stored_value = stored_value + delta_value as f64; + let stored_value = clamp(stored_value, clamp_range.clone()); + + let rounded_new_value = emath::round_to_decimals(stored_value, auto_decimals); + let rounded_new_value = clamp(rounded_new_value, clamp_range); + set(&mut value_function, rounded_new_value); + + ui.memory().drag_value = Some((response.id, stored_value)); } } response