motion_core/authoring/
scene.rs1use super::*;
4
5#[cfg(test)]
6mod authoring_helpers_tests;
7
8pub trait IntoSceneOutput {
10 fn into_scene_output(self) -> crate::Result<Node>;
12}
13
14impl<Output: Into<Node>> IntoSceneOutput for Output {
15 fn into_scene_output(self) -> crate::Result<Node> {
16 Ok(self.into())
17 }
18}
19
20impl<Output: Into<Node>, Failure: Into<crate::Error>> IntoSceneOutput
21 for std::result::Result<Output, Failure>
22{
23 fn into_scene_output(self) -> crate::Result<Node> {
24 self.map(Into::into).map_err(Into::into)
25 }
26}
27
28struct SceneFailure {
29 error: Arc<crate::Error>,
30}
31
32impl SceneFailure {
33 fn new(error: crate::Error) -> Self {
34 Self {
35 error: Arc::new(error),
36 }
37 }
38
39 fn diagnostic(&self, context: &DrawContext) -> ValidationError {
40 context.diagnostics().record_scene(self.error.clone());
41 if let Some(error) = self.error.downcast_ref::<ValidationError>() {
42 return error.clone();
43 }
44 ValidationError::invalid("scene", "output", self.error.to_string())
45 }
46}
47
48pub(crate) fn failure(error: impl Into<crate::Error>) -> Node {
49 Node::from(SceneFailure::new(error.into()))
50}
51
52impl Drawable for SceneFailure {
53 fn bounds(&self, context: &DrawContext) -> Result<Rect, ValidationError> {
54 Err(self.diagnostic(context))
55 }
56
57 fn draw(
58 &self,
59 context: &DrawContext,
60 _: &mut crate::Canvas<'_>,
61 ) -> Result<(), ValidationError> {
62 Err(self.diagnostic(context))
63 }
64}
65
66pub fn scene<Build, Output>(build: Build) -> impl Fn(&SceneContext<'_>) -> Node + Send + Sync
68where
69 Build: Fn(&SceneContext<'_>) -> Output + Send + Sync,
70 Output: IntoSceneOutput,
71{
72 move |context| match build(context).into_scene_output() {
73 Ok(node) => node,
74 Err(error) => {
75 let failure = SceneFailure::new(error);
76 context.diagnostics().record_scene(failure.error.clone());
77 Node::from(failure)
78 }
79 }
80}
81
82#[macro_export]
84macro_rules! group {
85 () => { $crate::Node::empty() };
86 ($($child:expr),* $(,)?) => {
87 $crate::Node::group([$($crate::Node::from($child)),*])
88 };
89}
90
91pub trait Scene: Send + Sync {
126 fn validate(&self) -> crate::Result<()> {
128 Ok(())
129 }
130
131 fn render(&self, context: &SceneContext<'_>) -> Node;
133
134 fn duration(&self) -> Option<Duration> {
136 None
137 }
138
139 fn with_duration(self, duration: Duration) -> WithDuration<Self>
143 where
144 Self: Sized,
145 {
146 WithDuration {
147 scene: self,
148 duration,
149 }
150 }
151}
152
153impl<Callback> Scene for Callback
154where
155 Callback: Fn(&SceneContext<'_>) -> Node + Send + Sync,
156{
157 fn render(&self, context: &SceneContext<'_>) -> Node {
158 self(context)
159 }
160}
161
162impl Scene for Arc<dyn Scene> {
163 fn validate(&self) -> crate::Result<()> {
164 self.as_ref().validate()
165 }
166
167 fn render(&self, context: &SceneContext<'_>) -> Node {
168 self.as_ref().render(context)
169 }
170
171 fn duration(&self) -> Option<Duration> {
172 self.as_ref().duration()
173 }
174}
175
176pub struct WithDuration<Content> {
178 scene: Content,
179 duration: Duration,
180}
181
182impl<Content: Scene> Scene for WithDuration<Content> {
183 fn validate(&self) -> crate::Result<()> {
184 self.scene.validate()
185 }
186
187 fn render(&self, context: &SceneContext<'_>) -> Node {
188 self.scene.render(context)
189 }
190
191 fn duration(&self) -> Option<Duration> {
192 Some(self.duration)
193 }
194}