mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 08:18:12 +08:00
Context nullification, cached monitor nodes
This commit is contained in:
+51
-21
@@ -5,8 +5,10 @@ use crate::messages::prelude::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Dispatcher {
|
||||
buffered_queue: Vec<Message>,
|
||||
queueing_messages: bool,
|
||||
evaluation_queue: Vec<Message>,
|
||||
introspection_queue: Vec<Message>,
|
||||
queueing_evaluation_messages: bool,
|
||||
queueing_introspection_messages: bool,
|
||||
message_queues: Vec<VecDeque<Message>>,
|
||||
pub responses: Vec<FrontendMessage>,
|
||||
pub message_handlers: DispatcherMessageHandlers,
|
||||
@@ -41,6 +43,9 @@ 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::CompileActiveDocument),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::EvaluateActiveDocument),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::IntrospectActiveDocument),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel(
|
||||
PropertiesPanelMessageDiscriminant::Refresh,
|
||||
))),
|
||||
@@ -91,13 +96,6 @@ impl Dispatcher {
|
||||
|
||||
pub fn handle_message<T: Into<Message>>(&mut self, message: T, process_after_all_current: bool) {
|
||||
let message = message.into();
|
||||
// Add all additional messages to the queue if it exists (except from the end queue message)
|
||||
if !matches!(message, Message::EndQueue) {
|
||||
if self.queueing_messages {
|
||||
self.buffered_queue.push(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are not maintaining the buffer, simply add to the current queue
|
||||
Self::schedule_execution(&mut self.message_queues, process_after_all_current, [message]);
|
||||
@@ -117,7 +115,21 @@ impl Dispatcher {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Add all messages to the queue if queuing messages (except from the end queue message)
|
||||
if !matches!(message, Message::EndEvaluationQueue) {
|
||||
if self.queueing_evaluation_messages {
|
||||
self.evaluation_queue.push(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add all messages to the queue if queuing messages (except from the end queue message)
|
||||
if !matches!(message, Message::EndIntrospectionQueue) {
|
||||
if self.queueing_introspection_messages {
|
||||
self.introspection_queue.push(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Print the message at a verbosity level of `info`
|
||||
self.log_message(&message, &self.message_queues, self.message_handlers.debug_message_handler.message_logging_verbosity);
|
||||
|
||||
@@ -126,22 +138,40 @@ impl Dispatcher {
|
||||
|
||||
// Process the action by forwarding it to the relevant message handler, or saving the FrontendMessage to be sent to the frontend
|
||||
match message {
|
||||
Message::StartQueue => {
|
||||
self.queueing_messages = true;
|
||||
Message::StartEvaluationQueue => {
|
||||
self.queueing_evaluation_messages = true;
|
||||
}
|
||||
Message::EndQueue => {
|
||||
self.queueing_messages = false;
|
||||
Message::EndEvaluationQueue => {
|
||||
self.queueing_evaluation_messages = false;
|
||||
}
|
||||
Message::ProcessQueue((render_output_metadata, introspected_inputs)) => {
|
||||
let message = PortfolioMessage::ProcessEvaluationResponse {
|
||||
Message::ProcessEvaluationQueue(render_output_metadata) => {
|
||||
let update_message = PortfolioMessage::ProcessEvaluationResponse {
|
||||
evaluation_metadata: render_output_metadata,
|
||||
introspected_inputs,
|
||||
};
|
||||
// Add the message to update the state with the render output
|
||||
Self::schedule_execution(&mut self.message_queues, true, [message]);
|
||||
}
|
||||
.into();
|
||||
// Update the state with the render output and introspected inputs
|
||||
Self::schedule_execution(&mut self.message_queues, true, [update_message]);
|
||||
|
||||
// Schedule all queued messages to be run (in the order they were added)
|
||||
Self::schedule_execution(&mut self.message_queues, true, std::mem::take(&mut self.buffered_queue));
|
||||
// Schedule all queued messages to be run, which use the introspected inputs (in the order they were added)
|
||||
Self::schedule_execution(&mut self.message_queues, true, std::mem::take(&mut self.evaluation_queue));
|
||||
}
|
||||
Message::StartIntrospectionQueue => {
|
||||
self.queueing_introspection_messages = true;
|
||||
}
|
||||
Message::EndIntrospectionQueue => {
|
||||
self.queueing_introspection_messages = false;
|
||||
}
|
||||
Message::ProcessIntrospectionQueue(introspected_inputs) => {
|
||||
let update_message = PortfolioMessage::ProcessIntrospectionResponse { introspected_inputs }.into();
|
||||
// Update the state with the render output and introspected inputs
|
||||
Self::schedule_execution(&mut self.message_queues, true, [update_message]);
|
||||
|
||||
// Schedule all queued messages to be run, which use the introspected inputs (in the order they were added)
|
||||
Self::schedule_execution(&mut self.message_queues, true, std::mem::take(&mut self.introspection_queue));
|
||||
|
||||
let clear_message = PortfolioMessage::ClearIntrospectedData.into();
|
||||
// Clear the introspected inputs since they are no longer required, and will cause a memory leak if not removed
|
||||
Self::schedule_execution(&mut self.message_queues, true, [clear_message]);
|
||||
}
|
||||
Message::NoOp => {}
|
||||
Message::Init => {
|
||||
|
||||
@@ -43,7 +43,7 @@ impl MessageHandler<ExportDialogMessage, ExportDialogMessageContext<'_>> for Exp
|
||||
ExportDialogMessage::TransparentBackground(transparent_background) => self.transparent_background = transparent_background,
|
||||
ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area,
|
||||
|
||||
ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::ActiveDocumentExport {
|
||||
ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::ExportActiveDocument {
|
||||
file_name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(),
|
||||
file_type: self.file_type,
|
||||
scale_factor: self.scale_factor,
|
||||
|
||||
+4
-7
@@ -1,7 +1,7 @@
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::{IVec2, UVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
/// A dialog to allow users to set some initial options about a new document.
|
||||
#[derive(Debug, Clone, Default, ExtractField)]
|
||||
@@ -24,17 +24,14 @@ impl MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHa
|
||||
|
||||
let create_artboard = !self.infinite && self.dimensions.x > 0 && self.dimensions.y > 0;
|
||||
if create_artboard {
|
||||
responses.add(Message::StartQueue);
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id: NodeId::new(),
|
||||
artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()),
|
||||
});
|
||||
}
|
||||
|
||||
// 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::StartQueue);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
responses.add(DocumentMessage::DeselectAllLayers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, La
|
||||
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::HintData;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::raster::color::Color;
|
||||
use graphene_std::text::Font;
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, Mou
|
||||
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
|
||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::DVec2;
|
||||
use std::time::Duration;
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct InputPreprocessorMessageContext {
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::messages::prelude::*;
|
||||
use graphene_std::{IntrospectMode, uuid::CompiledProtonodeInput};
|
||||
use crate::{messages::prelude::*, node_graph_executor::IntrospectionResponse};
|
||||
use graphite_proc_macros::*;
|
||||
|
||||
#[impl_message]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Message {
|
||||
NoOp,
|
||||
Init,
|
||||
Batched(Box<[Message]>),
|
||||
// Adds any subsequent messages to the queue
|
||||
StartQueue,
|
||||
StartEvaluationQueue,
|
||||
// Stop adding messages to the queue.
|
||||
EndQueue,
|
||||
// Processes all messages that are queued, which occurs on the evaluation response. This allows a message to be run with data from after the evaluation is complete
|
||||
ProcessQueue(
|
||||
(
|
||||
graphene_std::renderer::RenderMetadata,
|
||||
Vec<(CompiledProtonodeInput, IntrospectMode, Box<dyn std::any::Any + Send + Sync>)>,
|
||||
),
|
||||
),
|
||||
|
||||
EndEvaluationQueue,
|
||||
// Processes all messages that are queued to be run after evaluation, which occurs on the evaluation response. This allows a message to be run with data from after the evaluation is complete
|
||||
#[serde(skip)]
|
||||
ProcessEvaluationQueue(graphene_std::renderer::RenderMetadata),
|
||||
StartIntrospectionQueue,
|
||||
EndIntrospectionQueue,
|
||||
// Processes all messages that are queued to be run after introspection, which occurs on the evaluation response. This allows a message to be run with data from after the evaluation is complete
|
||||
#[serde(skip)]
|
||||
ProcessIntrospectionQueue(IntrospectionResponse),
|
||||
#[child]
|
||||
Animation(AnimationMessage),
|
||||
#[child]
|
||||
|
||||
@@ -7,11 +7,10 @@ use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate,
|
||||
use crate::messages::portfolio::utility_types::PanelType;
|
||||
use crate::messages::prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graphene_std::uuid::CompiledProtonodeInput;
|
||||
use graphene_std::vector::click_target::ClickTarget;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::renderer::ClickTarget;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::node_graph::utility_types::Transform;
|
||||
use super::overlays::utility_types::Pivot;
|
||||
use super::utility_types::error::EditorError;
|
||||
use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState};
|
||||
use super::utility_types::network_interface::{self, NodeNetworkInterface, TransactionStatus};
|
||||
use super::utility_types::network_interface::{NodeNetworkInterface, TransactionStatus};
|
||||
use super::utility_types::nodes::{CollapsedLayers, SelectedNodes};
|
||||
use crate::application::{GRAPHITE_GIT_COMMIT_HASH, generate_uuid};
|
||||
use crate::consts::{ASYMPTOTIC_EFFECT, COLOR_OVERLAY_GRAY, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
|
||||
@@ -13,10 +13,9 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
|
||||
use crate::messages::portfolio::document::node_graph::NodeGraphMessageContext;
|
||||
use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options};
|
||||
use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType, OverlaysVisibilitySettings};
|
||||
use crate::messages::portfolio::document::properties_panel::properties_panel_message_handler::PropertiesPanelMessageContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
|
||||
use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::*;
|
||||
@@ -24,11 +23,10 @@ use crate::messages::tool::common_functionality::graph_modification_utils::{self
|
||||
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||
use graph_craft::document::{InputConnector, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
||||
use graphene_std::raster::BlendMode;
|
||||
@@ -37,18 +35,16 @@ use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::PointId;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct DocumentMessageContext<'a> {
|
||||
pub document_id: DocumentId,
|
||||
pub struct DocumentMessageData<'a> {
|
||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||
pub persistent_data: &'a PersistentData,
|
||||
pub current_tool: &'a ToolType,
|
||||
pub preferences: &'a PreferencesMessageHandler,
|
||||
pub device_pixel_ratio: f64,
|
||||
// pub introspected_inputs: &HashMap<CompiledProtonodeInput, Box<dyn std::any::Any + Send + Sync>>,
|
||||
// pub introspected_inputs: &HashMap<CompiledProtonodeInput, Arc<dyn std::any::Any + Send + Sync>>,
|
||||
// pub downcasted_inputs: &mut HashMap<CompiledProtonodeInput, TaggedValue>,
|
||||
}
|
||||
|
||||
@@ -173,10 +169,9 @@ impl Default for DocumentMessageHandler {
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMessageHandler {
|
||||
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque<Message>, context: DocumentMessageContext) {
|
||||
let DocumentMessageContext {
|
||||
document_id,
|
||||
impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessageHandler {
|
||||
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque<Message>, data: DocumentMessageData) {
|
||||
let DocumentMessageData {
|
||||
ipp,
|
||||
persistent_data,
|
||||
current_tool,
|
||||
@@ -222,12 +217,10 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
);
|
||||
}
|
||||
DocumentMessage::PropertiesPanel(message) => {
|
||||
let context = PropertiesPanelMessageContext {
|
||||
let properties_panel_message_handler_data = super::properties_panel::PropertiesPanelMessageHandlerData {
|
||||
network_interface: &mut self.network_interface,
|
||||
selection_network_path: &self.selection_network_path,
|
||||
document_name: self.name.as_str(),
|
||||
executor,
|
||||
persistent_data,
|
||||
};
|
||||
self.properties_panel_message_handler.process_message(message, responses, context);
|
||||
}
|
||||
@@ -239,7 +232,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
network_interface: &mut self.network_interface,
|
||||
selection_network_path: &self.selection_network_path,
|
||||
breadcrumb_network_path: &self.breadcrumb_network_path,
|
||||
document_id,
|
||||
collapsed: &mut self.collapsed,
|
||||
ipp,
|
||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
||||
@@ -1432,7 +1424,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
center: Key::Alt,
|
||||
duplicate: Key::Alt,
|
||||
}));
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(PortfolioMessage::EvaluateActiveDocument);
|
||||
} else {
|
||||
let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else {
|
||||
return;
|
||||
@@ -1492,7 +1484,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
// Connect the current output data to the artboard's input data, and the artboard's output to the document output
|
||||
responses.add(NodeGraphMessage::InsertNodeBetween {
|
||||
node_id,
|
||||
input_connector: network_interface::InputConnector::Export(0),
|
||||
input_connector: InputConnector::Export(0),
|
||||
insert_node_input_index: 1,
|
||||
});
|
||||
|
||||
@@ -1914,13 +1906,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::CompileActiveDocument);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
||||
// 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(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::StartQueue);
|
||||
responses.add(NodeGraphMessage::UnloadWires);
|
||||
responses.add(NodeGraphMessage::SendWires);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
Some(previous_network)
|
||||
}
|
||||
pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
@@ -1946,12 +1939,14 @@ impl DocumentMessageHandler {
|
||||
network_interface.set_document_to_viewport_transform(transform);
|
||||
|
||||
let previous_network = std::mem::replace(&mut self.network_interface, network_interface);
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
// 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(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(NodeGraphMessage::UnloadWires);
|
||||
responses.add(NodeGraphMessage::SendWires);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
Some(previous_network)
|
||||
}
|
||||
|
||||
@@ -2108,7 +2103,7 @@ impl DocumentMessageHandler {
|
||||
/// Loads all of the fonts in the document.
|
||||
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
|
||||
let mut fonts = HashSet::new();
|
||||
for (_node_id, node, _) in self.document_network().recursive_nodes() {
|
||||
for (_node_path, node) in self.document_network().recursive_nodes() {
|
||||
for input in &node.inputs {
|
||||
if let Some(TaggedValue::Font(font)) = input.as_value() {
|
||||
fonts.insert(font.clone());
|
||||
@@ -2581,7 +2576,7 @@ impl DocumentMessageHandler {
|
||||
layout: Layout::WidgetLayout(document_bar_layout),
|
||||
layout_target: LayoutTarget::DocumentBar,
|
||||
});
|
||||
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
||||
responses.add(PortfolioMessage::EvaluateActiveDocument);
|
||||
}
|
||||
|
||||
pub fn update_layers_panel_control_bar_widgets(&self, responses: &mut VecDeque<Message>) {
|
||||
|
||||
@@ -4,12 +4,12 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
|
||||
use crate::messages::prelude::*;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::{CPU, RasterDataTable};
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::PointId;
|
||||
use graphene_std::vector::VectorModificationType;
|
||||
use graphene_std::vector::style::{Fill, Stroke};
|
||||
|
||||
+3
-2
@@ -2,12 +2,13 @@ use super::transform_utils;
|
||||
use super::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, OutputConnector, NodeInput};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::PointId;
|
||||
|
||||
/// Convert an affine transform into the tuple `(scale, angle, translation, shear)` assuming `shear.y = 0`.
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
use super::transform_utils;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, NodeNetworkInterface};
|
||||
use crate::messages::prelude::*;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, NodeInput, OutputConnector};
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::{CPU, RasterDataTable};
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::style::{Fill, Stroke};
|
||||
use graphene_std::vector::{PointId, VectorModificationType};
|
||||
use graphene_std::vector::{VectorData, VectorDataTable};
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct NavigationMessageContext<'a> {
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::messages::portfolio::document::utility_types::network_interface::{
|
||||
};
|
||||
use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::Message;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
use glam::DVec2;
|
||||
use graph_craft::ProtoNodeIdentifier;
|
||||
use graph_craft::concrete;
|
||||
@@ -23,6 +22,7 @@ use graphene_std::raster_types::{CPU, RasterDataTable};
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
#[allow(unused_imports)]
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::VectorDataTable;
|
||||
use graphene_std::*;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use super::utility_types::Direction;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, InputConnector, NodeTemplate, OutputConnector};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, NodeTemplate};
|
||||
use crate::messages::prelude::*;
|
||||
use glam::IVec2;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta;
|
||||
use graph_craft::document::{InputConnector, NodeInput, OutputConnector};
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
#[impl_message(Message, DocumentMessage, NodeGraph)]
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
@@ -111,8 +110,6 @@ pub enum NodeGraphMessage {
|
||||
start_index: usize,
|
||||
end_index: usize,
|
||||
},
|
||||
RunDocumentGraph,
|
||||
ForceRunDocumentGraph,
|
||||
SelectedNodesAdd {
|
||||
nodes: Vec<NodeId>,
|
||||
},
|
||||
|
||||
@@ -9,9 +9,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
||||
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::{
|
||||
self, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing, TypeSource,
|
||||
};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, Previewing, TypeSource};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
||||
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
|
||||
use crate::messages::prelude::*;
|
||||
@@ -20,9 +18,10 @@ use crate::messages::tool::common_functionality::graph_modification_utils::get_c
|
||||
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
|
||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::document::{DocumentNodeImplementation, InputConnector, NodeInput, OutputConnector};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graphene_std::math::math_ext::QuadExt;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::*;
|
||||
use renderer::Quad;
|
||||
use std::cmp::Ordering;
|
||||
@@ -32,7 +31,6 @@ pub struct NodeGraphMessageContext<'a> {
|
||||
pub network_interface: &'a mut NodeNetworkInterface,
|
||||
pub selection_network_path: &'a [NodeId],
|
||||
pub breadcrumb_network_path: &'a [NodeId],
|
||||
pub document_id: DocumentId,
|
||||
pub collapsed: &'a mut CollapsedLayers,
|
||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||
pub graph_view_overlay_open: bool,
|
||||
@@ -99,7 +97,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
network_interface,
|
||||
selection_network_path,
|
||||
breadcrumb_network_path,
|
||||
document_id,
|
||||
collapsed,
|
||||
ipp,
|
||||
graph_view_overlay_open,
|
||||
@@ -767,14 +764,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
self.initial_disconnecting = false;
|
||||
|
||||
self.wire_in_progress_from_connector = network_interface.output_position(&clicked_output, selection_network_path);
|
||||
if let Some((output_type, source)) = clicked_output
|
||||
.node_id()
|
||||
.map(|node_id| network_interface.output_type(&node_id, clicked_output.index(), breadcrumb_network_path))
|
||||
{
|
||||
self.wire_in_progress_type = FrontendGraphDataType::displayed_type(&output_type, &source);
|
||||
} else {
|
||||
self.wire_in_progress_type = FrontendGraphDataType::General;
|
||||
}
|
||||
let (output_type, source) = network_interface.output_type(&clicked_output, breadcrumb_network_path);
|
||||
self.wire_in_progress_type = FrontendGraphDataType::displayed_type(&output_type, &source);
|
||||
|
||||
self.update_node_graph_hints(responses);
|
||||
return;
|
||||
@@ -922,7 +913,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
false
|
||||
}
|
||||
});
|
||||
let vector_wire = build_vector_wire(
|
||||
let (vector_wire, _) = build_vector_wire(
|
||||
wire_in_progress_from_connector,
|
||||
wire_in_progress_to_connector,
|
||||
from_connector_is_layer,
|
||||
@@ -936,6 +927,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
data_type: self.wire_in_progress_type,
|
||||
thick: false,
|
||||
dashed: false,
|
||||
center: None,
|
||||
input_sni: None,
|
||||
};
|
||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) });
|
||||
}
|
||||
@@ -1078,15 +1071,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
};
|
||||
// Get the compatible type from the output connector
|
||||
let compatible_type = output_connector.and_then(|output_connector| {
|
||||
output_connector.node_id().and_then(|node_id| {
|
||||
// Get the output types from the network interface
|
||||
let (output_type, type_source) = network_interface.output_type(&node_id, output_connector.index(), selection_network_path);
|
||||
// Get the output types from the network interface
|
||||
let (output_type, type_source) = network_interface.output_type(&output_connector, selection_network_path);
|
||||
|
||||
match type_source {
|
||||
TypeSource::RandomProtonodeImplementation | TypeSource::Error(_) => None,
|
||||
_ => Some(format!("type:{}", output_type.nested_type())),
|
||||
}
|
||||
})
|
||||
match type_source {
|
||||
TypeSource::RandomProtonodeImplementation | TypeSource::Error(_) => None,
|
||||
_ => Some(format!("type:{}", output_type.nested_type())),
|
||||
}
|
||||
});
|
||||
let appear_right_of_mouse = if ipp.mouse.position.x > ipp.viewport_bounds.size().x - 173. { -173. } else { 0. };
|
||||
let appear_above_mouse = if ipp.mouse.position.y > ipp.viewport_bounds.size().y - 34. { -34. } else { 0. };
|
||||
@@ -1188,7 +1179,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let (wire, is_stack) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?;
|
||||
let (wire, is_stack, _) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?;
|
||||
wire.rectangle_intersections_exist(bounding_box[0], bounding_box[1]).then_some((input, is_stack))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -1290,12 +1281,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
}
|
||||
PortfolioMessage::CompileActiveDocument => {
|
||||
responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: false });
|
||||
}
|
||||
NodeGraphMessage::ForceRunDocumentGraph => {
|
||||
responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: true });
|
||||
}
|
||||
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesAdd");
|
||||
@@ -1340,14 +1325,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
|
||||
return;
|
||||
};
|
||||
let document_bbox: [DVec2; 2] = ipp.document_bounds();
|
||||
let document_bbox = ipp.document_bounds(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse());
|
||||
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);
|
||||
}
|
||||
@@ -1393,6 +1377,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
if !(network_interface.reference(&node_id, selection_network_path).is_none() || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) {
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(NodeGraphMessage::SendWires);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
}
|
||||
}
|
||||
NodeGraphMessage::SetInput { input_connector, input } => {
|
||||
@@ -1688,8 +1675,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
)
|
||||
.into_iter()
|
||||
.next();
|
||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
||||
responses.add(NodeGraphMessage::SendWires);
|
||||
responses.add(FrontendMessage::UpdateImportsExports {
|
||||
imports,
|
||||
exports,
|
||||
@@ -2182,6 +2167,7 @@ impl NodeGraphMessageHandler {
|
||||
|
||||
fn collect_nodes(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Vec<FrontendNode> {
|
||||
let Some(outward_wires) = network_interface.outward_wires(breadcrumb_network_path).cloned() else {
|
||||
log::error!("Could not collect outward wires in collect_nodes");
|
||||
return Vec::new();
|
||||
};
|
||||
let mut can_be_layer_lookup = HashSet::new();
|
||||
@@ -2232,7 +2218,7 @@ impl NodeGraphMessageHandler {
|
||||
let primary_input = inputs.next().flatten();
|
||||
let exposed_inputs = inputs.flatten().collect();
|
||||
|
||||
let (output_type, type_source) = network_interface.output_type(&node_id, 0, breadcrumb_network_path);
|
||||
let (output_type, type_source) = network_interface.output_type(&OutputConnector::node(node_id, 0), breadcrumb_network_path);
|
||||
let frontend_data_type = FrontendGraphDataType::displayed_type(&output_type, &type_source);
|
||||
|
||||
let connected_to = outward_wires.get(&OutputConnector::node(node_id, 0)).cloned().unwrap_or_default();
|
||||
@@ -2253,7 +2239,7 @@ impl NodeGraphMessageHandler {
|
||||
if output_index == 0 && network_interface.has_primary_output(&node_id, breadcrumb_network_path) {
|
||||
continue;
|
||||
}
|
||||
let (output_type, type_source) = network_interface.output_type(&node_id, 0, breadcrumb_network_path);
|
||||
let (output_type, type_source) = network_interface.output_type(&OutputConnector::node(node_id, 0), breadcrumb_network_path);
|
||||
let data_type = FrontendGraphDataType::displayed_type(&output_type, &type_source);
|
||||
|
||||
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
|
||||
@@ -2292,18 +2278,19 @@ impl NodeGraphMessageHandler {
|
||||
|
||||
let locked = network_interface.is_locked(&node_id, breadcrumb_network_path);
|
||||
|
||||
let errors = self
|
||||
.node_graph_errors
|
||||
.iter()
|
||||
.find(|error| error.node_path == node_id_path)
|
||||
.map(|error| format!("{:?}", error.error.clone()))
|
||||
.or_else(|| {
|
||||
if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
|
||||
Some("Node graph type error within this node".to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let errors = None; // TODO: Recursive traversal from export over all protonodes and match metadata with error
|
||||
// self
|
||||
// .node_graph_errors
|
||||
// .iter()
|
||||
// .find(|error| error.stable_node_id == node_id_path)
|
||||
// .map(|error| format!("{:?}", error.error.clone()))
|
||||
// .or_else(|| {
|
||||
// if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
|
||||
// Some("Node graph type error within this node".to_string())
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// });
|
||||
|
||||
nodes.push(FrontendNode {
|
||||
id: node_id,
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext};
|
||||
use super::utility_types::FrontendGraphDataType;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::*;
|
||||
use choice::enum_choice;
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use graph_craft::Type;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, InputConnector, NodeInput};
|
||||
use graphene_std::animation::RealTimeMode;
|
||||
use graphene_std::extract_xy::XY;
|
||||
use graphene_std::path_bool::BooleanOperation;
|
||||
@@ -22,6 +21,7 @@ use graphene_std::raster::{
|
||||
use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
|
||||
use graphene_std::text::Font;
|
||||
use graphene_std::transform::{Footprint, ReferencePoint};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::VectorDataTable;
|
||||
use graphene_std::vector::misc::GridType;
|
||||
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector, TypeSource};
|
||||
use graph_craft::document::NodeId;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{TypeSource};
|
||||
use graph_craft::document::{InputConnector, OutputConnector};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::Type;
|
||||
use std::borrow::Cow;
|
||||
|
||||
@@ -72,7 +73,7 @@ pub struct FrontendGraphOutput {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct FrontendNode {
|
||||
pub id: graph_craft::document::NodeId,
|
||||
pub id: NodeId,
|
||||
#[serde(rename = "isLayer")]
|
||||
pub is_layer: bool,
|
||||
#[serde(rename = "canBeLayer")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod properties_panel_message;
|
||||
pub mod properties_panel_message_handler;
|
||||
mod properties_panel_message_handler;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use properties_panel_message::{PropertiesPanelMessage, PropertiesPanelMessageDiscriminant};
|
||||
#[doc(inline)]
|
||||
pub use properties_panel_message_handler::PropertiesPanelMessageHandler;
|
||||
pub use properties_panel_message_handler::{PropertiesPanelMessageHandler, PropertiesPanelMessageHandlerData};
|
||||
|
||||
-1
@@ -7,7 +7,6 @@ use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use graph_craft::document::NodeId;
|
||||
pub struct PropertiesPanelMessageHandlerData<'a> {
|
||||
pub network_interface: &'a mut NodeNetworkInterface,
|
||||
pub selection_network_path: &'a [NodeId],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
use super::network_interface::NodeTemplate;
|
||||
use graph_craft::document::NodeId;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq, Debug, specta::Type)]
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Modify
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::{PointId, VectorData};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
@@ -11,15 +11,13 @@ use crate::messages::tool::tool_messages::tool_prelude::NumberInputMode;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, InputConnector, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork, OutputConnector};
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, InputConnector, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork, OutputConnector};
|
||||
use graph_craft::{Type, concrete};
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, NodeId};
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, NodeId, SNI};
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::{PointId, VectorData, VectorModificationType};
|
||||
use graphene_std::{CompiledProtonodeInput, SNI};
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
@@ -38,8 +36,9 @@ pub struct NodeNetworkInterface {
|
||||
#[serde(skip)]
|
||||
document_metadata: DocumentMetadata,
|
||||
/// All input/output types based on the compiled network.
|
||||
/// TODO: Move to portfolio message handler
|
||||
#[serde(skip)]
|
||||
pub resolved_types: ResolvedDocumentNodeTypes,
|
||||
pub resolved_types: HashMap<SNI, Vec<Type>>,
|
||||
#[serde(skip)]
|
||||
transaction_status: TransactionStatus,
|
||||
#[serde(skip)]
|
||||
@@ -54,6 +53,7 @@ impl Clone for NodeNetworkInterface {
|
||||
document_metadata: Default::default(),
|
||||
resolved_types: Default::default(),
|
||||
transaction_status: TransactionStatus::Finished,
|
||||
current_hash: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,7 +490,7 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
/// Try and get the [`DocumentNodeDefinition`] for a node
|
||||
pub fn get_node_definition(&self, network_path: &[NodeId], node_id: NodeId) -> Option<&DocumentNodeDefinition> {
|
||||
pub fn node_definition(&self, node_id: NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeDefinition> {
|
||||
let metadata = self.node_metadata(&node_id, network_path)?;
|
||||
resolve_document_node_type(metadata.persistent_metadata.reference.as_ref()?)
|
||||
}
|
||||
@@ -512,13 +512,13 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn downstream_caller_from_output(&self, output_connector: OutputConnector, network_path: &[NodeId]) -> Option<&CompiledProtonodeInput> {
|
||||
pub fn downstream_caller_from_output(&self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<&CompiledProtonodeInput> {
|
||||
match output_connector {
|
||||
OutputConnector::Node { node_id, output_index } => match self.implementation(&node_id, network_path)? {
|
||||
DocumentNodeImplementation::Network(node_network) => {
|
||||
OutputConnector::Node { node_id, output_index } => match self.implementation(node_id, network_path)? {
|
||||
DocumentNodeImplementation::Network(_) => {
|
||||
let mut nested_path = network_path.to_vec();
|
||||
nested_path.push(node_id);
|
||||
self.downstream_caller_from_input(InputConnector::Export(output_index), &nested_path)
|
||||
nested_path.push(*node_id);
|
||||
self.downstream_caller_from_input(&InputConnector::Export(*output_index), &nested_path)
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(_) => self.node_metadata(&node_id, network_path)?.transient_metadata.caller.as_ref(),
|
||||
DocumentNodeImplementation::Extract => todo!(),
|
||||
@@ -526,44 +526,44 @@ impl NodeNetworkInterface {
|
||||
OutputConnector::Import(import_index) => {
|
||||
let mut encapsulating_path = network_path.to_vec();
|
||||
let node_id = encapsulating_path.pop().expect("No imports in document network");
|
||||
self.downstream_caller_from_input(InputConnector::node(node_id, import_index), &encapsulating_path)
|
||||
self.downstream_caller_from_input(&InputConnector::node(node_id, *import_index), &encapsulating_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Returns the path and input index to the protonode which called the input, which has to be the same every time is is called for a given input.
|
||||
// This has to be done by iterating upstream, since a downstream traversal may lead to an uncompiled branch.
|
||||
// This requires that value inputs store their caller. Caller input metadata from compilation has to be stored for
|
||||
pub fn downstream_caller_from_input(&self, &input_connector: InputConnector, network_path: &[NodeId]) -> Option<&CompiledProtonodeInput> {
|
||||
pub fn downstream_caller_from_input(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<&CompiledProtonodeInput> {
|
||||
// Cases: Node/Value input to protonode, Node/Value input to network node
|
||||
let input = self.input_from_connector(input_connector, network_path)?;
|
||||
let caller_input = match input {
|
||||
NodeInput::Node { node_id, output_index, lambda } => {
|
||||
NodeInput::Node { node_id, output_index, .. } => {
|
||||
match self.implementation(node_id, network_path)? {
|
||||
DocumentNodeImplementation::Network(node_network) => {
|
||||
DocumentNodeImplementation::Network(_) => {
|
||||
// Continue traversal within network
|
||||
let mut nested_path = network_path.to_vec();
|
||||
nested_path.push(*node_id);
|
||||
self.downstream_caller_from_input(InputConnector::Export(*output_index), &nested_path)
|
||||
self.downstream_caller_from_input(&InputConnector::Export(*output_index), &nested_path)
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(proto_node_identifier) => self.node_metadata(node_id, network_path)?.transient_metadata.caller.as_ref(),
|
||||
DocumentNodeImplementation::ProtoNode(_) => self.node_metadata(node_id, network_path)?.transient_metadata.caller.as_ref(),
|
||||
// If connected to a protonode, use the data in the node metadata
|
||||
DocumentNodeImplementation::Extract => todo!(),
|
||||
}
|
||||
}
|
||||
// Can either be an input to a protonode, network node, or export
|
||||
NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Reflection(_) => match input_connector {
|
||||
InputConnector::Node { node_id, input_index } => self.input_metadata(node_id, *index, network_path)?.transient_metadata.caller.as_ref(),
|
||||
InputConnector::Export(export_index) => self.network_metadata(network_path)?.transient_metadata.callers.get(export_index)?.as_ref(),
|
||||
InputConnector::Node { node_id, .. } => self.transient_input_metadata(node_id, input_connector.input_index(), network_path)?.caller.as_ref(),
|
||||
InputConnector::Export(export_index) => self.network_metadata(network_path)?.transient_metadata.callers.get(*export_index)?.as_ref(),
|
||||
},
|
||||
NodeInput::Network { import_index } => {
|
||||
NodeInput::Network { import_index, .. } => {
|
||||
let mut encapsulating_path = network_path.to_vec();
|
||||
let node_id = encapsulating_path.pop().expect("No imports in document network");
|
||||
self.downstream_caller_from_input(InputConnector::node(node_id, *import_index), &encapsulating_path)
|
||||
self.downstream_caller_from_input(&InputConnector::node(node_id, *import_index), &encapsulating_path)
|
||||
}
|
||||
NodeInput::Inline(inline_rust) => None,
|
||||
NodeInput::Inline(_) => None,
|
||||
};
|
||||
let Some(caller_input) = caller_input else {
|
||||
log::error!("Could not get compiled caller input for input: {:?}", input_connector);
|
||||
log::error!("Could not get compiled caller input for input: {:?} in network: {:?}", input_connector, network_path);
|
||||
return None;
|
||||
};
|
||||
Some(caller_input)
|
||||
@@ -631,7 +631,7 @@ impl NodeNetworkInterface {
|
||||
{
|
||||
let mut inner_path = network_path.to_vec();
|
||||
inner_path.push(node_id);
|
||||
let result = self.guess_type_from_node(child_id, child_input_index, inner_path);
|
||||
let result = self.guess_type_from_node(child_id, child_input_index, &inner_path);
|
||||
inner_path.pop();
|
||||
return result;
|
||||
}
|
||||
@@ -645,6 +645,10 @@ impl NodeNetworkInterface {
|
||||
|
||||
/// Get the [`Type`] for any InputConnector
|
||||
pub fn input_type(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> (Type, TypeSource) {
|
||||
if let Some(NodeInput::Value { tagged_value, .. }) = self.input_from_connector(input_connector, network_path) {
|
||||
return (tagged_value.ty(), TypeSource::TaggedValue);
|
||||
}
|
||||
|
||||
if let Some(compiled_type) = self
|
||||
.downstream_caller_from_input(input_connector, network_path)
|
||||
.and_then(|(sni, input_index)| self.resolved_types.get(sni).and_then(|protonode_input_types| protonode_input_types.get(*input_index)))
|
||||
@@ -657,17 +661,14 @@ impl NodeNetworkInterface {
|
||||
return (concrete!(()), TypeSource::Error("input connector is not a node"));
|
||||
};
|
||||
|
||||
self.guess_type_from_node(node_id, input_connector.input_index(), network_path);
|
||||
self.guess_type_from_node(node_id, input_connector.input_index(), network_path)
|
||||
}
|
||||
|
||||
pub fn compiled_output_type(&self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<&Type> {
|
||||
let (sni, input_index) = self.downstream_caller_from_output(output_connector, network_path)?;
|
||||
let protonode_input_types = self.resolved_types.get(sni)?;
|
||||
protonode_input_types.get(*input_index)
|
||||
}
|
||||
|
||||
pub fn output_type(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> (Type, TypeSource) {
|
||||
if let Some(output_type) = self.compiled_output_type(output_connector, network_path) {
|
||||
pub fn output_type(&self, output_connector: &OutputConnector, network_path: &[NodeId]) -> (Type, TypeSource) {
|
||||
if let Some(output_type) = self
|
||||
.downstream_caller_from_output(output_connector, network_path)
|
||||
.and_then(|(sni, input_index)| self.resolved_types.get(sni).and_then(|protonode_input_types| protonode_input_types.get(*input_index)))
|
||||
{
|
||||
return (output_type.clone(), TypeSource::Compiled);
|
||||
}
|
||||
(concrete!(()), TypeSource::Error("Not compiled"))
|
||||
@@ -678,10 +679,10 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
pub fn remove_type(&mut self, sni: SNI) {
|
||||
self.resolved_types.remove(sni);
|
||||
self.resolved_types.remove(&sni);
|
||||
}
|
||||
|
||||
pub fn set_node_caller(&mut self, node: &NodeId, caller: CompiledProtonodeInput, network_path: &[NodeId]) {
|
||||
pub fn set_node_caller(&mut self, node_id: &NodeId, caller: CompiledProtonodeInput, network_path: &[NodeId]) {
|
||||
let Some(metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
return;
|
||||
};
|
||||
@@ -692,6 +693,7 @@ impl NodeNetworkInterface {
|
||||
match input_connector {
|
||||
InputConnector::Node { node_id, input_index } => {
|
||||
let Some(metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
log::error!("node metadata must exist when setting input caller for node {}, input index {}", node_id, input_index);
|
||||
return;
|
||||
};
|
||||
let Some(input_metadata) = metadata.persistent_metadata.input_metadata.get_mut(*input_index) else {
|
||||
@@ -770,84 +772,6 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the output types for a given document node and its exports.
|
||||
///
|
||||
/// This function traverses the node and its nested network structure (if applicable) to determine
|
||||
/// the types of all outputs, including the primary output and any additional exports.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `node` - A reference to the `DocumentNode` for which to determine output types.
|
||||
/// * `resolved_types` - A reference to `ResolvedDocumentNodeTypes` containing pre-resolved type information.
|
||||
/// * `node_id_path` - A slice of `NodeId`s representing the path to the current node in the document graph.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `Vec<Option<Type>>` where:
|
||||
/// - The first element is the primary output type of the node.
|
||||
/// - Subsequent elements are types of additional exports (if the node is a network).
|
||||
/// - `None` values indicate that a type couldn't be resolved for a particular output.
|
||||
///
|
||||
/// # Behavior
|
||||
///
|
||||
/// 1. Retrieves the primary output type from `resolved_types`.
|
||||
/// 2. If the node is a network:
|
||||
/// - Iterates through its exports (skipping the first/primary export).
|
||||
/// - For each export, traverses the network until reaching a protonode or terminal condition.
|
||||
/// - Determines the output type based on the final node/value encountered.
|
||||
/// 3. Collects and returns all resolved types.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function assumes that export indices and node IDs always exist within their respective
|
||||
/// collections. It will panic if these assumptions are violated.
|
||||
///
|
||||
pub fn output_type(&self, node_id: &NodeId, output_index: usize, network_path: &[NodeId]) -> (Type, TypeSource) {
|
||||
let Some(implementation) = self.implementation(node_id, network_path) else {
|
||||
log::error!("Could not get output type for node {node_id} output index {output_index}. This node is no longer supported, and needs to be upgraded.");
|
||||
return (concrete!(()), TypeSource::Error("Could not get implementation"));
|
||||
};
|
||||
|
||||
// If the node is not a protonode, get types by traversing across exports until a proto node is reached.
|
||||
match &implementation {
|
||||
graph_craft::document::DocumentNodeImplementation::Network(internal_network) => {
|
||||
let Some(export) = internal_network.exports.get(output_index) else {
|
||||
return (concrete!(()), TypeSource::Error("Could not get export index"));
|
||||
};
|
||||
match export {
|
||||
NodeInput::Node {
|
||||
node_id: nested_node_id,
|
||||
output_index,
|
||||
..
|
||||
} => self.output_type(nested_node_id, *output_index, &[network_path, &[*node_id]].concat()),
|
||||
NodeInput::Value { tagged_value, .. } => (tagged_value.ty(), TypeSource::TaggedValue),
|
||||
NodeInput::Network { .. } => {
|
||||
// let mut encapsulating_path = network_path.to_vec();
|
||||
// let encapsulating_node = encapsulating_path.pop().expect("No imports exist in document network");
|
||||
// self.input_type(&InputConnector::node(encapsulating_node, *import_index), network_path)
|
||||
(concrete!(()), TypeSource::Error("Could not type from network"))
|
||||
}
|
||||
NodeInput::Scope(_) => todo!(),
|
||||
NodeInput::Inline(_) => todo!(),
|
||||
NodeInput::Reflection(_) => todo!(),
|
||||
}
|
||||
}
|
||||
graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode) => {
|
||||
let node_id_path = &[network_path, &[*node_id]].concat();
|
||||
self.resolved_types
|
||||
.types
|
||||
.get(node_id_path)
|
||||
.map(|ty| (ty.output.clone(), TypeSource::Compiled))
|
||||
.or_else(|| {
|
||||
let node_types = random_protonode_implementation(protonode)?;
|
||||
Some((node_types.return_value.clone(), TypeSource::RandomProtonodeImplementation))
|
||||
})
|
||||
.unwrap_or((concrete!(()), TypeSource::Error("Could not get protonode implementation")))
|
||||
}
|
||||
graph_craft::document::DocumentNodeImplementation::Extract => (concrete!(()), TypeSource::Error("extract node")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<IVec2> {
|
||||
let top_left_position = self
|
||||
.node_click_targets(node_id, network_path)
|
||||
@@ -1231,7 +1155,7 @@ impl NodeNetworkInterface {
|
||||
|
||||
/// Returns the description of the node, or an empty string if it is not set.
|
||||
pub fn description(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
self.get_node_definition(network_path, *node_id)
|
||||
self.node_definition(*node_id, network_path)
|
||||
.map(|node_definition| node_definition.description.to_string())
|
||||
.filter(|description| description != "TODO")
|
||||
.unwrap_or_default()
|
||||
@@ -1568,7 +1492,7 @@ impl NodeNetworkInterface {
|
||||
continue;
|
||||
};
|
||||
nested_network.exports = old_network.exports;
|
||||
nested_network.scope_injections = old_network.scope_injections.into_iter().collect();
|
||||
// nested_network.scope_injections = old_network.scope_injections.into_iter().collect();
|
||||
let Some(nested_network_metadata) = network_metadata.nested_metadata_mut(&network_path) else {
|
||||
log::error!("Could not get nested network in from_old_network");
|
||||
continue;
|
||||
@@ -1621,6 +1545,7 @@ impl NodeNetworkInterface {
|
||||
document_metadata: DocumentMetadata::default(),
|
||||
resolved_types: HashMap::new(),
|
||||
transaction_status: TransactionStatus::Finished,
|
||||
current_hash: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2789,7 +2714,7 @@ impl NodeNetworkInterface {
|
||||
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||
let vertical_start: bool = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||
let thick = vertical_end && vertical_start;
|
||||
let vector_wire = build_vector_wire(output_position, input_position, vertical_start, vertical_end, graph_wire_style);
|
||||
let (vector_wire, _) = build_vector_wire(output_position, input_position, vertical_start, vertical_end, graph_wire_style);
|
||||
|
||||
let mut path_string = String::new();
|
||||
let _ = vector_wire.subpath_to_svg(&mut path_string, DAffine2::IDENTITY);
|
||||
@@ -2799,6 +2724,8 @@ impl NodeNetworkInterface {
|
||||
data_type,
|
||||
thick,
|
||||
dashed: false,
|
||||
center: None,
|
||||
input_sni: None,
|
||||
});
|
||||
|
||||
Some(WirePathUpdate {
|
||||
@@ -2809,14 +2736,14 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
/// Returns the vector subpath and a boolean of whether the wire should be thick.
|
||||
pub fn vector_wire_from_input(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<(Subpath<PointId>, bool)> {
|
||||
pub fn vector_wire_from_input(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<(Subpath<PointId>, bool, DVec2)> {
|
||||
let Some(input_position) = self.get_input_center(input, network_path) else {
|
||||
log::error!("Could not get dom rect for wire end: {:?}", input);
|
||||
return None;
|
||||
};
|
||||
// An upstream output could not be found, so the wire does not exist, but it should still be loaded as as empty vector
|
||||
let Some(upstream_output) = self.upstream_output_connector(input, network_path) else {
|
||||
return Some((Subpath::from_anchors(std::iter::empty(), false), false));
|
||||
return Some((Subpath::from_anchors(std::iter::empty(), false), false, DVec2::default()));
|
||||
};
|
||||
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
||||
log::error!("Could not get dom rect for wire start: {:?}", upstream_output);
|
||||
@@ -2825,19 +2752,23 @@ impl NodeNetworkInterface {
|
||||
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||
let thick = vertical_end && vertical_start;
|
||||
Some((build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style), thick))
|
||||
let (wire, center) = build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style);
|
||||
Some((wire, thick, center))
|
||||
}
|
||||
|
||||
pub fn wire_path_from_input(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, dashed: bool, network_path: &[NodeId]) -> Option<WirePath> {
|
||||
let (vector_wire, thick) = self.vector_wire_from_input(input, graph_wire_style, network_path)?;
|
||||
let (vector_wire, thick, center) = self.vector_wire_from_input(input, graph_wire_style, network_path)?;
|
||||
let mut path_string = String::new();
|
||||
let _ = vector_wire.subpath_to_svg(&mut path_string, DAffine2::IDENTITY);
|
||||
let data_type = FrontendGraphDataType::from_type(&self.input_type(input, network_path).0);
|
||||
let input_sni = self.downstream_caller_from_input(input, network_path).map(|caller| NodeId(caller.0.0 + caller.1 as u64));
|
||||
Some(WirePath {
|
||||
path_string,
|
||||
data_type,
|
||||
thick,
|
||||
dashed,
|
||||
center: Some((center.x, center.y)),
|
||||
input_sni,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6562,7 +6493,6 @@ impl InputPersistentMetadata {
|
||||
struct InputTransientMetadata {
|
||||
wire: TransientMetadata<WirePathUpdate>,
|
||||
caller: Option<CompiledProtonodeInput>,
|
||||
input_type: Option<Type>,
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
|
||||
@@ -12,6 +12,9 @@ pub struct WirePath {
|
||||
pub data_type: FrontendGraphDataType,
|
||||
pub thick: bool,
|
||||
pub dashed: bool,
|
||||
pub center: Option<(f64, f64)>,
|
||||
#[serde(rename = "inputSni")]
|
||||
pub input_sni: Option<NodeId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
@@ -53,7 +56,7 @@ impl GraphWireStyle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool, graph_wire_style: GraphWireStyle) -> Subpath<PointId> {
|
||||
pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool, graph_wire_style: GraphWireStyle) -> (Subpath<PointId>, DVec2) {
|
||||
let grid_spacing = 24.;
|
||||
match graph_wire_style {
|
||||
GraphWireStyle::Direct => {
|
||||
@@ -85,7 +88,7 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical
|
||||
let delta01 = DVec2::new((locations[1].x - locations[0].x) * smoothing, (locations[1].y - locations[0].y) * smoothing);
|
||||
let delta23 = DVec2::new((locations[3].x - locations[2].x) * smoothing, (locations[3].y - locations[2].y) * smoothing);
|
||||
|
||||
Subpath::new(
|
||||
let subpath = Subpath::new(
|
||||
vec![
|
||||
ManipulatorGroup {
|
||||
anchor: locations[0],
|
||||
@@ -113,7 +116,9 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical
|
||||
},
|
||||
],
|
||||
false,
|
||||
)
|
||||
);
|
||||
let center = subpath.center().unwrap();
|
||||
(subpath, center)
|
||||
}
|
||||
GraphWireStyle::GridAligned => {
|
||||
let locations = straight_wire_paths(output_position, input_position, vertical_out, vertical_in);
|
||||
@@ -446,13 +451,13 @@ fn straight_wire_paths(output_position: DVec2, input_position: DVec2, vertical_o
|
||||
vec![IVec2::new(x1, y1), IVec2::new(x20, y1), IVec2::new(x20, y3), IVec2::new(x4, y3)]
|
||||
}
|
||||
|
||||
fn straight_wire_subpath(locations: Vec<IVec2>) -> Subpath<PointId> {
|
||||
fn straight_wire_subpath(locations: Vec<IVec2>) -> (Subpath<PointId>, DVec2) {
|
||||
if locations.is_empty() {
|
||||
return Subpath::new(Vec::new(), false);
|
||||
return (Subpath::new(Vec::new(), false), DVec2::default());
|
||||
}
|
||||
|
||||
if locations.len() == 2 {
|
||||
return Subpath::new(
|
||||
let subpath = Subpath::new(
|
||||
vec![
|
||||
ManipulatorGroup {
|
||||
anchor: locations[0].into(),
|
||||
@@ -469,6 +474,8 @@ fn straight_wire_subpath(locations: Vec<IVec2>) -> Subpath<PointId> {
|
||||
],
|
||||
false,
|
||||
);
|
||||
let center = subpath.center().unwrap();
|
||||
return (subpath, center);
|
||||
}
|
||||
|
||||
let corner_radius = 10;
|
||||
@@ -585,5 +592,7 @@ fn straight_wire_subpath(locations: Vec<IVec2>) -> Subpath<PointId> {
|
||||
out_handle: None,
|
||||
id: PointId::generate(),
|
||||
});
|
||||
Subpath::new(path, false)
|
||||
let subpath = Subpath::new(path, false);
|
||||
let center = subpath.center().unwrap();
|
||||
(subpath, center)
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::prelude::DocumentMessageHandler;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::IVec2;
|
||||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
|
||||
use graph_craft::document::{InputConnector, OutputConnector};
|
||||
use graphene_std::ProtoNodeIdentifier;
|
||||
use graphene_std::text::TypesettingConfig;
|
||||
use graphene_std::uuid::NodeId;
|
||||
@@ -492,7 +493,8 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
|
||||
}
|
||||
});
|
||||
|
||||
for (node_id, node, network_path) in network.recursive_nodes() {
|
||||
for (node_path, node) in network.recursive_nodes() {
|
||||
let (node_id, network_path) = node_path.split_last().unwrap();
|
||||
if let DocumentNodeImplementation::ProtoNode(protonode_id) = &node.implementation {
|
||||
let node_path_without_type_args = protonode_id.name.split('<').next();
|
||||
if let Some(new) = node_path_without_type_args.and_then(|node_path| replacements.get(node_path)) {
|
||||
@@ -509,9 +511,9 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
|
||||
.network_interface
|
||||
.document_network()
|
||||
.recursive_nodes()
|
||||
.map(|(node_id, node, path)| (*node_id, node.clone(), path))
|
||||
.collect::<Vec<(NodeId, graph_craft::document::DocumentNode, Vec<NodeId>)>>();
|
||||
for (node_id, node, network_path) in &nodes {
|
||||
.map(|(node_path, node)| (node_path, node.clone()))
|
||||
.collect::<Vec<(Vec<NodeId>, graph_craft::document::DocumentNode)>>();
|
||||
for (node_path, node) in &nodes {
|
||||
migrate_node(node_id, node, network_path, document, reset_node_definitions_on_open);
|
||||
}
|
||||
}
|
||||
@@ -523,7 +525,6 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template());
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade old nodes to use `Context` instead of `()` or `Footprint` for manual composition
|
||||
if node.manual_composition == Some(graph_craft::concrete!(())) || node.manual_composition == Some(graph_craft::concrete!(graphene_std::transform::Footprint)) {
|
||||
document
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use super::utility_types::PanelType;
|
||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::node_graph_executor::CompilationResponse;
|
||||
use crate::node_graph_executor::IntrospectionResponse;
|
||||
use graph_craft::document::CompilationMetadata;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::renderer::RenderMetadata;
|
||||
use graphene_std::text::Font;
|
||||
use graphene_std::uuid::CompiledProtonodeInput;
|
||||
use graphene_std::{Color, IntrospectMode};
|
||||
|
||||
#[impl_message(Message, Portfolio)]
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
@@ -24,11 +22,24 @@ pub enum PortfolioMessage {
|
||||
#[child]
|
||||
Spreadsheet(SpreadsheetMessage),
|
||||
|
||||
// Introspected data is cleared after all queued messages which relied on the introspection are complete
|
||||
ClearIntrospectedData,
|
||||
|
||||
// Sends a request to compile the network. Should occur when any value, preference, or font changes
|
||||
CompileActiveDocument,
|
||||
// Sends a request to evaluate the network. Should occur when any context value changes.2
|
||||
// Sends a request to evaluate the network. Should occur when any context value changes.
|
||||
EvaluateActiveDocument,
|
||||
|
||||
// Sends a request to introspect data in the network, and return it to the editor
|
||||
IntrospectActiveDocument {
|
||||
inputs_to_introspect: HashSet<CompiledProtonodeInput>,
|
||||
},
|
||||
ExportActiveDocument {
|
||||
file_name: String,
|
||||
file_type: FileType,
|
||||
scale_factor: f64,
|
||||
bounds: ExportBounds,
|
||||
transparent_background: bool,
|
||||
},
|
||||
// Processes the compilation response and updates the data stored in the network interface for the active document
|
||||
// TODO: Add document ID in response for stability
|
||||
ProcessCompilationResponse {
|
||||
@@ -36,12 +47,13 @@ pub enum PortfolioMessage {
|
||||
},
|
||||
ProcessEvaluationResponse {
|
||||
evaluation_metadata: RenderMetadata,
|
||||
},
|
||||
ProcessIntrospectionResponse {
|
||||
#[serde(skip)]
|
||||
introspected_inputs: Vec<(CompiledProtonodeInput, IntrospectMode, Box<dyn std::any::Any + Send + Sync>)>,
|
||||
},
|
||||
ProcessThumbnails {
|
||||
inputs_to_render: HashSet<CompiledProtonodeInput>,
|
||||
introspected_inputs: IntrospectionResponse,
|
||||
},
|
||||
RenderThumbnails,
|
||||
ProcessThumbnails,
|
||||
DocumentPassMessage {
|
||||
document_id: DocumentId,
|
||||
message: DocumentMessage,
|
||||
@@ -134,13 +146,6 @@ pub enum PortfolioMessage {
|
||||
SelectDocument {
|
||||
document_id: DocumentId,
|
||||
},
|
||||
SubmitDocumentExport {
|
||||
file_name: String,
|
||||
file_type: FileType,
|
||||
scale_factor: f64,
|
||||
bounds: ExportBounds,
|
||||
transparent_background: bool,
|
||||
},
|
||||
ToggleRulers,
|
||||
UpdateDocumentWidgets,
|
||||
UpdateOpenDocumentsList,
|
||||
|
||||
@@ -6,24 +6,29 @@ use crate::application::generate_uuid;
|
||||
use crate::consts::{DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX};
|
||||
use crate::messages::debug::utility_types::MessageLoggingVerbosity;
|
||||
use crate::messages::dialog::simple_dialogs;
|
||||
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
||||
use crate::messages::frontend::utility_types::{ExportBounds, FrontendDocumentDetails};
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::DocumentMessageContext;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::portfolio::document_migration::*;
|
||||
use crate::messages::portfolio::spreadsheet::{InspectInputConnector, SpreadsheetMessageHandlerData};
|
||||
use crate::messages::portfolio::spreadsheet::SpreadsheetMessageHandlerData;
|
||||
use crate::messages::preferences::SelectionMode;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
|
||||
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
||||
use crate::node_graph_executor::{CompilationRequest, ExportConfig, NodeGraphExecutor};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graph_craft::document::value::EditorMetadata;
|
||||
use graph_craft::document::{AbsoluteInputConnector, InputConnector, NodeInput, OutputConnector};
|
||||
use graphene_std::any::EditorContext;
|
||||
use graphene_std::application_io::TimingInformation;
|
||||
use graphene_std::memo::IntrospectMode;
|
||||
use graphene_std::renderer::{Quad, RenderMetadata};
|
||||
use graphene_std::text::Font;
|
||||
use std::vec;
|
||||
use graphene_std::transform::{Footprint, RenderQuality};
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, NodeId, SNI};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct PortfolioMessageContext<'a> {
|
||||
@@ -54,9 +59,10 @@ pub struct PortfolioMessageHandler {
|
||||
pub reset_node_definitions_on_open: bool,
|
||||
// Data from the node graph. Data for inputs are set to be collected on each evaluation, and added on the evaluation response
|
||||
// Data from old nodes get deleted after a compilation
|
||||
pub introspected_input_data: HashMap<CompiledProtonodeInput, Box<dyn std::any::Any + Send + Sync>>,
|
||||
pub downcasted_input_data: HashMap<CompiledProtonodeInput, TaggedValue>,
|
||||
pub context_data: HashMap<CompiledProtonodeInput, Context>,
|
||||
// Always take data after requesting it
|
||||
pub introspected_data: HashMap<CompiledProtonodeInput, Option<Arc<dyn std::any::Any + Send + Sync>>>,
|
||||
pub introspected_call_argument: HashMap<CompiledProtonodeInput, Option<Arc<dyn std::any::Any + Send + Sync>>>,
|
||||
pub previous_thumbnail_data: HashMap<CompiledProtonodeInput, Arc<dyn std::any::Any + Send + Sync>>,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
@@ -105,13 +111,18 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
self.menu_bar_message_handler.process_message(message, responses, ());
|
||||
}
|
||||
PortfolioMessage::Spreadsheet(message) => {
|
||||
self.spreadsheet.process_message(message, responses, SpreadsheetMessageHandlerData {introspected_data});
|
||||
self.spreadsheet.process_message(
|
||||
message,
|
||||
responses,
|
||||
SpreadsheetMessageHandlerData {
|
||||
introspected_data: &self.introspected_data,
|
||||
},
|
||||
);
|
||||
}
|
||||
PortfolioMessage::Document(message) => {
|
||||
if let Some(document_id) = self.active_document_id {
|
||||
if let Some(document) = self.documents.get_mut(&document_id) {
|
||||
let document_inputs = DocumentMessageContext {
|
||||
document_id,
|
||||
let document_inputs = DocumentMessageData {
|
||||
ipp,
|
||||
persistent_data: &self.persistent_data,
|
||||
current_tool,
|
||||
@@ -143,8 +154,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
}
|
||||
PortfolioMessage::DocumentPassMessage { document_id, message } => {
|
||||
if let Some(document) = self.documents.get_mut(&document_id) {
|
||||
let document_inputs = DocumentMessageContext {
|
||||
document_id,
|
||||
let document_inputs = DocumentMessageData {
|
||||
ipp,
|
||||
persistent_data: &self.persistent_data,
|
||||
current_tool,
|
||||
@@ -356,12 +366,10 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
PortfolioMessage::NewDocumentWithName { name } => {
|
||||
let mut new_document = DocumentMessageHandler::default();
|
||||
new_document.name = name;
|
||||
responses.add(DocumentMessage::PTZUpdate);
|
||||
|
||||
let document_id = DocumentId(generate_uuid());
|
||||
if self.active_document().is_some() {
|
||||
responses.add(BroadcastEvent::ToolAbort);
|
||||
responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
||||
}
|
||||
|
||||
self.load_document(new_document, document_id, responses, false);
|
||||
@@ -664,13 +672,10 @@ 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::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
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::StartQueue);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
}
|
||||
}
|
||||
PortfolioMessage::PasteSvg {
|
||||
@@ -696,13 +701,10 @@ 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::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
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::StartQueue);
|
||||
responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll);
|
||||
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
}
|
||||
}
|
||||
PortfolioMessage::PrevDocument => {
|
||||
@@ -747,7 +749,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
responses.add(BroadcastEvent::ToolAbort);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
|
||||
if node_graph_open {
|
||||
@@ -768,8 +769,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
}
|
||||
}
|
||||
PortfolioMessage::CompileActiveDocument => {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get(&document_id)) else {
|
||||
log::error!("Tried to render non-existent document: {:?}", document_id);
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get_mut(&document_id)) else {
|
||||
log::error!("Tried to render non-existent document: {:?}", self.active_document_id);
|
||||
return;
|
||||
};
|
||||
if document.network_interface.hash_changed() {
|
||||
@@ -788,37 +789,49 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
},
|
||||
});
|
||||
}
|
||||
// Always evaluate after a recompile
|
||||
responses.add(PortfolioMessage::EvaluateActiveDocument);
|
||||
}
|
||||
PortfolioMessage::ProcessCompilationResponse { compilation_metadata } => {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get(&document_id)) else {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get_mut(&document_id)) else {
|
||||
log::error!("Tried to render non-existent document: {:?}", self.active_document_id);
|
||||
return;
|
||||
};
|
||||
for (AbsoluteInputConnector { network_path, connector }, caller) in compilation_metadata.protonode_callers_for_value {
|
||||
document.network_interface.set_input_caller(connector, caller, &network_path)
|
||||
for (value_connectors, caller) in compilation_metadata.protonode_caller_for_values {
|
||||
for AbsoluteInputConnector { network_path, connector } in value_connectors {
|
||||
let (first, network_path) = network_path.split_first().unwrap();
|
||||
if first != &NodeId(0) {
|
||||
continue;
|
||||
}
|
||||
document.network_interface.set_input_caller(&connector, caller, network_path)
|
||||
}
|
||||
}
|
||||
for (protonode_path, caller) in compilation_metadata.protonode_callers_for_node {
|
||||
let (node_id, network_path) = protonode_path.to_vec().split_last().expect("Protonode path cannot be empty");
|
||||
document.network_interface.set_node_caller(node_id, caller, &network_path)
|
||||
for (protonode_paths, caller) in compilation_metadata.protonode_caller_for_nodes {
|
||||
for protonode_path in protonode_paths {
|
||||
let (first, node_path) = protonode_path.split_first().unwrap();
|
||||
if first != &NodeId(0) {
|
||||
continue;
|
||||
}
|
||||
let (node_id, network_path) = node_path.split_last().expect("Protonode path cannot be empty");
|
||||
document.network_interface.set_node_caller(node_id, caller, &network_path)
|
||||
}
|
||||
}
|
||||
for (sni, input_types) in compilation_metadata.types_to_add {
|
||||
document.network_interface.add_type(sni, input_types);
|
||||
}
|
||||
for ((sni, number_of_inputs)) in compilation_metadata.types_to_remove {
|
||||
// Removed saves type of the document node
|
||||
let mut cleared_thumbnails = Vec::new();
|
||||
for (sni, number_of_inputs) in compilation_metadata.types_to_remove {
|
||||
// Removed saved type of the document node
|
||||
document.network_interface.remove_type(sni);
|
||||
// Remove introspection data for all monitor nodes and the thumbnails
|
||||
let mut cleared_thumbnails = Vec::new();
|
||||
for monitor_index in 0..number_of_inputs {
|
||||
self.introspected_input_data.remove((sni, monitor_index));
|
||||
self.downcasted_input_data.remove((sni, monitor_index));
|
||||
self.context_data.remove((sni, monitor_index));
|
||||
cleared_thumbnails.push(NodeId(sni.0+monitor_index as u64 +1));
|
||||
// Remove all thumbnails
|
||||
for input_index in 0..number_of_inputs {
|
||||
cleared_thumbnails.push(NodeId(sni.0 + input_index as u64 + 1));
|
||||
}
|
||||
responses.add(FrontendMessage::UpdateThumbnails { add: Vec::new(), clear: cleared_thumbnails })
|
||||
}
|
||||
responses.add(FrontendMessage::UpdateThumbnails {
|
||||
add: Vec::new(),
|
||||
clear: cleared_thumbnails,
|
||||
});
|
||||
// Always evaluate after a recompile
|
||||
responses.add(PortfolioMessage::EvaluateActiveDocument);
|
||||
}
|
||||
PortfolioMessage::EvaluateActiveDocument => {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get(&document_id)) else {
|
||||
@@ -827,100 +840,54 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
};
|
||||
|
||||
// Get all the inputs to save data for. This includes vector modify, thumbnails, and spreadsheet data
|
||||
let inputs_to_monitor = HashSet::new();
|
||||
let inputs_to_render = HashSet::new();
|
||||
let inspect_input = None;
|
||||
|
||||
// Get the protonode input for all side layer inputs connected to the export in the document network for thumbnails in the layer panel
|
||||
for caller in document
|
||||
.network_interface
|
||||
.document_metadata()
|
||||
.all_layers()
|
||||
.filter_map(|layer| {
|
||||
let input = InputConnector::Node {
|
||||
node_id: layer.to_node(),
|
||||
input_index: 1,
|
||||
};
|
||||
document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(&input, &[])
|
||||
}) {
|
||||
inputs_to_monitor.insert((*caller, IntrospectMode::Data));
|
||||
inputs_to_render.insert(*caller);
|
||||
}
|
||||
|
||||
// Save data for all inputs in the viewed node graph
|
||||
if document.graph_view_overlay_open {
|
||||
let Some(viewed_network) = document.network_interface.nested_network(&document.breadcrumb_network_path) else {
|
||||
return;
|
||||
};
|
||||
for (export_index, export) in viewed_network.exports.iter().enumerate() {
|
||||
if let Some(caller) = document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(InputConnector::Export(export_index), &document.breadcrumb_network_path)
|
||||
{
|
||||
inputs_to_monitor.push((*caller, IntrospectMode::Data))
|
||||
};
|
||||
if let Some(NodeInput::Node { node_id, .. }) = export {
|
||||
for upstream_node in document
|
||||
.network_interface
|
||||
.upstream_flow_back_from_nodes(vec![*node_id], &document.breadcrumb_network_path, network_interface::FlowType::UpstreamFlow)
|
||||
{
|
||||
let node = viewed_network.nodes[&upstream_node];
|
||||
for (index, _) in node.inputs.iter().enumerate().filter(|(_, node_input)| node_input.is_exposed()) {
|
||||
if let Some(caller) = document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(InputConnector::Node(node_id, index), &document.breadcrumb_network_path)
|
||||
{
|
||||
inputs_to_monitor.insert((*caller, IntrospectMode::Data));
|
||||
inputs_to_render.insert(*caller);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save vector data for all path/transform nodes in the document network
|
||||
match document.network_interface.input_from_connector(&InputConnector::Export(0), &[]) {
|
||||
Some(NodeInput::Node { node_id, .. }) => {
|
||||
for upstream_node in document.network_interface.upstream_flow_back_from_nodes(vec![*node_id], &[], network_interface::FlowType::UpstreamFlow) {
|
||||
let reference = document.network_interface.reference(node_id, &[]).unwrap_or_default().as_deref().unwrap_or_default();
|
||||
if reference == "Path" || reference == "Transform" {
|
||||
let input_connector = InputConnector::Node { node_id, input_index: 0 };
|
||||
let Some(downstream_caller) = document.network_interface.downstream_caller_from_input(&input_connector, &[]) else{
|
||||
log::error!("could not get downstream caller for node : {:?}", node_id);
|
||||
continue;
|
||||
};
|
||||
inputs_to_monitor.push(*downstream_caller)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
// match document.network_interface.input_from_connector(&InputConnector::Export(0), &[]) {
|
||||
// Some(NodeInput::Node { node_id, .. }) => {
|
||||
// for upstream_node in document.network_interface.upstream_flow_back_from_nodes(vec![*node_id], &[], network_interface::FlowType::UpstreamFlow) {
|
||||
// let reference = document.network_interface.reference(&upstream_node, &[]).and_then(|reference| reference.as_deref());
|
||||
// if reference == Some("Path") || reference == Some("Transform") {
|
||||
// let input_connector = InputConnector::Node { node_id: *node_id, input_index: 0 };
|
||||
// let Some(downstream_caller) = document.network_interface.downstream_caller_from_input(&input_connector, &[]) else {
|
||||
// log::error!("could not get downstream caller for node : {:?}", node_id);
|
||||
// continue;
|
||||
// };
|
||||
// inputs_to_monitor.insert((*downstream_caller, IntrospectMode::Data));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
|
||||
// Introspect data for the currently selected node (eventually thumbnail) if the spreadsheet view is open
|
||||
if self.spreadsheet.spreadsheet_view_open {
|
||||
let selected_network_path = &document.selection_network_path;
|
||||
// TODO: Replace with selected thumbnail
|
||||
if let Some(selected_node) = document.network_interface.selected_nodes_in_nested_network(selected_network_path).and_then(|selected_nodes| {
|
||||
if selected_nodes.0.len() == 1 {
|
||||
selected_nodes.0.first().copied()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
// TODO: Introspect any input rather than just the first input of the selected node
|
||||
let selected_connector = InputConnector::Node { node_id: selected_node, input_index: 0 };
|
||||
let Some(caller) = document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(&selected_connector, selected_network_path) else {
|
||||
log::error!("Could not get downstream caller for {:?}", selected_node);
|
||||
};
|
||||
inputs_to_monitor.push((*caller, IntrospectMode::Data));
|
||||
inspect_input = Some(InspectInputConnector { input_connector: AbsoluteInputConnector { network_path: selected_network_path.clone(), connector: selected_connector }, protonode_input: *caller });
|
||||
}
|
||||
}
|
||||
// if self.spreadsheet.spreadsheet_view_open {
|
||||
// let selected_network_path = &document.selection_network_path;
|
||||
// // TODO: Replace with selected thumbnail
|
||||
// if let Some(selected_node) = document
|
||||
// .network_interface
|
||||
// .selected_nodes_in_nested_network(selected_network_path)
|
||||
// .and_then(|selected_nodes| if selected_nodes.0.len() == 1 { selected_nodes.0.first().copied() } else { None })
|
||||
// {
|
||||
// // TODO: Introspect any input rather than just the first input of the selected node
|
||||
// let selected_connector = InputConnector::Node {
|
||||
// node_id: selected_node,
|
||||
// input_index: 0,
|
||||
// };
|
||||
// match document.network_interface.downstream_caller_from_input(&selected_connector, selected_network_path) {
|
||||
// Some(caller) => {
|
||||
// inputs_to_monitor.insert((*caller, IntrospectMode::Data));
|
||||
// inspect_input = Some(InspectInputConnector {
|
||||
// input_connector: AbsoluteInputConnector {
|
||||
// network_path: selected_network_path.clone(),
|
||||
// connector: selected_connector,
|
||||
// },
|
||||
// protonode_input: *caller,
|
||||
// });
|
||||
// }
|
||||
// None => log::error!("Could not get downstream caller for {:?}", selected_connector),
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// let animation_time = match animation.timing_information().animation_time {
|
||||
// AnimationState::Stopped => 0.,
|
||||
@@ -929,67 +896,18 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// };
|
||||
|
||||
let mut context = EditorContext::default();
|
||||
// context.footprint = Some(Footprint {
|
||||
// transform: document.metadata().document_to_viewport,
|
||||
// resolution: ipp.viewport_bounds.size().as_uvec2(),
|
||||
// quality: RenderQuality::Full,
|
||||
// });
|
||||
// context.animation_time = Some(animation_time);
|
||||
// context.real_time = Some(ipp.time);
|
||||
// context.downstream_transform = Some(DAffine2::IDENTITY);
|
||||
let render_config = RenderConfig {
|
||||
viewport: Footprint {
|
||||
transform: document.metadata().document_to_viewport,
|
||||
resolution: ipp.viewport_bounds.size().as_uvec2(),
|
||||
..Default::default()
|
||||
},
|
||||
time: animation.timing_information(),
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
export_format: graphene_std::application_io::ExportFormat::Canvas,
|
||||
#[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
export_format: graphene_std::application_io::ExportFormat::Svg,
|
||||
view_mode: document.view_mode,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
};
|
||||
context.footprint = Some(Footprint {
|
||||
transform: document.metadata().document_to_viewport,
|
||||
resolution: ipp.viewport_bounds.size().as_uvec2(),
|
||||
quality: RenderQuality::Full,
|
||||
});
|
||||
context.animation_time = Some(timing_information.animation_time.as_secs_f64());
|
||||
context.real_time = Some(ipp.time);
|
||||
context.downstream_transform = Some(DAffine2::IDENTITY);
|
||||
|
||||
context.render_config = render_config;
|
||||
|
||||
self.executor.submit_node_graph_evaluation(
|
||||
context,
|
||||
inputs_to_monitor,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
// Queue messages to be run after the evaluation returns data for the inputs to monitor
|
||||
responses.add(Message::StartQueue);
|
||||
if let Some(inspect_input) = inspect_input {
|
||||
responses.add(SpreadsheetMessage::UpdateLayout { inpect_input });
|
||||
}
|
||||
responses.add(PortfolioMessage::ProcessThumbnails {inputs_to_render});
|
||||
responses.add(Message::EndQueue);
|
||||
self.executor.submit_node_graph_evaluation(context, None, None);
|
||||
}
|
||||
PortfolioMessage::ProcessEvaluationResponse { evaluation_metadata, introspected_inputs } => {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get(&document_id)) else {
|
||||
log::error!("Tried to render non-existent document: {:?}", self.active_document_id);
|
||||
return;
|
||||
};
|
||||
|
||||
for (input, mode, data) in introspected_inputs {
|
||||
|
||||
match mode {
|
||||
IntrospectMode::Input => {
|
||||
let Some(context) = data.downcast_ref()
|
||||
self.introspected_input_data.extend(introspected_inputs);
|
||||
|
||||
},
|
||||
IntrospectMode::Data => {
|
||||
self.introspected_input_data.extend(introspected_inputs);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
PortfolioMessage::ProcessEvaluationResponse { evaluation_metadata } => {
|
||||
let RenderMetadata {
|
||||
upstream_footprints: footprints,
|
||||
local_transforms,
|
||||
@@ -1009,25 +927,117 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// AnimationState::Playing { .. } => responses.add(PortfolioMessage::EvaluateActiveDocument),
|
||||
// _ => {}
|
||||
// };
|
||||
},
|
||||
PortfolioMessage::ProcessThumbnails { inputs_to_render } => {
|
||||
let mut thumbnail_response = ThumbnailRenderResponse::default();
|
||||
for thumbnail_input in inputs_to_render {
|
||||
let monitor_node_id = thumbnail_input.0.0 + thumbnail_input.1 as u64 + 1;
|
||||
match self.try_render_thumbnail(&thumbnail_input) {
|
||||
ThumbnailRenderResult::NoChange => {}
|
||||
ThumbnailRenderResult::ClearThumbnail => thumbnail_response.clear.push(NodeId(monitor_node_id)),
|
||||
ThumbnailRenderResult::UpdateThumbnail(thumbnail) => {
|
||||
thumbnail_response.add.push((NodeId(monitor_node_id), thumbnail));
|
||||
},
|
||||
|
||||
// After an evaluation, always render all thumbnails
|
||||
responses.add(PortfolioMessage::RenderThumbnails);
|
||||
}
|
||||
PortfolioMessage::IntrospectActiveDocument { inputs_to_introspect } => {
|
||||
self.executor.submit_node_graph_introspection(inputs_to_introspect);
|
||||
}
|
||||
PortfolioMessage::ProcessIntrospectionResponse { introspected_inputs } => {
|
||||
for (input, mode, data) in introspected_inputs.0.into_iter() {
|
||||
match mode {
|
||||
IntrospectMode::Input => {
|
||||
self.introspected_call_argument.insert(input, data);
|
||||
}
|
||||
IntrospectMode::Data => {
|
||||
self.introspected_data.insert(input, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
responses.add(FrontendMessage::UpdateThumbnails { add: thumbnail_response.add, clear: thumbnail_response.clear })
|
||||
},
|
||||
PortfolioMessage::ActiveDocumentExport {
|
||||
}
|
||||
PortfolioMessage::ClearIntrospectedData => {
|
||||
self.introspected_call_argument.clear();
|
||||
self.introspected_data.clear()
|
||||
}
|
||||
PortfolioMessage::RenderThumbnails => {
|
||||
let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get(&document_id)) else {
|
||||
log::error!("Tried to render non-existent document: {:?}", self.active_document_id);
|
||||
return;
|
||||
};
|
||||
let mut inputs_to_render = HashSet::new();
|
||||
|
||||
// Get the protonode input for all side layer inputs connected to the export in the document network for thumbnails in the layer panel
|
||||
for caller in document.network_interface.document_metadata().all_layers().filter_map(|layer| {
|
||||
let input = InputConnector::Node {
|
||||
node_id: layer.to_node(),
|
||||
input_index: 1,
|
||||
};
|
||||
document.network_interface.downstream_caller_from_input(&input, &[])
|
||||
}) {
|
||||
inputs_to_render.insert(*caller);
|
||||
}
|
||||
|
||||
// Save data for all inputs in the viewed node graph
|
||||
if document.graph_view_overlay_open {
|
||||
let Some(viewed_network) = document.network_interface.nested_network(&document.breadcrumb_network_path) else {
|
||||
return;
|
||||
};
|
||||
for (export_index, export) in viewed_network.exports.iter().enumerate() {
|
||||
match document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(&InputConnector::Export(export_index), &document.breadcrumb_network_path)
|
||||
{
|
||||
Some(caller) => {
|
||||
// inputs_to_monitor.insert((*caller, IntrospectMode::Data));
|
||||
inputs_to_render.insert(*caller);
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
if let NodeInput::Node { node_id, .. } = export {
|
||||
for upstream_node in document
|
||||
.network_interface
|
||||
.upstream_flow_back_from_nodes(vec![*node_id], &document.breadcrumb_network_path, network_interface::FlowType::UpstreamFlow)
|
||||
{
|
||||
let node = &viewed_network.nodes[&upstream_node];
|
||||
for (index, _) in node.inputs.iter().enumerate().filter(|(_, node_input)| node_input.is_exposed()) {
|
||||
if let Some(caller) = document
|
||||
.network_interface
|
||||
.downstream_caller_from_input(&InputConnector::node(upstream_node, index), &document.breadcrumb_network_path)
|
||||
{
|
||||
// inputs_to_monitor.insert((*caller, IntrospectMode::Data));
|
||||
inputs_to_render.insert(*caller);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
responses.add(PortfolioMessage::IntrospectActiveDocument {
|
||||
inputs_to_introspect: inputs_to_render,
|
||||
});
|
||||
responses.add(Message::StartIntrospectionQueue);
|
||||
responses.add(PortfolioMessage::ProcessThumbnails);
|
||||
responses.add(Message::EndIntrospectionQueue);
|
||||
}
|
||||
PortfolioMessage::ProcessThumbnails => {
|
||||
let mut thumbnail_response = ThumbnailRenderResponse::default();
|
||||
for (thumbnail_input, introspected_data) in self.introspected_data.drain() {
|
||||
let input_node_id = thumbnail_input.0.0 + thumbnail_input.1 as u64;
|
||||
|
||||
let Some(evaluated_data) = introspected_data else {
|
||||
// Input was not evaluated, do not change its thumbnail
|
||||
continue;
|
||||
};
|
||||
|
||||
let previous_thumbnail_data = self.previous_thumbnail_data.get(&thumbnail_input);
|
||||
|
||||
match graph_craft::document::value::render_thumbnail_if_change(&evaluated_data, previous_thumbnail_data) {
|
||||
graph_craft::document::value::ThumbnailRenderResult::NoChange => return,
|
||||
graph_craft::document::value::ThumbnailRenderResult::ClearThumbnail => thumbnail_response.clear.push(NodeId(input_node_id)),
|
||||
graph_craft::document::value::ThumbnailRenderResult::UpdateThumbnail(thumbnail) => thumbnail_response.add.push((NodeId(input_node_id), thumbnail)),
|
||||
}
|
||||
self.previous_thumbnail_data.insert(thumbnail_input, evaluated_data);
|
||||
}
|
||||
responses.add(FrontendMessage::UpdateThumbnails {
|
||||
add: thumbnail_response.add,
|
||||
clear: thumbnail_response.clear,
|
||||
})
|
||||
}
|
||||
PortfolioMessage::ExportActiveDocument {
|
||||
file_name,
|
||||
file_type,
|
||||
animation_export_data,
|
||||
scale_factor,
|
||||
bounds,
|
||||
transparent_background,
|
||||
@@ -1035,57 +1045,45 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
let document = self.active_document_id.and_then(|id| self.documents.get_mut(&id)).expect("Tried to render non-existent document");
|
||||
|
||||
// Update the scope inputs with the render settings
|
||||
// self.executor.submit_node_graph_compilation(CompilationRequest {
|
||||
// network: document.network_interface.document_network().clone(),
|
||||
// font_cache: self.persistent_data.font_cache.clone(),
|
||||
// editor_metadata: EditorMetadata {
|
||||
// #[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
// use_vello: preferences.use_vello(),
|
||||
// #[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
// use_vello: false,
|
||||
// hide_artboards: transparent_background,
|
||||
// for_export: true,
|
||||
// view_mode: document.view_mode,
|
||||
// transform_to_viewport: true,
|
||||
// },
|
||||
// });
|
||||
self.executor.submit_node_graph_compilation(CompilationRequest {
|
||||
network: document.network_interface.document_network().clone(),
|
||||
font_cache: self.persistent_data.font_cache.clone(),
|
||||
editor_metadata: EditorMetadata {
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
use_vello: preferences.use_vello(),
|
||||
#[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
use_vello: false,
|
||||
hide_artboards: transparent_background,
|
||||
for_export: true,
|
||||
view_mode: document.view_mode,
|
||||
transform_to_viewport: true,
|
||||
},
|
||||
});
|
||||
|
||||
let document_to_viewport = document.metadata().document_to_viewport;
|
||||
// Calculate the bounding box of the region to be exported
|
||||
let document_bounds = match bounds {
|
||||
let Some(document_bounds) = (match bounds {
|
||||
ExportBounds::AllArtwork => document.network_interface.document_bounds_document_space(!transparent_background),
|
||||
ExportBounds::Selection => document.network_interface.selected_bounds_document_space(!transparent_background, &[]),
|
||||
ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id),
|
||||
// ExportBounds::Viewport => ipp.document_bounds(document_to_viewport),
|
||||
}
|
||||
.ok_or_else(|| "No bounding box".to_string())?;
|
||||
// ExportBounds::Viewport => ipp.document_bounds(document.metadata().document_to_viewport),
|
||||
}) else {
|
||||
log::error!("No bounding box when exporting");
|
||||
return;
|
||||
};
|
||||
|
||||
let size = document_bounds[1] - document_bounds[0];
|
||||
let scaled_size = size * scale_factor;
|
||||
let transform = DAffine2::from_translation(document_bounds[0]).inverse();
|
||||
|
||||
let mut context = EditorContext::default();
|
||||
// context.footprint = Footprint {
|
||||
// document_to_viewport: DAffine2::from_scale(DVec2::splat(scale_factor)) * transform,
|
||||
// resolution: scaled_size.as_uvec2(),
|
||||
// ..Default::default()
|
||||
// };
|
||||
// context.real_time = Some(ipp.time);
|
||||
// context.downstream_transform = Some(DAffine2::IDENTITY);
|
||||
context.footprint = Some(Footprint {
|
||||
transform: DAffine2::from_scale(DVec2::splat(scale_factor)) * transform,
|
||||
resolution: scaled_size.as_uvec2(),
|
||||
..Default::default()
|
||||
});
|
||||
context.real_time = Some(ipp.time);
|
||||
context.downstream_transform = Some(DAffine2::IDENTITY);
|
||||
|
||||
let render_config = RenderConfig {
|
||||
viewport: Footprint {
|
||||
transform: DAffine2::from_scale(DVec2::splat(scale_factor)) * transform,
|
||||
resolution: (size * scale_factor).as_uvec2(),
|
||||
..Default::default()
|
||||
},
|
||||
time: Default::default(),
|
||||
export_format: graphene_std::application_io::ExportFormat::Svg,
|
||||
view_mode: document.view_mode,
|
||||
hide_artboards: transparent_background,
|
||||
for_export: true,
|
||||
};
|
||||
|
||||
context.render_config = render_config;
|
||||
// Special handling for exporting the artwork
|
||||
let file_suffix = &format!(".{file_type:?}").to_lowercase();
|
||||
let file_name = match file_name.ends_with(FILE_SAVE_SUFFIX) {
|
||||
@@ -1093,28 +1091,18 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
false => file_name + file_suffix,
|
||||
};
|
||||
|
||||
let export_config = ExportConfig {
|
||||
file_name,
|
||||
file_type,
|
||||
scale_factor,
|
||||
bounds,
|
||||
transparent_background,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.executor.submit_node_graph_evaluation(
|
||||
context,
|
||||
Vec::new(),
|
||||
None,
|
||||
Some(ExportConfig {
|
||||
file_name,
|
||||
file_type,
|
||||
scale_factor,
|
||||
bounds,
|
||||
transparent_background,
|
||||
size: scaled_size,
|
||||
}),
|
||||
);
|
||||
None,
|
||||
Some(ExportConfig {
|
||||
file_name,
|
||||
file_type,
|
||||
scale_factor,
|
||||
bounds,
|
||||
transparent_background,
|
||||
size: scaled_size,
|
||||
}),
|
||||
);
|
||||
|
||||
// if let Some((start, end, fps)) = animation_export_data {
|
||||
// let total_frames = ((start - end) * fps) as u32;
|
||||
@@ -1155,20 +1143,20 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// }
|
||||
|
||||
// Reset the scope nodes for hide artboards/hide_artboard name
|
||||
// self.executor.submit_node_graph_compilation(CompilationRequest {
|
||||
// network: document.network_interface.document_network().clone(),
|
||||
// font_cache: self.persistent_data.font_cache.clone(),
|
||||
// editor_metadata: EditorMetadata {
|
||||
// #[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
// use_vello: preferences.use_vello().use_vello,
|
||||
// #[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
// use_vello: false,
|
||||
// hide_artboards: false,
|
||||
// for_export: false,
|
||||
// view_mode: document.view_mode,
|
||||
// transform_to_viewport: true,
|
||||
// },
|
||||
// });
|
||||
self.executor.submit_node_graph_compilation(CompilationRequest {
|
||||
network: document.network_interface.document_network().clone(),
|
||||
font_cache: self.persistent_data.font_cache.clone(),
|
||||
editor_metadata: EditorMetadata {
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
use_vello: preferences.use_vello(),
|
||||
#[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
use_vello: false,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
view_mode: document.view_mode,
|
||||
transform_to_viewport: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
PortfolioMessage::ToggleRulers => {
|
||||
@@ -1181,7 +1169,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
}
|
||||
PortfolioMessage::UpdateDocumentWidgets => {
|
||||
if let Some(document) = self.active_document() {
|
||||
document.update_document_widgets(responses, animation.is_playing(), animation_time);
|
||||
document.update_document_widgets(responses, animation.is_playing(), timing_information.animation_time);
|
||||
}
|
||||
}
|
||||
PortfolioMessage::UpdateOpenDocumentsList => {
|
||||
@@ -1333,57 +1321,11 @@ 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::ProcessQueue((graphene_std::renderer::EvaluationMetadata::default(), Vec::new())));
|
||||
responses.add(Message::ProcessEvaluationQueue(graphene_std::renderer::RenderMetadata::default()));
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg: error });
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// Returns an error if the data could not be introspected, returns None if the data type could not be rendered.
|
||||
fn try_render_thumbnail(&self, protonode_input: &CompiledProtonodeInput) -> ThumbnailRenderResult {
|
||||
let Ok(introspected_data) = self.introspected_input_data.get(protonode_input) else {
|
||||
log::error!("Could not introspect node from input: {:?}", protonode_input);
|
||||
return ThumbnailRenderResult::ClearThumbnail;
|
||||
};
|
||||
|
||||
if let Some(previous_tagged_value) = self.downcasted_input_data.get(protonode_input) {
|
||||
if previous_tagged_value.compare_value_to_dyn_any(introspected_data) {
|
||||
return ThumbnailRenderResult::NoChange;
|
||||
}
|
||||
}
|
||||
|
||||
let Ok(new_tagged_value) = TaggedValue::try_from_std_any_ref(&introspected_data) else {
|
||||
return ThumbnailRenderResult::ClearThumbnail;
|
||||
};
|
||||
|
||||
|
||||
let Some(renderable_data) = TaggedValue::as_renderable(&new_tagged_value) else {
|
||||
// New value is not renderable
|
||||
return ThumbnailRenderResult::ClearThumbnail;
|
||||
};
|
||||
|
||||
let render_params = RenderParams {
|
||||
view_mode: ViewMode::Normal,
|
||||
culling_bounds: bounds,
|
||||
thumbnail: true,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
for_mask: false,
|
||||
alignment_parent_transform: None,
|
||||
};
|
||||
|
||||
// Render the thumbnail data into an SVG string
|
||||
let mut render = SvgRender::new();
|
||||
renderable_data.render_svg(&mut render, &render_params);
|
||||
|
||||
// Give the SVG a viewbox and outer <svg>...</svg> wrapper tag
|
||||
let [min, max] = renderable_data.bounding_box(DAffine2::IDENTITY, true).unwrap_or_default();
|
||||
render.format_svg(min, max);
|
||||
|
||||
self.downcasted_input_data.insert(protonode_input, new_tagged_value);
|
||||
|
||||
ThumbnailRenderResult::UpdateThumbnail(render.svg.to_svg_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
@@ -1391,10 +1333,3 @@ pub struct ThumbnailRenderResponse {
|
||||
add: Vec<(SNI, String)>,
|
||||
clear: Vec<SNI>,
|
||||
}
|
||||
|
||||
pub enum ThumbnailRenderResult {
|
||||
NoChange,
|
||||
// Cleared if there is an error or the data could not be rendered
|
||||
ClearThumbnail,
|
||||
UpdateThumbnail(String),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::messages::prelude::*;
|
||||
use graph_craft::document::AbsoluteInputConnector;
|
||||
use graphene_std::uuid::CompiledProtonodeInput;
|
||||
|
||||
@@ -7,7 +8,7 @@ use graphene_std::uuid::CompiledProtonodeInput;
|
||||
pub enum SpreadsheetMessage {
|
||||
ToggleOpen,
|
||||
|
||||
UpdateLayout { inpect_input: InspectInputConnector },
|
||||
UpdateLayout { inspect_input: InspectInputConnector },
|
||||
|
||||
PushToInstancePath { index: usize },
|
||||
TruncateInstancePath { len: usize },
|
||||
@@ -15,7 +16,7 @@ pub enum SpreadsheetMessage {
|
||||
ViewVectorDataDomain { domain: VectorDataDomain },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum VectorDataDomain {
|
||||
#[default]
|
||||
Points,
|
||||
|
||||
@@ -3,21 +3,17 @@ use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup,
|
||||
use crate::messages::portfolio::spreadsheet::InspectInputConnector;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use graph_craft::document::{AbsoluteInputConnector, NodeId};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::Context;
|
||||
use graphene_std::GraphicGroupTable;
|
||||
use graphene_std::instances::Instances;
|
||||
use graphene_std::memo::IORecord;
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::uuid::CompiledProtonodeInput;
|
||||
use graphene_std::vector::{VectorData, VectorDataTable};
|
||||
use graphene_std::{Artboard, ArtboardGroupTable, GraphicElement};
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct SpreadsheetMessageHandlerData {
|
||||
pub introspected_data: &HashMap<CompiledProtonodeInput, Box<dyn std::any::Any + Send + Sync>>;
|
||||
pub struct SpreadsheetMessageHandlerData<'a> {
|
||||
pub introspected_data: &'a HashMap<CompiledProtonodeInput, Option<Arc<dyn std::any::Any + Send + Sync>>>,
|
||||
}
|
||||
|
||||
/// The spreadsheet UI allows for instance data to be previewed.
|
||||
@@ -35,7 +31,7 @@ pub struct SpreadsheetMessageHandler {
|
||||
#[message_handler_data]
|
||||
impl MessageHandler<SpreadsheetMessage, SpreadsheetMessageHandlerData> for SpreadsheetMessageHandler {
|
||||
fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque<Message>, data: SpreadsheetMessageHandlerData) {
|
||||
let {introspected_data} = data;
|
||||
let SpreadsheetMessageHandlerData { introspected_data } = data;
|
||||
match message {
|
||||
SpreadsheetMessage::ToggleOpen => {
|
||||
self.spreadsheet_view_open = !self.spreadsheet_view_open;
|
||||
@@ -48,12 +44,12 @@ impl MessageHandler<SpreadsheetMessage, SpreadsheetMessageHandlerData> for Sprea
|
||||
}
|
||||
// Update checked UI state for open
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
self.update_layout(responses);
|
||||
self.update_layout(introspected_data, responses);
|
||||
}
|
||||
|
||||
// Queued on introspection request, runs on introspection response when the data has been sent back to the editor
|
||||
SpreadsheetMessage::UpdateLayout { inpect_input } => {
|
||||
self.inspect_input = Some(inpect_input);
|
||||
SpreadsheetMessage::UpdateLayout { inspect_input } => {
|
||||
self.inspect_input = Some(inspect_input);
|
||||
self.update_layout(introspected_data, responses);
|
||||
}
|
||||
|
||||
@@ -79,7 +75,7 @@ impl MessageHandler<SpreadsheetMessage, SpreadsheetMessageHandlerData> for Sprea
|
||||
}
|
||||
|
||||
impl SpreadsheetMessageHandler {
|
||||
fn update_layout(&mut self, introspected_data: &HashMap<CompiledProtonodeInput, Box<dyn std::any::Any + Send + Sync>>, responses: &mut VecDeque<Message>) {
|
||||
fn update_layout(&mut self, introspected_data: &HashMap<CompiledProtonodeInput, Option<Arc<dyn std::any::Any + Send + Sync>>>, responses: &mut VecDeque<Message>) {
|
||||
responses.add(FrontendMessage::UpdateSpreadsheetState {
|
||||
// The node is sent when the data is available
|
||||
node: None,
|
||||
@@ -94,18 +90,20 @@ impl SpreadsheetMessageHandler {
|
||||
breadcrumbs: Vec::new(),
|
||||
vector_data_domain: self.viewing_vector_data_domain,
|
||||
};
|
||||
let mut layout = match self.inspect_input {
|
||||
let mut layout = match &self.inspect_input {
|
||||
Some(inspect_input) => {
|
||||
match introspected_data.get(&inspect_input.protonode_input){
|
||||
Some(data) => {
|
||||
match generate_layout(instrospected_data, &mut layout_data) {
|
||||
match introspected_data.get(&inspect_input.protonode_input) {
|
||||
Some(data) => match data {
|
||||
Some(instrospected_data) => match generate_layout(instrospected_data, &mut layout_data) {
|
||||
Some(layout) => layout,
|
||||
None => label("The introspected data is not a supported type to be displayed."),
|
||||
}
|
||||
},
|
||||
None => label("Introspected data is not available for this input. This input may be cached."),
|
||||
},
|
||||
None => label("Introspected data is not available for this input. This input may be cached."),
|
||||
// There should always be an entry for each protonode input. If its empty then it was not requested or an error occured
|
||||
None => label("Error getting introspected data"),
|
||||
}
|
||||
},
|
||||
}
|
||||
None => label("No input selected to show data for."),
|
||||
};
|
||||
|
||||
@@ -130,7 +128,7 @@ struct LayoutData<'a> {
|
||||
vector_data_domain: VectorDataDomain,
|
||||
}
|
||||
|
||||
fn generate_layout(introspected_data: &Box<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
|
||||
fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
|
||||
// We simply try random types. TODO: better strategy.
|
||||
#[allow(clippy::manual_map)]
|
||||
if let Some(io) = introspected_data.downcast_ref::<ArtboardGroupTable>() {
|
||||
|
||||
@@ -2,7 +2,7 @@ use graphene_std::text::FontCache;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PersistentData {
|
||||
pub font_cache: Arc<FontCache>,
|
||||
pub font_cache: std::sync::Arc<FontCache>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -20,10 +20,8 @@ impl PreferencesMessageHandler {
|
||||
self.selection_mode
|
||||
}
|
||||
|
||||
pub fn editor_preferences(&self) -> EditorPreferences {
|
||||
EditorPreferences {
|
||||
use_vello: self.use_vello && self.supports_wgpu(),
|
||||
}
|
||||
pub fn use_vello(&self) -> bool {
|
||||
self.use_vello && self.supports_wgpu()
|
||||
}
|
||||
|
||||
pub fn supports_wgpu(&self) -> bool {
|
||||
|
||||
+2
-3
@@ -3,16 +3,15 @@ use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::Responses;
|
||||
use crate::messages::prelude::{PortfolioMessage, Responses};
|
||||
use crate::messages::prelude::{DocumentMessageHandler, FrontendMessage, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_polygon_parameters, inside_polygon, inside_star, polygon_outline, polygon_vertex_position, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
|
||||
+3
-3
@@ -3,15 +3,15 @@ use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector};
|
||||
use crate::messages::prelude::FrontendMessage;
|
||||
use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext};
|
||||
use crate::messages::prelude::{FrontendMessage, PortfolioMessage};
|
||||
use crate::messages::prelude::Responses;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{draw_snapping_ticks, extract_polygon_parameters, polygon_outline, polygon_vertex_position, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position};
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::{FRAC_1_SQRT_2, FRAC_PI_4, PI, SQRT_2};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::prelude::*;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::NodeInputDecleration;
|
||||
@@ -154,8 +154,9 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
});
|
||||
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(PenToolMessage::RecalculateLatestPointsPosition);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
}
|
||||
|
||||
/// Merge the `first_endpoint` with `second_endpoint`.
|
||||
|
||||
@@ -3,11 +3,11 @@ use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{ NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ use crate::consts::{BOUNDS_SELECT_THRESHOLD, LINE_ROTATE_SNAP_ANGLE};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
pub use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapTypeConfiguration};
|
||||
use crate::messages::tool::tool_messages::shape_tool::ShapeToolData;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::NumberOfPointsDial;
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::NumberOfPointsDialState;
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::PointRadiusHandle;
|
||||
@@ -16,6 +16,7 @@ use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGiz
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::polygon_outline;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::InputConnector;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -3,11 +3,11 @@ use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ use super::ShapeToolData;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage, Responses};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
@@ -11,7 +10,7 @@ use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
use crate::messages::tool::utility_types::*;
|
||||
use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::misc::dvec2_to_point;
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::{NumberOfPointsDial, NumberOfPointsDialState};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::{PointRadiusHandle, PointRadiusHandleState};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
@@ -13,7 +13,7 @@ use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGi
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use core::f64;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapData;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
pub struct ArtboardTool {
|
||||
|
||||
@@ -5,11 +5,11 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::brush::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle};
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::uuid::NodeId;
|
||||
|
||||
const BRUSH_MAX_SIZE: f64 = 5000.;
|
||||
|
||||
@@ -379,8 +379,9 @@ impl Fsm for BrushToolFsmState {
|
||||
else {
|
||||
new_brush_layer(document, responses);
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(BrushToolMessage::DragStart);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
BrushToolFsmState::Ready
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::messages::tool::common_functionality::color_selector::{ToolColorOptio
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::utility_functions::should_extend;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::vector::VectorModificationType;
|
||||
use graphene_std::vector::{PointId, SegmentId};
|
||||
@@ -251,7 +251,6 @@ 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::StartQueue);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
|
||||
tool_data.layer = Some(layer);
|
||||
|
||||
@@ -643,12 +643,12 @@ impl PathToolData {
|
||||
|
||||
self.drag_start_pos = input.mouse.position;
|
||||
|
||||
if input.time - self.last_click_time > DOUBLE_CLICK_MILLISECONDS {
|
||||
if input.time as u64 - self.last_click_time > DOUBLE_CLICK_MILLISECONDS {
|
||||
self.saved_points_before_anchor_convert_smooth_sharp.clear();
|
||||
self.stored_selection = None;
|
||||
}
|
||||
|
||||
self.last_click_time = input.time;
|
||||
self.last_click_time = input.time as u64;
|
||||
|
||||
let old_selection = shape_editor.selected_points().cloned().collect::<Vec<_>>();
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
|
||||
use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, closest_point, should_extend};
|
||||
use bezier_rs::{Bezier, BezierHandles};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::{HandleId, ManipulatorPointId, NoHashBuilder, SegmentId, StrokeId, VectorData};
|
||||
use graphene_std::vector::{PointId, VectorModificationType};
|
||||
|
||||
@@ -1258,9 +1258,10 @@ impl PenToolData {
|
||||
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::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
// 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(Message::EndEvaluationQueue);
|
||||
}
|
||||
|
||||
/// Perform extension of an existing path
|
||||
|
||||
@@ -22,11 +22,11 @@ use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use crate::messages::tool::common_functionality::utility_functions::{resize_bounds, rotate_bounds, skew_bounds, text_bounding_box, transforming_transform_cage};
|
||||
use bezier_rs::Subpath;
|
||||
use glam::DMat2;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::path_bool::BooleanOperation;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::renderer::Rect;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
|
||||
@@ -3,7 +3,6 @@ use crate::consts::{DEFAULT_STROKE_WIDTH, SNAP_POINT_TOLERANCE};
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoManager;
|
||||
@@ -19,9 +18,10 @@ use crate::messages::tool::common_functionality::snapping::{self, SnapCandidateP
|
||||
use crate::messages::tool::common_functionality::transformation_cage::{BoundingBoxManager, EdgeBool};
|
||||
use crate::messages::tool::common_functionality::utility_functions::{closest_point, resize_bounds, rotate_bounds, skew_bounds, transforming_transform_cage};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::misc::ArcType;
|
||||
use std::vec;
|
||||
|
||||
@@ -599,17 +599,16 @@ 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::StartQueue);
|
||||
|
||||
match tool_data.current_shape {
|
||||
ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Polygon | ShapeType::Star => {
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer,
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
});
|
||||
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
}
|
||||
ShapeType::Line => {
|
||||
@@ -617,6 +616,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
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, responses);
|
||||
|
||||
@@ -10,7 +10,8 @@ use crate::messages::tool::common_functionality::color_selector::{ToolColorOptio
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, find_spline, merge_layers, merge_points};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapData, SnapManager, SnapTypeConfiguration, SnappedPoint};
|
||||
use crate::messages::tool::common_functionality::utility_functions::{closest_point, should_extend};
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
|
||||
|
||||
@@ -360,8 +361,6 @@ impl Fsm for SplineToolFsmState {
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
|
||||
tool_data.current_layer = Some(layer);
|
||||
|
||||
responses.add(Message::StartQueue);
|
||||
|
||||
SplineToolFsmState::Drawing
|
||||
}
|
||||
(SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => {
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_RED, DRAG_THRESHOLD};
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
|
||||
@@ -14,10 +13,11 @@ use crate::messages::tool::common_functionality::snapping::{self, SnapCandidateP
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use crate::messages::tool::common_functionality::utility_functions::text_bounding_box;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::document::{InputConnector, NodeInput};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::text::{Font, FontCache, TypesettingConfig, lines_clipping, load_font};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::style::Fill;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
@@ -381,7 +381,7 @@ impl TextToolData {
|
||||
parent: document.new_layer_parent(true),
|
||||
insert_index: 0,
|
||||
});
|
||||
responses.add(Message::StartQueue);
|
||||
responses.add(Message::StartEvaluationQueue);
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: self.layer,
|
||||
fill: if editing_text.color.is_some() {
|
||||
@@ -394,15 +394,14 @@ impl TextToolData {
|
||||
layer: self.layer,
|
||||
transform: editing_text.transform,
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
skip_rerender: false,
|
||||
});
|
||||
self.editing_text = Some(editing_text);
|
||||
|
||||
self.set_editing(true, font_cache, responses);
|
||||
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] });
|
||||
|
||||
responses.add(PortfolioMessage::CompileActiveDocument);
|
||||
responses.add(Message::EndEvaluationQueue);
|
||||
}
|
||||
|
||||
fn check_click(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, font_cache: &FontCache) -> Option<LayerNodeIdentifier> {
|
||||
|
||||
@@ -1,32 +1,18 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::consts::FILE_SAVE_SUFFIX;
|
||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||
use crate::messages::frontend::utility_types::FileType;
|
||||
use crate::messages::prelude::*;
|
||||
use dyn_any::DynAny;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::value::{NetworkOutput, TaggedValue};
|
||||
use graph_craft::document::{
|
||||
AbsoluteInputConnector, AbsoluteOutputConnector, CompilationMetadata, CompiledNodeMetadata, DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, generate_uuid,
|
||||
};
|
||||
use graph_craft::document::value::{EditorMetadata, RenderOutput, TaggedValue};
|
||||
use graph_craft::document::{CompilationMetadata, DocumentNode, NodeNetwork, generate_uuid};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graph_craft::wasm_application_io::{EditorCompilationMetadata, EditorEvaluationMetadata, EditorMetadata};
|
||||
use graphene_std::application_io::{CompilationMetadata, TimingInformation};
|
||||
use graphene_std::application_io::{EditorEvaluationMetadata, NodeGraphUpdateMessage};
|
||||
use graphene_std::any::EditorContext;
|
||||
use graphene_std::memo::IntrospectMode;
|
||||
use graphene_std::renderer::{EvaluationMetadata, format_transform_matrix};
|
||||
use graphene_std::renderer::{RenderMetadata, RenderSvgSegmentList};
|
||||
use graphene_std::renderer::{RenderParams, SvgRender};
|
||||
use graphene_std::renderer::format_transform_matrix;
|
||||
use graphene_std::text::FontCache;
|
||||
use graphene_std::transform::{Footprint, RenderQuality};
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, ProtonodePath, SNI};
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use graphene_std::wasm_application_io::NetworkOutput;
|
||||
use graphene_std::{CompiledProtonodeInput, OwnedContextImpl, SNI};
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, NodeId, SNI};
|
||||
|
||||
mod runtime_io;
|
||||
use interpreted_executor::dynamic_executor::{EditorContext, ResolvedDocumentNodeMetadata};
|
||||
pub use runtime_io::NodeRuntimeIO;
|
||||
|
||||
mod runtime;
|
||||
@@ -35,7 +21,7 @@ pub use runtime::*;
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
pub struct CompilationRequest {
|
||||
pub network: NodeNetwork,
|
||||
// Data which is avaialable from scope inputs (currently WasmEditorApi, but will be split)
|
||||
// Data which is available from scope inputs
|
||||
pub font_cache: Arc<FontCache>,
|
||||
pub editor_metadata: EditorMetadata,
|
||||
}
|
||||
@@ -46,27 +32,34 @@ pub struct CompilationResponse {
|
||||
}
|
||||
|
||||
// Metadata the editor sends when evaluating the network
|
||||
#[derive(Debug, Default, DynAny)]
|
||||
#[derive(Debug, Default, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EvaluationRequest {
|
||||
pub evaluation_id: u64,
|
||||
pub inputs_to_monitor: Vec<(CompiledProtonodeInput, IntrospectMode)>,
|
||||
#[serde(skip)]
|
||||
pub context: EditorContext,
|
||||
// pub custom_node_to_evaluate: Option<SNI>,
|
||||
pub node_to_evaluate: Option<SNI>,
|
||||
}
|
||||
|
||||
// #[cfg_attr(feature = "decouple-execution", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct EvaluationResponse {
|
||||
evaluation_id: u64,
|
||||
result: Result<TaggedValue, String>,
|
||||
introspected_inputs: Vec<(CompiledProtonodeInput, IntrospectMode, Box<dyn std::any::Any + Send + Sync>)>,
|
||||
// TODO: Handle transforming node graph output in the node graph itself
|
||||
transform: DAffine2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct IntrospectionResponse(pub Vec<((NodeId, usize), IntrospectMode, Option<Arc<dyn std::any::Any + Send + Sync>>)>);
|
||||
|
||||
impl PartialEq for IntrospectionResponse {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg_attr(feature = "decouple-execution", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum NodeGraphUpdate {
|
||||
CompilationResponse(CompilationResponse),
|
||||
EvaluationResponse(EvaluationResponse),
|
||||
IntrospectionResponse(IntrospectionResponse),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -98,6 +91,7 @@ impl NodeGraphExecutor {
|
||||
let node_runtime = NodeRuntime::new(request_receiver, response_sender);
|
||||
|
||||
let node_executor = Self {
|
||||
busy: false,
|
||||
futures: HashMap::new(),
|
||||
runtime_io: NodeRuntimeIO::with_channels(request_sender, response_receiver),
|
||||
};
|
||||
@@ -118,34 +112,39 @@ impl NodeGraphExecutor {
|
||||
|
||||
/// Compile the network
|
||||
pub fn submit_node_graph_compilation(&mut self, compilation_request: CompilationRequest) {
|
||||
self.runtime_io.send(GraphRuntimeRequest::CompilationRequest(compilation_request)).map_err(|e| e.to_string());
|
||||
if let Err(error) = self.runtime_io.send(GraphRuntimeRequest::CompilationRequest(compilation_request)) {
|
||||
log::error!("Could not send evaluation request. {:?}", error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an evaluate request for whatever current network is cached.
|
||||
pub fn submit_node_graph_evaluation(
|
||||
&mut self,
|
||||
context: EditorContext,
|
||||
inputs_to_monitor: Vec<(CompiledProtonodeInput, IntrospectMode)>,
|
||||
custom_node_to_evaluate: Option<SNI>,
|
||||
export_config: Option<ExportConfig>,
|
||||
) {
|
||||
/// Adds an evaluation request for whatever current network is cached.
|
||||
pub fn submit_node_graph_evaluation(&mut self, context: EditorContext, node_to_evaluate: Option<SNI>, export_config: Option<ExportConfig>) {
|
||||
let evaluation_id = generate_uuid();
|
||||
self.runtime_io.send(GraphRuntimeRequest::EvaluationRequest(editor_evaluation_request)).map_err(|e| e.to_string());
|
||||
if let Err(error) = self.runtime_io.send(GraphRuntimeRequest::EvaluationRequest(EvaluationRequest {
|
||||
evaluation_id,
|
||||
context,
|
||||
node_to_evaluate,
|
||||
})) {
|
||||
log::error!("Could not send evaluation request. {:?}", error);
|
||||
return;
|
||||
}
|
||||
let evaluation_context = EvaluationContext { export_config };
|
||||
self.futures.insert(evaluation_id, evaluation_context);
|
||||
}
|
||||
|
||||
pub fn submit_node_graph_introspection(&mut self, nodes_to_introspect: HashSet<CompiledProtonodeInput>) {
|
||||
if let Err(error) = self.runtime_io.send(GraphRuntimeRequest::IntrospectionRequest(nodes_to_introspect)) {
|
||||
log::error!("Could not send evaluation request. {:?}", error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Continuously poll the executor (called by request animation frame)
|
||||
pub fn poll_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Result<(), String> {
|
||||
// Moved into portfolio message handler, since this is where the introspected inputs are saved
|
||||
for response in self.runtime_io.receive() {
|
||||
match response {
|
||||
NodeGraphUpdate::EvaluationResponse(EvaluationResponse {
|
||||
evaluation_id,
|
||||
result,
|
||||
transform,
|
||||
introspected_inputs,
|
||||
}) => {
|
||||
NodeGraphUpdate::EvaluationResponse(EvaluationResponse { evaluation_id, result }) => {
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
let node_graph_output = match result {
|
||||
@@ -160,18 +159,14 @@ impl NodeGraphExecutor {
|
||||
let render_output = match node_graph_output {
|
||||
TaggedValue::RenderOutput(render_output) => render_output,
|
||||
value => {
|
||||
return Err("Incorrect render type for exporting (expected NetworkOutput)".to_string());
|
||||
return Err(format!("Incorrect render type for exporting {:?} (expected NetworkOutput)", value.ty()));
|
||||
}
|
||||
};
|
||||
|
||||
let evaluation_context = self.futures.remove(&evaluation_id).ok_or_else(|| "Invalid generation ID".to_string())?;
|
||||
if let Some(export_config) = evaluation_context.export_config {
|
||||
// Export
|
||||
let TaggedValue::RenderOutput(RenderOutput {
|
||||
data: graphene_std::wasm_application_io::RenderOutputType::Svg(svg),
|
||||
..
|
||||
}) = node_graph_output
|
||||
else {
|
||||
let graphene_std::wasm_application_io::RenderOutputType::Svg(svg) = render_output.data else {
|
||||
return Err("Incorrect render type for exporting (expected RenderOutput::Svg)".to_string());
|
||||
};
|
||||
|
||||
@@ -193,7 +188,7 @@ impl NodeGraphExecutor {
|
||||
}
|
||||
} else {
|
||||
// Update artwork
|
||||
self.process_node_graph_output(render_output, introspected_inputs, transform, responses);
|
||||
self.process_node_graph_output(render_output, responses)?
|
||||
}
|
||||
}
|
||||
NodeGraphUpdate::CompilationResponse(compilation_response) => {
|
||||
@@ -213,58 +208,35 @@ impl NodeGraphExecutor {
|
||||
Ok(result) => result,
|
||||
};
|
||||
responses.add(PortfolioMessage::ProcessCompilationResponse { compilation_metadata });
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
NodeGraphUpdate::IntrospectionResponse(introspection_response) => {
|
||||
responses.add(Message::ProcessIntrospectionQueue(introspection_response));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_node_graph_output(
|
||||
&mut self,
|
||||
node_graph_output: TaggedValue,
|
||||
introspected_inputs: Vec<(CompiledProtonodeInput, IntrospectMode, Box<dyn std::any::Any + Send + Sync>)>,
|
||||
transform: DAffine2,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Result<(), String> {
|
||||
let mut render_output_metadata = RenderMetadata::default();
|
||||
match node_graph_output {
|
||||
TaggedValue::RenderOutput(render_output) => {
|
||||
match render_output.data {
|
||||
graphene_std::wasm_application_io::RenderOutputType::Svg(svg) => {
|
||||
// Send to frontend
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
||||
}
|
||||
graphene_std::wasm_application_io::RenderOutputType::CanvasFrame(frame) => {
|
||||
let matrix = format_transform_matrix(frame.transform);
|
||||
let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{}\"", matrix) };
|
||||
let svg = format!(
|
||||
r#"<svg><foreignObject width="{}" height="{}"{transform}><div data-canvas-placeholder="canvas{}"></div></foreignObject></svg>"#,
|
||||
frame.resolution.x, frame.resolution.y, frame.surface_id.0
|
||||
);
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
||||
}
|
||||
_ => {
|
||||
return Err(format!("Invalid node graph output type: {:#?}", render_output.data));
|
||||
}
|
||||
}
|
||||
|
||||
render_output_metadata = render_output.metadata;
|
||||
fn process_node_graph_output(&self, render_output: RenderOutput, responses: &mut VecDeque<Message>) -> Result<(), String> {
|
||||
match render_output.data {
|
||||
graphene_std::wasm_application_io::RenderOutputType::Svg(svg) => {
|
||||
// Send to frontend
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
||||
}
|
||||
graphene_std::wasm_application_io::RenderOutputType::CanvasFrame(frame) => {
|
||||
let matrix = format_transform_matrix(frame.transform);
|
||||
let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{}\"", matrix) };
|
||||
let svg = format!(
|
||||
r#"<svg><foreignObject width="{}" height="{}"{transform}><div data-canvas-placeholder="canvas{}"></div></foreignObject></svg>"#,
|
||||
frame.resolution.x, frame.resolution.y, frame.surface_id.0
|
||||
);
|
||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
||||
}
|
||||
// TaggedValue::Bool(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::String(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::F64(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::DVec2(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::GraphicGroup(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::RasterData(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
// TaggedValue::Palette(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
_ => {
|
||||
return Err(format!("Invalid node graph output type: {node_graph_output:#?}"));
|
||||
return Err(format!("Invalid node graph output type: {:#?}", render_output.data));
|
||||
}
|
||||
};
|
||||
responses.add(Message::ProcessQueue((render_output_metadata, introspected_inputs)));
|
||||
}
|
||||
responses.add(Message::ProcessEvaluationQueue(render_output.metadata));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -404,3 +376,35 @@ impl NodeGraphExecutor {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Passed as a scope input
|
||||
#[derive(Clone, Debug, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EditorMetadata {
|
||||
// pub imaginate_hostname: String,
|
||||
pub use_vello: bool,
|
||||
pub hide_artboards: bool,
|
||||
// If exporting, hide the artboard name and do not collect metadata
|
||||
pub for_export: bool,
|
||||
pub view_mode: graphene_core::vector::style::ViewMode,
|
||||
pub transform_to_viewport: bool,
|
||||
}
|
||||
|
||||
unsafe impl dyn_any::StaticType for EditorMetadata {
|
||||
type Static = EditorMetadata;
|
||||
}
|
||||
|
||||
impl Default for EditorMetadata {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// imaginate_hostname: "http://localhost:7860/".into(),
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use_vello: false,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use_vello: true,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
view_mode: graphene_core::vector::style::ViewMode::Normal,
|
||||
transform_to_viewport: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
use super::*;
|
||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeNetwork};
|
||||
use graph_craft::graphene_compiler::Compiler;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeNetwork;
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graph_craft::wasm_application_io::EditorPreferences;
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graphene_std::Context;
|
||||
use graphene_std::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_std::instances::Instance;
|
||||
use graphene_std::memo::IORecord;
|
||||
use graphene_std::renderer::{GraphicElementRendered, RenderParams, SvgRender};
|
||||
use graphene_std::renderer::{RenderSvgSegmentList, SvgSegment};
|
||||
use graphene_std::text::FontCache;
|
||||
use graphene_std::uuid::{CompiledProtonodeInput, NodeId};
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use graphene_std::vector::{VectorData, VectorDataTable};
|
||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||
use graphene_std::uuid::CompiledProtonodeInput;
|
||||
use graphene_std::wasm_application_io::WasmApplicationIo;
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
use interpreted_executor::util::wrap_network_in_scope;
|
||||
use once_cell::sync::Lazy;
|
||||
use spin::Mutex;
|
||||
@@ -41,9 +29,6 @@ pub struct NodeRuntime {
|
||||
|
||||
node_graph_errors: GraphErrors,
|
||||
|
||||
/// Which node is inspected and which monitor node is used (if any) for the current execution
|
||||
inspect_state: Option<InspectState>,
|
||||
|
||||
/// Mapping of the fully-qualified node paths to their preprocessor substitutions.
|
||||
substitutions: HashMap<ProtoNodeIdentifier, DocumentNode>,
|
||||
|
||||
@@ -61,10 +46,10 @@ pub enum GraphRuntimeRequest {
|
||||
// Renders thumbnails for the data from the last execution
|
||||
// If the upstream node stores data for the context override, then another evaluation must be performed at the input
|
||||
// This is performed separately from execution requests, since thumbnails for animation should be updated once every 50ms or so.
|
||||
ThumbnailRenderRequest(HashSet<CompiledProtonodeInput>),
|
||||
// ThumbnailRenderRequest(HashSet<CompiledProtonodeInput>),
|
||||
// Request the data from a list of node inputs. For example, used by vector modify to get the data at the input of every Path node.
|
||||
// Can also be used by the spreadsheet/introspection system
|
||||
IntrospectionRequest(HashSet<(CompiledProtonodeInput, IntrospectMode)>),
|
||||
IntrospectionRequest(HashSet<CompiledProtonodeInput>),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
@@ -87,6 +72,9 @@ impl NodeGraphRuntimeSender {
|
||||
fn send_evaluation_response(&self, response: EvaluationResponse) {
|
||||
self.0.send(NodeGraphUpdate::EvaluationResponse(response)).expect("Failed to send evaluation response")
|
||||
}
|
||||
fn send_introspection_response(&self, response: IntrospectionResponse) {
|
||||
self.0.send(NodeGraphUpdate::IntrospectionResponse(response)).expect("Failed to send introspection response")
|
||||
}
|
||||
}
|
||||
|
||||
pub static NODE_RUNTIME: Lazy<Mutex<Option<NodeRuntime>>> = Lazy::new(|| Mutex::new(None));
|
||||
@@ -103,119 +91,103 @@ impl NodeRuntime {
|
||||
node_graph_errors: Vec::new(),
|
||||
|
||||
substitutions: preprocessor::generate_node_substitutions(),
|
||||
thumbnail_render_tagged_values: HashSet::new(),
|
||||
inspect_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
if self.application_io.is_none() {
|
||||
#[cfg(not(test))]
|
||||
// #[cfg(not(test))]
|
||||
self.application_io = Some(Arc::new(WasmApplicationIo::new().await));
|
||||
#[cfg(test)]
|
||||
self.application_io = Some(Arc::new(WasmApplicationIo::new_offscreen().await));
|
||||
// #[cfg(test)]
|
||||
// self.application_io = Some(Arc::new(WasmApplicationIo::new_offscreen().await));
|
||||
}
|
||||
|
||||
// TODO: This deduplication of messages will probably cause more issues than it solved
|
||||
// let mut graph = None;
|
||||
// let mut execution = None;
|
||||
// let mut thumbnails = None;
|
||||
// let mut introspection = None;
|
||||
// for request in self.receiver.try_iter() {
|
||||
// match request {
|
||||
// GraphRuntimeRequest::CompilationRequest(_) => graph = Some(request),
|
||||
// GraphRuntimeRequest::EvaluationRequest(_) => execution = Some(request),
|
||||
// GraphRuntimeRequest::ThumbnailRenderResponse(_) => thumbnails = Some(request),
|
||||
// GraphRuntimeRequest::IntrospectionResponse(_) => introspection = Some(request),
|
||||
// }
|
||||
// }
|
||||
// let requests = [font, preferences, graph, execution].into_iter().flatten();
|
||||
|
||||
// TODO: This deduplication of messages will probably cause issues
|
||||
let mut compilation = None;
|
||||
let mut evaluation = None;
|
||||
let mut introspection = None;
|
||||
for request in self.receiver.try_iter() {
|
||||
match request {
|
||||
GraphRuntimeRequest::CompilationRequest(CompilationRequest {
|
||||
mut network,
|
||||
font_cache,
|
||||
editor_metadata,
|
||||
}) => {
|
||||
GraphRuntimeRequest::CompilationRequest(_) => compilation = Some(request),
|
||||
GraphRuntimeRequest::EvaluationRequest(_) => evaluation = Some(request),
|
||||
GraphRuntimeRequest::IntrospectionRequest(_) => introspection = Some(request),
|
||||
}
|
||||
}
|
||||
let requests = [compilation, evaluation, introspection].into_iter().flatten();
|
||||
|
||||
for request in requests {
|
||||
match request {
|
||||
GraphRuntimeRequest::CompilationRequest(CompilationRequest { network, font_cache, editor_metadata }) => {
|
||||
// Insert the monitor node to manage the inspection
|
||||
// self.inspect_state = inspect_node.map(|inspect| InspectState::monitor_inspect_node(&mut network, inspect));
|
||||
|
||||
self.node_graph_errors.clear();
|
||||
let result = self.update_network(network).await;
|
||||
let result = self.update_network(network, font_cache, editor_metadata).await;
|
||||
self.sender.send_compilation_response(CompilationResponse {
|
||||
result,
|
||||
node_graph_errors: self.node_graph_errors.clone(),
|
||||
});
|
||||
}
|
||||
// Inputs to monitor is sent from the editor, and represents a list of input connectors to track the data through
|
||||
// During the execution. If the value is None, then the node was not evaluated, which can occur due to caching
|
||||
GraphRuntimeRequest::EvaluationRequest(EvaluationRequest {
|
||||
evaluation_id,
|
||||
context,
|
||||
inputs_to_monitor,
|
||||
// custom_node_to_evaluate
|
||||
node_to_evaluate,
|
||||
}) => {
|
||||
for (protonode_input, introspect_mode) in inputs_to_monitor {
|
||||
self.executor.set_introspect(protonode_input, introspect_mode)
|
||||
}
|
||||
let transform = context.render_config.viewport.transform;
|
||||
// for (protonode_input, introspect_mode) in &inputs_to_monitor {
|
||||
// self.executor.set_introspect(*protonode_input, *introspect_mode)
|
||||
// }
|
||||
let result = self.executor.evaluate_from_node(context, node_to_evaluate).await;
|
||||
|
||||
let result = self.execute_network(render_config).await;
|
||||
|
||||
let introspected_inputs = Vec::new();
|
||||
for (protonode_input, mode) in inputs_to_introspect {
|
||||
let Ok(introspected_data) = self.executor.introspect(protonode_input, mode) else {
|
||||
log::error!("Could not introspect node from input: {:?}", protonode_input);
|
||||
continue;
|
||||
self.sender.send_evaluation_response(EvaluationResponse { evaluation_id, result });
|
||||
}
|
||||
// GraphRuntimeRequest::ThumbnailRenderRequest(_) => {}
|
||||
GraphRuntimeRequest::IntrospectionRequest(inputs) => {
|
||||
let mut introspected_inputs = Vec::new();
|
||||
for protonode_input in inputs {
|
||||
let introspected_data = match self.executor.introspect(protonode_input, IntrospectMode::Data) {
|
||||
Ok(introspected_data) => introspected_data,
|
||||
Err(e) => {
|
||||
log::error!("Could not introspect input: {:?}, error: {:?}", protonode_input, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
introspected_inputs.push((protonode_input, mode, introspected_data));
|
||||
introspected_inputs.push((protonode_input, IntrospectMode::Data, introspected_data));
|
||||
}
|
||||
|
||||
self.sender.send_evaluation_response(EvaluationResponse {
|
||||
evaluation_id,
|
||||
result,
|
||||
transform,
|
||||
introspected_inputs,
|
||||
});
|
||||
}
|
||||
GraphRuntimeRequest::ThumbnailRenderRequest(input_to_render) => {
|
||||
let mut thumbnail_response = ThumbnailRenderResponse::default();
|
||||
for input in input_to_render {}
|
||||
self.sender.send_thumbnail_render_response(thumbnail_response);
|
||||
}
|
||||
GraphRuntimeRequest::IntrospectionRequest(inputs_to_introspect) => {
|
||||
self.sender.send_introspection_response(introspection_response);
|
||||
self.sender.send_introspection_response(IntrospectionResponse(introspected_inputs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_network(&mut self, mut graph: NodeNetwork) -> Result<CompilationMetadata, String> {
|
||||
async fn update_network(&mut self, mut graph: NodeNetwork, font_cache: Arc<FontCache>, editor_metadata: EditorMetadata) -> Result<CompilationMetadata, String> {
|
||||
preprocessor::expand_network(&mut graph, &self.substitutions);
|
||||
|
||||
// Creates a network where the node paths to the document network are prefixed with NodeId(0)
|
||||
let scoped_network = wrap_network_in_scope(graph, self.editor_api.clone());
|
||||
let mut scoped_network = wrap_network_in_scope(graph, font_cache, editor_metadata, self.application_io.as_ref().unwrap().clone());
|
||||
|
||||
// We assume only one output
|
||||
assert_eq!(scoped_network.exports.len(), 1, "Graph with multiple outputs not yet handled");
|
||||
|
||||
// Modifies the NodeNetwork so the tagged values are removed and the document nodes with protonode implementations have their protonode ids set
|
||||
// Needs to return a mapping of absolute input connectors to protonode callers, types for protonodes, and callers for protonodes, add/remove delta for resolved types
|
||||
let (proto_network, protonode_callers_for_value, protonode_callers_for_node) = match scoped_network.flatten() {
|
||||
let (proto_network, protonode_caller_for_values, protonode_caller_for_nodes) = match scoped_network.flatten() {
|
||||
Ok(network) => network,
|
||||
Err(e) => {
|
||||
log::error!("Error compiling network: {e:?}");
|
||||
return;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
assert_ne!(proto_network.len(), 0, "No proto nodes exist?");
|
||||
let result = match self.executor.update(proto_network).await {
|
||||
Ok((types_to_add, types_to_remove)) => {
|
||||
// Used to remove thumbnails from the mapping of SNI to rendered SVG strings on the frontend, which occurs when the SNI is removed
|
||||
// When native frontend rendering is possible, the strings can just be stored in the network interface for each protonode with the rest of the type metadata
|
||||
Ok(CompilationMetadata {
|
||||
protonode_callers_for_value,
|
||||
protonode_callers_for_node,
|
||||
protonode_caller_for_values,
|
||||
protonode_caller_for_nodes,
|
||||
types_to_add,
|
||||
types_to_remove,
|
||||
})
|
||||
@@ -225,23 +197,8 @@ impl NodeRuntime {
|
||||
Err(format!("{e:?}"))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn execute_network(&mut self, render_config: RenderConfig) -> Result<TaggedValue, String> {
|
||||
use graph_craft::graphene_compiler::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(RenderConfig) => (&self.executor).execute(render_config).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => (&self.executor).execute(()).await.map_err(|e| e.to_string()),
|
||||
Some(t) => Err(format!("Invalid input type {t:?}")),
|
||||
_ => Err(format!("No input type:\n{:?}", self.node_graph_errors)),
|
||||
};
|
||||
let result = match result {
|
||||
Ok(value) => value,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
// log::debug!("result: {:?}", result);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user