1use std::cell::Cell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use sequoia_async::Resource;
6use sequoia_reactive::{I18n, Memo, Signal};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum PropType {
10 Str,
11 Bool,
12 Int,
13 Float,
14}
15
16impl PropType {
17 pub fn from_seq(name: &str) -> Option<Self> {
18 match name {
19 "String" => Some(Self::Str),
20 "Bool" => Some(Self::Bool),
21 "Int" => Some(Self::Int),
22 "Float" => Some(Self::Float),
23 _ => None,
24 }
25 }
26
27 pub fn seq_name(self) -> &'static str {
28 match self {
29 Self::Str => "String",
30 Self::Bool => "Bool",
31 Self::Int => "Int",
32 Self::Float => "Float",
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub enum ActionSig {
39 A0,
40
41 Int,
42
43 Float,
44
45 Str,
46
47 Bool,
48
49 Point,
50
51 PointNamed,
52
53 Wheel,
54
55 Pinch,
56}
57
58#[derive(Clone)]
59pub enum FieldSignal {
60 Str(Signal<String>),
61
62 Bool(Signal<bool>),
63
64 Int(Signal<i64>),
65
66 Float(Signal<f64>),
67}
68
69pub trait SeqRow {
70 fn id(&self) -> i64;
71
72 fn fields(&self) -> Vec<(String, FieldSignal)>;
73}
74
75#[derive(Clone)]
76pub struct SeqRowData {
77 pub id: i64,
78
79 pub fields: HashMap<String, FieldSignal>,
80}
81
82pub(crate) type RowsFn = std::rc::Rc<dyn Fn() -> Vec<SeqRowData>>;
83
84pub(crate) type PointNamedAction = Rc<dyn Fn(f64, f64, String)>;
85
86pub(crate) type WheelAction = Rc<dyn Fn(f64, f64, f64)>;
87
88pub(crate) type PinchAction = Rc<dyn Fn(f64, f64, f64)>;
89
90impl SeqRowData {
91 fn snapshot<R: SeqRow>(row: &R) -> Self {
92 Self {
93 id: row.id(),
94 fields: row.fields().into_iter().collect(),
95 }
96 }
97}
98
99#[derive(Clone, Default)]
100pub struct HostBindings {
101 strings: HashMap<String, Signal<String>>,
102 bools: HashMap<String, Signal<bool>>,
103 ints: HashMap<String, Signal<i64>>,
104 floats: HashMap<String, Signal<f64>>,
105 memo_strings: HashMap<String, Memo<String>>,
106 memo_bools: HashMap<String, Memo<bool>>,
107 memo_ints: HashMap<String, Memo<i64>>,
108 memo_floats: HashMap<String, Memo<f64>>,
109 env_strings: HashMap<String, Signal<String>>,
110 env_bools: HashMap<String, Signal<bool>>,
111 env_ints: HashMap<String, Signal<i64>>,
112 env_floats: HashMap<String, Signal<f64>>,
113 i18n: Option<I18n>,
114 resources: HashMap<String, Resource<String>>,
115 rows: HashMap<String, RowsFn>,
116 actions0: HashMap<String, Rc<dyn Fn()>>,
117 actions_int: HashMap<String, Rc<dyn Fn(i64)>>,
118 actions_float: HashMap<String, Rc<dyn Fn(f64)>>,
119 actions_str: HashMap<String, Rc<dyn Fn(String)>>,
120 actions_bool: HashMap<String, Rc<dyn Fn(bool)>>,
121 actions_point: HashMap<String, Rc<dyn Fn(f64, f64)>>,
122 actions_point_named: HashMap<String, PointNamedAction>,
123 actions_wheel: HashMap<String, WheelAction>,
124 actions_pinch: HashMap<String, PinchAction>,
125
126 tick_angles: HashMap<String, Rc<Cell<f32>>>,
127
128 seq: Option<Rc<crate::eval::SeqRuntime>>,
129}
130
131impl HostBindings {
132 pub fn new() -> Self {
133 Self::default()
134 }
135
136 #[must_use]
137 pub(crate) fn with_seq(mut self, rt: Rc<crate::eval::SeqRuntime>) -> Self {
138 self.seq = Some(rt);
139 self
140 }
141
142 pub(crate) fn get_seq(&self) -> Option<Rc<crate::eval::SeqRuntime>> {
143 self.seq.clone()
144 }
145
146 pub fn prop_str(mut self, name: impl Into<String>, sig: Signal<String>) -> Self {
147 self.strings.insert(name.into(), sig);
148 self
149 }
150
151 pub fn prop_bool(mut self, name: impl Into<String>, sig: Signal<bool>) -> Self {
152 self.bools.insert(name.into(), sig);
153 self
154 }
155
156 pub fn prop_int(mut self, name: impl Into<String>, sig: Signal<i64>) -> Self {
157 self.ints.insert(name.into(), sig);
158 self
159 }
160
161 pub fn prop_float(mut self, name: impl Into<String>, sig: Signal<f64>) -> Self {
162 self.floats.insert(name.into(), sig);
163 self
164 }
165
166 pub fn tick_angle(mut self, name: impl Into<String>, angle: Rc<Cell<f32>>) -> Self {
167 self.tick_angles.insert(name.into(), angle);
168 self
169 }
170
171 pub fn memo_str(mut self, name: impl Into<String>, memo: Memo<String>) -> Self {
172 self.memo_strings.insert(name.into(), memo);
173 self
174 }
175
176 pub fn memo_bool(mut self, name: impl Into<String>, memo: Memo<bool>) -> Self {
177 self.memo_bools.insert(name.into(), memo);
178 self
179 }
180
181 pub fn memo_int(mut self, name: impl Into<String>, memo: Memo<i64>) -> Self {
182 self.memo_ints.insert(name.into(), memo);
183 self
184 }
185
186 pub fn memo_float(mut self, name: impl Into<String>, memo: Memo<f64>) -> Self {
187 self.memo_floats.insert(name.into(), memo);
188 self
189 }
190
191 pub fn env_str(mut self, name: impl Into<String>, sig: Signal<String>) -> Self {
192 self.env_strings.insert(name.into(), sig);
193 self
194 }
195
196 pub fn env_bool(mut self, name: impl Into<String>, sig: Signal<bool>) -> Self {
197 self.env_bools.insert(name.into(), sig);
198 self
199 }
200
201 pub fn env_int(mut self, name: impl Into<String>, sig: Signal<i64>) -> Self {
202 self.env_ints.insert(name.into(), sig);
203 self
204 }
205
206 pub fn env_float(mut self, name: impl Into<String>, sig: Signal<f64>) -> Self {
207 self.env_floats.insert(name.into(), sig);
208 self
209 }
210
211 pub fn i18n(mut self, i18n: I18n) -> Self {
212 self.i18n = Some(i18n);
213 self
214 }
215
216 pub fn resource(mut self, name: impl Into<String>, res: Resource<String>) -> Self {
217 self.resources.insert(name.into(), res);
218 self
219 }
220
221 pub fn on(mut self, name: impl Into<String>, f: impl Fn() + 'static) -> Self {
222 self.actions0.insert(name.into(), Rc::new(f));
223 self
224 }
225
226 pub fn on_int(mut self, name: impl Into<String>, f: impl Fn(i64) + 'static) -> Self {
227 self.actions_int.insert(name.into(), Rc::new(f));
228 self
229 }
230
231 pub fn on_float(mut self, name: impl Into<String>, f: impl Fn(f64) + 'static) -> Self {
232 self.actions_float.insert(name.into(), Rc::new(f));
233 self
234 }
235
236 pub fn on_str(mut self, name: impl Into<String>, f: impl Fn(String) + 'static) -> Self {
237 self.actions_str.insert(name.into(), Rc::new(f));
238 self
239 }
240
241 pub fn on_bool(mut self, name: impl Into<String>, f: impl Fn(bool) + 'static) -> Self {
242 self.actions_bool.insert(name.into(), Rc::new(f));
243 self
244 }
245
246 pub fn on_point(mut self, name: impl Into<String>, f: impl Fn(f64, f64) + 'static) -> Self {
247 self.actions_point.insert(name.into(), Rc::new(f));
248 self
249 }
250
251 pub fn on_point_named(
252 mut self,
253 name: impl Into<String>,
254 f: impl Fn(f64, f64, String) + 'static,
255 ) -> Self {
256 self.actions_point_named.insert(name.into(), Rc::new(f));
257 self
258 }
259
260 pub fn rows<R>(mut self, name: impl Into<String>, sig: Signal<Vec<R>>) -> Self
261 where
262 R: SeqRow + Clone + PartialEq + 'static,
263 {
264 self.rows.insert(
265 name.into(),
266 Rc::new(move || sig.get().iter().map(SeqRowData::snapshot).collect()),
267 );
268 self
269 }
270
271 pub(crate) fn prop_type(&self, name: &str) -> Option<PropType> {
272 if self.strings.contains_key(name) || self.memo_strings.contains_key(name) {
273 Some(PropType::Str)
274 } else if self.bools.contains_key(name) || self.memo_bools.contains_key(name) {
275 Some(PropType::Bool)
276 } else if self.ints.contains_key(name) || self.memo_ints.contains_key(name) {
277 Some(PropType::Int)
278 } else if self.floats.contains_key(name) || self.memo_floats.contains_key(name) {
279 Some(PropType::Float)
280 } else {
281 None
282 }
283 }
284
285 pub(crate) fn get_str(&self, name: &str) -> Option<Signal<String>> {
286 self.strings.get(name).cloned()
287 }
288
289 pub(crate) fn get_bool(&self, name: &str) -> Option<Signal<bool>> {
290 self.bools.get(name).cloned()
291 }
292
293 pub(crate) fn get_int(&self, name: &str) -> Option<Signal<i64>> {
294 self.ints.get(name).cloned()
295 }
296
297 pub(crate) fn get_float(&self, name: &str) -> Option<Signal<f64>> {
298 self.floats.get(name).cloned()
299 }
300
301 pub(crate) fn get_tick_angle(&self, name: &str) -> Option<Rc<Cell<f32>>> {
302 self.tick_angles.get(name).cloned()
303 }
304
305 pub(crate) fn get_memo_str(&self, name: &str) -> Option<Memo<String>> {
306 self.memo_strings.get(name).cloned()
307 }
308
309 pub(crate) fn get_memo_bool(&self, name: &str) -> Option<Memo<bool>> {
310 self.memo_bools.get(name).cloned()
311 }
312
313 pub(crate) fn get_memo_int(&self, name: &str) -> Option<Memo<i64>> {
314 self.memo_ints.get(name).cloned()
315 }
316
317 pub(crate) fn get_memo_float(&self, name: &str) -> Option<Memo<f64>> {
318 self.memo_floats.get(name).cloned()
319 }
320
321 pub(crate) fn get_env_str(&self, name: &str) -> Option<Signal<String>> {
322 self.env_strings.get(name).cloned()
323 }
324
325 pub(crate) fn get_env_bool(&self, name: &str) -> Option<Signal<bool>> {
326 self.env_bools.get(name).cloned()
327 }
328
329 pub(crate) fn get_env_int(&self, name: &str) -> Option<Signal<i64>> {
330 self.env_ints.get(name).cloned()
331 }
332
333 pub(crate) fn get_env_float(&self, name: &str) -> Option<Signal<f64>> {
334 self.env_floats.get(name).cloned()
335 }
336
337 pub(crate) fn get_i18n(&self) -> Option<I18n> {
338 self.i18n.clone()
339 }
340
341 pub(crate) fn get_resource(&self, name: &str) -> Option<Resource<String>> {
342 self.resources.get(name).cloned()
343 }
344
345 pub(crate) fn get_rows(&self, name: &str) -> Option<RowsFn> {
346 self.rows.get(name).cloned()
347 }
348
349 pub(crate) fn action_sig(&self, name: &str) -> Option<ActionSig> {
350 if self.actions0.contains_key(name) {
351 Some(ActionSig::A0)
352 } else if self.actions_int.contains_key(name) {
353 Some(ActionSig::Int)
354 } else if self.actions_float.contains_key(name) {
355 Some(ActionSig::Float)
356 } else if self.actions_str.contains_key(name) {
357 Some(ActionSig::Str)
358 } else if self.actions_bool.contains_key(name) {
359 Some(ActionSig::Bool)
360 } else if self.actions_point.contains_key(name) {
361 Some(ActionSig::Point)
362 } else if self.actions_point_named.contains_key(name) {
363 Some(ActionSig::PointNamed)
364 } else if self.actions_wheel.contains_key(name) {
365 Some(ActionSig::Wheel)
366 } else if self.actions_pinch.contains_key(name) {
367 Some(ActionSig::Pinch)
368 } else {
369 None
370 }
371 }
372
373 pub(crate) fn get_action0(&self, name: &str) -> Option<Rc<dyn Fn()>> {
374 self.actions0.get(name).cloned()
375 }
376
377 pub(crate) fn get_action_int(&self, name: &str) -> Option<Rc<dyn Fn(i64)>> {
378 self.actions_int.get(name).cloned()
379 }
380
381 pub(crate) fn get_action_float(&self, name: &str) -> Option<Rc<dyn Fn(f64)>> {
382 self.actions_float.get(name).cloned()
383 }
384
385 pub(crate) fn get_action_str(&self, name: &str) -> Option<Rc<dyn Fn(String)>> {
386 self.actions_str.get(name).cloned()
387 }
388
389 pub(crate) fn get_action_bool(&self, name: &str) -> Option<Rc<dyn Fn(bool)>> {
390 self.actions_bool.get(name).cloned()
391 }
392
393 pub(crate) fn get_action_point(&self, name: &str) -> Option<Rc<dyn Fn(f64, f64)>> {
394 self.actions_point.get(name).cloned()
395 }
396
397 pub(crate) fn get_action_point_named(&self, name: &str) -> Option<PointNamedAction> {
398 self.actions_point_named.get(name).cloned()
399 }
400
401 pub(crate) fn get_action_wheel(&self, name: &str) -> Option<WheelAction> {
402 self.actions_wheel.get(name).cloned()
403 }
404
405 pub(crate) fn get_action_pinch(&self, name: &str) -> Option<PinchAction> {
406 self.actions_pinch.get(name).cloned()
407 }
408
409 pub fn on_wheel(
410 mut self,
411 name: impl Into<String>,
412 f: impl Fn(f64, f64, f64) + 'static,
413 ) -> Self {
414 self.actions_wheel.insert(name.into(), Rc::new(f));
415 self
416 }
417
418 pub fn on_pinch(
419 mut self,
420 name: impl Into<String>,
421 f: impl Fn(f64, f64, f64) + 'static,
422 ) -> Self {
423 self.actions_pinch.insert(name.into(), Rc::new(f));
424 self
425 }
426}