mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Consolidate frontend node
This commit is contained in:
@@ -41,6 +41,7 @@ impl DispatcherMessageHandlers {
|
||||
/// The last occurrence of the message in the message queue is sufficient to ensure correct behavior.
|
||||
/// In addition, these messages do not change any state in the backend (aside from caches).
|
||||
const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::NodeGraph(NodeGraphMessageDiscriminant::SendGraph))),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel(
|
||||
PropertiesPanelMessageDiscriminant::Refresh,
|
||||
))),
|
||||
|
||||
@@ -2,13 +2,12 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
|
||||
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{
|
||||
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, Transform,
|
||||
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, FrontendXY, Transform,
|
||||
};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer};
|
||||
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::HintData;
|
||||
use glam::IVec2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::raster::color::Color;
|
||||
@@ -133,18 +132,14 @@ pub enum FrontendMessage {
|
||||
exports: Vec<Option<FrontendGraphInput>>,
|
||||
/// The primary import location.
|
||||
#[serde(rename = "importPosition")]
|
||||
import_position: IVec2,
|
||||
import_position: FrontendXY,
|
||||
/// The primary export location.
|
||||
#[serde(rename = "exportPosition")]
|
||||
export_position: IVec2,
|
||||
export_position: FrontendXY,
|
||||
/// The document network does not have an add import or export button.
|
||||
#[serde(rename = "addImportExport")]
|
||||
add_import_export: bool,
|
||||
},
|
||||
UpdateInSelectedNetwork {
|
||||
#[serde(rename = "inSelectedNetwork")]
|
||||
in_selected_network: bool,
|
||||
},
|
||||
UpdateBox {
|
||||
#[serde(rename = "box")]
|
||||
box_selection: Option<BoxSelection>,
|
||||
@@ -185,10 +180,6 @@ pub enum FrontendMessage {
|
||||
UpdateLayerWidths {
|
||||
#[serde(rename = "layerWidths")]
|
||||
layer_widths: HashMap<NodeId, u32>,
|
||||
#[serde(rename = "chainWidths")]
|
||||
chain_widths: HashMap<NodeId, u32>,
|
||||
#[serde(rename = "hasLeftInputWire")]
|
||||
has_left_input_wire: HashMap<NodeId, bool>,
|
||||
},
|
||||
UpdateDialogButtons {
|
||||
#[serde(rename = "layoutTarget")]
|
||||
@@ -284,7 +275,13 @@ pub enum FrontendMessage {
|
||||
cursor: MouseCursorIcon,
|
||||
},
|
||||
UpdateNodeGraphNodes {
|
||||
nodes: Vec<FrontendNode>,
|
||||
#[serde(rename = "nodesToRender")]
|
||||
nodes_to_render: Vec<FrontendNode>,
|
||||
#[serde(rename = "inSelectedNetwork")]
|
||||
in_selected_network: bool,
|
||||
// Displays a dashed border around the node
|
||||
#[serde(rename = "previewedNode")]
|
||||
previewed_node: Option<NodeId>,
|
||||
},
|
||||
UpdateVisibleNodes {
|
||||
nodes: Vec<NodeId>,
|
||||
@@ -298,9 +295,6 @@ pub enum FrontendMessage {
|
||||
layout_target: LayoutTarget,
|
||||
diff: Vec<WidgetDiff>,
|
||||
},
|
||||
UpdateNodeGraphSelection {
|
||||
selected: Vec<NodeId>,
|
||||
},
|
||||
UpdateNodeGraphTransform {
|
||||
transform: Transform,
|
||||
},
|
||||
|
||||
@@ -1191,7 +1191,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
}
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||
responses.add(NodeGraphMessage::UpdateInSelectedNetwork);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
DocumentMessage::SetBlendModeForSelectedLayers { blend_mode } => {
|
||||
for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) {
|
||||
|
||||
@@ -231,7 +231,5 @@ pub enum NodeGraphMessage {
|
||||
},
|
||||
UpdateActionButtons,
|
||||
UpdateGraphBarRight,
|
||||
UpdateInSelectedNetwork,
|
||||
UpdateHints,
|
||||
SendSelectedNodes,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::document_message_handler::navigation_controls;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, FrontendXY};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{
|
||||
@@ -192,7 +192,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
responses.add(NodeGraphMessage::SendSelectedNodes);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
responses.add(ArtboardToolMessage::UpdateSelectedArtboard);
|
||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
@@ -1633,21 +1633,22 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
if breadcrumb_network_path == selection_network_path && graph_view_overlay_open {
|
||||
let nodes = network_interface.collect_nodes(&self.node_graph_errors, breadcrumb_network_path);
|
||||
self.frontend_nodes = nodes.iter().map(|node| node.id).collect();
|
||||
responses.add(FrontendMessage::UpdateNodeGraphNodes { nodes });
|
||||
responses.add(NodeGraphMessage::UpdateActionButtons);
|
||||
if graph_view_overlay_open {
|
||||
let nodes_to_render = network_interface.collect_nodes(&self.node_graph_errors, breadcrumb_network_path);
|
||||
self.frontend_nodes = nodes_to_render.iter().map(|node| node.id).collect();
|
||||
let previewed_node = network_interface.previewed_node(breadcrumb_network_path);
|
||||
responses.add(FrontendMessage::UpdateNodeGraphNodes {
|
||||
nodes_to_render,
|
||||
in_selected_network: selection_network_path == breadcrumb_network_path,
|
||||
previewed_node,
|
||||
});
|
||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
||||
|
||||
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path);
|
||||
let layer_widths = network_interface.collect_layer_widths(breadcrumb_network_path);
|
||||
|
||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||
responses.add(FrontendMessage::UpdateLayerWidths {
|
||||
layer_widths,
|
||||
chain_widths,
|
||||
has_left_input_wire,
|
||||
});
|
||||
responses.add(NodeGraphMessage::SendSelectedNodes);
|
||||
responses.add(FrontendMessage::UpdateLayerWidths { layer_widths });
|
||||
responses.add(NodeGraphMessage::SendWires);
|
||||
self.update_node_graph_hints(responses);
|
||||
}
|
||||
@@ -1956,6 +1957,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
return;
|
||||
};
|
||||
|
||||
let import_position = FrontendXY {
|
||||
x: import_position.x,
|
||||
y: import_position.y,
|
||||
};
|
||||
let export_position = FrontendXY {
|
||||
x: export_position.x,
|
||||
y: export_position.y,
|
||||
};
|
||||
|
||||
// Do not show the add import or add export button in the document network;
|
||||
let add_import_export = !breadcrumb_network_path.is_empty();
|
||||
|
||||
@@ -2000,22 +2010,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
self.update_graph_bar_right(graph_fade_artwork_percentage, network_interface, breadcrumb_network_path, navigation_handler);
|
||||
self.send_node_bar_layout(responses);
|
||||
}
|
||||
NodeGraphMessage::UpdateInSelectedNetwork => responses.add(FrontendMessage::UpdateInSelectedNetwork {
|
||||
in_selected_network: selection_network_path == breadcrumb_network_path,
|
||||
}),
|
||||
NodeGraphMessage::UpdateHints => {
|
||||
self.update_node_graph_hints(responses);
|
||||
}
|
||||
NodeGraphMessage::SendSelectedNodes => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(breadcrumb_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::SendSelectedNodes");
|
||||
return;
|
||||
};
|
||||
responses.add(NodeGraphMessage::UpdateActionButtons);
|
||||
responses.add(FrontendMessage::UpdateNodeGraphSelection {
|
||||
selected: selected_nodes.selected_nodes().cloned().collect::<Vec<_>>(),
|
||||
});
|
||||
}
|
||||
}
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessageHandler");
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use glam::IVec2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::Type;
|
||||
@@ -51,6 +50,12 @@ impl FrontendGraphDataType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct FrontendXY {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct FrontendGraphInput {
|
||||
#[serde(rename = "dataType")]
|
||||
@@ -85,6 +90,7 @@ pub struct FrontendNode {
|
||||
pub is_layer: bool,
|
||||
#[serde(rename = "canBeLayer")]
|
||||
pub can_be_layer: bool,
|
||||
pub selected: bool,
|
||||
pub reference: Option<String>,
|
||||
#[serde(rename = "displayName")]
|
||||
pub display_name: String,
|
||||
@@ -96,11 +102,15 @@ pub struct FrontendNode {
|
||||
pub primary_output: Option<FrontendGraphOutput>,
|
||||
#[serde(rename = "exposedOutputs")]
|
||||
pub exposed_outputs: Vec<FrontendGraphOutput>,
|
||||
#[serde(rename = "chainWidth")]
|
||||
pub chain_width: u32,
|
||||
#[serde(rename = "layerHasLeftBorderGap")]
|
||||
pub layer_has_left_border_gap: bool,
|
||||
#[serde(rename = "primaryOutputConnectedToLayer")]
|
||||
pub primary_output_connected_to_layer: bool,
|
||||
#[serde(rename = "primaryInputConnectedToLayer")]
|
||||
pub primary_input_connected_to_layer: bool,
|
||||
pub position: IVec2,
|
||||
pub position: FrontendXY,
|
||||
pub visible: bool,
|
||||
pub locked: bool,
|
||||
pub previewed: bool,
|
||||
|
||||
@@ -2853,10 +2853,11 @@ impl NodeNetworkInterface {
|
||||
bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport)
|
||||
}
|
||||
|
||||
pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> (HashMap<NodeId, u32>, HashMap<NodeId, u32>, HashMap<NodeId, bool>) {
|
||||
// TODO: Remove and get layer click targets from render output
|
||||
pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> HashMap<NodeId, u32> {
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in collect_layer_widths");
|
||||
return (HashMap::new(), HashMap::new(), HashMap::new());
|
||||
return HashMap::new();
|
||||
};
|
||||
let nodes = network_metadata
|
||||
.persistent_metadata
|
||||
@@ -2868,13 +2869,8 @@ impl NodeNetworkInterface {
|
||||
.iter()
|
||||
.filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width)))
|
||||
.collect::<HashMap<NodeId, u32>>();
|
||||
let chain_widths = nodes.iter().map(|node_id| (*node_id, self.chain_width(node_id, network_path))).collect::<HashMap<NodeId, u32>>();
|
||||
let has_left_input_wire = nodes
|
||||
.iter()
|
||||
.map(|node_id| (*node_id, self.layer_has_left_border_gap(node_id, network_path)))
|
||||
.collect::<HashMap<NodeId, bool>>();
|
||||
|
||||
(layer_widths, chain_widths, has_left_input_wire)
|
||||
layer_widths
|
||||
}
|
||||
|
||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||
|
||||
@@ -5,7 +5,7 @@ use graphene_std::uuid::NodeId;
|
||||
use crate::{
|
||||
consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP},
|
||||
messages::portfolio::document::{
|
||||
node_graph::utility_types::{FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput, FrontendNode},
|
||||
node_graph::utility_types::{FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendXY},
|
||||
utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, OutputConnector},
|
||||
},
|
||||
};
|
||||
@@ -17,6 +17,7 @@ impl NodeNetworkInterface {
|
||||
log::error!("Could not get nested network when collecting nodes");
|
||||
return Vec::new();
|
||||
};
|
||||
let selected_nodes = self.selected_nodes_in_nested_network(network_path).unwrap_or_default();
|
||||
let mut nodes = Vec::new();
|
||||
for (node_id, visible) in network.nodes.iter().map(|(node_id, node)| (*node_id, node.visible)).collect::<Vec<_>>() {
|
||||
let node_id_path = [network_path, &[node_id]].concat();
|
||||
@@ -37,19 +38,12 @@ impl NodeNetworkInterface {
|
||||
let exposed_outputs = (1..self.number_of_outputs(&node_id, network_path))
|
||||
.filter_map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path))
|
||||
.collect();
|
||||
let (primary_output_connected_to_layer, primary_input_connected_to_layer) = if self.is_layer(&node_id, network_path) {
|
||||
(
|
||||
self.primary_output_connected_to_layer(&node_id, network_path),
|
||||
self.primary_input_connected_to_layer(&node_id, network_path),
|
||||
)
|
||||
} else {
|
||||
(false, false)
|
||||
};
|
||||
|
||||
let Some(position) = self.position(&node_id, network_path) else {
|
||||
log::error!("Could not get position for node: {node_id}");
|
||||
continue;
|
||||
};
|
||||
let position = FrontendXY { x: position.x, y: position.y };
|
||||
let previewed = self.previewed_node(network_path) == Some(node_id);
|
||||
|
||||
let locked = self.is_locked(&node_id, network_path);
|
||||
@@ -70,19 +64,24 @@ impl NodeNetworkInterface {
|
||||
id: node_id,
|
||||
is_layer: self.node_metadata(&node_id, network_path).is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
||||
can_be_layer: self.is_eligible_to_be_layer(&node_id, network_path),
|
||||
selected: selected_nodes.0.contains(&node_id),
|
||||
reference: self.reference(&node_id, network_path).cloned().unwrap_or_default(),
|
||||
display_name: self.display_name(&node_id, network_path),
|
||||
previewed,
|
||||
visible,
|
||||
errors,
|
||||
|
||||
primary_input,
|
||||
exposed_inputs,
|
||||
primary_output,
|
||||
exposed_outputs,
|
||||
primary_output_connected_to_layer,
|
||||
primary_input_connected_to_layer,
|
||||
position,
|
||||
previewed,
|
||||
visible,
|
||||
|
||||
locked,
|
||||
errors,
|
||||
chain_width: self.chain_width(&node_id, network_path),
|
||||
layer_has_left_border_gap: self.layer_has_left_border_gap(&node_id, network_path),
|
||||
primary_input_connected_to_layer: self.primary_output_connected_to_layer(&node_id, network_path),
|
||||
primary_output_connected_to_layer: self.primary_input_connected_to_layer(&node_id, network_path),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,9 +258,12 @@ impl NodeNetworkInterface {
|
||||
|
||||
/// Checks if a layer should display a gap in its left border
|
||||
pub fn layer_has_left_border_gap(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||
self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow)
|
||||
.skip(1)
|
||||
.any(|node_id| !self.is_chain(&node_id, network_path))
|
||||
self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow).skip(1).any(|node_id| {
|
||||
!self.is_chain(&node_id, network_path)
|
||||
|| self
|
||||
.upstream_output_connector(&InputConnector::node(node_id, 0), network_path)
|
||||
.is_some_and(|output_connector| matches!(output_connector, OutputConnector::Import(_)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the node which should have a dashed border drawn around it
|
||||
|
||||
Reference in New Issue
Block a user