Skip to content

Commit 5866553

Browse files
committed
Refactor editor api to allow for future timeouts and side effect messages
1 parent 294409b commit 5866553

File tree

25 files changed

+336
-250
lines changed

25 files changed

+336
-250
lines changed

desktop/wrapper/src/message_dispatcher.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ impl<'a> DesktopWrapperMessageDispatcher<'a> {
6565
.editor
6666
.handle_message(EditorMessage::Batched {
6767
messages: std::mem::take(&mut self.editor_message_queue).into_boxed_slice(),
68-
})
69-
.into_iter()
70-
.filter_map(|m| intercept_frontend_message(self, m));
68+
});
69+
// .into_iter()
70+
// .filter_map(|m| intercept_frontend_message(self, m));
7171
frontend_messages.extend(current_frontend_messages);
7272
}
7373

editor/src/application.rs

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use crate::dispatcher::Dispatcher;
2-
use crate::messages::portfolio::document::node_graph::generate_node_graph_overlay::generate_node_graph_overlay;
2+
use crate::dispatcher::EditorOutput;
33
use crate::messages::prelude::*;
4-
use graph_craft::document::{NodeInput, NodeNetwork};
5-
use graphene_std::node_graph_overlay::types::NodeGraphOverlayData;
64
pub use graphene_std::uuid::*;
75

86
// TODO: serialize with serde to save the current editor state
@@ -24,41 +22,13 @@ impl Editor {
2422
(Self { dispatcher }, runtime)
2523
}
2624

27-
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Vec<FrontendMessage> {
28-
self.dispatcher.handle_message(message, true);
29-
30-
std::mem::take(&mut self.dispatcher.responses)
25+
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Vec<EditorOutput> {
26+
self.dispatcher.handle_message(message, true)
3127
}
3228

3329
pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque<Message>) -> Result<(), String> {
3430
self.dispatcher.poll_node_graph_evaluation(responses)
3531
}
36-
37-
pub fn generate_node_graph_overlay_network(&mut self) -> Option<NodeNetwork> {
38-
let Some(active_document) = self.dispatcher.message_handlers.portfolio_message_handler.active_document_mut() else {
39-
return None;
40-
};
41-
let breadcrumb_network_path = &active_document.breadcrumb_network_path;
42-
let nodes_to_render = active_document.network_interface.collect_nodes(
43-
&active_document.node_graph_handler.node_graph_errors,
44-
self.dispatcher.message_handlers.preferences_message_handler.graph_wire_style,
45-
breadcrumb_network_path,
46-
);
47-
let previewed_node = active_document.network_interface.previewed_node(breadcrumb_network_path);
48-
let node_graph_render_data = NodeGraphOverlayData {
49-
nodes_to_render,
50-
open: active_document.graph_view_overlay_open,
51-
in_selected_network: &active_document.selection_network_path == breadcrumb_network_path,
52-
previewed_node,
53-
};
54-
let opacity = active_document.graph_fade_artwork_percentage;
55-
let node_graph_overlay_node = generate_node_graph_overlay(node_graph_render_data, opacity);
56-
Some(NodeNetwork {
57-
exports: vec![NodeInput::node(NodeId(0), 0)],
58-
nodes: vec![(NodeId(0), node_graph_overlay_node)].into_iter().collect(),
59-
..Default::default()
60-
})
61-
}
6232
}
6333

6434
impl Default for Editor {

editor/src/dispatcher.rs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use std::time::Duration;
2+
3+
use interpreted_executor::ui_runtime::CompilationRequest;
4+
15
use crate::messages::debug::utility_types::MessageLoggingVerbosity;
26
use crate::messages::defer::DeferMessageContext;
37
use crate::messages::dialog::DialogMessageContext;
@@ -7,7 +11,6 @@ use crate::messages::prelude::*;
711
#[derive(Debug, Default)]
812
pub struct Dispatcher {
913
message_queues: Vec<VecDeque<Message>>,
10-
pub responses: Vec<FrontendMessage>,
1114
pub message_handlers: DispatcherMessageHandlers,
1215
}
1316

@@ -28,6 +31,15 @@ pub struct DispatcherMessageHandlers {
2831
tool_message_handler: ToolMessageHandler,
2932
}
3033

34+
// Output messages are what the editor returns after processing Messages. It is handled by the scope outside the editor,
35+
// which has access to the node graph executor, frontend, etc
36+
pub enum EditorOutput {
37+
// These messages perform some side effect other than updating the frontend, but outside the scope of the editor
38+
RequestNativeNodeGraphRender { compilation_request: CompilationRequest },
39+
RequestDeferredMessage { message: Box<Message>, timeout: Duration },
40+
FrontendMessage { frontend_message: FrontendMessage },
41+
}
42+
3143
impl DispatcherMessageHandlers {
3244
pub fn with_executor(executor: crate::node_graph_executor::NodeGraphExecutor) -> Self {
3345
Self {
@@ -41,7 +53,6 @@ impl DispatcherMessageHandlers {
4153
/// The last occurrence of the message in the message queue is sufficient to ensure correct behavior.
4254
/// In addition, these messages do not change any state in the backend (aside from caches).
4355
const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
44-
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::NodeGraph(NodeGraphMessageDiscriminant::SendGraph))),
4556
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel(
4657
PropertiesPanelMessageDiscriminant::Refresh,
4758
))),
@@ -93,12 +104,14 @@ impl Dispatcher {
93104
}
94105
}
95106

