Skip to main content

egui_charts/ui/replay/
actions.rs

1//! Replay actions
2//!
3//! User actions for controlling historical data replay/playback.
4
5use chrono::{DateTime, Utc};
6
7/// Actions that can be performed during replay mode
8#[derive(Debug, Clone, PartialEq, Default)]
9#[non_exhaustive]
10pub enum ReplayAction {
11    /// No action
12    #[default]
13    None,
14
15    // Playback Controls
16    /// Start playing from current position
17    Play,
18    /// Pause playback
19    Pause,
20    /// Toggle play/pause
21    TogglePlayPause,
22    /// Stop playback and reset to beginning
23    Stop,
24    /// Reset to initial state without stopping mode
25    Reset,
26
27    // Navigation
28    /// Move forward one bar
29    StepForward,
30    /// Move backward one bar
31    StepBackward,
32    /// Move forward by specified number of bars
33    StepForwardN(usize),
34    /// Move backward by specified number of bars
35    StepBackwardN(usize),
36    /// Jump to specific bar index (0-based)
37    JumpToBar(usize),
38    /// Jump to specific date/time
39    JumpToDate(DateTime<Utc>),
40    /// Jump to beginning
41    JumpToStart,
42    /// Jump to end
43    JumpToEnd,
44    /// Jump to percentage position (0.0 - 1.0)
45    JumpToPercent(f32),
46
47    // Speed Control
48    /// Set playback speed multiplier (0.1x - 100x)
49    SetSpeed(f32),
50    /// Increase speed by one preset level
51    SpeedUp,
52    /// Decrease speed by one preset level
53    SlowDown,
54
55    // Mode Control
56    /// Enter replay mode
57    EnterReplayMode,
58    /// Exit replay mode
59    ExitReplayMode,
60    /// Toggle replay mode on/off
61    ToggleReplayMode,
62
63    // Data Loading
64    /// Load replay data from source
65    LoadData {
66        /// Instrument identifier used by the host.
67        symbol: String,
68        /// Start time of the requested range, when specified.
69        start: Option<DateTime<Utc>>,
70        /// End time of the requested range, when specified.
71        end: Option<DateTime<Utc>>,
72    },
73    /// Unload current replay data
74    UnloadData,
75
76    // Range Selection
77    /// Set replay start date
78    SetStartDate(DateTime<Utc>),
79    /// Set replay end date
80    SetEndDate(DateTime<Utc>),
81    /// Set both start and end dates
82    SetDateRange {
83        /// Start time of the requested range.
84        start: DateTime<Utc>,
85        /// End time of the requested range.
86        end: DateTime<Utc>,
87    },
88
89    // Markers and Annotations
90    /// Add marker at current position
91    AddMarker {
92        /// Optional label for the replay marker.
93        label: Option<String>,
94        /// Optional RGBA color for the replay marker.
95        color: Option<[u8; 4]>,
96    },
97    /// Remove marker at bar index
98    RemoveMarker(usize),
99    /// Clear all markers
100    ClearMarkers,
101}
102
103impl ReplayAction {
104    /// Check if this action affects playback state
105    pub fn affects_playback(&self) -> bool {
106        matches!(
107            self,
108            ReplayAction::Play
109                | ReplayAction::Pause
110                | ReplayAction::TogglePlayPause
111                | ReplayAction::Stop
112                | ReplayAction::SetSpeed(_)
113                | ReplayAction::SpeedUp
114                | ReplayAction::SlowDown
115        )
116    }
117
118    /// Check if this action affects position
119    pub fn affects_pos(&self) -> bool {
120        matches!(
121            self,
122            ReplayAction::StepForward
123                | ReplayAction::StepBackward
124                | ReplayAction::StepForwardN(_)
125                | ReplayAction::StepBackwardN(_)
126                | ReplayAction::JumpToBar(_)
127                | ReplayAction::JumpToDate(_)
128                | ReplayAction::JumpToStart
129                | ReplayAction::JumpToEnd
130                | ReplayAction::JumpToPercent(_)
131        )
132    }
133
134    /// Check if this action affects mode
135    pub fn affects_mode(&self) -> bool {
136        matches!(
137            self,
138            ReplayAction::EnterReplayMode
139                | ReplayAction::ExitReplayMode
140                | ReplayAction::ToggleReplayMode
141        )
142    }
143}
144
145/// Predefined speed presets for replay
146#[derive(Debug, Clone, Copy, PartialEq, Default)]
147pub enum ReplaySpeed {
148    /// 0.1x speed (very slow)
149    Slowest,
150    /// 0.25x speed
151    Slower,
152    /// 0.5x speed
153    Slow,
154    /// 1x speed (real-time)
155    #[default]
156    Normal,
157    /// 2x speed
158    Fast,
159    /// 5x speed
160    Faster,
161    /// 10x speed
162    VeryFast,
163    /// 25x speed
164    Fastest,
165    /// 50x speed
166    Turbo,
167    /// 100x speed (max)
168    Max,
169    /// Custom speed multiplier, clamped to 0.1 to 100; a value that is not finite plays at 1x
170    Custom(f32),
171}
172
173impl ReplaySpeed {
174    /// Get the speed multiplier value; a custom speed is clamped to 0.1 to 100, and plays at 1x
175    /// when it is not finite
176    pub fn multiplier(&self) -> f32 {
177        match self {
178            ReplaySpeed::Slowest => 0.1,
179            ReplaySpeed::Slower => 0.25,
180            ReplaySpeed::Slow => 0.5,
181            ReplaySpeed::Normal => 1.0,
182            ReplaySpeed::Fast => 2.0,
183            ReplaySpeed::Faster => 5.0,
184            ReplaySpeed::VeryFast => 10.0,
185            ReplaySpeed::Fastest => 25.0,
186            ReplaySpeed::Turbo => 50.0,
187            ReplaySpeed::Max => 100.0,
188            ReplaySpeed::Custom(v) if v.is_finite() => v.clamp(0.1, 100.0),
189            ReplaySpeed::Custom(_) => 1.0,
190        }
191    }
192
193    /// Get the next faster preset
194    pub fn faster(&self) -> Self {
195        match self {
196            ReplaySpeed::Slowest => ReplaySpeed::Slower,
197            ReplaySpeed::Slower => ReplaySpeed::Slow,
198            ReplaySpeed::Slow => ReplaySpeed::Normal,
199            ReplaySpeed::Normal => ReplaySpeed::Fast,
200            ReplaySpeed::Fast => ReplaySpeed::Faster,
201            ReplaySpeed::Faster => ReplaySpeed::VeryFast,
202            ReplaySpeed::VeryFast => ReplaySpeed::Fastest,
203            ReplaySpeed::Fastest => ReplaySpeed::Turbo,
204            ReplaySpeed::Turbo | ReplaySpeed::Max => ReplaySpeed::Max,
205            ReplaySpeed::Custom(_) => ReplaySpeed::Custom((self.multiplier() * 2.0).min(100.0)),
206        }
207    }
208
209    /// Get the next slower preset
210    pub fn slower(&self) -> Self {
211        match self {
212            ReplaySpeed::Max => ReplaySpeed::Turbo,
213            ReplaySpeed::Turbo => ReplaySpeed::Fastest,
214            ReplaySpeed::Fastest => ReplaySpeed::VeryFast,
215            ReplaySpeed::VeryFast => ReplaySpeed::Faster,
216            ReplaySpeed::Faster => ReplaySpeed::Fast,
217            ReplaySpeed::Fast => ReplaySpeed::Normal,
218            ReplaySpeed::Normal => ReplaySpeed::Slow,
219            ReplaySpeed::Slow => ReplaySpeed::Slower,
220            ReplaySpeed::Slower | ReplaySpeed::Slowest => ReplaySpeed::Slowest,
221            ReplaySpeed::Custom(_) => ReplaySpeed::Custom((self.multiplier() / 2.0).max(0.1)),
222        }
223    }
224
225    /// Get display label for the speed
226    pub fn label(&self) -> String {
227        format!("{:.1}x", self.multiplier())
228    }
229
230    /// All standard presets
231    pub fn presets() -> &'static [ReplaySpeed] {
232        &[
233            ReplaySpeed::Slowest,
234            ReplaySpeed::Slower,
235            ReplaySpeed::Slow,
236            ReplaySpeed::Normal,
237            ReplaySpeed::Fast,
238            ReplaySpeed::Faster,
239            ReplaySpeed::VeryFast,
240            ReplaySpeed::Fastest,
241            ReplaySpeed::Turbo,
242            ReplaySpeed::Max,
243        ]
244    }
245}
246
247impl From<f32> for ReplaySpeed {
248    fn from(value: f32) -> Self {
249        let value = ReplaySpeed::Custom(value).multiplier();
250        // Try to match a preset
251        for preset in Self::presets() {
252            if (preset.multiplier() - value).abs() < 0.01 {
253                return *preset;
254            }
255        }
256        ReplaySpeed::Custom(value)
257    }
258}