mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 11:28:30 +08:00
Add handler for deferred execution of messages (#2951)
* Add Handler for defered execution of messages * Cleanup * Track graph execution id to associate messages with their corresponding execution id * Rename ViewportReady -> NavigationReady * Defer layer deselection
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
#[impl_message(Message, Defer)]
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum DeferMessage {
|
||||
TriggerGraphRun(u64),
|
||||
AfterGraphRun { messages: Vec<Message> },
|
||||
TriggerNavigationReady,
|
||||
AfterNavigationReady { messages: Vec<Message> },
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
#[derive(Debug, Default, ExtractField)]
|
||||
pub struct DeferMessageHandler {
|
||||
after_graph_run: Vec<(u64, Message)>,
|
||||
after_viewport_resize: Vec<Message>,
|
||||
current_graph_submission_id: u64,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
impl MessageHandler<DeferMessage, ()> for DeferMessageHandler {
|
||||
fn process_message(&mut self, message: DeferMessage, responses: &mut VecDeque<Message>, _: ()) {
|
||||
match message {
|
||||
DeferMessage::AfterGraphRun { mut messages } => {
|
||||
self.after_graph_run.extend(messages.drain(..).map(|m| (self.current_graph_submission_id, m)));
|
||||
}
|
||||
DeferMessage::AfterNavigationReady { messages } => {
|
||||
self.after_viewport_resize.extend_from_slice(&messages);
|
||||
}
|
||||
DeferMessage::TriggerGraphRun(execution_id) => {
|
||||
self.current_graph_submission_id = execution_id;
|
||||
for message in self.after_graph_run.extract_if(.., |x| x.0 < self.current_graph_submission_id) {
|
||||
responses.push_front(message.1);
|
||||
}
|
||||
}
|
||||
DeferMessage::TriggerNavigationReady => {
|
||||
for message in self.after_viewport_resize.drain(..) {
|
||||
responses.push_front(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
advertise_actions!(DeferMessageDiscriminant;
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mod defer_message;
|
||||
mod defer_message_handler;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use defer_message::{DeferMessage, DeferMessageDiscriminant};
|
||||
#[doc(inline)]
|
||||
pub use defer_message_handler::DeferMessageHandler;
|
||||
+12
-9
@@ -24,18 +24,21 @@ impl MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHa
|
||||
|
||||
let create_artboard = !self.infinite && self.dimensions.x > 0 && self.dimensions.y > 0;
|
||||
if create_artboard {
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id: NodeId::new(),
|
||||
artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()),
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![
|
||||
GraphOperationMessage::NewArtboard {
|
||||
id: NodeId::new(),
|
||||
artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()),
|
||||
}
|
||||
.into(),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead
|
||||
// Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(DocumentMessage::DeselectAllLayers);
|
||||
responses.add(DeferMessage::AfterNavigationReady {
|
||||
messages: vec![DocumentMessage::ZoomCanvasToFitAll.into(), DocumentMessage::DeselectAllLayers.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ pub enum FrontendMessage {
|
||||
#[serde(rename = "commitDate")]
|
||||
commit_date: String,
|
||||
},
|
||||
TriggerDelayedZoomCanvasToFitAll,
|
||||
TriggerDownloadImage {
|
||||
svg: String,
|
||||
name: String,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::messages::prelude::*;
|
||||
use graphene_std::renderer::RenderMetadata;
|
||||
use graphite_proc_macros::*;
|
||||
|
||||
#[impl_message]
|
||||
@@ -15,6 +14,8 @@ pub enum Message {
|
||||
#[child]
|
||||
Debug(DebugMessage),
|
||||
#[child]
|
||||
Defer(DeferMessage),
|
||||
#[child]
|
||||
Dialog(DialogMessage),
|
||||
#[child]
|
||||
Frontend(FrontendMessage),
|
||||
@@ -40,10 +41,6 @@ pub enum Message {
|
||||
Batched {
|
||||
messages: Box<[Message]>,
|
||||
},
|
||||
StartBuffer,
|
||||
EndBuffer {
|
||||
render_metadata: RenderMetadata,
|
||||
},
|
||||
}
|
||||
|
||||
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
|
||||
|
||||
@@ -4,6 +4,7 @@ pub mod animation;
|
||||
pub mod app_window;
|
||||
pub mod broadcast;
|
||||
pub mod debug;
|
||||
pub mod defer;
|
||||
pub mod dialog;
|
||||
pub mod frontend;
|
||||
pub mod globals;
|
||||
|
||||
@@ -1435,6 +1435,20 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
},
|
||||
})
|
||||
}
|
||||
// Some parts of the editior (e.g. navigation messages) depend on these bounds to be present
|
||||
let bounds = if self.graph_view_overlay_open {
|
||||
self.network_interface.all_nodes_bounding_box(&self.breadcrumb_network_path).cloned()
|
||||
} else {
|
||||
self.network_interface.document_bounds_document_space(true)
|
||||
};
|
||||
if bounds.is_some() {
|
||||
responses.add(DeferMessage::TriggerNavigationReady);
|
||||
} else {
|
||||
// If we don't have bounds yet, we need wait until the node graph has run once more
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![DocumentMessage::PTZUpdate.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
DocumentMessage::SelectionStepBack => {
|
||||
self.network_interface.selection_step_back(&self.selection_network_path);
|
||||
@@ -1866,14 +1880,14 @@ impl DocumentMessageHandler {
|
||||
|
||||
let previous_network = std::mem::replace(&mut self.network_interface, network_interface);
|
||||
|
||||
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
|
||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
||||
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
||||
// TODO: Remove once the footprint is used to load the imports/export distances from the edge
|
||||
responses.add(NodeGraphMessage::UnloadWires);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.push_front(NodeGraphMessage::UnloadWires.into());
|
||||
responses.push_front(NodeGraphMessage::SetGridAlignedEdges.into());
|
||||
|
||||
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
|
||||
responses.push_front(NodeGraphMessage::ForceRunDocumentGraph.into());
|
||||
responses.push_front(NodeGraphMessage::SelectedNodesUpdated.into());
|
||||
responses.push_front(PortfolioMessage::UpdateOpenDocumentsList.into());
|
||||
Some(previous_network)
|
||||
}
|
||||
pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
|
||||
@@ -568,8 +568,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all_new_ids });
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(PortfolioMessage::CenterPastedLayers { layers });
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![PortfolioMessage::CenterPastedLayers { layers }.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,13 +702,12 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
if create_document {
|
||||
// Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true });
|
||||
|
||||
// TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead
|
||||
// Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(DeferMessage::AfterNavigationReady {
|
||||
messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()],
|
||||
});
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
PortfolioMessage::PasteSvg {
|
||||
@@ -733,13 +733,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
if create_document {
|
||||
// Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true });
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()],
|
||||
});
|
||||
|
||||
// TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead
|
||||
// Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(DeferMessage::AfterNavigationReady {
|
||||
messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
PortfolioMessage::PrevDocument => {
|
||||
@@ -1019,9 +1019,6 @@ impl PortfolioMessageHandler {
|
||||
/text>"#
|
||||
// It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed.
|
||||
.to_string();
|
||||
responses.add(Message::EndBuffer {
|
||||
render_metadata: graphene_std::renderer::RenderMetadata::default(),
|
||||
});
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg: error });
|
||||
}
|
||||
result
|
||||
|
||||
@@ -6,6 +6,7 @@ pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscrimin
|
||||
pub use crate::messages::app_window::{AppWindowMessage, AppWindowMessageDiscriminant, AppWindowMessageHandler};
|
||||
pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler};
|
||||
pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler};
|
||||
pub use crate::messages::defer::{DeferMessage, DeferMessageDiscriminant, DeferMessageHandler};
|
||||
pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDialogMessageContext, ExportDialogMessageDiscriminant, ExportDialogMessageHandler};
|
||||
pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler};
|
||||
pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageContext, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler};
|
||||
|
||||
@@ -153,8 +153,9 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(PenToolMessage::RecalculateLatestPointsPosition);
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![PenToolMessage::RecalculateLatestPointsPosition.into()],
|
||||
});
|
||||
}
|
||||
|
||||
/// Merge the `first_endpoint` with `second_endpoint`.
|
||||
|
||||
@@ -383,8 +383,9 @@ impl Fsm for BrushToolFsmState {
|
||||
else {
|
||||
new_brush_layer(document, responses);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(BrushToolMessage::DragStart);
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![BrushToolMessage::DragStart.into()],
|
||||
});
|
||||
BrushToolFsmState::Ready
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,9 +251,12 @@ impl Fsm for FreehandToolFsmState {
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses);
|
||||
responses.add(Message::StartBuffer);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
|
||||
let defered_responses = &mut VecDeque::new();
|
||||
tool_options.fill.apply_fill(layer, defered_responses);
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, defered_responses);
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: defered_responses.drain(..).collect(),
|
||||
});
|
||||
tool_data.layer = Some(layer);
|
||||
|
||||
FreehandToolFsmState::Drawing
|
||||
|
||||
@@ -1257,10 +1257,10 @@ impl PenToolData {
|
||||
self.prior_segments = None;
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
|
||||
|
||||
// This causes the following message to be run only after the next graph evaluation runs and the transforms are updated
|
||||
responses.add(Message::StartBuffer);
|
||||
// It is necessary to defer this until the transform of the layer can be accurately computed (quite hacky)
|
||||
responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport });
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![PenToolMessage::AddPointLayerPosition { layer, viewport }.into()],
|
||||
});
|
||||
}
|
||||
|
||||
/// Perform extension of an existing path
|
||||
@@ -1721,9 +1721,9 @@ impl Fsm for PenToolFsmState {
|
||||
let next_point = tool_data.next_point;
|
||||
let start = latest_point.id;
|
||||
|
||||
if let Some(layer) = layer {
|
||||
let mut vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
|
||||
if let Some(layer) = layer
|
||||
&& let Some(mut vector_data) = document.network_interface.compute_modified_vector(layer)
|
||||
{
|
||||
let closest_point = vector_data.extendable_points(preferences.vector_meshes).filter(|&id| id != start).find(|&id| {
|
||||
vector_data.point_domain.position_from_id(id).map_or(false, |pos| {
|
||||
let dist_sq = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point));
|
||||
|
||||
@@ -624,29 +624,33 @@ impl Fsm for ShapeToolFsmState {
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, document.new_layer_bounding_artboard(input), responses);
|
||||
|
||||
responses.add(Message::StartBuffer);
|
||||
let defered_responses = &mut VecDeque::new();
|
||||
|
||||
match tool_data.current_shape {
|
||||
ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Arc | ShapeType::Polygon | ShapeType::Star => {
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
defered_responses.add(GraphOperationMessage::TransformSet {
|
||||
layer,
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
});
|
||||
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.fill.apply_fill(layer, defered_responses);
|
||||
}
|
||||
ShapeType::Line => {
|
||||
tool_data.line_data.weight = tool_options.line_weight;
|
||||
tool_data.line_data.editing_layer = Some(layer);
|
||||
}
|
||||
}
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, defered_responses);
|
||||
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, defered_responses);
|
||||
tool_data.data.layer = Some(layer);
|
||||
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: defered_responses.drain(..).collect(),
|
||||
});
|
||||
|
||||
ShapeToolFsmState::Drawing(tool_data.current_shape)
|
||||
}
|
||||
(ShapeToolFsmState::Drawing(shape), ShapeToolMessage::PointerMove(modifier)) => {
|
||||
|
||||
@@ -360,8 +360,6 @@ impl Fsm for SplineToolFsmState {
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
|
||||
tool_data.current_layer = Some(layer);
|
||||
|
||||
responses.add(Message::StartBuffer);
|
||||
|
||||
SplineToolFsmState::Drawing
|
||||
}
|
||||
(SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => {
|
||||
|
||||
@@ -385,20 +385,25 @@ impl TextToolData {
|
||||
parent: document.new_layer_parent(true),
|
||||
insert_index: 0,
|
||||
});
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: self.layer,
|
||||
fill: if editing_text.color.is_some() {
|
||||
Fill::Solid(editing_text.color.unwrap().to_gamma_srgb())
|
||||
} else {
|
||||
Fill::None
|
||||
},
|
||||
});
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: self.layer,
|
||||
transform: editing_text.transform,
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![
|
||||
GraphOperationMessage::FillSet {
|
||||
layer: self.layer,
|
||||
fill: if editing_text.color.is_some() {
|
||||
Fill::Solid(editing_text.color.unwrap().to_gamma_srgb())
|
||||
} else {
|
||||
Fill::None
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
GraphOperationMessage::TransformSet {
|
||||
layer: self.layer,
|
||||
transform: editing_text.transform,
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
}
|
||||
.into(),
|
||||
],
|
||||
});
|
||||
self.editing_text = Some(editing_text);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user