96-
pub fn handle_message<T: Into<Message>>(&mut self, message: T, process_after_all_current: bool) {
107+
pub fn handle_message<T: Into<Message>>(&mut self, message: T, process_after_all_current: bool) -> Vec<EditorOutput> {
97108
let message = message.into();
98-
99109
// If we are not maintaining the buffer, simply add to the current queue
100110
Self::schedule_execution(&mut self.message_queues, process_after_all_current, [message]);
101111

112+
let mut side_effects = Vec::new();
113+
let mut output_messages = Vec::new();
114+
102115
while let Some(message) = self.message_queues.last_mut().and_then(VecDeque::pop_front) {
103116
// Skip processing of this message if it will be processed later (at the end of the shallowest level queue)
104117
if SIDE_EFFECT_FREE_MESSAGES.contains(&message.to_discriminant()) {
@@ -148,20 +161,8 @@ impl Dispatcher {
148161
self.message_handlers.dialog_message_handler.process_message(message, &mut queue, context);
149162
}
150163
Message::Frontend(message) => {
151-
// Handle these messages immediately by returning early
152-
if let FrontendMessage::TriggerFontLoad { .. } = message {
153-
self.responses.push(message);
154-
self.cleanup_queues(false);
155-
156-
// Return early to avoid running the code after the match block
157-
return;
158-
} else {
159-
// `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed
160-
// Deduplicate the render native node graph messages. TODO: Replace responses with hashset
161-
if !(message == FrontendMessage::RequestNativeNodeGraphRender && self.responses.contains(&FrontendMessage::RequestNativeNodeGraphRender)) {
162-
self.responses.push(message);
163-
}
164-
}
164+
// `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed
165+
output_messages.push(EditorOutput::FrontendMessage { frontend_message: message });
165166
}
166167
Message::Globals(message) => {
167168
self.message_handlers.globals_message_handler.process_message(message, &mut queue, ());
@@ -213,14 +214,19 @@ impl Dispatcher {
213214
Message::Preferences(message) => {
214215
self.message_handlers.preferences_message_handler.process_message(message, &mut queue, ());
215216
}
217+
Message::SideEffect(message) => {
218+
if !side_effects.contains(&message) {
219+
side_effects.push(message);
220+
}
221+
}
216222
Message::Tool(message) => {
217223
let Some(document_id) = self.message_handlers.portfolio_message_handler.active_document_id() else {
218224
warn!("Called ToolMessage without an active document.\nGot {message:?}");
219-
return;
225+
return Vec::new();
220226
};
221227
let Some(document) = self.message_handlers.portfolio_message_handler.documents.get_mut(&document_id) else {
222228
warn!("Called ToolMessage with an invalid active document.\nGot {message:?}");
223-
return;
229+
return Vec::new();
224230
};
225231

226232
let context = ToolMessageContext {
@@ -236,7 +242,9 @@ impl Dispatcher {
236242
}
237243
Message::NoOp => {}
238244
Message::Batched { messages } => {
239-
messages.iter().for_each(|message| self.handle_message(message.to_owned(), false));
245+
for nested_outputs in messages.into_iter().map(|message| self.handle_message(message, false)) {
246+
output_messages.extend(nested_outputs);
247+
}
240248
}
241249
}
242250

@@ -247,6 +255,12 @@ impl Dispatcher {
247255

248256
self.cleanup_queues(false);
249257
}
258+
259+
// The full message tree has been processed, so the side effects can be processed
260+
for message in side_effects {
261+
output_messages.extend(self.handle_side_effect(message));
262+
}
263+
output_messages
250264
}
251265

252266
pub fn collect_actions(&self) -> ActionList {
@@ -314,6 +328,7 @@ impl Dispatcher {
314328

315329
#[cfg(test)]
316330
mod test {
331+
use crate::messages::side_effects::EditorOutputMessage;
317332
pub use crate::test_utils::test_prelude::*;
318333

319334
/// Create an editor with three layers
@@ -513,7 +528,10 @@ mod test {
513528

514529
for response in responses {
515530
// Check for the existence of the file format incompatibility warning dialog after opening the test file
516-
if let FrontendMessage::UpdateDialogColumn1 { layout_target: _, diff } = response {
531+
if let EditorOutputMessage::FrontendMessage {
532+
frontend_message: FrontendMessage::UpdateDialogColumn1 { layout_target: _, diff },
533+
} = response
534+
{
517535
if let DiffUpdate::SubLayout(sub_layout) = &diff[0].new_value {
518536
if let LayoutGroup::Row { widgets } = &sub_layout[0] {
519537
if let Widget::TextLabel(TextLabel { value, .. }) = &widgets[0].widget {

editor/src/messages/frontend/frontend_message.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,6 @@ pub enum FrontendMessage {
267267
UpdateMouseCursor {
268268
cursor: MouseCursorIcon,
269269
},
270-
RequestNativeNodeGraphRender,
271270
UpdateNativeNodeGraphSVG {
272271
#[serde(rename = "svgString")]
273272
svg_string: String,
@@ -293,6 +292,10 @@ pub enum FrontendMessage {
293292
layout_target: LayoutTarget,
294293
diff: Vec<WidgetDiff>,
295294
},
295+
UpdateTooltip {
296+
position: Option<FrontendXY>,
297+
text: String,
298+
},
296299
UpdateToolOptionsLayout {
297300
#[serde(rename = "layoutTarget")]
298301
layout_target: LayoutTarget,

editor/src/messages/message.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::messages::prelude::*;
1+
use crate::messages::{prelude::*, side_effects::{SideEffectMessage}};
22
use graphite_proc_macros::*;
33

44
#[impl_message]
@@ -18,6 +18,8 @@ pub enum Message {
1818
#[child]
1919
Dialog(DialogMessage),
2020
#[child]
21+
SideEffect(SideEffectMessage),
22+
#[child]
2123
Frontend(FrontendMessage),
2224
#[child]
2325
Globals(GlobalsMessage),

editor/src/messages/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ pub mod message;
1515
pub mod portfolio;
1616
pub mod preferences;
1717
pub mod prelude;
18+
pub mod side_effects;
1819
pub mod tool;

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,8 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
14811481
x: transform.translation.x,
14821482
y: transform.translation.y,
14831483
},
1484-
})
1484+
});
1485+
responses.add(NodeGraphMessage::PointerMove { shift: Key::Shift });
14851486
}
14861487
}
14871488
DocumentMessage::SelectionStepBack => {

editor/src/messages/portfolio/document/node_graph/node_graph_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ pub enum NodeGraphMessage {
214214
SetLockedOrVisibilitySideEffects {
215215
node_ids: Vec<NodeId>,
216216
},
217+
TryDisplayTooltip,
217218
UpdateBoxSelection,
218219
UpdateImportsExports,
219220
UpdateLayerPanel,

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{
1515
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
1616
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePathInProgress, build_vector_wire};
1717
use crate::messages::prelude::*;
18+
use crate::messages::side_effects::SideEffectMessage;
1819
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
1920
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
2021
use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed;
@@ -30,6 +31,7 @@ use graphene_std::*;
3031
use kurbo::{DEFAULT_ACCURACY, Shape};
3132
use renderer::Quad;
3233
use std::cmp::Ordering;
34+
use std::time::Duration;
3335

3436
#[derive(Debug, ExtractField)]
3537
pub struct NodeGraphMessageContext<'a> {
@@ -92,6 +94,10 @@ pub struct NodeGraphMessageHandler {
9294
reordering_export: Option<usize>,
9395
/// The end index of the moved connector
9496
end_index: Option<usize>,
97+
// If an input is being hovered. Used for tooltip
98+
hovering_input: bool,
99+
// If an output is being hovered. Used for tooltip
100+
hovering_output: bool,
95101
}
96102

97103
/// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network.
@@ -1141,6 +1147,31 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
11411147
.unwrap_or_else(|| modify_import_export.reorder_imports_exports.input_ports().count() + 1),
11421148
);
11431149
responses.add(FrontendMessage::UpdateExportReorderIndex { index: self.end_index });
1150+
} else if !self.hovering_input && !self.hovering_output {
1151+
if network_interface.input_connector_from_click(ipp.mouse.position, breadcrumb_network_path).is_some() {
1152+
self.hovering_input = true;
1153+
responses.add(SideEffectMessage::RequestDeferredMessage {
1154+
message: Box::new(NodeGraphMessage::TryDisplayTooltip.into()),
1155+
timeout: Duration::from_millis(800),
1156+
});
1157+
}
1158+
if network_interface.output_connector_from_click(ipp.mouse.position, breadcrumb_network_path).is_some() {
1159+
self.hovering_output = true;
1160+
responses.add(SideEffectMessage::RequestDeferredMessage {
1161+
message: Box::new(NodeGraphMessage::TryDisplayTooltip.into()),
1162+
timeout: Duration::from_millis(800),
1163+
})
1164+
}
1165+
} else if self.hovering_input {
1166+
if !network_interface.input_connector_from_click(ipp.mouse.position, breadcrumb_network_path).is_some() {
1167+
self.hovering_input = false;
1168+
responses.add(FrontendMessage::UpdateTooltip { position: None, text: String::new() });
1169+
}
1170+
} else if self.hovering_output {
1171+
if !network_interface.output_connector_from_click(ipp.mouse.position, breadcrumb_network_path).is_some() {
1172+
self.hovering_output = false;
1173+
responses.add(FrontendMessage::UpdateTooltip { position: None, text: String::new() });
1174+
}
11441175
}
11451176
}
11461177
NodeGraphMessage::PointerUp => {
@@ -1594,7 +1625,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
15941625
responses.add(PropertiesPanelMessage::Refresh);
15951626
responses.add(NodeGraphMessage::UpdateActionButtons);
15961627

1597-
responses.add(FrontendMessage::RequestNativeNodeGraphRender);
1628+
responses.add(SideEffectMessage::RenderNodeGraph);
15981629
responses.add(NodeGraphMessage::UpdateImportsExports);
15991630
self.update_node_graph_hints(responses);
16001631
}
@@ -1820,6 +1851,36 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
18201851

18211852
responses.add(PropertiesPanelMessage::Refresh);
18221853
}
1854+
NodeGraphMessage::TryDisplayTooltip => {
1855+
if let Some(input) = network_interface.input_connector_from_click(ipp.mouse.position, breadcrumb_network_path) {
1856+
let text = network_interface.input_tooltip_text(&input, breadcrumb_network_path);
1857+
if let Some(position) = network_interface.input_position(&input, breadcrumb_network_path) {
1858+
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
1859+
return;
1860+
};
1861+
let position = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(position);
1862+
let xy = FrontendXY {
1863+
x: position.x as i32,
1864+
y: position.y as i32,
1865+
};
1866+
responses.add(FrontendMessage::UpdateTooltip { position: Some(xy), text });
1867+
}
1868+
} else if let Some(output) = network_interface.output_connector_from_click(ipp.mouse.position, breadcrumb_network_path) {
1869+
let text = network_interface.output_tooltip_text(&output, breadcrumb_network_path);
1870+
if let Some(position) = network_interface.output_position(&output, breadcrumb_network_path) {
1871+
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
1872+
return;
1873+
};
1874+
let position = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(position);
1875+
1876+
let xy = FrontendXY {
1877+
x: position.x as i32,
1878+
y: position.y as i32,
1879+
};
1880+
responses.add(FrontendMessage::UpdateTooltip { position: Some(xy), text });
1881+
}
1882+
}
1883+
}
18231884
NodeGraphMessage::UpdateBoxSelection => {
18241885
if let Some((box_selection_start, _)) = self.box_selection_start {
18251886
// The mouse button was released but we missed the pointer up event
@@ -2559,6 +2620,8 @@ impl Default for NodeGraphMessageHandler {
25592620
reordering_export: None,
25602621
reordering_import: None,
25612622
end_index: None,
2623+
hovering_input: false,
2624+
hovering_output: false,
25622625
}
25632626
}
25642627
}

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,13 +1024,6 @@ pub fn get_document_node<'a>(node_id: NodeId, context: &'a NodePropertiesContext
10241024
network.nodes.get(&node_id).ok_or(format!("node {node_id} not found in get_document_node"))
10251025
}
10261026

1027-
pub fn query_node_and_input_info<'a>(node_id: NodeId, input_index: usize, context: &'a mut NodePropertiesContext<'a>) -> Result<(&'a DocumentNode, String, String), String> {
1028-
let (name, description) = context.network_interface.displayed_input_name_and_description(&node_id, input_index, context.selection_network_path);
1029-
let document_node = get_document_node(node_id, context)?;
1030-
1031-
Ok((document_node, name, description))
1032-
}
1033-
10341027
pub fn query_noise_pattern_state(node_id: NodeId, context: &NodePropertiesContext) -> Result<(bool, bool, bool, bool, bool, bool), String> {
10351028
let document_node = get_document_node(node_id, context)?;
10361029
let current_noise_type = document_node.inputs.iter().find_map(|input| match input.as_value() {

0 commit comments

Comments
 (0)