tui_slider/state.rs
1//! Slider state management module
2//!
3//! This module provides the state management for sliders, including value tracking
4//! and bounds checking.
5//!
6//! # Overview
7//!
8//! The `SliderState` struct manages the value and bounds of a slider. It ensures
9//! that values are always clamped within the specified min/max range.
10//!
11//! # Examples
12//!
13//! ## Basic Usage
14//!
15//! ```
16//! use tui_slider::SliderState;
17//!
18//! let mut state = SliderState::new(50.0, 0.0, 100.0);
19//! assert_eq!(state.value(), 50.0);
20//!
21//! state.set_value(75.0);
22//! assert_eq!(state.value(), 75.0);
23//! ```
24//!
25//! ## Value Clamping
26//!
27//! ```
28//! use tui_slider::SliderState;
29//!
30//! let mut state = SliderState::new(50.0, 0.0, 100.0);
31//!
32//! // Values are automatically clamped
33//! state.set_value(150.0);
34//! assert_eq!(state.value(), 100.0);
35//!
36//! state.set_value(-10.0);
37//! assert_eq!(state.value(), 0.0);
38//! ```
39//!
40//! ## Percentage Operations
41//!
42//! ```
43//! use tui_slider::SliderState;
44//!
45//! let mut state = SliderState::new(50.0, 0.0, 100.0);
46//!
47//! // Get value as percentage (0.0 to 1.0)
48//! assert_eq!(state.percentage(), 0.5);
49//!
50//! // Set value from percentage
51//! state.set_percentage(0.75);
52//! assert_eq!(state.value(), 75.0);
53//! ```
54
55/// State management for a slider widget
56///
57/// Manages the current value and min/max bounds. All values are automatically
58/// clamped to stay within the specified range.
59///
60/// # Examples
61///
62/// ```
63/// use tui_slider::SliderState;
64///
65/// let mut state = SliderState::new(50.0, 0.0, 100.0);
66///
67/// // Direct value manipulation
68/// state.increase(10.0);
69/// assert_eq!(state.value(), 60.0);
70///
71/// state.decrease(5.0);
72/// assert_eq!(state.value(), 55.0);
73/// ```
74#[derive(Debug, Clone)]
75pub struct SliderState {
76 /// Current value of the slider
77 value: f64,
78 /// Minimum value
79 min: f64,
80 /// Maximum value
81 max: f64,
82 /// Step size for increment/decrement operations
83 step: f64,
84}
85
86impl SliderState {
87 /// Creates a new slider state with the given value and bounds
88 ///
89 /// # Arguments
90 ///
91 /// * `value` - Initial value
92 /// * `min` - Minimum value
93 /// * `max` - Maximum value
94 ///
95 /// # Panics
96 ///
97 /// Panics if min >= max
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use tui_slider::SliderState;
103 ///
104 /// let state = SliderState::new(50.0, 0.0, 100.0);
105 /// assert_eq!(state.value(), 50.0);
106 /// assert_eq!(state.min(), 0.0);
107 /// assert_eq!(state.max(), 100.0);
108 /// ```
109 ///
110 /// ```should_panic
111 /// use tui_slider::SliderState;
112 ///
113 /// // This will panic because min >= max
114 /// let state = SliderState::new(50.0, 100.0, 0.0);
115 /// ```
116 pub fn new(value: f64, min: f64, max: f64) -> Self {
117 assert!(min < max, "min must be less than max");
118 let clamped_value = value.clamp(min, max);
119 Self {
120 value: clamped_value,
121 min,
122 max,
123 step: 1.0, // Default step size
124 }
125 }
126
127 /// Gets the current value
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// use tui_slider::SliderState;
133 ///
134 /// let state = SliderState::new(75.0, 0.0, 100.0);
135 /// assert_eq!(state.value(), 75.0);
136 /// ```
137 pub fn value(&self) -> f64 {
138 self.value
139 }
140
141 /// Sets the value (automatically clamped to min..max range)
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// use tui_slider::SliderState;
147 ///
148 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
149 /// state.set_value(75.0);
150 /// assert_eq!(state.value(), 75.0);
151 ///
152 /// // Values are clamped to the valid range
153 /// state.set_value(150.0);
154 /// assert_eq!(state.value(), 100.0);
155 /// ```
156 pub fn set_value(&mut self, value: f64) {
157 self.value = value.clamp(self.min, self.max);
158 }
159
160 /// Gets the minimum value
161 ///
162 /// # Examples
163 ///
164 /// ```
165 /// use tui_slider::SliderState;
166 ///
167 /// let state = SliderState::new(50.0, 0.0, 100.0);
168 /// assert_eq!(state.min(), 0.0);
169 /// ```
170 pub fn min(&self) -> f64 {
171 self.min
172 }
173
174 /// Gets the maximum value
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use tui_slider::SliderState;
180 ///
181 /// let state = SliderState::new(50.0, 0.0, 100.0);
182 /// assert_eq!(state.max(), 100.0);
183 /// ```
184 pub fn max(&self) -> f64 {
185 self.max
186 }
187
188 /// Sets the minimum value
189 ///
190 /// # Panics
191 ///
192 /// Panics if the new min is >= max
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// use tui_slider::SliderState;
198 ///
199 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
200 /// state.set_min(-10.0);
201 /// assert_eq!(state.min(), -10.0);
202 /// ```
203 pub fn set_min(&mut self, min: f64) {
204 assert!(min < self.max, "min must be less than max");
205 self.min = min;
206 self.value = self.value.clamp(self.min, self.max);
207 }
208
209 /// Sets the maximum value
210 ///
211 /// # Panics
212 ///
213 /// Panics if the new max is <= min
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// use tui_slider::SliderState;
219 ///
220 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
221 /// state.set_max(200.0);
222 /// assert_eq!(state.max(), 200.0);
223 /// ```
224 pub fn set_max(&mut self, max: f64) {
225 assert!(max > self.min, "max must be greater than min");
226 self.max = max;
227 self.value = self.value.clamp(self.min, self.max);
228 }
229
230 /// Gets the value as a percentage (0.0 to 1.0)
231 ///
232 /// # Examples
233 ///
234 /// ```
235 /// use tui_slider::SliderState;
236 ///
237 /// let state = SliderState::new(50.0, 0.0, 100.0);
238 /// assert_eq!(state.percentage(), 0.5);
239 ///
240 /// let state = SliderState::new(25.0, 0.0, 100.0);
241 /// assert_eq!(state.percentage(), 0.25);
242 /// ```
243 pub fn percentage(&self) -> f64 {
244 if (self.max - self.min).abs() < f64::EPSILON {
245 return 0.0;
246 }
247 (self.value - self.min) / (self.max - self.min)
248 }
249
250 /// Sets the value from a percentage (0.0 to 1.0)
251 ///
252 /// The percentage is automatically clamped to the 0.0-1.0 range.
253 ///
254 /// # Examples
255 ///
256 /// ```
257 /// use tui_slider::SliderState;
258 ///
259 /// let mut state = SliderState::new(0.0, 0.0, 100.0);
260 /// state.set_percentage(0.75);
261 /// assert_eq!(state.value(), 75.0);
262 ///
263 /// state.set_percentage(0.5);
264 /// assert_eq!(state.value(), 50.0);
265 /// ```
266 pub fn set_percentage(&mut self, percentage: f64) {
267 let clamped_percentage = percentage.clamp(0.0, 1.0);
268 self.set_value(self.min + (self.max - self.min) * clamped_percentage);
269 }
270
271 /// Increases the value by a step
272 ///
273 /// The result is automatically clamped to the maximum value.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use tui_slider::SliderState;
279 ///
280 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
281 /// state.increase(10.0);
282 /// assert_eq!(state.value(), 60.0);
283 ///
284 /// // Won't exceed max
285 /// state.increase(100.0);
286 /// assert_eq!(state.value(), 100.0);
287 /// ```
288 pub fn increase(&mut self, step: f64) {
289 self.set_value(self.value + step);
290 }
291
292 /// Increases the value by the configured step size
293 ///
294 /// This is a convenience method that uses the step size set via `set_step()`.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use tui_slider::SliderState;
300 ///
301 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
302 /// state.set_step(5.0);
303 /// state.step_up();
304 /// assert_eq!(state.value(), 55.0);
305 /// ```
306 pub fn step_up(&mut self) {
307 self.increase(self.step);
308 }
309
310 /// Decreases the value by a step
311 ///
312 /// The result is automatically clamped to the minimum value.
313 ///
314 /// # Examples
315 ///
316 /// ```
317 /// use tui_slider::SliderState;
318 ///
319 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
320 /// state.decrease(10.0);
321 /// assert_eq!(state.value(), 40.0);
322 ///
323 /// // Won't go below min
324 /// state.decrease(100.0);
325 /// assert_eq!(state.value(), 0.0);
326 /// ```
327 pub fn decrease(&mut self, step: f64) {
328 self.set_value(self.value - step);
329 }
330
331 /// Decreases the value by the configured step size
332 ///
333 /// This is a convenience method that uses the step size set via `set_step()`.
334 ///
335 /// # Examples
336 ///
337 /// ```
338 /// use tui_slider::SliderState;
339 ///
340 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
341 /// state.set_step(5.0);
342 /// state.step_down();
343 /// assert_eq!(state.value(), 45.0);
344 /// ```
345 pub fn step_down(&mut self) {
346 self.decrease(self.step);
347 }
348
349 /// Gets the current step size
350 ///
351 /// # Examples
352 ///
353 /// ```
354 /// use tui_slider::SliderState;
355 ///
356 /// let state = SliderState::new(50.0, 0.0, 100.0);
357 /// assert_eq!(state.step(), 1.0);
358 /// ```
359 pub fn step(&self) -> f64 {
360 self.step
361 }
362
363 /// Sets the step size for increment/decrement operations
364 ///
365 /// The step size determines how much the value changes when using
366 /// `step_up()` and `step_down()` methods.
367 ///
368 /// # Arguments
369 ///
370 /// * `step` - The step size (must be positive)
371 ///
372 /// # Panics
373 ///
374 /// Panics if step is not positive (step <= 0.0)
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// use tui_slider::SliderState;
380 ///
381 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
382 /// state.set_step(5.0);
383 /// state.step_up();
384 /// assert_eq!(state.value(), 55.0);
385 ///
386 /// state.set_step(10.0);
387 /// state.step_up();
388 /// assert_eq!(state.value(), 65.0);
389 /// ```
390 ///
391 /// ```should_panic
392 /// use tui_slider::SliderState;
393 ///
394 /// let mut state = SliderState::new(50.0, 0.0, 100.0);
395 /// state.set_step(-1.0); // Panics!
396 /// ```
397 pub fn set_step(&mut self, step: f64) {
398 assert!(step > 0.0, "step must be positive");
399 self.step = step;
400 }
401
402 /// Creates a new slider state with a custom step size
403 ///
404 /// # Arguments
405 ///
406 /// * `value` - Initial value
407 /// * `min` - Minimum value
408 /// * `max` - Maximum value
409 /// * `step` - Step size for increment/decrement operations
410 ///
411 /// # Panics
412 ///
413 /// Panics if min >= max or if step <= 0.0
414 ///
415 /// # Examples
416 ///
417 /// ```
418 /// use tui_slider::SliderState;
419 ///
420 /// let mut state = SliderState::with_step(50.0, 0.0, 100.0, 5.0);
421 /// assert_eq!(state.step(), 5.0);
422 /// state.step_up();
423 /// assert_eq!(state.value(), 55.0);
424 /// ```
425 pub fn with_step(value: f64, min: f64, max: f64, step: f64) -> Self {
426 assert!(min < max, "min must be less than max");
427 assert!(step > 0.0, "step must be positive");
428 let clamped_value = value.clamp(min, max);
429 Self {
430 value: clamped_value,
431 min,
432 max,
433 step,
434 }
435 }
436
437 /// Sets the value from a position within a given length
438 ///
439 /// # Arguments
440 ///
441 /// * `position` - Position in the slider (0 to length)
442 /// * `length` - Total length of the slider
443 ///
444 /// # Examples
445 ///
446 /// ```
447 /// use tui_slider::SliderState;
448 ///
449 /// let mut state = SliderState::new(0.0, 0.0, 100.0);
450 /// state.set_from_position(50, 100);
451 /// assert_eq!(state.value(), 50.0);
452 /// ```
453 pub fn set_from_position(&mut self, position: u16, length: u16) {
454 if length == 0 {
455 return;
456 }
457 let percentage = position as f64 / length as f64;
458 self.set_percentage(percentage);
459 }
460
461 /// Gets the position within a given length
462 ///
463 /// # Examples
464 ///
465 /// ```
466 /// use tui_slider::SliderState;
467 ///
468 /// let state = SliderState::new(50.0, 0.0, 100.0);
469 /// assert_eq!(state.position(100), 50);
470 ///
471 /// let state = SliderState::new(25.0, 0.0, 100.0);
472 /// assert_eq!(state.position(100), 25);
473 /// ```
474 pub fn position(&self, length: u16) -> u16 {
475 (self.percentage() * length as f64).round() as u16
476 }
477
478 /// Returns the range (max - min)
479 ///
480 /// # Examples
481 ///
482 /// ```
483 /// use tui_slider::SliderState;
484 ///
485 /// let state = SliderState::new(50.0, 0.0, 100.0);
486 /// assert_eq!(state.range(), 100.0);
487 ///
488 /// let state = SliderState::new(50.0, 25.0, 75.0);
489 /// assert_eq!(state.range(), 50.0);
490 /// ```
491 pub fn range(&self) -> f64 {
492 self.max - self.min
493 }
494
495 /// Returns true if the slider is at its minimum value
496 ///
497 /// # Examples
498 ///
499 /// ```
500 /// use tui_slider::SliderState;
501 ///
502 /// let state = SliderState::new(0.0, 0.0, 100.0);
503 /// assert!(state.is_at_min());
504 ///
505 /// let state = SliderState::new(50.0, 0.0, 100.0);
506 /// assert!(!state.is_at_min());
507 /// ```
508 pub fn is_at_min(&self) -> bool {
509 (self.value - self.min).abs() < f64::EPSILON
510 }
511
512 /// Returns true if the slider is at its maximum value
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use tui_slider::SliderState;
518 ///
519 /// let state = SliderState::new(100.0, 0.0, 100.0);
520 /// assert!(state.is_at_max());
521 ///
522 /// let state = SliderState::new(50.0, 0.0, 100.0);
523 /// assert!(!state.is_at_max());
524 /// ```
525 pub fn is_at_max(&self) -> bool {
526 (self.value - self.max).abs() < f64::EPSILON
527 }
528
529 /// Returns true if the slider is at or near the middle of its range
530 ///
531 /// # Examples
532 ///
533 /// ```
534 /// use tui_slider::SliderState;
535 ///
536 /// let state = SliderState::new(50.0, 0.0, 100.0);
537 /// assert!(state.is_at_middle());
538 ///
539 /// let state = SliderState::new(0.0, 0.0, 100.0);
540 /// assert!(!state.is_at_middle());
541 /// ```
542 pub fn is_at_middle(&self) -> bool {
543 let middle = (self.min + self.max) / 2.0;
544 (self.value - middle).abs() < self.range() * 0.1
545 }
546
547 /// Returns true if the slider value is in the lower third of its range
548 ///
549 /// # Examples
550 ///
551 /// ```
552 /// use tui_slider::SliderState;
553 ///
554 /// let state = SliderState::new(20.0, 0.0, 100.0);
555 /// assert!(state.is_low());
556 ///
557 /// let state = SliderState::new(80.0, 0.0, 100.0);
558 /// assert!(!state.is_low());
559 /// ```
560 pub fn is_low(&self) -> bool {
561 self.percentage() < 0.33
562 }
563
564 /// Returns true if the slider value is in the middle third of its range
565 ///
566 /// # Examples
567 ///
568 /// ```
569 /// use tui_slider::SliderState;
570 ///
571 /// let state = SliderState::new(50.0, 0.0, 100.0);
572 /// assert!(state.is_medium());
573 ///
574 /// let state = SliderState::new(10.0, 0.0, 100.0);
575 /// assert!(!state.is_medium());
576 /// ```
577 pub fn is_medium(&self) -> bool {
578 let pct = self.percentage();
579 (0.33..0.67).contains(&pct)
580 }
581
582 /// Returns true if the slider value is in the upper third of its range
583 ///
584 /// # Examples
585 ///
586 /// ```
587 /// use tui_slider::SliderState;
588 ///
589 /// let state = SliderState::new(80.0, 0.0, 100.0);
590 /// assert!(state.is_high());
591 ///
592 /// let state = SliderState::new(20.0, 0.0, 100.0);
593 /// assert!(!state.is_high());
594 /// ```
595 pub fn is_high(&self) -> bool {
596 self.percentage() >= 0.67
597 }
598
599 /// Returns the distance from the minimum value
600 ///
601 /// # Examples
602 ///
603 /// ```
604 /// use tui_slider::SliderState;
605 ///
606 /// let state = SliderState::new(75.0, 0.0, 100.0);
607 /// assert_eq!(state.distance_from_min(), 75.0);
608 ///
609 /// let state = SliderState::new(75.0, 25.0, 100.0);
610 /// assert_eq!(state.distance_from_min(), 50.0);
611 /// ```
612 pub fn distance_from_min(&self) -> f64 {
613 self.value - self.min
614 }
615
616 /// Returns the distance from the maximum value
617 ///
618 /// # Examples
619 ///
620 /// ```
621 /// use tui_slider::SliderState;
622 ///
623 /// let state = SliderState::new(75.0, 0.0, 100.0);
624 /// assert_eq!(state.distance_from_max(), 25.0);
625 ///
626 /// let state = SliderState::new(75.0, 25.0, 100.0);
627 /// assert_eq!(state.distance_from_max(), 25.0);
628 /// ```
629 pub fn distance_from_max(&self) -> f64 {
630 self.max - self.value
631 }
632
633 /// Returns a formatted string representation of the current value
634 ///
635 /// # Examples
636 ///
637 /// ```
638 /// use tui_slider::SliderState;
639 ///
640 /// let state = SliderState::new(75.5, 0.0, 100.0);
641 /// assert_eq!(state.value_string(1), "75.5");
642 /// assert_eq!(state.value_string(0), "76");
643 /// ```
644 pub fn value_string(&self, decimals: usize) -> String {
645 format!("{:.decimals$}", self.value, decimals = decimals)
646 }
647
648 /// Returns a formatted percentage string (e.g., "75%")
649 ///
650 /// # Examples
651 ///
652 /// ```
653 /// use tui_slider::SliderState;
654 ///
655 /// let state = SliderState::new(75.0, 0.0, 100.0);
656 /// assert_eq!(state.percentage_string(), "75%");
657 ///
658 /// let state = SliderState::new(50.0, 0.0, 100.0);
659 /// assert_eq!(state.percentage_string(), "50%");
660 /// ```
661 pub fn percentage_string(&self) -> String {
662 format!("{:.0}%", self.percentage() * 100.0)
663 }
664}
665
666impl Default for SliderState {
667 fn default() -> Self {
668 Self::new(0.0, 0.0, 100.0)
669 }
670}
671
672#[cfg(test)]
673mod tests {
674 use super::*;
675
676 #[test]
677 fn test_new_state() {
678 let state = SliderState::new(50.0, 0.0, 100.0);
679 assert_eq!(state.value(), 50.0);
680 assert_eq!(state.min(), 0.0);
681 assert_eq!(state.max(), 100.0);
682 }
683
684 #[test]
685 fn test_clamping() {
686 let mut state = SliderState::new(50.0, 0.0, 100.0);
687
688 state.set_value(150.0);
689 assert_eq!(state.value(), 100.0);
690
691 state.set_value(-50.0);
692 assert_eq!(state.value(), 0.0);
693 }
694
695 #[test]
696 fn test_percentage() {
697 let state = SliderState::new(50.0, 0.0, 100.0);
698 assert_eq!(state.percentage(), 0.5);
699
700 let state = SliderState::new(25.0, 0.0, 100.0);
701 assert_eq!(state.percentage(), 0.25);
702
703 let state = SliderState::new(0.0, 0.0, 100.0);
704 assert_eq!(state.percentage(), 0.0);
705
706 let state = SliderState::new(100.0, 0.0, 100.0);
707 assert_eq!(state.percentage(), 1.0);
708 }
709
710 #[test]
711 fn test_set_percentage() {
712 let mut state = SliderState::new(0.0, 0.0, 100.0);
713 state.set_percentage(0.5);
714 assert_eq!(state.value(), 50.0);
715
716 state.set_percentage(0.25);
717 assert_eq!(state.value(), 25.0);
718 }
719
720 #[test]
721 fn test_increase_decrease() {
722 let mut state = SliderState::new(50.0, 0.0, 100.0);
723
724 state.increase(10.0);
725 assert_eq!(state.value(), 60.0);
726
727 state.set_value(50.0); // Reset
728 state.decrease(10.0);
729 assert_eq!(state.value(), 40.0);
730 }
731
732 #[test]
733 fn test_position() {
734 let state = SliderState::new(50.0, 0.0, 100.0);
735 assert_eq!(state.position(100), 50);
736
737 let state = SliderState::new(25.0, 0.0, 100.0);
738 assert_eq!(state.position(100), 25);
739 }
740
741 #[test]
742 fn test_set_from_position() {
743 let mut state = SliderState::new(0.0, 0.0, 100.0);
744 state.set_from_position(50, 100);
745 assert_eq!(state.value(), 50.0);
746 }
747
748 #[test]
749 #[should_panic(expected = "min must be less than max")]
750 fn test_invalid_bounds() {
751 SliderState::new(50.0, 100.0, 0.0);
752 }
753
754 #[test]
755 fn test_default_step() {
756 let state = SliderState::new(50.0, 0.0, 100.0);
757 assert_eq!(state.step(), 1.0);
758 }
759
760 #[test]
761 fn test_set_step() {
762 let mut state = SliderState::new(50.0, 0.0, 100.0);
763 state.set_step(5.0);
764 assert_eq!(state.step(), 5.0);
765
766 state.set_step(10.0);
767 assert_eq!(state.step(), 10.0);
768 }
769
770 #[test]
771 #[should_panic(expected = "step must be positive")]
772 fn test_invalid_step_negative() {
773 let mut state = SliderState::new(50.0, 0.0, 100.0);
774 state.set_step(-1.0);
775 }
776
777 #[test]
778 #[should_panic(expected = "step must be positive")]
779 fn test_invalid_step_zero() {
780 let mut state = SliderState::new(50.0, 0.0, 100.0);
781 state.set_step(0.0);
782 }
783
784 #[test]
785 fn test_step_up() {
786 let mut state = SliderState::new(50.0, 0.0, 100.0);
787 state.set_step(5.0);
788
789 state.step_up();
790 assert_eq!(state.value(), 55.0);
791
792 state.step_up();
793 assert_eq!(state.value(), 60.0);
794 }
795
796 #[test]
797 fn test_step_down() {
798 let mut state = SliderState::new(50.0, 0.0, 100.0);
799 state.set_step(5.0);
800
801 state.step_down();
802 assert_eq!(state.value(), 45.0);
803
804 state.step_down();
805 assert_eq!(state.value(), 40.0);
806 }
807
808 #[test]
809 fn test_step_up_clamping() {
810 let mut state = SliderState::new(95.0, 0.0, 100.0);
811 state.set_step(10.0);
812
813 state.step_up();
814 assert_eq!(state.value(), 100.0); // Clamped to max
815 }
816
817 #[test]
818 fn test_step_down_clamping() {
819 let mut state = SliderState::new(5.0, 0.0, 100.0);
820 state.set_step(10.0);
821
822 state.step_down();
823 assert_eq!(state.value(), 0.0); // Clamped to min
824 }
825
826 #[test]
827 fn test_with_step() {
828 let state = SliderState::with_step(50.0, 0.0, 100.0, 5.0);
829 assert_eq!(state.value(), 50.0);
830 assert_eq!(state.min(), 0.0);
831 assert_eq!(state.max(), 100.0);
832 assert_eq!(state.step(), 5.0);
833 }
834
835 #[test]
836 fn test_with_step_operations() {
837 let mut state = SliderState::with_step(50.0, 0.0, 100.0, 2.5);
838
839 state.step_up();
840 assert_eq!(state.value(), 52.5);
841
842 state.step_down();
843 assert_eq!(state.value(), 50.0);
844 }
845
846 #[test]
847 #[should_panic(expected = "step must be positive")]
848 fn test_with_step_invalid() {
849 SliderState::with_step(50.0, 0.0, 100.0, -1.0);
850 }
851
852 #[test]
853 fn test_different_step_sizes() {
854 let mut state = SliderState::new(50.0, 0.0, 100.0);
855
856 // Step by 0.1
857 state.set_step(0.1);
858 state.step_up();
859 assert!((state.value() - 50.1).abs() < 0.0001);
860
861 // Step by 25
862 state.set_value(50.0);
863 state.set_step(25.0);
864 state.step_up();
865 assert_eq!(state.value(), 75.0);
866 }
867}