1use anyhow::Result;
2
3use crate::attr::{Attr, AttrValue, Bounded, Bounds};
4use crate::decl::{BoundAttrDecl, FreeAttrDecl};
5use crate::input::{Input, InputValue, Poll};
6use crate::scene::{AttrBuilder, InputHandle};
7use crate::{input, scene};
8
9#[derive(Debug)]
10pub struct InputAttrDecl<A>
11where A: AttrValue + input::Coerced
12{
13 input: InputHandle<A::Input>,
14 initial: A,
15}
16
17impl<A> BoundAttrDecl<A> for InputAttrDecl<A>
18where A: AttrValue + input::Coerced + Bounded
19{
20 const KIND: &'static str = "input";
21
22 type Attr = BoundInputAttr<A>;
23
24 fn materialize(self, bounds: Bounds<A>, builder: &mut AttrBuilder) -> Result<Self::Attr> {
25 let initial = bounds.ensure(self.initial)?;
26
27 let input = builder.input("value", self.input)?;
28
29 return Ok(Self::Attr {
30 bounds,
31 input,
32 current: initial,
33 });
34 }
35}
36
37impl<A> FreeAttrDecl<A> for InputAttrDecl<A>
38where A: AttrValue + input::Coerced
39{
40 const KIND: &'static str = "input";
41
42 type Attr = FreeInputAttr<A>;
43
44 fn materialize(self, builder: &mut AttrBuilder) -> Result<Self::Attr> {
45 let input = builder.input("value", self.input)?;
46
47 return Ok(Self::Attr {
48 input,
49 current: self.initial,
50 });
51 }
52}
53
54#[derive(Debug)]
55pub struct BoundInputAttr<A>
56where A: AttrValue + input::Coerced + Bounded
57{
58 input: Input<A::Input>,
59 current: A,
60
61 bounds: Bounds<A>,
62}
63
64impl<A> Attr<A> for BoundInputAttr<A>
65where A: AttrValue + input::Coerced + Bounded
66{
67 fn update(&mut self, _ctx: &scene::RenderContext) -> A {
68 if let Poll::Update(update) = self.input.poll(|value| {
69 let value = A::try_from_input(value)?;
70 let value = self.bounds.ensure(value)?;
71 return anyhow::Ok(value);
72 }) {
73 self.current = update;
74 }
75
76 return self.current;
77 }
78}
79
80#[derive(Debug)]
81pub struct FreeInputAttr<A>
82where A: AttrValue + input::Coerced
83{
84 input: Input<A::Input>,
85 current: A,
86}
87
88impl<A> Attr<A> for FreeInputAttr<A>
89where A: AttrValue + input::Coerced
90{
91 fn update(&mut self, _ctx: &scene::RenderContext) -> A {
92 if let Poll::Update(update) = self.input.poll(A::try_from_input) {
93 self.current = update;
94 }
95
96 return self.current;
97 }
98}
99
100impl<I> InputHandle<I>
101where I: InputValue
102{
103 pub fn attr<A>(self, initial: A) -> InputAttrDecl<A>
104 where A: AttrValue + input::Coerced<Input = I> {
105 return InputAttrDecl {
106 input: self,
107 initial,
108 };
109 }
110}