playa/entities/
node_kind.rs1use enum_dispatch::enum_dispatch;
7use serde::{Deserialize, Serialize};
8use std::sync::Arc;
9use uuid::Uuid;
10
11use super::attrs::Attrs;
12use super::camera_node::CameraNode;
13use super::comp_node::CompNode;
14use super::file_node::FileNode;
15use super::frame::Frame;
16use super::node::{ComputeContext, Node};
17use super::text_node::TextNode;
18
19#[enum_dispatch(Node)]
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub enum NodeKind {
24 File(FileNode),
25 Comp(CompNode),
26 Camera(CameraNode),
27 Text(TextNode),
28}
29
30impl NodeKind {
31 pub fn is_file(&self) -> bool {
33 matches!(self, NodeKind::File(_))
34 }
35
36 pub fn is_comp(&self) -> bool {
38 matches!(self, NodeKind::Comp(_))
39 }
40
41 pub fn is_camera(&self) -> bool {
43 matches!(self, NodeKind::Camera(_))
44 }
45
46 pub fn is_text(&self) -> bool {
48 matches!(self, NodeKind::Text(_))
49 }
50
51 pub fn is_renderable(&self) -> bool {
54 match self {
55 NodeKind::Camera(_) => false,
56 _ => true,
58 }
59 }
60
61 pub fn is_listed(&self) -> bool {
63 self.attrs().get_bool("listed").unwrap_or(true)
64 }
65
66 pub fn add_child_layer(
76 &mut self,
77 source_uuid: Uuid,
78 name: &str,
79 start_frame: i32,
80 duration: i32,
81 insert_idx: Option<usize>,
82 source_dim: (usize, usize),
83 renderable: bool,
84 initial_position: Option<[f32; 3]>,
85 ) -> anyhow::Result<Uuid> {
86 match self {
87 NodeKind::Comp(comp) => comp.add_child_layer(source_uuid, name, start_frame, duration, insert_idx, source_dim, renderable, initial_position),
88 _ => anyhow::bail!("Cannot add child to non-Comp node"),
89 }
90 }
91
92 pub fn as_file(&self) -> Option<&FileNode> {
94 match self {
95 NodeKind::File(n) => Some(n),
96 _ => None,
97 }
98 }
99
100 pub fn as_file_mut(&mut self) -> Option<&mut FileNode> {
102 match self {
103 NodeKind::File(n) => Some(n),
104 _ => None,
105 }
106 }
107
108 pub fn as_comp(&self) -> Option<&CompNode> {
110 match self {
111 NodeKind::Comp(n) => Some(n),
112 _ => None,
113 }
114 }
115
116 pub fn as_comp_mut(&mut self) -> Option<&mut CompNode> {
118 match self {
119 NodeKind::Comp(n) => Some(n),
120 _ => None,
121 }
122 }
123
124 pub fn as_camera(&self) -> Option<&CameraNode> {
126 match self {
127 NodeKind::Camera(n) => Some(n),
128 _ => None,
129 }
130 }
131
132 pub fn as_camera_mut(&mut self) -> Option<&mut CameraNode> {
134 match self {
135 NodeKind::Camera(n) => Some(n),
136 _ => None,
137 }
138 }
139
140 pub fn as_text(&self) -> Option<&TextNode> {
142 match self {
143 NodeKind::Text(n) => Some(n),
144 _ => None,
145 }
146 }
147
148 pub fn as_text_mut(&mut self) -> Option<&mut TextNode> {
150 match self {
151 NodeKind::Text(n) => Some(n),
152 _ => None,
153 }
154 }
155
156 pub fn is_file_mode(&self) -> bool {
158 matches!(self, NodeKind::File(_))
159 }
160
161 pub fn fps(&self) -> f32 {
163 match self {
164 NodeKind::File(n) => n.fps(),
165 NodeKind::Comp(n) => n.fps(),
166 NodeKind::Camera(_) => 24.0, NodeKind::Text(_) => 24.0, }
169 }
170
171 pub fn file_mask(&self) -> Option<String> {
173 match self {
174 NodeKind::File(n) => n.file_mask().map(|s| s.to_string()),
175 _ => None,
176 }
177 }
178
179 pub fn _in(&self) -> i32 {
181 match self {
182 NodeKind::File(n) => n._in(),
183 NodeKind::Comp(n) => n._in(),
184 NodeKind::Camera(n) => n._in(),
185 NodeKind::Text(n) => n._in(),
186 }
187 }
188
189 pub fn _out(&self) -> i32 {
191 match self {
192 NodeKind::File(n) => n._out(),
193 NodeKind::Comp(n) => n._out(),
194 NodeKind::Camera(n) => n._out(),
195 NodeKind::Text(n) => n._out(),
196 }
197 }
198
199 pub fn frame(&self) -> i32 {
201 match self {
202 NodeKind::File(n) => n.frame(),
203 NodeKind::Comp(n) => n.frame(),
204 NodeKind::Camera(n) => n.frame(),
205 NodeKind::Text(n) => n.frame(),
206 }
207 }
208
209 pub fn set_event_emitter(&mut self, emitter: crate::core::event_bus::CompEventEmitter) {
211 if let NodeKind::Comp(n) = self {
212 n.set_event_emitter(emitter);
213 }
214 }
215}
216#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn test_node_kind_file() {
224 let file = FileNode::new("test.*.exr".to_string(), 1, 100, 24.0);
225 let kind: NodeKind = file.into();
226
227 assert!(kind.is_file());
228 assert!(!kind.is_comp());
229 assert_eq!(kind.node_type(), "File");
230 }
231
232 #[test]
233 fn test_node_kind_comp() {
234 let comp = CompNode::new("Test Comp", 0, 100, 24.0);
235 let kind: NodeKind = comp.into();
236
237 assert!(!kind.is_file());
238 assert!(kind.is_comp());
239 assert_eq!(kind.node_type(), "Comp");
240 }
241
242 #[test]
243 fn test_node_trait_delegation() {
244 let file = FileNode::new("test.*.exr".to_string(), 1, 100, 24.0);
245 let file_uuid = file.uuid();
246 let kind: NodeKind = file.into();
247
248 assert_eq!(kind.uuid(), file_uuid);
249 assert!(kind.inputs().is_empty());
250 }
251}