this repo has no description

RUNTIME WORKS FUCK YEA

phaz.uk 9a7bb29c f9016d75

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