armas_basic/animation/
velocity_drag.rs1use egui::Modifiers;
7
8#[derive(Debug, Clone)]
10pub struct VelocityDragConfig {
11 pub sensitivity: f64,
13 pub threshold: i32,
15 pub offset: f64,
17 pub allow_modifier_toggle: bool,
19 pub toggle_modifiers: Modifiers,
21}
22
23impl Default for VelocityDragConfig {
24 fn default() -> Self {
25 Self {
26 sensitivity: 1.0,
27 threshold: 1,
28 offset: 0.0,
29 allow_modifier_toggle: true,
30 toggle_modifiers: Modifiers::COMMAND | Modifiers::CTRL,
31 }
32 }
33}
34
35impl VelocityDragConfig {
36 #[must_use]
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 #[must_use]
44 pub const fn sensitivity(mut self, sensitivity: f64) -> Self {
45 self.sensitivity = sensitivity.max(0.1);
46 self
47 }
48
49 #[must_use]
51 pub fn threshold(mut self, threshold: i32) -> Self {
52 self.threshold = threshold.max(1);
53 self
54 }
55
56 #[must_use]
58 pub const fn offset(mut self, offset: f64) -> Self {
59 self.offset = offset.max(0.0);
60 self
61 }
62
63 #[must_use]
65 pub const fn allow_modifier_toggle(mut self, allow: bool) -> Self {
66 self.allow_modifier_toggle = allow;
67 self
68 }
69
70 #[must_use]
72 pub const fn toggle_modifiers(mut self, modifiers: Modifiers) -> Self {
73 self.toggle_modifiers = modifiers;
74 self
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
80pub enum DragMode {
81 #[default]
83 None,
84 Absolute,
86 Velocity,
88}
89
90#[derive(Debug, Clone)]
112pub struct VelocityDrag {
113 config: VelocityDragConfig,
114 mode: DragMode,
115 start_value: f64,
116 start_pos: f64,
117 last_pos: f64,
118 accumulated_delta: f64,
119}
120
121impl VelocityDrag {
122 #[must_use]
124 pub const fn new(config: VelocityDragConfig) -> Self {
125 Self {
126 config,
127 mode: DragMode::None,
128 start_value: 0.0,
129 start_pos: 0.0,
130 last_pos: 0.0,
131 accumulated_delta: 0.0,
132 }
133 }
134
135 #[must_use]
137 pub fn with_defaults() -> Self {
138 Self::new(VelocityDragConfig::default())
139 }
140
141 #[must_use]
143 pub const fn mode(&self) -> DragMode {
144 self.mode
145 }
146
147 #[must_use]
149 pub fn is_dragging(&self) -> bool {
150 self.mode != DragMode::None
151 }
152
153 #[must_use]
155 pub fn is_velocity_mode(&self) -> bool {
156 self.mode == DragMode::Velocity
157 }
158
159 #[must_use]
161 pub fn is_absolute_mode(&self) -> bool {
162 self.mode == DragMode::Absolute
163 }
164
165 pub const fn begin(&mut self, current_value: f64, mouse_pos: f64, use_velocity_mode: bool) {
171 self.start_value = current_value;
172 self.start_pos = mouse_pos;
173 self.last_pos = mouse_pos;
174 self.accumulated_delta = 0.0;
175 self.mode = if use_velocity_mode {
176 DragMode::Velocity
177 } else {
178 DragMode::Absolute
179 };
180 }
181
182 pub fn begin_auto(
187 &mut self,
188 current_value: f64,
189 mouse_pos: f64,
190 modifiers: &Modifiers,
191 default_velocity_mode: bool,
192 ) {
193 let modifier_pressed = self.config.allow_modifier_toggle
194 && modifiers.matches_logically(self.config.toggle_modifiers);
195
196 let use_velocity = if default_velocity_mode {
197 !modifier_pressed
198 } else {
199 modifier_pressed
200 };
201
202 self.begin(current_value, mouse_pos, use_velocity);
203 }
204
205 pub fn update(&mut self, mouse_pos: f64, value_range: f64, drag_pixels: f64) -> f64 {
213 if self.mode == DragMode::None {
214 return 0.0;
215 }
216
217 let pixel_delta = mouse_pos - self.last_pos;
218 self.last_pos = mouse_pos;
219
220 if pixel_delta.abs() < f64::from(self.config.threshold) {
222 return 0.0;
223 }
224
225 match self.mode {
226 DragMode::Absolute => {
227 let total_delta = mouse_pos - self.start_pos;
229 let value_per_pixel = value_range / drag_pixels;
230 let target_value = self.start_value + total_delta * value_per_pixel;
231 target_value - (self.start_value + self.accumulated_delta)
232 }
233 DragMode::Velocity => {
234 let speed = pixel_delta.abs();
236 let sign = pixel_delta.signum();
237
238 let velocity = (speed * self.config.sensitivity + self.config.offset) * sign;
240
241 let value_per_unit = value_range / 200.0;
243 velocity * value_per_unit
244 }
245 DragMode::None => 0.0,
246 }
247 }
248
249 pub fn update_tracked(&mut self, mouse_pos: f64, value_range: f64, drag_pixels: f64) -> f64 {
253 let delta = self.update(mouse_pos, value_range, drag_pixels);
254 self.accumulated_delta += delta;
255 delta
256 }
257
258 pub const fn end(&mut self) {
260 self.mode = DragMode::None;
261 }
262
263 #[must_use]
265 pub const fn start_value(&self) -> f64 {
266 self.start_value
267 }
268
269 #[must_use]
271 pub const fn accumulated_delta(&self) -> f64 {
272 self.accumulated_delta
273 }
274}
275
276#[derive(Debug, Clone)]
278pub struct DoubleClickReset {
279 pub enabled: bool,
281 pub default_value: f64,
283 pub double_click_time: f64,
285 last_click: f64,
287}
288
289impl DoubleClickReset {
290 #[must_use]
292 pub const fn new(default_value: f64) -> Self {
293 Self {
294 enabled: true,
295 default_value,
296 double_click_time: 0.3,
297 last_click: 0.0,
298 }
299 }
300
301 #[must_use]
303 pub const fn enabled(mut self, enabled: bool) -> Self {
304 self.enabled = enabled;
305 self
306 }
307
308 #[must_use]
310 pub const fn default_value(mut self, value: f64) -> Self {
311 self.default_value = value;
312 self
313 }
314
315 #[must_use]
317 pub const fn double_click_time(mut self, seconds: f64) -> Self {
318 self.double_click_time = seconds.max(0.1);
319 self
320 }
321
322 pub fn on_click(&mut self, current_time: f64) -> bool {
326 if !self.enabled {
327 return false;
328 }
329
330 let is_double_click = (current_time - self.last_click) < self.double_click_time;
331 self.last_click = current_time;
332 is_double_click
333 }
334
335 #[must_use]
337 pub const fn reset_value(&self) -> f64 {
338 self.default_value
339 }
340}