mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 07:18:12 +08:00
Add icons
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::messages::portfolio::document::utility_types::wires::WirePathInProgre
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::HintData;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::node_graph_overlay::types::{FrontendExports, FrontendImport, FrontendNodeToRender, FrontendXY, NodeGraphTransform};
|
||||
use graphene_std::node_graph_overlay::types::{FrontendExports, FrontendImport, FrontendXY, NodeGraphTransform};
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::raster::color::Color;
|
||||
use graphene_std::text::{Font, TextAlign};
|
||||
@@ -270,17 +270,10 @@ pub enum FrontendMessage {
|
||||
cursor: MouseCursorIcon,
|
||||
},
|
||||
RequestNativeNodeGraphRender,
|
||||
UpdateShouldRenderSvelteNodes {
|
||||
#[serde(rename = "shouldRenderSvelteNodes")]
|
||||
should_render_svelte_nodes: bool,
|
||||
},
|
||||
UpdateNativeNodeGraphSVG {
|
||||
#[serde(rename = "svgString")]
|
||||
svg_string: String,
|
||||
},
|
||||
UpdateVisibleNodes {
|
||||
nodes: Vec<NodeId>,
|
||||
},
|
||||
UpdateNodeGraphControlBarLayout {
|
||||
#[serde(rename = "layoutTarget")]
|
||||
layout_target: LayoutTarget,
|
||||
|
||||
@@ -34,7 +34,6 @@ impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext> f
|
||||
self.viewport_bounds = bounds;
|
||||
|
||||
responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO });
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![
|
||||
|
||||
@@ -476,7 +476,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
self.selection_network_path.clone_from(&self.breadcrumb_network_path);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
DocumentMessage::Escape => {
|
||||
if self.node_graph_handler.drag_start.is_some() {
|
||||
@@ -505,7 +504,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
}
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
responses.add(DocumentMessage::PTZUpdate);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
DocumentMessage::FlipSelectedLayers { flip_axis } => {
|
||||
let scale = match flip_axis {
|
||||
@@ -568,7 +566,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
responses.add(ToolMessage::DeactivateTools);
|
||||
responses.add(OverlaysMessage::Draw); // Clear the overlays
|
||||
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
responses.add(NodeGraphMessage::UpdateGraphBarRight);
|
||||
responses.add(NodeGraphMessage::UpdateHints);
|
||||
} else {
|
||||
@@ -1489,10 +1486,8 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
|
||||
responses.add(DocumentMessage::RenderRulers);
|
||||
responses.add(DocumentMessage::RenderScrollbars);
|
||||
responses.add(NodeGraphMessage::UpdateEdges);
|
||||
responses.add(NodeGraphMessage::UpdateBoxSelection);
|
||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||
|
||||
responses.add(FrontendMessage::UpdateNodeGraphTransform {
|
||||
transform: NodeGraphTransform {
|
||||
scale: transform.matrix2.x_axis.x,
|
||||
@@ -1942,9 +1937,6 @@ impl DocumentMessageHandler {
|
||||
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::SetGridAlignedEdges);
|
||||
|
||||
Some(previous_network)
|
||||
}
|
||||
pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
|
||||
@@ -178,7 +178,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
NavigationMessage::CanvasPanMouseWheel { use_y_as_x } => {
|
||||
let delta = if use_y_as_x { (-ipp.mouse.scroll_delta.y, 0.).into() } else { -ipp.mouse.scroll_delta.as_dvec2() } * VIEWPORT_SCROLL_RATE;
|
||||
responses.add(NavigationMessage::CanvasPan { delta });
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
NavigationMessage::CanvasTiltResetAndZoomTo100Percent => {
|
||||
let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else {
|
||||
@@ -193,7 +192,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
}
|
||||
responses.add(DocumentMessage::PTZUpdate);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
NavigationMessage::CanvasTiltSet { angle_radians } => {
|
||||
let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else {
|
||||
@@ -272,7 +270,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
}
|
||||
responses.add(DocumentMessage::PTZUpdate);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
NavigationMessage::CanvasFlip => {
|
||||
if graph_view_overlay_open {
|
||||
@@ -320,7 +317,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
} else {
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
}
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
// Reset the navigation operation now that it's done
|
||||
self.navigation_operation = NavigationOperation::None;
|
||||
|
||||
@@ -382,7 +378,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
}
|
||||
responses.add(DocumentMessage::PTZUpdate);
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
// Fully zooms in on the selected
|
||||
NavigationMessage::FitViewportToSelection => {
|
||||
@@ -476,7 +471,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
||||
};
|
||||
|
||||
responses.add(NavigationMessage::CanvasZoomSet { zoom_factor: ptz.zoom() });
|
||||
responses.add(NodeGraphMessage::SetGridAlignedEdges);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,7 @@ pub enum NodeGraphMessage {
|
||||
},
|
||||
SendClickTargets,
|
||||
EndSendClickTargets,
|
||||
UpdateVisibleNodes,
|
||||
SendGraph,
|
||||
SetGridAlignedEdges,
|
||||
SetInputValue {
|
||||
node_id: NodeId,
|
||||
input_index: usize,
|
||||
@@ -183,7 +181,6 @@ pub enum NodeGraphMessage {
|
||||
TogglePreviewImpl {
|
||||
node_id: NodeId,
|
||||
},
|
||||
ToggleNativeNodeGraphRender,
|
||||
SetImportExportName {
|
||||
name: String,
|
||||
index: ImportOrExport,
|
||||
@@ -217,7 +214,6 @@ pub enum NodeGraphMessage {
|
||||
SetLockedOrVisibilitySideEffects {
|
||||
node_ids: Vec<NodeId>,
|
||||
},
|
||||
UpdateEdges,
|
||||
UpdateBoxSelection,
|
||||
UpdateImportsExports,
|
||||
UpdateLayerPanel,
|
||||
|
||||
@@ -92,8 +92,6 @@ pub struct NodeGraphMessageHandler {
|
||||
reordering_export: Option<usize>,
|
||||
/// The end index of the moved connector
|
||||
end_index: Option<usize>,
|
||||
/// Used to keep track of what nodes are sent to the front end so that only visible ones are sent to the frontend
|
||||
frontend_nodes: Vec<NodeId>,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@@ -1590,61 +1588,16 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)),
|
||||
}),
|
||||
NodeGraphMessage::EndSendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { click_targets: None }),
|
||||
NodeGraphMessage::UpdateVisibleNodes => {
|
||||
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let viewport_bbox = ipp.document_bounds();
|
||||
let document_bbox: [DVec2; 2] = viewport_bbox.map(|p| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(p));
|
||||
|
||||
let mut nodes = Vec::new();
|
||||
for node_id in &self.frontend_nodes {
|
||||
let Some(node_bbox) = network_interface.node_bounding_box(node_id, breadcrumb_network_path) else {
|
||||
log::error!("Could not get bbox for node: {node_id:?}");
|
||||
continue;
|
||||
};
|
||||
|
||||
if node_bbox[1].x >= document_bbox[0].x && node_bbox[0].x <= document_bbox[1].x && node_bbox[1].y >= document_bbox[0].y && node_bbox[0].y <= document_bbox[1].y {
|
||||
nodes.push(*node_id);
|
||||
}
|
||||
for error in &self.node_graph_errors {
|
||||
if error.node_path.contains(node_id) {
|
||||
nodes.push(*node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
responses.add(FrontendMessage::UpdateVisibleNodes { nodes });
|
||||
}
|
||||
NodeGraphMessage::SendGraph => {
|
||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
responses.add(NodeGraphMessage::UpdateActionButtons);
|
||||
|
||||
if !self.should_render_svelte_nodes {
|
||||
// Generate and render node graph overlay network
|
||||
} else {
|
||||
let nodes_to_render = network_interface.collect_nodes(&self.node_graph_errors, preferences.graph_wire_style, breadcrumb_network_path);
|
||||
self.frontend_nodes = nodes_to_render.iter().map(|node| node.metadata.node_id).collect();
|
||||
let previewed_node = network_interface.previewed_node(breadcrumb_network_path);
|
||||
}
|
||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
||||
|
||||
let layer_widths = network_interface.collect_layer_widths(breadcrumb_network_path);
|
||||
|
||||
responses.add(FrontendMessage::RequestNativeNodeGraphRender);
|
||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||
responses.add(FrontendMessage::UpdateLayerWidths { layer_widths });
|
||||
self.update_node_graph_hints(responses);
|
||||
}
|
||||
NodeGraphMessage::SetGridAlignedEdges => {
|
||||
if graph_view_overlay_open {
|
||||
network_interface.set_grid_aligned_edges(DVec2::new(ipp.viewport_bounds.bottom_right.x - ipp.viewport_bounds.top_left.x, 0.), breadcrumb_network_path);
|
||||
// Send the new edges to the frontend
|
||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||
}
|
||||
}
|
||||
NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
|
||||
let input = NodeInput::value(value, false);
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
@@ -1780,14 +1733,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
NodeGraphMessage::TogglePreviewImpl { node_id } => {
|
||||
network_interface.toggle_preview(node_id, selection_network_path);
|
||||
}
|
||||
NodeGraphMessage::ToggleNativeNodeGraphRender => {
|
||||
self.should_render_svelte_nodes = !self.should_render_svelte_nodes;
|
||||
responses.add(FrontendMessage::UpdateShouldRenderSvelteNodes {
|
||||
should_render_svelte_nodes: self.should_render_svelte_nodes,
|
||||
});
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
}
|
||||
NodeGraphMessage::ToggleSelectedLocked => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked");
|
||||
@@ -1957,7 +1902,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
// Do not show the add import or add export button in the document network;
|
||||
let add_import_export = !breadcrumb_network_path.is_empty();
|
||||
|
||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
||||
responses.add(FrontendMessage::UpdateImportsExports {
|
||||
imports,
|
||||
exports,
|
||||
@@ -1970,9 +1914,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
NodeGraphMessage::UpdateLayerPanel => {
|
||||
Self::update_layer_panel(network_interface, selection_network_path, collapsed, layers_panel_open, responses);
|
||||
}
|
||||
NodeGraphMessage::UpdateEdges => {
|
||||
// Update the import/export UI edges whenever the PTZ changes or the bounding box of all nodes changes
|
||||
}
|
||||
NodeGraphMessage::UpdateNewNodeGraph => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::UpdateNewNodeGraph");
|
||||
@@ -2618,7 +2559,6 @@ impl Default for NodeGraphMessageHandler {
|
||||
reordering_export: None,
|
||||
reordering_import: None,
|
||||
end_index: None,
|
||||
frontend_nodes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +262,6 @@ pub struct FrontendClickTargets {
|
||||
pub icon_click_targets: Vec<String>,
|
||||
#[serde(rename = "allNodesBoundingBox")]
|
||||
pub all_nodes_bounding_box: String,
|
||||
#[serde(rename = "importExportsBoundingBox")]
|
||||
pub import_exports_bounding_box: String,
|
||||
#[serde(rename = "modifyImportExport")]
|
||||
pub modify_import_export: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations};
|
||||
use super::misc::PTZ;
|
||||
use super::nodes::SelectedNodes;
|
||||
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};
|
||||
use crate::consts::GRID_SIZE;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type};
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets};
|
||||
@@ -1620,68 +1620,6 @@ impl NodeNetworkInterface {
|
||||
network_metadata.transient_metadata.modify_import_export.unload();
|
||||
}
|
||||
|
||||
pub fn rounded_network_edge_distance(&mut self, network_path: &[NodeId]) -> Option<&NetworkEdgeDistance> {
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in rounded_network_edge_distance");
|
||||
return None;
|
||||
};
|
||||
if !network_metadata.transient_metadata.rounded_network_edge_distance.is_loaded() {
|
||||
self.load_rounded_network_edge_distance(network_path);
|
||||
}
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in rounded_network_edge_distance");
|
||||
return None;
|
||||
};
|
||||
let TransientMetadata::Loaded(rounded_network_edge_distance) = &network_metadata.transient_metadata.rounded_network_edge_distance else {
|
||||
log::error!("could not load import rounded_network_edge_distance");
|
||||
return None;
|
||||
};
|
||||
Some(rounded_network_edge_distance)
|
||||
}
|
||||
|
||||
fn load_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) {
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get nested network in set_grid_aligned_edges");
|
||||
return;
|
||||
};
|
||||
// When setting the edges to be grid aligned, update the pixel offset to ensure the next pan starts from the snapped import/export position
|
||||
let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport;
|
||||
// TODO: Eventually replace node graph top right with the footprint when trying to get the network edge distance
|
||||
let node_graph_top_right = network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right;
|
||||
let target_exports_distance = node_graph_to_viewport.inverse().transform_point2(DVec2::new(
|
||||
node_graph_top_right.x - EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP as f64,
|
||||
node_graph_top_right.y + EXPORTS_TO_TOP_EDGE_PIXEL_GAP as f64,
|
||||
));
|
||||
|
||||
let target_imports_distance = node_graph_to_viewport
|
||||
.inverse()
|
||||
.transform_point2(DVec2::new(IMPORTS_TO_LEFT_EDGE_PIXEL_GAP as f64, IMPORTS_TO_TOP_EDGE_PIXEL_GAP as f64));
|
||||
|
||||
let rounded_exports_distance = DVec2::new((target_exports_distance.x / 24. + 0.5).floor() * 24., (target_exports_distance.y / 24. + 0.5).floor() * 24.);
|
||||
let rounded_imports_distance = DVec2::new((target_imports_distance.x / 24. + 0.5).floor() * 24., (target_imports_distance.y / 24. + 0.5).floor() * 24.);
|
||||
|
||||
let rounded_viewport_exports_distance = node_graph_to_viewport.transform_point2(rounded_exports_distance);
|
||||
let rounded_viewport_imports_distance = node_graph_to_viewport.transform_point2(rounded_imports_distance);
|
||||
|
||||
let network_edge_distance = NetworkEdgeDistance {
|
||||
exports_to_edge_distance: rounded_viewport_exports_distance,
|
||||
imports_to_edge_distance: rounded_viewport_imports_distance,
|
||||
};
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get current network in load_export_ports");
|
||||
return;
|
||||
};
|
||||
network_metadata.transient_metadata.rounded_network_edge_distance = TransientMetadata::Loaded(network_edge_distance);
|
||||
}
|
||||
|
||||
fn unload_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) {
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in unload_export_ports");
|
||||
return;
|
||||
};
|
||||
network_metadata.transient_metadata.rounded_network_edge_distance.unload();
|
||||
}
|
||||
|
||||
fn owned_nodes(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&HashSet<NodeId>> {
|
||||
let layer_node = self.node_metadata(node_id, network_path)?;
|
||||
let NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { owned_nodes, .. }) = &layer_node.persistent_metadata.node_type_metadata else {
|
||||
@@ -2299,33 +2237,6 @@ impl NodeNetworkInterface {
|
||||
let rect = Subpath::<PointId>::new_rect(bounds[0], bounds[1]);
|
||||
let all_nodes_bounding_box = rect.to_bezpath().to_svg();
|
||||
|
||||
let Some(rounded_network_edge_distance) = self.rounded_network_edge_distance(network_path).cloned() else {
|
||||
log::error!("Could not get rounded_network_edge_distance in collect_frontend_click_targets");
|
||||
return FrontendClickTargets::default();
|
||||
};
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in collect_frontend_click_targets");
|
||||
return FrontendClickTargets::default();
|
||||
};
|
||||
let import_exports_viewport_top_left = rounded_network_edge_distance.imports_to_edge_distance;
|
||||
let import_exports_viewport_bottom_right = rounded_network_edge_distance.exports_to_edge_distance;
|
||||
|
||||
let node_graph_top_left = network_metadata
|
||||
.persistent_metadata
|
||||
.navigation_metadata
|
||||
.node_graph_to_viewport
|
||||
.inverse()
|
||||
.transform_point2(import_exports_viewport_top_left);
|
||||
let node_graph_bottom_right = network_metadata
|
||||
.persistent_metadata
|
||||
.navigation_metadata
|
||||
.node_graph_to_viewport
|
||||
.inverse()
|
||||
.transform_point2(import_exports_viewport_bottom_right);
|
||||
|
||||
let import_exports_target = Subpath::<PointId>::new_rect(node_graph_top_left, node_graph_bottom_right);
|
||||
let import_exports_bounding_box = import_exports_target.to_bezpath().to_svg();
|
||||
|
||||
let mut modify_import_export = Vec::new();
|
||||
if let Some(modify_import_export_click_targets) = self.modify_import_export(network_path) {
|
||||
for click_target in modify_import_export_click_targets
|
||||
@@ -2344,7 +2255,6 @@ impl NodeNetworkInterface {
|
||||
connector_click_targets,
|
||||
icon_click_targets,
|
||||
all_nodes_bounding_box,
|
||||
import_exports_bounding_box,
|
||||
modify_import_export,
|
||||
}
|
||||
}
|
||||
@@ -2591,26 +2501,6 @@ impl NodeNetworkInterface {
|
||||
bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport)
|
||||
}
|
||||
|
||||
// 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();
|
||||
};
|
||||
let nodes = network_metadata
|
||||
.persistent_metadata
|
||||
.node_metadata
|
||||
.iter()
|
||||
.filter_map(|(node_id, _)| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None })
|
||||
.collect::<Vec<_>>();
|
||||
let layer_widths = nodes
|
||||
.iter()
|
||||
.filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width)))
|
||||
.collect::<HashMap<NodeId, u32>>();
|
||||
|
||||
layer_widths
|
||||
}
|
||||
|
||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||
|
||||
@@ -2785,18 +2675,6 @@ impl NodeNetworkInterface {
|
||||
self.unload_modify_import_export(network_path);
|
||||
}
|
||||
|
||||
// This should be run whenever the pan ends, a zoom occurs, or the network is opened
|
||||
pub fn set_grid_aligned_edges(&mut self, node_graph_top_right: DVec2, network_path: &[NodeId]) {
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in set_grid_aligned_edges");
|
||||
return;
|
||||
};
|
||||
network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right = node_graph_top_right;
|
||||
self.unload_rounded_network_edge_distance(network_path);
|
||||
self.unload_import_export_ports(network_path);
|
||||
self.unload_modify_import_export(network_path);
|
||||
}
|
||||
|
||||
pub fn vector_modify(&mut self, node_id: &NodeId, modification_type: VectorModificationType) {
|
||||
let Some(node) = self.network_mut(&[]).unwrap().nodes.get_mut(node_id) else {
|
||||
log::error!("Could not get node in vector_modification");
|
||||
@@ -5581,8 +5459,6 @@ pub struct NodeNetworkTransientMetadata {
|
||||
pub import_export_ports: TransientMetadata<Ports>,
|
||||
/// Click targets for adding, removing, and moving import/export ports
|
||||
pub modify_import_export: TransientMetadata<ModifyImportExportClickTarget>,
|
||||
// Distance to the edges of the network, where the import/export ports are displayed. Rounded to nearest grid space when the panning ends.
|
||||
pub rounded_network_edge_distance: TransientMetadata<NetworkEdgeDistance>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
+13
-5
@@ -90,15 +90,23 @@ impl NodeNetworkInterface {
|
||||
|
||||
let position = FrontendXY { x: position.x, y: position.y };
|
||||
|
||||
let inputs = (0..self.number_of_inputs(&node_id, network_path))
|
||||
.map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path))
|
||||
let primary_input = self.frontend_input_from_connector(&InputConnector::node(node_id, 0), network_path);
|
||||
let secondary_inputs = (1..self.number_of_inputs(&node_id, network_path))
|
||||
.filter_map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path))
|
||||
.collect();
|
||||
|
||||
let outputs = (0..self.number_of_outputs(&node_id, network_path))
|
||||
.map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path))
|
||||
let primary_output = self.frontend_output_from_connector(&OutputConnector::node(node_id, 0), network_path);
|
||||
let secondary_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 node = Some(FrontendNode { position, inputs, outputs });
|
||||
let node = Some(FrontendNode {
|
||||
position,
|
||||
primary_input,
|
||||
primary_output,
|
||||
secondary_inputs,
|
||||
secondary_outputs,
|
||||
});
|
||||
|
||||
FrontendNodeOrLayer { node, layer: None }
|
||||
}
|
||||
|
||||
@@ -54,8 +54,19 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical
|
||||
let horizontal_curve = horizontal_curve_amount * curve_length;
|
||||
let vertical_curve = vertical_curve_amount * curve_length;
|
||||
|
||||
let wire_start = if vertical_in && vertical_out { output_position + DVec2::new(0., -4.) } else { output_position };
|
||||
let wire_end = if vertical_in && vertical_in {
|
||||
DVec2::new(input_position.x, input_position.y) + DVec2::new(0., 4.)
|
||||
} else {
|
||||
DVec2::new(input_position.x, input_position.y)
|
||||
};
|
||||
|
||||
if vertical_in && vertical_in && wire_end.y + 5. > wire_start.y {
|
||||
return BezPath::new();
|
||||
}
|
||||
|
||||
let locations = [
|
||||
output_position,
|
||||
wire_start,
|
||||
DVec2::new(
|
||||
if vertical_out { output_position.x } else { output_position.x + horizontal_curve },
|
||||
if vertical_out { output_position.y - vertical_curve } else { output_position.y },
|
||||
@@ -64,7 +75,7 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical
|
||||
if vertical_in { input_position.x } else { input_position.x - horizontal_curve },
|
||||
if vertical_in { input_position.y + vertical_curve } else { input_position.y },
|
||||
),
|
||||
DVec2::new(input_position.x, input_position.y),
|
||||
wire_end,
|
||||
];
|
||||
|
||||
let smoothing = 0.5;
|
||||
|
||||
@@ -18,7 +18,6 @@ pub struct MenuBarMessageHandler {
|
||||
pub has_selection_history: (bool, bool),
|
||||
pub message_logging_verbosity: MessageLoggingVerbosity,
|
||||
pub reset_node_definitions_on_open: bool,
|
||||
pub should_render_svelte_nodes: bool,
|
||||
pub make_path_editable_is_allowed: bool,
|
||||
pub data_panel_open: bool,
|
||||
pub layers_panel_open: bool,
|
||||
@@ -49,7 +48,6 @@ impl LayoutHolder for MenuBarMessageHandler {
|
||||
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
|
||||
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
|
||||
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
|
||||
let should_render_svelte_nodes = self.should_render_svelte_nodes;
|
||||
let make_path_editable_is_allowed = self.make_path_editable_is_allowed;
|
||||
|
||||
let menu_bar_entries = vec![
|
||||
@@ -698,12 +696,6 @@ impl LayoutHolder for MenuBarMessageHandler {
|
||||
action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen.into()),
|
||||
..MenuBarEntry::default()
|
||||
}],
|
||||
vec![MenuBarEntry {
|
||||
label: "HTML Node Graph Render".into(),
|
||||
icon: Some(if should_render_svelte_nodes { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()),
|
||||
action: MenuBarEntry::create_action(|_| NodeGraphMessage::ToggleNativeNodeGraphRender.into()),
|
||||
..MenuBarEntry::default()
|
||||
}],
|
||||
vec![
|
||||
MenuBarEntry {
|
||||
label: "Print Trace Logs".into(),
|
||||
|
||||
@@ -587,7 +587,6 @@
|
||||
thumbPosition={scrollbarPos.x}
|
||||
on:trackShift={({ detail }) => editor.handle.panCanvasByFraction(detail, 0)}
|
||||
on:thumbPosition={({ detail }) => panCanvasX(detail)}
|
||||
on:thumbDragEnd={() => editor.handle.setGridAlignedEdges()}
|
||||
on:thumbDragStart={() => editor.handle.panCanvasAbortPrepare(true)}
|
||||
on:thumbDragAbort={() => editor.handle.panCanvasAbort(true)}
|
||||
/>
|
||||
|
||||
@@ -617,7 +617,6 @@
|
||||
<path class="visibility" d={pathString} />
|
||||
{/each}
|
||||
<path class="all-nodes-bounding-box" d={$nodeGraph.clickTargets.allNodesBoundingBox} />
|
||||
<path class="all-nodes-bounding-box" d={$nodeGraph.clickTargets.importExportsBoundingBox} />
|
||||
{#each $nodeGraph.clickTargets.modifyImportExport as pathString}
|
||||
<path class="modify-import-export" d={pathString} />
|
||||
{/each}
|
||||
|
||||
@@ -35,7 +35,6 @@ export class FrontendClickTargets {
|
||||
readonly connectorClickTargets!: string[];
|
||||
readonly iconClickTargets!: string[];
|
||||
readonly allNodesBoundingBox!: string;
|
||||
readonly importExportsBoundingBox!: string;
|
||||
readonly modifyImportExport!: string[];
|
||||
}
|
||||
|
||||
@@ -106,30 +105,10 @@ export class UpdateLayerWidths extends JsMessage {
|
||||
readonly layerWidths!: Map<bigint, number>;
|
||||
}
|
||||
|
||||
export class UpdateNodeGraphSvelteRender extends JsMessage {
|
||||
readonly nodesToRender!: FrontendNodeToRender[];
|
||||
|
||||
readonly open!: boolean;
|
||||
|
||||
readonly opacity!: number;
|
||||
|
||||
readonly inSelectedNetwork!: boolean;
|
||||
|
||||
readonly previewedNode!: bigint | undefined;
|
||||
}
|
||||
|
||||
export class UpdateShouldRenderSvelteNodes extends JsMessage {
|
||||
readonly shouldRenderSvelteNodes!: boolean;
|
||||
}
|
||||
|
||||
export class UpdateNativeNodeGraphSVG extends JsMessage {
|
||||
readonly svgString!: string;
|
||||
}
|
||||
|
||||
export class UpdateVisibleNodes extends JsMessage {
|
||||
readonly nodes!: bigint[];
|
||||
}
|
||||
|
||||
export class UpdateNodeGraphTransform extends JsMessage {
|
||||
readonly transform!: NodeGraphTransform;
|
||||
}
|
||||
@@ -1762,9 +1741,9 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||
UpdateMenuBarLayout,
|
||||
UpdateMouseCursor,
|
||||
UpdateNodeGraphControlBarLayout,
|
||||
UpdateNodeGraphRender,
|
||||
UpdateNodeGraphSelectionBox,
|
||||
UpdateNativeNodeGraphSVG,
|
||||
UpdateNodeGraphTransform,
|
||||
UpdateNodeGraphSelectionBox,
|
||||
UpdateNodeThumbnail,
|
||||
UpdateOpenDocumentsList,
|
||||
UpdatePlatform,
|
||||
@@ -1776,7 +1755,6 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||
UpdateToolOptionsLayout,
|
||||
UpdateToolShelfLayout,
|
||||
UpdateViewportHolePunch,
|
||||
UpdateVisibleNodes,
|
||||
UpdateWirePathInProgress,
|
||||
UpdateWorkingColorsLayout,
|
||||
} as const;
|
||||
|
||||
@@ -15,14 +15,11 @@ import {
|
||||
UpdateExportReorderIndex,
|
||||
UpdateImportsExports,
|
||||
UpdateLayerWidths,
|
||||
UpdateNodeGraphSvelteRender,
|
||||
UpdateShouldRenderSvelteNodes,
|
||||
UpdateNativeNodeGraphSVG,
|
||||
UpdateVisibleNodes,
|
||||
UpdateNodeGraphTransform,
|
||||
UpdateNodeThumbnail,
|
||||
UpdateWirePathInProgress,
|
||||
UpdateNodeGraphSelectionBox,
|
||||
UpdateNodeGraphTransform,
|
||||
} from "@graphite/messages";
|
||||
|
||||
export function createNodeGraphState(editor: Editor) {
|
||||
@@ -46,11 +43,6 @@ export function createNodeGraphState(editor: Editor) {
|
||||
inSelectedNetwork: true,
|
||||
previewedNode: undefined as bigint | undefined,
|
||||
|
||||
// TODO: Remove these fields
|
||||
visibleNodes: new Set<bigint>(),
|
||||
layerWidths: new Map<bigint, number>(),
|
||||
shouldRenderSvelteNodes: false,
|
||||
|
||||
// Data that will be passed in the context
|
||||
thumbnails: new Map<bigint, string>(),
|
||||
transform: { scale: 1, x: 0, y: 0 },
|
||||
@@ -107,42 +99,12 @@ export function createNodeGraphState(editor: Editor) {
|
||||
});
|
||||
});
|
||||
|
||||
editor.subscriptions.subscribeJsMessage(UpdateLayerWidths, (updateLayerWidths) => {
|
||||
update((state) => {
|
||||
state.layerWidths = updateLayerWidths.layerWidths;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphSvelteRender, (updateNodeGraphSvelteRender) => {
|
||||
update((state) => {
|
||||
state.nodesToRender.clear();
|
||||
updateNodeGraphSvelteRender.nodesToRender.forEach((node) => {
|
||||
state.nodesToRender.set(node.metadata.nodeId, node);
|
||||
});
|
||||
state.opacity = updateNodeGraphSvelteRender.opacity;
|
||||
state.inSelectedNetwork = updateNodeGraphSvelteRender.inSelectedNetwork;
|
||||
state.previewedNode = updateNodeGraphSvelteRender.previewedNode;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateShouldRenderSvelteNodes, (UpdateShouldRenderSvelteNodes) => {
|
||||
update((state) => {
|
||||
state.shouldRenderSvelteNodes = UpdateShouldRenderSvelteNodes.shouldRenderSvelteNodes;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateNativeNodeGraphSVG, (updateNativeNodeGraphRender) => {
|
||||
update((state) => {
|
||||
state.nativeNodeGraphSVGString = updateNativeNodeGraphRender.svgString;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateVisibleNodes, (updateVisibleNodes) => {
|
||||
update((state) => {
|
||||
state.visibleNodes = new Set<bigint>(updateVisibleNodes.nodes);
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphTransform, (updateNodeGraphTransform) => {
|
||||
update((state) => {
|
||||
state.transform = updateNodeGraphTransform.transform;
|
||||
@@ -155,12 +117,6 @@ export function createNodeGraphState(editor: Editor) {
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateWirePathInProgress, (updateWirePathInProgress) => {
|
||||
update((state) => {
|
||||
state.wirePathInProgress = updateWirePathInProgress.wirePathInProgress;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
@@ -785,13 +785,6 @@ impl EditorHandle {
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Snaps the import/export edges to a grid space when the scroll bar is released
|
||||
#[wasm_bindgen(js_name = setGridAlignedEdges)]
|
||||
pub fn set_grid_aligned_edges(&self) {
|
||||
let message = NodeGraphMessage::SetGridAlignedEdges;
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Merge the selected nodes into a subnetwork
|
||||
#[wasm_bindgen(js_name = mergeSelectedNodes)]
|
||||
pub fn merge_nodes(&self) {
|
||||
|
||||
@@ -21,12 +21,14 @@ pub mod ui_context;
|
||||
#[node_macro::node(skip_impl)]
|
||||
pub fn generate_nodes(_: impl Ctx, mut node_graph_overlay_data: NodeGraphOverlayData) -> Table<Graphic> {
|
||||
let mut nodes_and_wires = Table::new();
|
||||
let layers = draw_layers(&node_graph_overlay_data.nodes_to_render);
|
||||
let (layers, side_ports) = draw_layers(&node_graph_overlay_data.nodes_to_render);
|
||||
nodes_and_wires.extend(layers);
|
||||
|
||||
let wires = draw_wires(&mut node_graph_overlay_data.nodes_to_render);
|
||||
nodes_and_wires.extend(wires);
|
||||
|
||||
nodes_and_wires.extend(side_ports);
|
||||
|
||||
let nodes = draw_nodes(&node_graph_overlay_data.nodes_to_render);
|
||||
nodes_and_wires.extend(nodes);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core_shaders::color::{AlphaMut, Color};
|
||||
use kurbo::{BezPath, Rect, RoundedRect, Shape};
|
||||
use kurbo::{BezPath, Circle, Rect, RoundedRect, Shape};
|
||||
|
||||
use crate::{
|
||||
Graphic,
|
||||
@@ -26,9 +26,9 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
let x = frontend_node.position.x as f64 * GRID_SIZE;
|
||||
let y = frontend_node.position.y as f64 * GRID_SIZE + GRID_SIZE / 2.;
|
||||
let node_width = GRID_SIZE * 5.0;
|
||||
let number_of_exposed_inputs = frontend_node.inputs.iter().skip(1).filter(|x| x.is_some()).count();
|
||||
let number_of_exposed_outputs = frontend_node.outputs.iter().skip(1).filter(|x| x.is_some()).count();
|
||||
let number_of_rows = 1 + number_of_exposed_inputs.max(number_of_exposed_outputs);
|
||||
let number_of_secondary_inputs = frontend_node.secondary_inputs.len();
|
||||
let number_of_secondary_outputs = frontend_node.secondary_outputs.len();
|
||||
let number_of_rows = 1 + number_of_secondary_inputs.max(number_of_secondary_outputs);
|
||||
let node_height = number_of_rows as f64 * GRID_SIZE;
|
||||
|
||||
let node_rect = RoundedRect::new(x, y, x + node_width, y + node_height, 2.);
|
||||
@@ -49,7 +49,7 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
bg_vector.style.fill = crate::vector::style::Fill::Solid(node_color.clone());
|
||||
bg_table.push(TableRow::new_from_element(bg_vector));
|
||||
// Make primary input brighter
|
||||
if number_of_exposed_inputs == 0 {
|
||||
if number_of_secondary_inputs == 0 {
|
||||
// Draw the first row with rounded bottom corners
|
||||
bg_table.push(TableRow::new_from_element(node_first_row(x, y, false)));
|
||||
} else {
|
||||
@@ -62,7 +62,7 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
let mut border_mask_path = BezPath::new();
|
||||
border_mask_path.move_to((-2., -2.));
|
||||
border_mask_path.line_to((node_width + 2., -2.));
|
||||
if frontend_node.outputs[0].is_some() {
|
||||
if frontend_node.primary_output.is_some() {
|
||||
border_mask_path.line_to((node_width + 2., 4.));
|
||||
border_mask_path.line_to((node_width - 2., 4.));
|
||||
border_mask_path.line_to((node_width - 2., 20.));
|
||||
@@ -70,7 +70,7 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
border_mask_path.line_to((node_width + 2., 20.));
|
||||
for row in 1..number_of_rows {
|
||||
border_mask_path.line_to((node_width + 2., row as f64 * GRID_SIZE + 4.));
|
||||
if frontend_node.outputs.get(row).is_some_and(|output| output.is_some()) {
|
||||
if row <= number_of_secondary_outputs {
|
||||
border_mask_path.line_to((node_width - 2., row as f64 * GRID_SIZE + 4.));
|
||||
border_mask_path.line_to((node_width - 2., row as f64 * GRID_SIZE + 20.));
|
||||
border_mask_path.line_to((node_width + 2., row as f64 * GRID_SIZE + 20.));
|
||||
@@ -80,13 +80,13 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
border_mask_path.line_to((-2., number_of_rows as f64 * GRID_SIZE + 2.));
|
||||
for row in (1..number_of_rows).rev() {
|
||||
border_mask_path.line_to((-2., row as f64 * GRID_SIZE + 20.));
|
||||
if frontend_node.inputs.iter().skip(1).filter(|input| input.is_some()).nth(row - 1).is_some_and(|input| input.is_some()) {
|
||||
if row <= number_of_secondary_inputs {
|
||||
border_mask_path.line_to((2., row as f64 * GRID_SIZE + 20.));
|
||||
border_mask_path.line_to((2., row as f64 * GRID_SIZE + 4.));
|
||||
border_mask_path.line_to((2., row as f64 * GRID_SIZE + 4.));
|
||||
}
|
||||
}
|
||||
if frontend_node.inputs[0].is_some() {
|
||||
if frontend_node.primary_input.is_some() {
|
||||
border_mask_path.line_to((-2., 20.));
|
||||
border_mask_path.line_to((2., 20.));
|
||||
border_mask_path.line_to((2., 4.));
|
||||
@@ -105,7 +105,8 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
// Border table is implemented as a clip mask
|
||||
let mut border_table = Table::new();
|
||||
let mut border_vector = Vector::from_bezpath(node_bez_path);
|
||||
let primary_output_color = frontend_node.outputs[0]
|
||||
let primary_output_color = frontend_node
|
||||
.primary_output
|
||||
.as_ref()
|
||||
.map(|primary_output| primary_output.data_type.data_color_dim())
|
||||
.unwrap_or(FrontendGraphDataType::General.data_color_dim());
|
||||
@@ -132,15 +133,16 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
for text_row in node_text.iter_mut() {
|
||||
*text_row.transform = DAffine2::from_translation(DVec2::new(x + 8., y + 3.));
|
||||
}
|
||||
for (row, input) in frontend_node.inputs.iter().enumerate().skip(1) {
|
||||
if let Some(input) = input {
|
||||
|
||||
for row in 1..=number_of_rows {
|
||||
if let Some(input) = frontend_node.secondary_inputs.get(row - 1) {
|
||||
let font_blob = Some(text::load_font(SOURCE_SANS_FONT_DATA));
|
||||
let mut input_row_text = crate::text::to_path(&input.name, font_blob, typesetting, false);
|
||||
for text_row in input_row_text.iter_mut() {
|
||||
*text_row.transform = DAffine2::from_translation(DVec2::new(x + 8., y + 24. * row as f64 + 3.));
|
||||
}
|
||||
node_text.extend(input_row_text);
|
||||
} else if let Some(Some(output)) = frontend_node.outputs.get(row) {
|
||||
} else if let Some(output) = frontend_node.secondary_outputs.get(row - 1) {
|
||||
let font_blob = Some(text::load_font(SOURCE_SANS_FONT_DATA));
|
||||
let mut output_row_text = crate::text::to_path(&output.name, font_blob, typesetting, false);
|
||||
// Find width to right align text
|
||||
@@ -176,14 +178,41 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
text_area_row.alpha_blending.clip = true;
|
||||
let text_area_table = Table::new_from_row(text_area_row);
|
||||
node_table.push(TableRow::new_from_element(Graphic::Vector(text_area_table)));
|
||||
|
||||
// Input and output ports
|
||||
let mut ports_table = Table::new();
|
||||
if let Some(primary_input) = &frontend_node.primary_input {
|
||||
let mut row = port_row(&primary_input.data_type);
|
||||
row.transform = DAffine2::from_translation(DVec2::new(0., 12.));
|
||||
ports_table.push(row);
|
||||
}
|
||||
for (index, secondary_input) in frontend_node.secondary_inputs.iter().enumerate() {
|
||||
let mut row = port_row(&secondary_input.data_type);
|
||||
row.transform = DAffine2::from_translation(DVec2::new(0., 12. + GRID_SIZE * (index + 1) as f64));
|
||||
ports_table.push(row);
|
||||
}
|
||||
if let Some(primary_output) = &frontend_node.primary_output {
|
||||
let mut row = port_row(&primary_output.data_type);
|
||||
row.transform = DAffine2::from_translation(DVec2::new(5. * GRID_SIZE, 12.));
|
||||
ports_table.push(row);
|
||||
}
|
||||
for (index, secondary_output) in frontend_node.secondary_outputs.iter().enumerate() {
|
||||
let mut row = port_row(&secondary_output.data_type);
|
||||
row.transform = DAffine2::from_translation(DVec2::new(5. * GRID_SIZE, 12. + GRID_SIZE * (index + 1) as f64));
|
||||
ports_table.push(row);
|
||||
}
|
||||
let mut graphic_ports_row = TableRow::new_from_element(Graphic::Vector(ports_table));
|
||||
graphic_ports_row.transform = DAffine2::from_translation(DVec2::new(x - 3., y - 4.));
|
||||
node_table.push(graphic_ports_row);
|
||||
}
|
||||
}
|
||||
|
||||
node_table
|
||||
}
|
||||
|
||||
pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> (Table<Graphic>, Table<Graphic>) {
|
||||
let mut layer_table = Table::new();
|
||||
let mut side_ports = Table::new();
|
||||
for node_to_render in nodes {
|
||||
if let Some(frontend_layer) = node_to_render.node_or_layer.layer.as_ref() {
|
||||
// The layer position is the top left of the thumbnail
|
||||
@@ -219,12 +248,12 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
|
||||
// Text starts at thumbnail + left padding
|
||||
let text_start = 12. + 8.;
|
||||
let right_text_edge = text_start + text_width;
|
||||
let right_text_edge = 8. + text_width;
|
||||
let rounded_text_edge = (right_text_edge as f64 / 24.).ceil() * 24.;
|
||||
|
||||
let rounded_layer_width_pixels = rounded_text_edge + 24.;
|
||||
// Subtract the left thumbnail
|
||||
let layer_right_edge_width = rounded_layer_width_pixels - 12.;
|
||||
// add the left thumbnail gap
|
||||
let layer_right_edge_width = rounded_layer_width_pixels + 12.;
|
||||
|
||||
let right_layer_width = layer_right_edge_width.max(4.5 * GRID_SIZE);
|
||||
let thumbnail_width = 3. * GRID_SIZE;
|
||||
@@ -305,10 +334,84 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
}
|
||||
let top_layer = text_table;
|
||||
layer_table.push(TableRow::new_from_element(Graphic::Vector(top_layer)));
|
||||
|
||||
// Ports
|
||||
let mut ports_table = Table::new();
|
||||
if let Some(side_input) = &frontend_layer.side_input {
|
||||
let mut port = port_row(&side_input.data_type);
|
||||
port.transform = DAffine2::from_translation(DVec2::new(layer_position.x - 15., layer_position.y + GRID_SIZE - 4.));
|
||||
ports_table.push(port);
|
||||
}
|
||||
let top_port = BezPath::from_svg("M0,6.953l2.521,-1.694a2.649,2.649,0,0,1,2.959,0l2.52,1.694v5.047h-8z").unwrap();
|
||||
let mut vector = Vector::from_bezpath(top_port);
|
||||
vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.output.data_type.data_color()).unwrap());
|
||||
let mut side_port = TableRow::new_from_element(vector);
|
||||
side_port.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y - 12.));
|
||||
side_ports.push(side_port);
|
||||
if frontend_layer.primary_output_connected_to_layer {
|
||||
let top_wire_cap = BezPath::from_svg("M0,-3.5h8v8l-2.521,-1.681a2.666,2.666,0,0,0,-2.959,0l-2.52,1.681z").unwrap();
|
||||
let mut vector = Vector::from_bezpath(top_wire_cap);
|
||||
vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.output.data_type.data_color_dim()).unwrap());
|
||||
let mut vector_row = TableRow::new_from_element(vector);
|
||||
vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y - 12.));
|
||||
ports_table.push(vector_row);
|
||||
}
|
||||
let bottom_port = BezPath::from_svg("M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z").unwrap();
|
||||
let mut vector = Vector::from_bezpath(bottom_port);
|
||||
vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.bottom_input.data_type.data_color()).unwrap());
|
||||
let mut vector_row = TableRow::new_from_element(vector);
|
||||
vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y + 2. * GRID_SIZE));
|
||||
ports_table.push(vector_row);
|
||||
if frontend_layer.primary_input_connected_to_layer {
|
||||
let bottom_port_cap = BezPath::from_svg("M0,10.95l2.52,-1.69c0.89,-0.6,2.06,-0.6,2.96,0l2.52,1.69v5.05h-8v-5.05z").unwrap();
|
||||
let mut vector = Vector::from_bezpath(bottom_port_cap);
|
||||
vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.bottom_input.data_type.data_color_dim()).unwrap());
|
||||
let mut vector_row = TableRow::new_from_element(vector);
|
||||
vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y + 2. * GRID_SIZE));
|
||||
ports_table.push(vector_row);
|
||||
}
|
||||
layer_table.push(TableRow::new_from_element(Graphic::Vector(ports_table)));
|
||||
|
||||
// Eye and grip icon
|
||||
let mut icons_table = Table::new();
|
||||
let icon_svg = if node_to_render.metadata.visible {
|
||||
BezPath::from_svg("M8,3C3,3,0,8,0,8s3,5,8,5s8-5,8-5S13,3,8,3z M8,12c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S10.2,12,8,12z").unwrap()
|
||||
} else {
|
||||
BezPath::from_svg("M8,4c3.5,0,5.9,2.8,6.8,4c-0.9,1.2-3.3,4-6.8,4S2.1,9.2,1.2,8C2.1,6.8,4.5,4,8,4 M8,3C3,3,0,8,0,8s3,5,8,5s8-5,8-5S13,3,8,3L8,3z").unwrap()
|
||||
};
|
||||
let mut icon_vector = Vector::from_bezpath(icon_svg);
|
||||
icon_vector.style.fill = Fill::Solid(Color::WHITE);
|
||||
let mut icon_row = TableRow::new_from_element(icon_vector);
|
||||
icon_row.transform = DAffine2::from_translation(layer_position + DVec2::new(thumbnail_width + right_layer_width - 8., 16.));
|
||||
icons_table.push(icon_row);
|
||||
|
||||
if node_to_render.metadata.selected {
|
||||
let mut grip_path = BezPath::new();
|
||||
let circle = Circle::new((0.5, 1.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let circle = Circle::new((0.5, 4.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let circle = Circle::new((0.5, 7.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let circle = Circle::new((3.5, 1.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let circle = Circle::new((3.5, 4.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let circle = Circle::new((3.5, 7.5), 0.5);
|
||||
grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE));
|
||||
let mut grip_vector = Vector::from_bezpath(grip_path);
|
||||
grip_vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(COLOR_E_NEARWHITE).unwrap());
|
||||
let mut grip_row = TableRow::new_from_element(grip_vector);
|
||||
grip_row.transform = DAffine2::from_translation(layer_position + DVec2::new(thumbnail_width + right_layer_width + 6. - GRID_SIZE, 19.5));
|
||||
icons_table.push(grip_row);
|
||||
}
|
||||
layer_table.push(TableRow::new_from_element(Graphic::Vector(icons_table)));
|
||||
}
|
||||
}
|
||||
|
||||
layer_table
|
||||
let mut ports_table = Table::new();
|
||||
ports_table.push(TableRow::new_from_element(Graphic::Vector(side_ports)));
|
||||
(layer_table, ports_table)
|
||||
}
|
||||
|
||||
fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector {
|
||||
@@ -352,10 +455,13 @@ fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector {
|
||||
vector
|
||||
}
|
||||
|
||||
fn port() -> BezPath {
|
||||
BezPath::from_svg("M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z").unwrap_or_else(|e| {
|
||||
fn port_row(data_type: &FrontendGraphDataType) -> TableRow<Vector> {
|
||||
let path = BezPath::from_svg("M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z").unwrap_or_else(|e| {
|
||||
panic!("Could not parse port svg from string: {}", e);
|
||||
})
|
||||
});
|
||||
let mut vector = Vector::from_bezpath(path);
|
||||
vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(data_type.data_color()).unwrap());
|
||||
TableRow::new_from_element(vector)
|
||||
}
|
||||
|
||||
pub fn draw_wires(nodes: &mut Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
|
||||
@@ -75,8 +75,10 @@ pub struct FrontendNodeMetadata {
|
||||
pub struct FrontendNode {
|
||||
// pub position: FrontendNodePosition,
|
||||
pub position: FrontendXY,
|
||||
pub inputs: Vec<Option<FrontendGraphInput>>,
|
||||
pub outputs: Vec<Option<FrontendGraphOutput>>,
|
||||
pub primary_output: Option<FrontendGraphOutput>,
|
||||
pub primary_input: Option<FrontendGraphInput>,
|
||||
pub secondary_inputs: Vec<FrontendGraphInput>,
|
||||
pub secondary_outputs: Vec<FrontendGraphOutput>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
|
||||
Reference in New Issue
Block a user