1use anyhow::{anyhow, Result};
2
3#[cfg(feature = "egui")]
4use crate::ui::*;
5use crate::*;
6
7#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
8pub enum InputKey {
9 Idx(u32),
10 Name(String),
11}
12
13impl From<InputId> for InputKey {
14 fn from(id: InputId) -> Self {
15 Self::Idx(id.idx)
16 }
17}
18
19impl From<u32> for InputKey {
20 fn from(idx: u32) -> Self {
21 Self::Idx(idx)
22 }
23}
24
25impl From<String> for InputKey {
26 fn from(name: String) -> Self {
27 Self::Name(name)
28 }
29}
30
31impl From<&String> for InputKey {
32 fn from(name: &String) -> Self {
33 Self::Name(name.clone())
34 }
35}
36
37impl From<&str> for InputKey {
38 fn from(name: &str) -> Self {
39 Self::Name(name.to_string())
40 }
41}
42
43#[derive(Clone, Debug)]
44pub enum Input {
45 Disconnect,
46 Connect(OutputId, Option<DataType>),
47 Value(Value),
48}
49
50impl<T: Into<Value>> From<T> for Input {
51 fn from(v: T) -> Self {
52 Self::Value(v.into())
53 }
54}
55
56impl From<NodeId> for Input {
57 fn from(n: NodeId) -> Self {
58 Self::Connect(OutputId::new(n, 0), None)
59 }
60}
61
62#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
63pub struct InputTyped<T, const N: u32> {
64 value: T,
65 connected: Option<(OutputId, Option<DataType>)>,
66}
67
68impl<T: ValueType, const N: u32> InputTyped<T, N> {
69 pub fn new(value: T) -> Self {
70 Self {
71 value,
72 connected: None,
73 }
74 }
75
76 pub fn is_connected(&self) -> bool {
77 self.connected.is_some()
78 }
79
80 pub fn is_dynamic(&self) -> bool {
81 self.value.is_dynamic()
82 }
83
84 pub fn as_input(&self) -> Input {
85 match &self.connected {
86 Some((id, dt)) => Input::Connect(*id, *dt),
87 None => Input::Value(self.value.to_value()),
88 }
89 }
90
91 pub fn resolve(
92 &self,
93 concrete_type: &mut NodeConcreteType,
94 graph: &NodeGraph,
95 compile: &mut NodeGraphCompile,
96 ) -> Result<CompiledValue> {
97 let mut value = match &self.connected {
98 Some((id, _)) => {
99 let value = compile.resolve_output(graph, *id)?;
100 if self.is_dynamic() {
101 concrete_type.add_input_type(value.dt);
103 }
104 value
105 }
106 None => self.value.compile()?,
107 };
108 value.convert(self.value.data_type())?;
110 Ok(value)
111 }
112
113 pub fn compile(
114 &self,
115 graph: &NodeGraph,
116 compile: &mut NodeGraphCompile,
117 ) -> Result<CompiledValue> {
118 let mut value = match &self.connected {
119 Some((id, _)) => compile.resolve_output(graph, *id)?,
120 None => self.value.compile()?,
121 };
122 value.convert(self.value.data_type())?;
124 Ok(value)
125 }
126
127 pub fn set_input(&mut self, input: Input) -> Result<Option<OutputId>> {
128 let old = self.connected.take().map(|(id, _)| id);
129 match input {
130 Input::Disconnect => (),
131 Input::Value(val) => {
132 self.value.set_value(val)?;
133 }
134 Input::Connect(id, dt) => {
135 if let Some(output_dt) = dt {
136 if !self.value.data_type().is_compatible(&output_dt) {
137 return Err(anyhow!("Incompatible output"));
138 }
139 }
140 self.connected = Some((id, dt));
141 }
142 }
143 Ok(old)
144 }
145
146 #[cfg(feature = "egui")]
147 pub fn ui(
148 &mut self,
149 concrete_type: &mut NodeConcreteType,
150 def: &InputDefinition,
151 ui: &mut egui::Ui,
152 id: NodeId,
153 details: bool,
154 ) -> bool {
155 let mut changed = false;
156 ui.horizontal(|ui| {
157 if details {
158 ui.collapsing(&def.name, |ui| {
159 changed = self.value.ui(ui);
160 });
161 } else {
162 match self.connected {
163 Some((output_id, mut dt)) => {
164 if self.is_dynamic() {
165 dt = NodeGraphMeta::get(ui).and_then(|g| g.resolve_output(&output_id));
166 if let Some(dt) = dt {
167 concrete_type.add_input_type(dt);
168 }
169 }
170 let mut socket = NodeSocket::input(id, N, true, def);
171 if let Some(dt) = dt {
172 socket.set_data_type(dt);
173 }
174 ui.add(socket);
175 ui.label(&def.name);
176 }
177 None => {
178 ui.add(NodeSocket::input(id, N, false, def));
179 ui.collapsing(&def.name, |ui| {
180 changed = self.value.ui(ui);
181 });
182 }
183 }
184 }
185 });
186 changed
187 }
188}
189
190impl<T: ValueType + Clone + Default, const N: u32> InputTyped<T, N> {
191 pub fn eval(&self, graph: &NodeGraph, execution: &mut NodeGraphExecution) -> Result<T> {
192 match &self.connected {
193 Some((OutputId { node: id, .. }, _)) => {
194 let mut val = T::default();
195 val.set_value(execution.eval_node(graph, *id)?)?;
196 Ok(val)
197 }
198 None => Ok(self.value.clone()),
199 }
200 }
201}