1use std::{path::PathBuf, time::Duration};
2
3use glam::Vec2;
4use serde_derive::{Deserialize, Serialize};
5
6use crate::{error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage};
7
8#[derive(Debug, Clone, Deserialize, Serialize)]
11pub enum ActionLoader {
12 AsusAnimation {
14 file: PathBuf,
15 time: AnimTime,
16 brightness: f32,
17 },
18 AsusImage {
20 file: PathBuf,
21 time: AnimTime,
22 brightness: f32,
23 },
24 ImageAnimation {
26 file: PathBuf,
27 scale: f32,
28 angle: f32,
29 translation: Vec2,
30 time: AnimTime,
31 brightness: f32,
32 },
33 Image {
34 file: PathBuf,
35 scale: f32,
36 angle: f32,
37 translation: Vec2,
38 time: AnimTime,
39 brightness: f32,
40 },
41 Pause(Duration),
43}
44
45#[derive(Debug, Clone, Deserialize, Serialize)]
48pub enum ActionData {
49 Animation(AnimeGif),
51 Image(Box<AnimeDataBuffer>),
53 Pause(Duration),
55 AudioEq,
57 SystemInfo,
59 TimeDate,
61 Matrix,
63}
64
65impl ActionData {
66 pub fn from_anime_action(action: &ActionLoader) -> Result<ActionData, AnimeError> {
67 let a = match action {
68 ActionLoader::AsusAnimation {
69 file,
70 time,
71 brightness,
72 } => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?),
73 ActionLoader::AsusImage {
74 file,
75 time,
76 brightness,
77 } => match time {
78 AnimTime::Infinite => {
79 let image = AnimeDiagonal::from_png(file, None, *brightness)?;
80 let data = <AnimeDataBuffer>::from(&image);
81 ActionData::Image(Box::new(data))
82 }
83 _ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?),
84 },
85 ActionLoader::ImageAnimation {
86 file,
87 scale,
88 angle,
89 translation,
90 time,
91 brightness,
92 } => {
93 if let Some(ext) = file.extension() {
94 if ext.to_string_lossy().to_lowercase() == "png" {
95 return Ok(ActionData::Animation(AnimeGif::from_png(
96 file,
97 *scale,
98 *angle,
99 *translation,
100 *time,
101 *brightness,
102 )?));
103 }
104 }
105 ActionData::Animation(AnimeGif::from_gif(
106 file,
107 *scale,
108 *angle,
109 *translation,
110 *time,
111 *brightness,
112 )?)
113 }
114 ActionLoader::Image {
115 file,
116 scale,
117 angle,
118 translation,
119 brightness,
120 time,
121 } => {
122 match time {
123 AnimTime::Infinite => {
124 let image =
126 AnimeImage::from_png(file, *scale, *angle, *translation, *brightness)?;
127 let data = <AnimeDataBuffer>::from(&image);
128 ActionData::Image(Box::new(data))
129 }
130 _ => ActionData::Animation(AnimeGif::from_png(
131 file,
132 *scale,
133 *angle,
134 *translation,
135 *time,
136 *brightness,
137 )?),
138 }
139 }
140 ActionLoader::Pause(duration) => ActionData::Pause(*duration),
141 };
142 Ok(a)
143 }
144}
145
146#[derive(Debug, Deserialize, Serialize, Default)]
148pub struct Sequences(Vec<ActionData>);
149
150impl Sequences {
151 #[inline]
152 pub fn new() -> Self {
153 Self(Vec::new())
154 }
155
156 #[inline]
159 pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<(), AnimeError> {
160 self.0.insert(index, ActionData::from_anime_action(action)?);
161 Ok(())
162 }
163
164 #[inline]
168 pub fn remove_item(&mut self, index: usize) -> Option<ActionData> {
169 if index < self.0.len() {
170 return Some(self.0.remove(index));
171 }
172 None
173 }
174
175 pub fn iter(&self) -> ActionIterator {
176 ActionIterator {
177 actions: self,
178 next_idx: 0,
179 }
180 }
181}
182
183pub struct ActionIterator<'a> {
185 actions: &'a Sequences,
186 next_idx: usize,
187}
188
189impl<'a> Iterator for ActionIterator<'a> {
190 type Item = &'a ActionData;
191
192 #[inline]
193 fn next(&mut self) -> Option<&'a ActionData> {
194 if self.next_idx == self.actions.0.len() {
195 self.next_idx = 0;
196 return None;
197 }
198
199 let current = self.next_idx;
200 self.next_idx += 1;
201
202 Some(&self.actions.0[current])
203 }
204}