+1
src-tauri/Cargo.lock
+1
src-tauri/Cargo.lock
+1
src-tauri/Cargo.toml
+1
src-tauri/Cargo.toml
+3
-3
src-tauri/src/frontend_calls/sync_tab.rs
+3
-3
src-tauri/src/frontend_calls/sync_tab.rs
···
1
-
use std::sync::mpsc::Sender;
1
+
use crossbeam_channel::Sender;
2
2
3
3
use tauri::State;
4
4
5
5
use crate::{ runtime::commands::RuntimeCommand, structs::nodes::Node };
6
6
7
7
#[tauri::command]
8
-
pub fn sync_tab( graph: Vec<Node>, id: String, cmd: State<Sender<RuntimeCommand>> ) {
8
+
pub fn sync_tab( graph: Vec<Node>, id: String, cmd: State<Sender<RuntimeCommand>> ){
9
9
cmd.send(RuntimeCommand::AddTab(graph, id)).unwrap();
10
10
}
11
11
12
12
#[tauri::command]
13
-
pub fn discard_tab( id: String, cmd: State<Sender<RuntimeCommand>> ) {
13
+
pub fn discard_tab( id: String, cmd: State<Sender<RuntimeCommand>> ){
14
14
cmd.send(RuntimeCommand::RemoveTab(id)).unwrap();
15
15
}
+5
-3
src-tauri/src/lib.rs
+5
-3
src-tauri/src/lib.rs
···
1
-
use std::{collections::HashMap, fs, sync::{self, Arc, Mutex}};
1
+
use std::{ fs, sync::Mutex };
2
+
use crossbeam_channel::bounded;
3
+
use tokio::sync;
2
4
3
5
use frontend_calls::*;
4
6
5
-
use crate::{ osc::OSCMessage, runtime::nodes::RuntimeNodeTree, setup::setup, utils::config::Config };
7
+
use crate::{ osc::OSCMessage, setup::setup, utils::config::Config };
6
8
7
9
mod frontend_calls;
8
10
mod osc;
···
34
36
35
37
static ADDRESSES: Mutex<Vec<OSCMessage>> = Mutex::new(Vec::new());
36
38
37
-
let ( runtime_sender, runtime_receiver ) = sync::mpsc::channel();
39
+
let ( runtime_sender, runtime_receiver ) = bounded(1024);
38
40
39
41
tauri::Builder::default()
40
42
.plugin(tauri_plugin_dialog::init())
+2
-2
src-tauri/src/osc.rs
+2
-2
src-tauri/src/osc.rs
+21
-24
src-tauri/src/runtime.rs
+21
-24
src-tauri/src/runtime.rs
···
7
7
8
8
// This is horrible. I know, I'm sorry.
9
9
10
-
pub fn runtime_dry( entry: String, parameters: &Vec<ParameterType>, tab: &RuntimeNodeTree ) -> Result<()>{
11
-
let node = tab.nodes.get(&entry);
10
+
pub fn runtime_dry( entry: String, parameters: &Vec<ParameterType>, tab: &mut RuntimeNodeTree ) -> Result<()>{
11
+
let node = tab.nodes.get_mut(&entry);
12
12
if node.is_none(){ bail!("Cannot find node"); }
13
13
14
-
let mut node = node.unwrap().lock().unwrap();
14
+
let node = node.unwrap();
15
15
16
16
let output_map = node.outputs();
17
17
let args = node.execute_dry(parameters);
18
18
19
-
drop(node);
20
-
21
19
if args.is_some(){
22
20
let args = args.unwrap();
23
21
···
27
25
for output in &output_map[i]{
28
26
if output.2 == 5{ break; } // Ignore flow outputs
29
27
30
-
let next_node = tab.nodes.get(&output.0);
28
+
let next_node = tab.nodes.get_mut(&output.0);
31
29
if next_node.is_none(){ bail!("Cannot find node {}", output.0) }
32
30
33
-
let mut next_node = next_node.unwrap().lock().unwrap();
31
+
let next_node = next_node.unwrap();
34
32
let can_update = next_node.update_arg(output.1 as usize, arg.clone());
35
33
36
34
if can_update{
37
-
drop(next_node);
38
-
// ^^ Drop this MutexGuard before we enter the runtime,
39
-
// as it blocks the runtime for gaining a lock on the node
40
-
// TODO: Please find a better way of making it mutable
41
-
42
-
runtime_dry(output.0.clone(), &vec![], &tab)?;
35
+
runtime_dry(output.0.clone(), &vec![], tab)?;
43
36
}
44
37
}
45
38
}
···
48
41
Ok(())
49
42
}
50
43
51
-
52
-
pub fn runtime( entry: String, tab: &RuntimeNodeTree ) -> Result<()>{
53
-
let node = tab.nodes.get(&entry);
44
+
pub fn runtime( entry: String, tab: &mut RuntimeNodeTree ) -> Result<()>{
45
+
let node = tab.nodes.get_mut(&entry);
54
46
if node.is_none(){ bail!("Cannot find node"); }
55
47
56
-
let mut node = node.unwrap().lock().unwrap();
48
+
let node = node.unwrap();
57
49
58
50
let next = node.execute();
59
-
if next{
51
+
if next.is_some(){
52
+
let next = next.unwrap();
53
+
60
54
let outputs = node.outputs();
61
55
62
-
drop(node);
56
+
for i in 0..next.len(){
57
+
let arg = &next[i];
58
+
if i >= outputs.len() { break; }
63
59
64
-
for outputs in outputs{
65
-
for output in outputs{
66
-
if output.2 == 5{
67
-
// This is a flow output, continue
68
-
runtime(output.0, &tab)?;
60
+
for output in &outputs[i]{
61
+
if let ParameterType::Flow(next) = arg{
62
+
if *next{
63
+
// This is a flow output, continue
64
+
runtime(output.0.clone(), tab)?;
65
+
}
69
66
}
70
67
}
71
68
}
+1
src-tauri/src/runtime/commands.rs
+1
src-tauri/src/runtime/commands.rs
+20
-7
src-tauri/src/runtime/nodes.rs
+20
-7
src-tauri/src/runtime/nodes.rs
···
1
-
use std::{collections::HashMap, sync::Mutex};
1
+
use std::collections::HashMap;
2
2
3
-
use crate::{ runtime::nodes::{ debug::Debug, osctrigger::OSCTrigger }, structs::{ nodes::Node, parameter_types::ParameterType } };
3
+
use crate::{ runtime::nodes::{ conditional::{ ifequal::ConditionalIfEqual, iffalse::ConditionalIfFalse, iftrue::ConditionalIfTrue }, debug::Debug, osctrigger::OSCTrigger, statics::{ float::StaticFloat, int::StaticInt, string::StaticString } }, structs::{ nodes::Node, parameter_types::ParameterType } };
4
4
5
5
mod osctrigger;
6
6
mod debug;
7
+
mod statics;
8
+
mod conditional;
7
9
8
10
pub struct RuntimeNodeTree{
9
-
pub nodes: HashMap<String, Mutex<Box<dyn RuntimeNode>>>
11
+
pub nodes: HashMap<String, Box<dyn RuntimeNode>>
10
12
}
11
13
14
+
unsafe impl Send for RuntimeNodeTree{}
15
+
12
16
impl RuntimeNodeTree{
13
17
pub fn from( tree: Vec<Node> ) -> Self{
14
-
let mut runtime_nodes: HashMap<String, Mutex<Box<dyn RuntimeNode>>> = HashMap::new();
18
+
let mut runtime_nodes: HashMap<String, Box<dyn RuntimeNode>> = HashMap::new();
15
19
for node in tree{
16
20
match node.type_id.as_str(){
17
-
"osctrigger" => { runtime_nodes.insert(node.id.clone(), Mutex::new(OSCTrigger::new(node))); }
18
-
"debug" => { runtime_nodes.insert(node.id.clone(), Mutex::new(Debug::new(node))); }
21
+
"osctrigger" => { runtime_nodes.insert(node.id.clone(), OSCTrigger::new(node)); }
22
+
23
+
"staticstring" => { runtime_nodes.insert(node.id.clone(), StaticString::new(node)); }
24
+
"staticint" => { runtime_nodes.insert(node.id.clone(), StaticInt::new(node)); }
25
+
"staticfloat" => { runtime_nodes.insert(node.id.clone(), StaticFloat::new(node)); }
26
+
27
+
"iftrue" => { runtime_nodes.insert(node.id.clone(), ConditionalIfTrue::new(node)); }
28
+
"iffalse" => { runtime_nodes.insert(node.id.clone(), ConditionalIfFalse::new(node)); }
29
+
"ifequal" => { runtime_nodes.insert(node.id.clone(), ConditionalIfEqual::new(node)); }
30
+
31
+
"debug" => { runtime_nodes.insert(node.id.clone(), Debug::new(node)); }
19
32
_ => {}
20
33
}
21
34
}
···
27
40
pub trait RuntimeNode{
28
41
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>>; // Node ID, input index, output value type
29
42
fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>>; // Only update values on the first loop through
30
-
fn execute( &mut self ) -> bool; // Then call functions on the second loop
43
+
fn execute( &mut self ) -> Option<Vec<ParameterType>>; // Then call functions on the second loop
31
44
fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool;
32
45
fn is_entrypoint( &self ) -> bool;
33
46
}
+52
src-tauri/src/runtime/nodes/conditional/ifequal.rs
+52
src-tauri/src/runtime/nodes/conditional/ifequal.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct ConditionalIfEqual{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
value1: ParameterType,
6
+
value2: ParameterType
7
+
}
8
+
9
+
impl ConditionalIfEqual{
10
+
pub fn new( node: Node ) -> Box<Self>{
11
+
dbg!(&node);
12
+
13
+
Box::new(Self {
14
+
outputs: node.outputs.iter()
15
+
.map(| x | {
16
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
17
+
}).collect(),
18
+
value1: ParameterType::None,
19
+
value2: ParameterType::None,
20
+
})
21
+
}
22
+
}
23
+
24
+
impl RuntimeNode for ConditionalIfEqual{
25
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() }
26
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) }
27
+
28
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> {
29
+
if self.value1 == ParameterType::None && self.value2 == ParameterType::None{
30
+
None
31
+
} else{
32
+
let equal = self.value1 == self.value2;
33
+
Some(vec![ ParameterType::Flow(equal), ParameterType::Flow(!equal) ])
34
+
}
35
+
}
36
+
37
+
fn update_arg( &mut self, index: usize, arg: ParameterType ) -> bool {
38
+
match index{
39
+
1 => {
40
+
self.value1 = arg;
41
+
}
42
+
2 => {
43
+
self.value2 = arg;
44
+
}
45
+
_ => {}
46
+
}
47
+
48
+
false
49
+
}
50
+
51
+
fn is_entrypoint( &self ) -> bool { false }
52
+
}
+46
src-tauri/src/runtime/nodes/conditional/iffalse.rs
+46
src-tauri/src/runtime/nodes/conditional/iffalse.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct ConditionalIfFalse{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
runtime_active: bool
6
+
}
7
+
8
+
impl ConditionalIfFalse{
9
+
pub fn new( node: Node ) -> Box<Self>{
10
+
dbg!(&node);
11
+
12
+
Box::new(Self {
13
+
outputs: node.outputs.iter()
14
+
.map(| x | {
15
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
16
+
}).collect(),
17
+
runtime_active: false
18
+
})
19
+
}
20
+
}
21
+
22
+
impl RuntimeNode for ConditionalIfFalse{
23
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() }
24
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) }
25
+
26
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> {
27
+
Some(vec![ ParameterType::Flow(!self.runtime_active), ParameterType::Flow(self.runtime_active) ])
28
+
}
29
+
30
+
fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool {
31
+
if let ParameterType::Boolean(boolean) = arg{
32
+
if boolean{
33
+
self.runtime_active = true;
34
+
true
35
+
} else{
36
+
self.runtime_active = false;
37
+
false
38
+
}
39
+
} else{
40
+
self.runtime_active = false;
41
+
false
42
+
}
43
+
}
44
+
45
+
fn is_entrypoint( &self ) -> bool { false }
46
+
}
+46
src-tauri/src/runtime/nodes/conditional/iftrue.rs
+46
src-tauri/src/runtime/nodes/conditional/iftrue.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct ConditionalIfTrue{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
runtime_active: bool
6
+
}
7
+
8
+
impl ConditionalIfTrue{
9
+
pub fn new( node: Node ) -> Box<Self>{
10
+
dbg!(&node);
11
+
12
+
Box::new(Self {
13
+
outputs: node.outputs.iter()
14
+
.map(| x | {
15
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
16
+
}).collect(),
17
+
runtime_active: false
18
+
})
19
+
}
20
+
}
21
+
22
+
impl RuntimeNode for ConditionalIfTrue{
23
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() }
24
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) }
25
+
26
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> {
27
+
Some(vec![ ParameterType::Flow(self.runtime_active), ParameterType::Flow(!self.runtime_active) ])
28
+
}
29
+
30
+
fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool {
31
+
if let ParameterType::Boolean(boolean) = arg{
32
+
if boolean{
33
+
self.runtime_active = true;
34
+
true
35
+
} else{
36
+
self.runtime_active = false;
37
+
false
38
+
}
39
+
} else{
40
+
self.runtime_active = false;
41
+
false
42
+
}
43
+
}
44
+
45
+
fn is_entrypoint( &self ) -> bool { false }
46
+
}
+3
src-tauri/src/runtime/nodes/conditional/mod.rs
+3
src-tauri/src/runtime/nodes/conditional/mod.rs
+3
-3
src-tauri/src/runtime/nodes/debug.rs
+3
-3
src-tauri/src/runtime/nodes/debug.rs
···
5
5
}
6
6
7
7
impl Debug{
8
-
pub fn new( node: Node ) -> Box<Self>{
8
+
pub fn new( _: Node ) -> Box<Self>{
9
9
Box::new(Self { to_log: None })
10
10
}
11
11
}
···
14
14
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { vec![] }
15
15
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) }
16
16
17
-
fn execute( &mut self ) -> bool {
17
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> {
18
18
dbg!(&self.to_log);
19
19
self.to_log = None;
20
20
21
-
false
21
+
None
22
22
}
23
23
24
24
fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool {
+12
-5
src-tauri/src/runtime/nodes/osctrigger.rs
+12
-5
src-tauri/src/runtime/nodes/osctrigger.rs
···
2
2
3
3
pub struct OSCTrigger{
4
4
outputs: Vec<Vec<( String, isize, isize )>>,
5
-
address: String,
5
+
address: Option<String>,
6
6
runtime_active: bool
7
7
}
8
8
···
10
10
pub fn new( node: Node ) -> Box<Self>{
11
11
dbg!(&node);
12
12
13
+
let value = &node.statics[0].value;
14
+
13
15
Box::new(Self {
14
-
address: node.statics[0].value.as_str().unwrap().to_owned(),
16
+
address: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) },
15
17
outputs: node.outputs.iter()
16
18
.map(| x | {
17
19
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
···
27
29
}
28
30
29
31
fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> {
32
+
if self.address.is_none(){
33
+
self.runtime_active = false;
34
+
return None
35
+
}
36
+
30
37
if let ParameterType::String(address) = &msg[0]{
31
-
if *address == self.address{
38
+
if *address == *self.address.as_ref().unwrap(){
32
39
self.runtime_active = true;
33
40
Some(msg.clone())
34
41
// The first value is technically the address value,
···
45
52
}
46
53
}
47
54
48
-
fn execute( &mut self ) -> bool {
55
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> {
49
56
let execute = self.runtime_active;
50
57
self.runtime_active = false;
51
58
52
-
execute
59
+
Some(vec![ ParameterType::Flow(execute) ])
53
60
}
54
61
55
62
fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false }
+41
src-tauri/src/runtime/nodes/statics/float.rs
+41
src-tauri/src/runtime/nodes/statics/float.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct StaticFloat{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
value: Option<f32>
6
+
}
7
+
8
+
impl StaticFloat{
9
+
pub fn new( node: Node ) -> Box<Self>{
10
+
dbg!(&node);
11
+
12
+
let value = &node.statics[0].value;
13
+
14
+
Box::new(Self {
15
+
value: if value.is_null(){ None } else { Some(value.as_f64().unwrap() as f32) },
16
+
outputs: node.outputs.iter()
17
+
.map(| x | {
18
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
19
+
}).collect(),
20
+
})
21
+
}
22
+
}
23
+
24
+
impl RuntimeNode for StaticFloat{
25
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> {
26
+
self.outputs.clone()
27
+
}
28
+
29
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> {
30
+
if self.value.is_some(){
31
+
Some(vec![ ParameterType::Float(self.value.clone().unwrap()) ])
32
+
} else{
33
+
None
34
+
}
35
+
}
36
+
37
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> { None }
38
+
39
+
fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false }
40
+
fn is_entrypoint( &self ) -> bool { true }
41
+
}
+41
src-tauri/src/runtime/nodes/statics/int.rs
+41
src-tauri/src/runtime/nodes/statics/int.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct StaticInt{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
value: Option<i32>
6
+
}
7
+
8
+
impl StaticInt{
9
+
pub fn new( node: Node ) -> Box<Self>{
10
+
dbg!(&node);
11
+
12
+
let value = &node.statics[0].value;
13
+
14
+
Box::new(Self {
15
+
value: if value.is_null(){ None } else { Some(value.as_i64().unwrap() as i32) },
16
+
outputs: node.outputs.iter()
17
+
.map(| x | {
18
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
19
+
}).collect(),
20
+
})
21
+
}
22
+
}
23
+
24
+
impl RuntimeNode for StaticInt{
25
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> {
26
+
self.outputs.clone()
27
+
}
28
+
29
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> {
30
+
if self.value.is_some(){
31
+
Some(vec![ ParameterType::Int(self.value.clone().unwrap()) ])
32
+
} else{
33
+
None
34
+
}
35
+
}
36
+
37
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> { None }
38
+
39
+
fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false }
40
+
fn is_entrypoint( &self ) -> bool { true }
41
+
}
+3
src-tauri/src/runtime/nodes/statics/mod.rs
+3
src-tauri/src/runtime/nodes/statics/mod.rs
+41
src-tauri/src/runtime/nodes/statics/string.rs
+41
src-tauri/src/runtime/nodes/statics/string.rs
···
1
+
use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } };
2
+
3
+
pub struct StaticString{
4
+
outputs: Vec<Vec<( String, isize, isize )>>,
5
+
value: Option<String>
6
+
}
7
+
8
+
impl StaticString{
9
+
pub fn new( node: Node ) -> Box<Self>{
10
+
dbg!(&node);
11
+
12
+
let value = &node.statics[0].value;
13
+
14
+
Box::new(Self {
15
+
value: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) },
16
+
outputs: node.outputs.iter()
17
+
.map(| x | {
18
+
x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect()
19
+
}).collect(),
20
+
})
21
+
}
22
+
}
23
+
24
+
impl RuntimeNode for StaticString{
25
+
fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> {
26
+
self.outputs.clone()
27
+
}
28
+
29
+
fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> {
30
+
if self.value.is_some(){
31
+
Some(vec![ ParameterType::String(self.value.clone().unwrap()) ])
32
+
} else{
33
+
None
34
+
}
35
+
}
36
+
37
+
fn execute( &mut self ) -> Option<Vec<ParameterType>> { None }
38
+
39
+
fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false }
40
+
fn is_entrypoint( &self ) -> bool { true }
41
+
}
+19
-26
src-tauri/src/setup.rs
+19
-26
src-tauri/src/setup.rs
···
1
-
use std::{ collections::HashMap, fs::File, io::Read, sync::{ self, mpsc::Receiver, Mutex } };
1
+
use std::{ collections::HashMap, fs::File, io::Read, sync::Mutex };
2
+
use crossbeam_channel::{ Receiver, bounded };
2
3
3
4
use flate2::read::GzDecoder;
4
5
use serde_json::{ Map, Value };
···
9
10
pub fn setup(
10
11
app: &mut App,
11
12
addresses: &'static Mutex<Vec<OSCMessage>>,
12
-
runtime_command_receiver: Receiver<RuntimeCommand>
13
+
mut runtime_command_receiver: Receiver<RuntimeCommand>
13
14
) {
14
15
let window = app.get_webview_window("main").unwrap();
15
16
···
32
33
handle.emit("load_new_tab", Value::Object(map)).unwrap();
33
34
});
34
35
35
-
let ( sender, receiver ) = sync::mpsc::channel();
36
+
let ( sender, receiver ) = bounded(1024);
36
37
37
38
tokio::spawn(async move {
38
39
osc::start_server(sender, "127.0.0.1:9001");
39
40
});
40
41
41
-
let ( runtime_sender, runtime_receiver ) = sync::mpsc::channel();
42
+
let ( runtime_sender, runtime_receiver ) = bounded(1024);
42
43
43
44
let runtime_sender_1 = runtime_sender.clone();
44
45
tokio::spawn(async move {
···
55
56
window.emit("osc-message", &message).unwrap();
56
57
57
58
let msg = message.clone();
58
-
let mut addresses = addresses.lock().unwrap();
59
-
if !addresses.contains(&msg) { addresses.push(msg); }
59
+
let mut addrs = addresses.lock().unwrap();
60
+
if !addrs.contains(&msg) { addrs.push(msg); }
60
61
61
62
runtime_sender.send(RuntimeCommand::OSCMessage(message)).unwrap();
62
63
}
···
70
71
71
72
match cmd{
72
73
RuntimeCommand::OSCMessage( msg ) => {
73
-
for ( _, tab ) in &mut tabs{
74
-
for ( id, node ) in &tab.nodes{
75
-
let node = node.lock().unwrap();
74
+
for ( _, mut tab ) in &mut tabs{
75
+
let keys: Vec<String> = tab.nodes.keys().map(| x | { x.clone() }).collect();
76
76
77
-
if node.is_entrypoint(){
77
+
for id in keys.clone(){
78
+
let entry = tab.nodes[&id].is_entrypoint();
79
+
80
+
if entry{
78
81
let args = vec![
79
82
vec![ ParameterType::String(msg.address.clone()) ], msg.values.clone()
80
83
].concat();
81
84
82
-
drop(node);
83
-
// ^^ Drop this MutexGuard before we enter the runtime,
84
-
// as it blocks the runtime for gaining a lock on the node
85
-
// TODO: Please find a better way of making it mutable
86
-
87
-
runtime_dry(id.clone(), &args, tab).unwrap();
85
+
runtime_dry(id.clone(), &args, &mut tab).unwrap();
88
86
}
89
87
}
90
88
91
-
for ( id, node ) in &tab.nodes{
92
-
let node = node.lock().unwrap();
93
-
94
-
if node.is_entrypoint(){
95
-
drop(node);
96
-
// ^^ Drop this MutexGuard before we enter the runtime,
97
-
// as it blocks the runtime for gaining a lock on the node
98
-
// TODO: Please find a better way of making it mutable
89
+
for id in keys{
90
+
let entry = tab.nodes[&id].is_entrypoint();
99
91
100
-
runtime(id.clone(), tab).unwrap();
92
+
if entry{
93
+
let _ = runtime(id.clone(), &mut tab);
101
94
}
102
95
}
103
96
}
···
112
105
}
113
106
}
114
107
});
115
-
}
108
+
}
+3
-1
src-tauri/src/structs/parameter_types.rs
+3
-1
src-tauri/src/structs/parameter_types.rs
···
1
1
use serde::Serialize;
2
2
3
-
#[derive(Serialize, Clone, Debug)]
3
+
#[derive(Serialize, Clone, Debug, PartialEq)]
4
4
#[serde(tag = "key", content = "value")]
5
5
pub enum ParameterType {
6
6
AnyType(String),
···
11
11
Boolean(bool),
12
12
String(String),
13
13
Flow(bool),
14
+
15
+
None
14
16
}
+5
src/App.css
+5
src/App.css
+3
-1
src/Nodes/Statics.tsx
+3
-1
src/Nodes/Statics.tsx
···
1
1
import { NodeDefinition } from "./Nodes";
2
+
import { NodeStaticsFloat } from "./Statics/Float";
2
3
3
4
import { NodeStaticsInt } from "./Statics/Int";
4
5
import { NodeStaticsString } from "./Statics/String";
···
8
9
name: 'Statics',
9
10
items: [
10
11
NodeStaticsInt,
11
-
NodeStaticsString
12
+
NodeStaticsString,
13
+
NodeStaticsFloat
12
14
]
13
15
}
+21
src/Nodes/Statics/Float.tsx
+21
src/Nodes/Statics/Float.tsx
···
1
+
import { Node, NodeType } from "../../structs/node";
2
+
import { NodeDefinition } from "../Nodes";
3
+
4
+
export let NodeStaticsFloat: NodeDefinition = {
5
+
isSingle: true,
6
+
name: 'Float',
7
+
typeId: 'staticfloat',
8
+
9
+
w: 200,
10
+
h: 85,
11
+
12
+
statics: [{
13
+
type: NodeType.Float,
14
+
name: 'Value',
15
+
value: null
16
+
}],
17
+
18
+
outputs: [{ name: "Float", type: NodeType.Float }],
19
+
20
+
onStaticsUpdate: async ( _node: Node ) => {}
21
+
}
+1
-1
src/Nodes/Statics/Int.tsx
+1
-1
src/Nodes/Statics/Int.tsx
+41
-1
src/components/ControlBar.tsx
+41
-1
src/components/ControlBar.tsx
···
1
1
import './ControlBar.css';
2
2
3
-
import { Accessor, createSignal, For, Match, Show, Switch } from 'solid-js';
3
+
import { Accessor, createEffect, createSignal, For, Match, Show, Switch } from 'solid-js';
4
4
import { Node, NodeType } from '../structs/node';
5
5
import { TextInput } from './TextInput';
6
6
import { invoke } from '@tauri-apps/api/core';
···
14
14
}
15
15
16
16
export let ControlBar = ( props: ControlBarProps ) => {
17
+
createEffect(() => {
18
+
console.log(props.node());
19
+
})
20
+
17
21
return (
18
22
<div class="control-bar">
19
23
<For each={props.node()?.statics}>
···
26
30
<Match when={item.type == NodeType.String}>
27
31
{ item.name }
28
32
<div style={{ display: 'inline-block', 'margin-left': '10px' }}>
33
+
<input
34
+
type="text"
35
+
placeholder='Enter Value...'
36
+
value={item.value || ''}
37
+
onChange={( el ) => {
38
+
let value = el.target.value;
39
+
let node = props.node()!;
40
+
41
+
item.value = value;
42
+
node.onStaticsUpdate(node);
29
43
44
+
NodeManager.Instance.UpdateConfig();
45
+
}} />
30
46
</div>
31
47
</Match>
32
48
<Match when={item.type == NodeType.Int}>
33
49
{ item.name }
34
50
<div style={{ display: 'inline-block', 'margin-left': '10px' }}>
51
+
<input
52
+
type="number"
53
+
placeholder='Enter Value...'
54
+
value={item.value !== undefined ? item.value : ''}
55
+
onChange={( el ) => {
56
+
let value = el.target.value;
57
+
let node = props.node()!;
35
58
59
+
item.value = parseInt(value);
60
+
node.onStaticsUpdate(node);
61
+
62
+
NodeManager.Instance.UpdateConfig();
63
+
}} />
36
64
</div>
37
65
</Match>
38
66
<Match when={item.type == NodeType.Float}>
39
67
{ item.name }
40
68
<div style={{ display: 'inline-block', 'margin-left': '10px' }}>
69
+
<input
70
+
type="number"
71
+
placeholder='Enter Value...'
72
+
value={item.value !== undefined ? item.value : ''}
73
+
onChange={( el ) => {
74
+
let value = el.target.value;
75
+
let node = props.node()!;
41
76
77
+
item.value = parseFloat(value);
78
+
node.onStaticsUpdate(node);
79
+
80
+
NodeManager.Instance.UpdateConfig();
81
+
}} />
42
82
</div>
43
83
</Match>
44
84
<Match when={item.type == NodeType.OSCAddress}>
+2
src/components/TabMenu.css
+2
src/components/TabMenu.css
+11
src/components/TextInput.css
+11
src/components/TextInput.css
···
9
9
width: 400px;
10
10
}
11
11
12
+
input[type="number"]{
13
+
outline: none;
14
+
background: none;
15
+
border: none;
16
+
border-bottom: 2px solid #525252;
17
+
font-size: 15px;
18
+
font-family: Rubik, 'Courier New';
19
+
color: #fff;
20
+
width: 400px;
21
+
}
22
+
12
23
div[input-dropdown]{
13
24
position: absolute;
14
25
width: fit-content;