+3
src-tauri/Cargo.lock
+3
src-tauri/Cargo.lock
···
7
7
version = "0.1.0"
8
8
dependencies = [
9
9
"anyhow",
10
+
"chrono",
10
11
"crossbeam-channel",
11
12
"dirs",
12
13
"enigo",
···
519
520
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
520
521
dependencies = [
521
522
"iana-time-zone",
523
+
"js-sys",
522
524
"num-traits",
523
525
"serde",
526
+
"wasm-bindgen",
524
527
"windows-link 0.2.1",
525
528
]
526
529
+1
src-tauri/Cargo.toml
+1
src-tauri/Cargo.toml
+1
-1
src-tauri/src/frontend_calls/load_previous_tabs.rs
+1
-1
src-tauri/src/frontend_calls/load_previous_tabs.rs
···
8
8
pub fn load_previous_tabs(
9
9
window: Window,
10
10
conf: State<Config>,
11
-
) -> HashMap<String, (Vec<Node>, String, Option<String>)> {
11
+
) -> HashMap<String, (Vec<Node>, String, Option<String>, bool)> {
12
12
let config = conf.store.lock().unwrap();
13
13
14
14
if !config.hide_editor_on_start {
+6
-1
src-tauri/src/frontend_calls/sync_tab.rs
+6
-1
src-tauri/src/frontend_calls/sync_tab.rs
···
1
+
use chrono::Utc;
1
2
use crossbeam_channel::Sender;
2
3
3
4
use tauri::State;
···
9
10
graph: Vec<Node>,
10
11
id: String,
11
12
name: String,
13
+
save_state: bool,
12
14
location: Option<String>,
13
15
cmd: State<Sender<RuntimeCommand>>,
14
16
conf: State<Config>,
···
18
20
.unwrap();
19
21
20
22
let mut config = conf.store.lock().unwrap();
21
-
config.loaded_tabs.insert(id, (graph, name, location)); // TODO: When loading a tab into config, store the save state of it too
23
+
config.loaded_tabs.insert(id, (graph, name, location, save_state)); // TODO: When loading a tab into config, store the save state of it too
24
+
25
+
// If we haven't updated the config in the last second, let's update it again.
26
+
if config.last_save + 1 < Utc::now().timestamp(){ conf.save_prelocked(config); }
22
27
}
23
28
24
29
#[tauri::command]
-4
src-tauri/src/runtime.rs
-4
src-tauri/src/runtime.rs
···
55
55
if node.is_none() { bail!("Cannot find node"); }
56
56
57
57
let node = node.unwrap();
58
-
59
58
let inputs = node.inputs();
60
-
dbg!(&inputs);
61
59
62
60
let mut needed_input_nodes = HashMap::new();
63
61
···
72
70
}
73
71
}
74
72
}
75
-
76
-
dbg!(&needed_input_nodes);
77
73
78
74
for ( id, needed ) in needed_input_nodes{
79
75
let (out_args, _) = runtime(id, tab, vec![]).unwrap();
+4
-3
src-tauri/src/runtime/nodes/shell.rs
+4
-3
src-tauri/src/runtime/nodes/shell.rs
···
1
-
use std::process::Command;
1
+
use std::{io::Stdin, process::{Command, Stdio}};
2
2
3
3
use crate::{
4
4
runtime::nodes::RuntimeNode,
···
40
40
41
41
fn execute(&mut self, args: Vec<ParameterType>) -> Vec<ParameterType> {
42
42
if let Ok(cmd) = args[1].as_string(){
43
-
dbg!(&cmd);
44
-
45
43
if cmd != ""{
46
44
let mut split_cmd = cmd.split(" ");
47
45
48
46
let mut cmd = Command::new(split_cmd.nth(0).unwrap());
49
47
if split_cmd.clone().count() > 0{ cmd.args(split_cmd); }
48
+
49
+
cmd.stdout(Stdio::piped());
50
+
cmd.stderr(Stdio::piped());
50
51
51
52
let child = cmd.spawn().unwrap();
52
53
let output = child.wait_with_output().unwrap();
+10
-3
src-tauri/src/setup.rs
+10
-3
src-tauri/src/setup.rs
···
23
23
window.hide().unwrap();
24
24
25
25
let win_handle = window.clone();
26
+
26
27
window.on_window_event(move |event| match event {
27
28
WindowEvent::CloseRequested { api, .. } => {
28
29
api.prevent_close();
29
-
30
-
win_handle.hide().unwrap();
31
-
win_handle.emit("hide-window", ()).unwrap();
30
+
win_handle.emit("prompt_to_close", ()).unwrap();
31
+
}
32
+
WindowEvent::Resized(_) => {
33
+
let minimised = win_handle.is_minimized().unwrap();
34
+
if minimised{
35
+
win_handle.hide().unwrap();
36
+
win_handle.emit("hide-window", ()).unwrap();
37
+
win_handle.unminimize().unwrap();
38
+
}
32
39
}
33
40
_ => {}
34
41
});
+23
-6
src-tauri/src/utils/config.rs
+23
-6
src-tauri/src/utils/config.rs
···
3
3
fs::File,
4
4
io::{Read, Write},
5
5
path::PathBuf,
6
-
sync::Mutex,
6
+
sync::{Mutex, MutexGuard},
7
7
};
8
8
9
+
use chrono::Utc;
9
10
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
10
11
use serde::{Deserialize, Serialize};
11
12
···
14
15
#[derive(Clone, Serialize, Deserialize, Debug)]
15
16
pub struct ConfigValues {
16
17
#[serde(default)]
17
-
pub loaded_tabs: HashMap<String, (Vec<Node>, String, Option<String>)>,
18
+
pub loaded_tabs: HashMap<String, (Vec<Node>, String, Option<String>, bool)>,
18
19
19
20
#[serde(default)]
20
21
pub hide_editor_on_start: bool,
22
+
23
+
#[serde(default)]
24
+
pub last_save: i64,
21
25
}
22
26
23
27
pub struct Config {
28
+
24
29
pub store: Mutex<ConfigValues>,
25
30
path: PathBuf,
26
31
}
···
39
44
40
45
let json: ConfigValues = serde_json::from_str(&json_string).unwrap();
41
46
42
-
dbg!(&json);
43
-
44
47
Config {
45
48
store: Mutex::new(json),
46
49
path: path,
···
48
51
}
49
52
50
53
pub fn save(&self) {
51
-
let dat = serde_json::to_string(&self.store.lock().unwrap().clone()).unwrap();
52
-
dbg!(&dat);
54
+
let mut dat = self.store.lock().unwrap();
55
+
dat.last_save = Utc::now().timestamp();
56
+
57
+
let dat = serde_json::to_string(&*dat).unwrap();
58
+
59
+
let file = File::create(&self.path).unwrap();
60
+
let mut encoder = GzEncoder::new(file, Compression::default());
61
+
62
+
encoder.write_all(dat.as_bytes()).unwrap();
63
+
encoder.finish().unwrap();
64
+
}
65
+
66
+
pub fn save_prelocked(&self, mut dat: MutexGuard<'_, ConfigValues>) {
67
+
dat.last_save = Utc::now().timestamp();
68
+
69
+
let dat = serde_json::to_string(&*dat).unwrap();
53
70
54
71
let file = File::create(&self.path).unwrap();
55
72
let mut encoder = GzEncoder::new(file, Compression::default());
+14
-2
src/Mangers/NodeManager.tsx
+14
-2
src/Mangers/NodeManager.tsx
···
27
27
setInterval(() => {
28
28
let tabs = Object.values(this._tabs).filter(x => x.needSync);
29
29
for(let tab of tabs){
30
-
invoke('sync_tab', { graph: this._generateTabGraph(tab.id)[0], id: tab.id, name: tab.name, location: tab.saveLocation });
30
+
invoke('sync_tab', {
31
+
graph: this._generateTabGraph(tab.id)[0],
32
+
id: tab.id,
33
+
name: tab.name,
34
+
location: tab.saveLocation,
35
+
saveState: tab.needsSave()
36
+
});
37
+
31
38
tab.needSync = false;
32
39
}
33
40
}, 1000);
···
40
47
let version = await getVersion();
41
48
42
49
for(let tab of Object.entries<any>(tabs)){
43
-
await this._loadFromConfig(tab[1][2], tab[0], JSON.stringify({
50
+
let loaded_tab = await this._loadFromConfig(tab[1][2], tab[0], JSON.stringify({
44
51
tab_name: tab[1][1],
45
52
version,
46
53
graph: tab[1][0]
47
54
}));
55
+
56
+
if(loaded_tab)
57
+
loaded_tab.setNeedsSave(tab[1][3]);
48
58
};
49
59
50
60
this.UpdateConfig();
···
336
346
337
347
tab.needSync = false;
338
348
if(!id)this.UpdateConfig(false);
349
+
350
+
return tab;
339
351
}
340
352
341
353
private _generateTabGraph( tabId: string | null ): [ any, Tab | null ]{
-1
src/Nodes/Conditional/IfEqual.tsx
-1
src/Nodes/Conditional/IfEqual.tsx
-1
src/Nodes/Conditional/IfFalse.tsx
-1
src/Nodes/Conditional/IfFalse.tsx
-1
src/Nodes/Conditional/IfTrue.tsx
-1
src/Nodes/Conditional/IfTrue.tsx
-1
src/Nodes/Debug.tsx
-1
src/Nodes/Debug.tsx
+1
-2
src/Nodes/Nodes.tsx
+1
-2
src/Nodes/Nodes.tsx
···
17
17
onStaticsUpdate?: ( node: Node ) => Promise<void>,
18
18
// build?: ( pos: [ number, number ], onStaticsUpdate: ( node: Node ) => void ) => Promise<Node>,
19
19
w?: number,
20
-
h?: number,
21
20
statics?: NodeStatic[],
22
21
inputs?: { name: string, type: NodeType }[],
23
22
outputs?: { name: string, type: NodeType }[],
···
29
28
[details: string] : NodeDefinition;
30
29
}
31
30
32
-
// TODO: (Node Additions) Pressing keyboard keys
31
+
// TODO: (Node Additions) Pressing keyboard keys (like to do linux, but has extra steps)
33
32
// TODO: (Node Additions) Getting media state from os
34
33
// TODO: (Node Additions) Sending custom OSC messages
35
34
// TODO: (Node Additions) Sending HTTP requests?
-1
src/Nodes/OSCActions/Send Chatbox.tsx
-1
src/Nodes/OSCActions/Send Chatbox.tsx
+1
-2
src/Nodes/OSCTrigger.tsx
+1
-2
src/Nodes/OSCTrigger.tsx
-1
src/Nodes/PressKey.tsx
-1
src/Nodes/PressKey.tsx
-1
src/Nodes/Shell.tsx
-1
src/Nodes/Shell.tsx
-1
src/Nodes/Statics/Float.tsx
-1
src/Nodes/Statics/Float.tsx
-1
src/Nodes/Statics/Int.tsx
-1
src/Nodes/Statics/Int.tsx
-1
src/Nodes/Statics/String.tsx
-1
src/Nodes/Statics/String.tsx
+7
-2
src/structs/node.ts
+7
-2
src/structs/node.ts
···
20
20
this.typeId = node.typeId!;
21
21
this.x = pos[0];
22
22
this.y = pos[1];
23
-
this.w = node.w!;
24
-
this.h = node.h!;
25
23
26
24
this.inputs = node.inputs ? node.inputs.map(( x, indx ) => {
27
25
return {
···
43
41
}
44
42
}) : [];
45
43
44
+
this.w = node.w || 200;
45
+
this.h = 50 + Math.max(this.outputs.length, this.inputs.length) * 30;
46
+
46
47
this.selected = false;
47
48
this.statics = node.statics!,
48
49
this.onStaticsUpdate = node.onStaticsUpdate!;
50
+
}
51
+
52
+
updateSize(){
53
+
this.h = 50 + Math.max(this.outputs.length, this.inputs.length) * 30;
49
54
}
50
55
}
51
56