diff --git a/reaction_systems_gui/check.sh b/reaction_systems_gui/check.sh index 29485f3..27e9911 100755 --- a/reaction_systems_gui/check.sh +++ b/reaction_systems_gui/check.sh @@ -4,7 +4,7 @@ set -eux cargo check --workspace --all-targets cargo check --workspace --all-features --lib --target wasm32-unknown-unknown -cargo fmt --all -- --check +# cargo fmt --all -- --check cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all cargo test --workspace --all-targets --all-features cargo test --workspace --doc diff --git a/reaction_systems_gui/src/app.rs b/reaction_systems_gui/src/app.rs index 811a981..0ef3be0 100644 --- a/reaction_systems_gui/src/app.rs +++ b/reaction_systems_gui/src/app.rs @@ -538,6 +538,7 @@ pub enum CustomResponse { SetActiveNode(NodeId), ClearActiveNode, SaveToFile(NodeId), + FieldModified, } #[derive(Default, Debug)] @@ -549,6 +550,7 @@ struct CacheInternals { values: HashMap, hash_values: HashMap, hash_inputs: HashMap)>, + last_output: Option, } /// Cache used to save intermediate values between executions. @@ -651,6 +653,21 @@ impl OutputsCache { let mut internals = self.internals.write().unwrap(); *internals = CacheInternals::default(); } + + pub fn get_last_state(&self) -> Option { + let internals = self.internals.read().unwrap(); + internals.last_output.clone() + } + + pub fn invalidate_last_state(&mut self) { + let mut internals = self.internals.write().unwrap(); + internals.last_output = None; + } + + pub fn set_last_state(&mut self, val: LayoutJob) { + let mut internals = self.internals.write().unwrap(); + internals.last_output = Some(val); + } } /// The graph 'global' state. @@ -930,6 +947,8 @@ impl WidgetValueTrait for BasicValue { _user_state: &mut GlobalState, _node_data: &NodeData, ) -> Vec { + let mut responses = vec![]; + match self { // Dummy values used to save files, no ui since not needed | BasicValue::SaveString { path: _, value: _ } => {}, @@ -938,21 +957,27 @@ impl WidgetValueTrait for BasicValue { | BasicValue::String { value } => { ui.label(param_name); ui.horizontal(|ui| { - ui.add( + let field = ui.add( egui::TextEdit::multiline(value) .hint_text("String here") .clip_text(false), ); + if field.changed() { + responses.push(CustomResponse::FieldModified); + } }); }, | BasicValue::Path { value } => { ui.label(param_name); ui.horizontal(|ui| { - ui.add( + let field = ui.add( egui::TextEdit::multiline(value) .hint_text("Path here") .clip_text(false), ); + if field.changed() { + responses.push(CustomResponse::FieldModified); + } }); }, | BasicValue::System { value: _ } => { @@ -968,11 +993,14 @@ impl WidgetValueTrait for BasicValue { | BasicValue::Symbol { value } => { ui.label(param_name); ui.horizontal(|ui| { - ui.add( + let field = ui.add( egui::TextEdit::singleline(value) .hint_text("Symbol here") .clip_text(false), ); + if field.changed() { + responses.push(CustomResponse::FieldModified); + } }); }, | BasicValue::Experiment { value: _ } => { @@ -1051,8 +1079,8 @@ impl WidgetValueTrait for BasicValue { }); }, } - // Custom response (not used currently). - Vec::new() + + responses } } @@ -1075,20 +1103,12 @@ impl NodeDataTrait for NodeData { where CustomResponse: UserResponseTrait, { - // This logic is entirely up to the user. In this case, we check if the - // current node we're drawing is the active one, by comparing against - // the value stored in the global user state, and draw different button - // UIs based on that. let mut responses = vec![]; let is_active = user_state .active_node .map(|id| id == node_id) .unwrap_or(false); - // Pressing the button will emit a custom user response to either set, - // or clear the active node. These responses do nothing by themselves, - // the library only makes the responses available to you after the graph - // has been drawn. See below at the update method for an example. match (is_active, graph[node_id].user_data.template) { | (_, NodeInstruction::SaveString) => { if ui.button("Write").clicked() { @@ -1293,37 +1313,58 @@ impl eframe::App for AppHandle { }) .inner; - for node_response in graph_response.node_responses { + for node_response in graph_response.node_responses.iter() { // graph events match node_response { | NodeResponse::User(CustomResponse::SetActiveNode(node)) => { - self.user_state.active_node = Some(node); + self.user_state.active_node = Some(*node); self.user_state.display_result = true; + self.user_state.cache.invalidate_last_state(); }, | NodeResponse::User(CustomResponse::ClearActiveNode) => { self.user_state.active_node = None; self.user_state.display_result = false; + self.user_state.cache.invalidate_last_state(); }, | NodeResponse::User(CustomResponse::SaveToFile(node)) => { - self.user_state.save_node = Some(node); + self.user_state.save_node = Some(*node); self.user_state.display_result = true; + self.user_state.cache.invalidate_last_state(); }, | NodeResponse::DisconnectEvent { output, input: _ } => { - self.user_state.cache.invalidate_cache(&output); + self.user_state.cache.invalidate_cache(output); }, | NodeResponse::ConnectEventEnded { output, input: _, input_hook: _, } => { - self.user_state.cache.invalidate_cache(&output); + self.user_state.cache.invalidate_cache(output); }, | _ => {}, } } if self.user_state.display_result { - let text = create_output(self, ctx); + let text = { + if !graph_response.node_responses.is_empty() { + let computed_output = create_output(self, ctx); + self.user_state + .cache + .set_last_state(computed_output.clone()); + computed_output + } else if let Some(pre_computed) = + self.user_state.cache.get_last_state() + { + pre_computed + } else { + let computed_output = create_output(self, ctx); + self.user_state + .cache + .set_last_state(computed_output.clone()); + computed_output + } + }; let window = egui::SidePanel::right("Results").resizable(true); diff --git a/reaction_systems_gui/src/app_logic.rs b/reaction_systems_gui/src/app_logic.rs index 114f494..dbaa10f 100644 --- a/reaction_systems_gui/src/app_logic.rs +++ b/reaction_systems_gui/src/app_logic.rs @@ -184,105 +184,94 @@ fn process_template( => {retrieve_from_cache!(@as_expr ($($body)*))}; (@accum (1) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (0) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (0) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[0].0.clone())?,))}; + .inputs()[0].0.clone())?, $($body)*))}; (@accum (2) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (1) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (1) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[1].0.clone())?,))}; + .inputs()[1].0.clone())?, $($body)*))}; (@accum (3) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (2) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (2) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[2].0.clone())?,))}; + .inputs()[2].0.clone())?, $($body)*))}; (@accum (4) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (3) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (3) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[3].0.clone())?,))}; + .inputs()[3].0.clone())?, $($body)*))}; (@accum (5) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (4) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (4) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[4].0.clone())?,))}; + .inputs()[4].0.clone())?, $($body)*))}; (@accum (6) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (5) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (5) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[5].0.clone())?,))}; + .inputs()[5].0.clone())?, $($body)*))}; (@accum (7) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (6) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (6) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[6].0.clone())?,))}; + .inputs()[6].0.clone())?, $($body)*))}; (@accum (8) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (7) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (7) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[7].0.clone())?,))}; + .inputs()[7].0.clone())?, $($body)*))}; (@accum (9) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (8) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (8) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[8].0.clone())?,))}; + .inputs()[8].0.clone())?, $($body)*))}; (@accum (10) -> ($($body:tt)*)) => {retrieve_from_cache!( - @accum (9) -> ($($body)* - outputs_cache.retrieve_cache_output( + @accum (9) -> (outputs_cache.retrieve_cache_output( graph, node_id, &graph[node_id] .user_data .template - .inputs()[9].0.clone())?,))}; - + .inputs()[9].0.clone())?, $($body)*))}; (@as_expr $e:expr) => {$e}; [0] => { compile_error!("Macro returns a value or a tuple, supply an \ @@ -895,6 +884,7 @@ fn process_template( color_node, color_edge, ) = retrieve_from_cache![5]; + let hash_inputs = hash_inputs!( input_graph, display_node,