Skip to main content

ringkernel_procint/gui/canvas/
token_animation.rs

1//! Token animation for case flow visualization.
2//!
3//! Animates tokens flowing along DFG edges.
4
5/// Active token representing a case flowing through the process.
6#[derive(Debug, Clone)]
7pub struct Token {
8    /// Token ID.
9    pub id: u64,
10    /// Case ID this token represents.
11    pub case_id: u64,
12    /// Source activity.
13    pub source_activity: u32,
14    /// Target activity.
15    pub target_activity: u32,
16    /// Progress along edge (0.0 to 1.0).
17    pub progress: f32,
18    /// Speed multiplier.
19    pub speed: f32,
20}
21
22impl Token {
23    /// Create a new token.
24    pub fn new(id: u64, case_id: u64, source: u32, target: u32) -> Self {
25        Self {
26            id,
27            case_id,
28            source_activity: source,
29            target_activity: target,
30            progress: 0.0,
31            speed: 1.0,
32        }
33    }
34
35    /// Update token position.
36    pub fn update(&mut self, dt: f32) -> bool {
37        self.progress += dt * self.speed;
38        self.progress >= 1.0
39    }
40}
41
42/// Token animation manager.
43#[derive(Debug, Default)]
44pub struct TokenAnimation {
45    /// Active tokens.
46    tokens: Vec<Token>,
47    /// Next token ID.
48    next_id: u64,
49    /// Maximum concurrent tokens.
50    max_tokens: usize,
51    /// Base animation speed.
52    base_speed: f32,
53}
54
55impl TokenAnimation {
56    /// Create a new token animation manager.
57    pub fn new() -> Self {
58        Self {
59            tokens: Vec::new(),
60            next_id: 1,
61            max_tokens: 50,
62            base_speed: 0.5,
63        }
64    }
65
66    /// Set maximum tokens.
67    pub fn with_max_tokens(mut self, max: usize) -> Self {
68        self.max_tokens = max;
69        self
70    }
71
72    /// Set base speed.
73    pub fn with_base_speed(mut self, speed: f32) -> Self {
74        self.base_speed = speed;
75        self
76    }
77
78    /// Spawn a new token.
79    pub fn spawn(&mut self, case_id: u64, source: u32, target: u32) {
80        if self.tokens.len() >= self.max_tokens {
81            // Remove oldest token
82            self.tokens.remove(0);
83        }
84
85        let mut token = Token::new(self.next_id, case_id, source, target);
86        token.speed = self.base_speed;
87        self.tokens.push(token);
88        self.next_id += 1;
89    }
90
91    /// Spawn multiple tokens from events.
92    pub fn spawn_from_transitions(&mut self, transitions: &[(u64, u32, u32)]) {
93        for &(case_id, source, target) in transitions {
94            self.spawn(case_id, source, target);
95        }
96    }
97
98    /// Update all tokens.
99    pub fn update(&mut self, dt: f32) {
100        // Update and remove completed tokens
101        self.tokens.retain_mut(|token| !token.update(dt));
102    }
103
104    /// Get active tokens.
105    pub fn active_tokens(&self) -> &[Token] {
106        &self.tokens
107    }
108
109    /// Get token count.
110    pub fn count(&self) -> usize {
111        self.tokens.len()
112    }
113
114    /// Clear all tokens.
115    pub fn clear(&mut self) {
116        self.tokens.clear();
117    }
118
119    /// Set animation speed.
120    pub fn set_speed(&mut self, speed: f32) {
121        self.base_speed = speed;
122        for token in &mut self.tokens {
123            token.speed = speed;
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_token_creation() {
134        let token = Token::new(1, 100, 1, 2);
135        assert_eq!(token.progress, 0.0);
136        assert_eq!(token.source_activity, 1);
137        assert_eq!(token.target_activity, 2);
138    }
139
140    #[test]
141    fn test_token_update() {
142        let mut token = Token::new(1, 100, 1, 2);
143        token.speed = 1.0;
144
145        // Update to 50%
146        let completed = token.update(0.5);
147        assert!(!completed);
148        assert_eq!(token.progress, 0.5);
149
150        // Update to 100%
151        let completed = token.update(0.5);
152        assert!(completed);
153    }
154
155    #[test]
156    fn test_animation_manager() {
157        let mut anim = TokenAnimation::new().with_max_tokens(5);
158        anim.spawn(100, 1, 2);
159        anim.spawn(101, 2, 3);
160
161        assert_eq!(anim.count(), 2);
162
163        // Update
164        anim.update(0.1);
165        assert_eq!(anim.count(), 2);
166
167        // Update until completion
168        for _ in 0..20 {
169            anim.update(0.1);
170        }
171        assert_eq!(anim.count(), 0);
172    }
173}