Improve older document upgrading compatibility and make node type errors clearer (#2201)
* Improve older document upgrading compatibility and make node type errors clearer Misc. * Fixes * Avoid unwrap
This commit is contained in:
parent
eec0ef761c
commit
8505ed3f10
|
|
@ -6,7 +6,7 @@
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/node:1": {}
|
"ghcr.io/devcontainers/features/node:1": {}
|
||||||
},
|
},
|
||||||
"onCreateCommand": "cargo install wasm-pack cargo-watch cargo-about",
|
"onCreateCommand": "cargo install cargo-watch wasm-pack cargo-about && cargo install -f wasm-bindgen-cli@0.2.99",
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
// NOTE: Keep this in sync with `.vscode/extensions.json`
|
// NOTE: Keep this in sync with `.vscode/extensions.json`
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
// Rust
|
// Rust
|
||||||
"rust-lang.rust-analyzer",
|
"rust-lang.rust-analyzer",
|
||||||
"tamasfe.even-better-toml",
|
"tamasfe.even-better-toml",
|
||||||
"serayuzgur.crates",
|
|
||||||
// Web
|
// Web
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"svelte.svelte-vscode",
|
"svelte.svelte-vscode",
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ jobs:
|
||||||
name: Run Clippy
|
name: Run Clippy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# TODO(Keavon): Find a workaround (passing the output text to a separate action with permission to read the secrets?) that allows this to work on fork PRs
|
# TODO(Keavon): Find a workaround (passing the output text to a separate action with permission to read the secrets?) that allows this to work on fork PRs
|
||||||
if: ${{ !github.event.pull_request.draft && !github.event.pull_request.head.repo.fork }}
|
if: false
|
||||||
|
# if: ${{ !github.event.pull_request.draft && !github.event.pull_request.head.repo.fork }}
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub struct NodePropertiesContext<'a> {
|
||||||
impl NodePropertiesContext<'_> {
|
impl NodePropertiesContext<'_> {
|
||||||
pub fn call_widget_override(&mut self, node_id: &NodeId, index: usize) -> Option<Vec<LayoutGroup>> {
|
pub fn call_widget_override(&mut self, node_id: &NodeId, index: usize) -> Option<Vec<LayoutGroup>> {
|
||||||
let Some(input_properties_row) = self.network_interface.input_properties_row(node_id, index, self.selection_network_path) else {
|
let Some(input_properties_row) = self.network_interface.input_properties_row(node_id, index, self.selection_network_path) else {
|
||||||
log::error!("Could not get input properties row in call_widget_override");
|
log::error!("Could not get input properties row at the beginning of call_widget_override");
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
if let Some(widget_override) = &input_properties_row.widget_override {
|
if let Some(widget_override) = &input_properties_row.widget_override {
|
||||||
|
|
@ -2466,7 +2466,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
nodes: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorData), 0)],
|
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorData), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_nodes::SubpathSegmentLengthsNode")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SubpathSegmentLengthsNode")),
|
||||||
manual_composition: Some(generic!(T)),
|
manual_composition: Some(generic!(T)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
@ -2479,7 +2479,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
NodeInput::network(concrete!(bool), 4), // From the document node's parameters
|
NodeInput::network(concrete!(bool), 4), // From the document node's parameters
|
||||||
NodeInput::node(NodeId(0), 0), // From output 0 of SubpathSegmentLengthsNode
|
NodeInput::node(NodeId(0), 0), // From output 0 of SubpathSegmentLengthsNode
|
||||||
],
|
],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_nodes::SamplePointsNode")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SamplePointsNode")),
|
||||||
manual_composition: Some(generic!(T)),
|
manual_composition: Some(generic!(T)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -240,8 +240,7 @@ pub(crate) fn property_from_type(node_id: NodeId, index: usize, ty: &Type, conte
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
TextLabel::new("-")
|
TextLabel::new("-")
|
||||||
.tooltip(format!(
|
.tooltip(format!(
|
||||||
"This data can only be supplied through the\n\
|
"This data can only be supplied through the node graph because no widget exists for its type:\n\
|
||||||
node graph because no widget exists for its type:\n\
|
|
||||||
{}",
|
{}",
|
||||||
concrete_type.name
|
concrete_type.name
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
|
||||||
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
||||||
|
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{NodeId, NodeInput};
|
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||||
use graphene_core::text::{Font, TypesettingConfig};
|
use graphene_core::text::{Font, TypesettingConfig};
|
||||||
use graphene_std::vector::style::{Fill, FillType, Gradient};
|
use graphene_std::vector::style::{Fill, FillType, Gradient};
|
||||||
use interpreted_executor::dynamic_executor::IntrospectError;
|
use interpreted_executor::dynamic_executor::IntrospectError;
|
||||||
|
|
@ -383,11 +383,25 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
document_is_saved,
|
document_is_saved,
|
||||||
document_serialized_content,
|
document_serialized_content,
|
||||||
} => {
|
} => {
|
||||||
|
// TODO: Eventually remove this document upgrade code
|
||||||
|
// This big code block contains lots of hacky code for upgrading old documents to the new format
|
||||||
|
|
||||||
// It can be helpful to temporarily set `upgrade_from_before_editable_subgraphs` to true if it's desired to upgrade a piece of artwork to use fresh copies of all nodes
|
// It can be helpful to temporarily set `upgrade_from_before_editable_subgraphs` to true if it's desired to upgrade a piece of artwork to use fresh copies of all nodes
|
||||||
let replace_implementations_from_definition = document_serialized_content.contains("node_output_index");
|
let replace_implementations_from_definition = document_serialized_content.contains("node_output_index");
|
||||||
|
// Upgrade layer implementation from https://github.com/GraphiteEditor/Graphite/pull/1946 (see also `fn fix_nodes()` in `main.rs` of Graphene CLI)
|
||||||
|
let upgrade_from_before_returning_nested_click_targets =
|
||||||
|
document_serialized_content.contains("graphene_core::ConstructLayerNode") || document_serialized_content.contains("graphene_core::AddArtboardNode");
|
||||||
let upgrade_vector_manipulation_format = document_serialized_content.contains("ManipulatorGroupIds") && !document_name.contains("__DO_NOT_UPGRADE__");
|
let upgrade_vector_manipulation_format = document_serialized_content.contains("ManipulatorGroupIds") && !document_name.contains("__DO_NOT_UPGRADE__");
|
||||||
let document_name = document_name.replace("__DO_NOT_UPGRADE__", "");
|
let document_name = document_name.replace("__DO_NOT_UPGRADE__", "");
|
||||||
|
|
||||||
|
const TEXT_REPLACEMENTS: [(&str, &str); 2] = [
|
||||||
|
("graphene_core::vector::vector_nodes::SamplePointsNode", "graphene_core::vector::SamplePointsNode"),
|
||||||
|
("graphene_core::vector::vector_nodes::SubpathSegmentLengthsNode", "graphene_core::vector::SubpathSegmentLengthsNode"),
|
||||||
|
];
|
||||||
|
let document_serialized_content = TEXT_REPLACEMENTS
|
||||||
|
.iter()
|
||||||
|
.fold(document_serialized_content, |document_serialized_content, (old, new)| document_serialized_content.replace(old, new));
|
||||||
|
|
||||||
let document = DocumentMessageHandler::deserialize_document(&document_serialized_content).map(|mut document| {
|
let document = DocumentMessageHandler::deserialize_document(&document_serialized_content).map(|mut document| {
|
||||||
document.name.clone_from(&document_name);
|
document.name.clone_from(&document_name);
|
||||||
document
|
document
|
||||||
|
|
@ -407,9 +421,72 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Eventually remove this document upgrade code
|
const REPLACEMENTS: [(&str, &str); 36] = [
|
||||||
|
("graphene_core::AddArtboardNode", "graphene_core::graphic_element::AppendArtboardNode"),
|
||||||
|
("graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"),
|
||||||
|
("graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"),
|
||||||
|
("graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"),
|
||||||
|
("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"),
|
||||||
|
("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"),
|
||||||
|
("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"),
|
||||||
|
("graphene_core::ops::ConstructVector2", "graphene_core::ops::Vector2ValueNode"),
|
||||||
|
("graphene_core::raster::BlackAndWhiteNode", "graphene_core::raster::adjustments::BlackAndWhiteNode"),
|
||||||
|
("graphene_core::raster::BlendNode", "graphene_core::raster::adjustments::BlendNode"),
|
||||||
|
("graphene_core::raster::ChannelMixerNode", "graphene_core::raster::adjustments::ChannelMixerNode"),
|
||||||
|
("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_core::raster::adjustments::ColorOverlayNode"),
|
||||||
|
("graphene_core::raster::ExposureNode", "graphene_core::raster::adjustments::ExposureNode"),
|
||||||
|
("graphene_core::raster::ExtractChannelNode", "graphene_core::raster::adjustments::ExtractChannelNode"),
|
||||||
|
("graphene_core::raster::GradientMapNode", "graphene_core::raster::adjustments::GradientMapNode"),
|
||||||
|
("graphene_core::raster::HueSaturationNode", "graphene_core::raster::adjustments::HueSaturationNode"),
|
||||||
|
("graphene_core::raster::IndexNode", "graphene_core::raster::adjustments::IndexNode"),
|
||||||
|
("graphene_core::raster::InvertNode", "graphene_core::raster::adjustments::InvertNode"),
|
||||||
|
("graphene_core::raster::InvertRGBNode", "graphene_core::raster::adjustments::InvertNode"),
|
||||||
|
("graphene_core::raster::LevelsNode", "graphene_core::raster::adjustments::LevelsNode"),
|
||||||
|
("graphene_core::raster::LuminanceNode", "graphene_core::raster::adjustments::LuminanceNode"),
|
||||||
|
("graphene_core::raster::ExtractOpaqueNode", "graphene_core::raster::adjustments::MakeOpaqueNode"),
|
||||||
|
("graphene_core::raster::PosterizeNode", "graphene_core::raster::adjustments::PosterizeNode"),
|
||||||
|
("graphene_core::raster::ThresholdNode", "graphene_core::raster::adjustments::ThresholdNode"),
|
||||||
|
("graphene_core::raster::VibranceNode", "graphene_core::raster::adjustments::VibranceNode"),
|
||||||
|
("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"),
|
||||||
|
("graphene_core::transform::SetTransformNode", "graphene_core::transform::ReplaceTransformNode"),
|
||||||
|
("graphene_core::vector::generator_nodes::EllipseGenerator", "graphene_core::vector::generator_nodes::EllipseNode"),
|
||||||
|
("graphene_core::vector::generator_nodes::LineGenerator", "graphene_core::vector::generator_nodes::LineNode"),
|
||||||
|
("graphene_core::vector::generator_nodes::PathGenerator", "graphene_core::vector::generator_nodes::PathNode"),
|
||||||
|
("graphene_core::vector::generator_nodes::RectangleGenerator", "graphene_core::vector::generator_nodes::RectangleNode"),
|
||||||
|
(
|
||||||
|
"graphene_core::vector::generator_nodes::RegularPolygonGenerator",
|
||||||
|
"graphene_core::vector::generator_nodes::RegularPolygonNode",
|
||||||
|
),
|
||||||
|
("graphene_core::vector::generator_nodes::SplineGenerator", "graphene_core::vector::generator_nodes::SplineNode"),
|
||||||
|
("graphene_core::vector::generator_nodes::StarGenerator", "graphene_core::vector::generator_nodes::StarNode"),
|
||||||
|
("graphene_std::executor::BlendGpuImageNode", "graphene_std::gpu_nodes::BlendGpuImageNode"),
|
||||||
|
("graphene_std::raster::SampleNode", "graphene_std::raster::SampleImageNode"),
|
||||||
|
];
|
||||||
|
for node_id in &document
|
||||||
|
.network_interface
|
||||||
|
.network_metadata(&[])
|
||||||
|
.unwrap()
|
||||||
|
.persistent_metadata
|
||||||
|
.node_metadata
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<NodeId>>()
|
||||||
|
{
|
||||||
|
if let Some(DocumentNodeImplementation::ProtoNode(protonode_id)) = document.network_interface.network(&[]).unwrap().nodes.get(node_id).map(|node| node.implementation.clone()) {
|
||||||
|
for (old, new) in REPLACEMENTS {
|
||||||
|
let node_path_without_type_args = protonode_id.name.split('<').next();
|
||||||
|
if node_path_without_type_args == Some(old) {
|
||||||
|
document
|
||||||
|
.network_interface
|
||||||
|
.replace_implementation(node_id, &[], DocumentNodeImplementation::ProtoNode(new.to_string().into()));
|
||||||
|
document.network_interface.set_manual_compostion(node_id, &[], Some(graph_craft::Type::Generic("T".into())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Upgrade all old nodes to support editable subgraphs introduced in #1750
|
// Upgrade all old nodes to support editable subgraphs introduced in #1750
|
||||||
if replace_implementations_from_definition {
|
if replace_implementations_from_definition || upgrade_from_before_returning_nested_click_targets {
|
||||||
// This can be used, if uncommented, to upgrade demo artwork with outdated document node internals from their definitions. Delete when it's no longer needed.
|
// This can be used, if uncommented, to upgrade demo artwork with outdated document node internals from their definitions. Delete when it's no longer needed.
|
||||||
// Used for upgrading old internal networks for demo artwork nodes. Will reset all node internals for any opened file
|
// Used for upgrading old internal networks for demo artwork nodes. Will reset all node internals for any opened file
|
||||||
for node_id in &document
|
for node_id in &document
|
||||||
|
|
@ -431,12 +508,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
.get(node_id)
|
.get(node_id)
|
||||||
.and_then(|node| node.persistent_metadata.reference.as_ref())
|
.and_then(|node| node.persistent_metadata.reference.as_ref())
|
||||||
{
|
{
|
||||||
let node_definition = resolve_document_node_type(reference).unwrap();
|
let Some(node_definition) = resolve_document_node_type(reference) else { continue };
|
||||||
let default_definition_node = node_definition.default_node_template();
|
let default_definition_node = node_definition.default_node_template();
|
||||||
document.network_interface.replace_implementation(node_id, &[], default_definition_node.document_node.implementation);
|
document.network_interface.replace_implementation(node_id, &[], default_definition_node.document_node.implementation);
|
||||||
document
|
document
|
||||||
.network_interface
|
.network_interface
|
||||||
.replace_implementation_metadata(node_id, &[], default_definition_node.persistent_node_metadata);
|
.replace_implementation_metadata(node_id, &[], default_definition_node.persistent_node_metadata);
|
||||||
|
document.network_interface.set_manual_compostion(node_id, &[], default_definition_node.document_node.manual_composition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -460,8 +538,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Upgrade Fill nodes to the format change in #1778
|
|
||||||
// TODO: Eventually remove this document upgrade code
|
|
||||||
let Some(ref reference) = node_metadata.persistent_metadata.reference.clone() else {
|
let Some(ref reference) = node_metadata.persistent_metadata.reference.clone() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
@ -472,6 +548,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
};
|
};
|
||||||
let inputs_count = node.inputs.len();
|
let inputs_count = node.inputs.len();
|
||||||
|
|
||||||
|
// Upgrade Fill nodes to the format change in #1778
|
||||||
if reference == "Fill" && inputs_count == 8 {
|
if reference == "Fill" && inputs_count == 8 {
|
||||||
let node_definition = resolve_document_node_type(reference).unwrap();
|
let node_definition = resolve_document_node_type(reference).unwrap();
|
||||||
let document_node = node_definition.default_node_template().document_node;
|
let document_node = node_definition.default_node_template().document_node;
|
||||||
|
|
@ -600,15 +677,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
||||||
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), &[]);
|
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade layer implementation from https://github.com/GraphiteEditor/Graphite/pull/1946
|
|
||||||
if reference == "Merge" || reference == "Artboard" {
|
|
||||||
let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type(reference).unwrap();
|
|
||||||
let new_merge_node = node_definition.default_node_template();
|
|
||||||
document.network_interface.replace_implementation(node_id, &[], new_merge_node.document_node.implementation)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade artboard name being passed as hidden value input to "To Artboard"
|
// Upgrade artboard name being passed as hidden value input to "To Artboard"
|
||||||
if reference == "Artboard" {
|
if reference == "Artboard" && upgrade_from_before_returning_nested_click_targets {
|
||||||
let label = document.network_interface.frontend_display_name(node_id, &[]);
|
let label = document.network_interface.frontend_display_name(node_id, &[]);
|
||||||
document
|
document
|
||||||
.network_interface
|
.network_interface
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string {
|
function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string {
|
||||||
return value.resolvedType ? `Resolved Data: ${value.resolvedType}` : `Unresolved Data: ${value.dataType}`;
|
return value.resolvedType ? `Resolved Data:\n${value.resolvedType}` : `Unresolved Data ${value.dataType}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validTypesText(value: FrontendGraphInput): string {
|
function validTypesText(value: FrontendGraphInput): string {
|
||||||
|
|
@ -502,7 +502,7 @@
|
||||||
style:--offset-top={position.y / 24}
|
style:--offset-top={position.y / 24}
|
||||||
bind:this={outputs[0][index]}
|
bind:this={outputs[0][index]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(outputMetadata)}\n${outputConnectedToText(outputMetadata)}`}</title>
|
<title>{`${dataTypeTooltip(outputMetadata)}\n\n${outputConnectedToText(outputMetadata)}`}</title>
|
||||||
{#if outputMetadata.connectedTo !== undefined}
|
{#if outputMetadata.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -576,7 +576,7 @@
|
||||||
style:--offset-top={position.y / 24}
|
style:--offset-top={position.y / 24}
|
||||||
bind:this={inputs[0][index]}
|
bind:this={inputs[0][index]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(inputMetadata)}\n${inputConnectedToText(inputMetadata)}`}</title>
|
<title>{`${dataTypeTooltip(inputMetadata)}\n\n${inputConnectedToText(inputMetadata)}`}</title>
|
||||||
{#if inputMetadata.connectedTo !== undefined}
|
{#if inputMetadata.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -670,8 +670,8 @@
|
||||||
bind:this={nodeElements[nodeIndex]}
|
bind:this={nodeElements[nodeIndex]}
|
||||||
>
|
>
|
||||||
{#if node.errors}
|
{#if node.errors}
|
||||||
<span class="node-error faded" transition:fade={FADE_TRANSITION} data-node-error>{node.errors}</span>
|
<span class="node-error faded" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||||
<span class="node-error hover" transition:fade={FADE_TRANSITION} data-node-error>{node.errors}</span>
|
<span class="node-error hover" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="thumbnail">
|
<div class="thumbnail">
|
||||||
{#if $nodeGraph.thumbnails.has(node.id)}
|
{#if $nodeGraph.thumbnails.has(node.id)}
|
||||||
|
|
@ -689,7 +689,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={outputs[nodeIndex + 1][0]}
|
bind:this={outputs[nodeIndex + 1][0]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(node.primaryOutput)}\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
<title>{`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
||||||
{#if node.primaryOutput.connectedTo.length > 0}
|
{#if node.primaryOutput.connectedTo.length > 0}
|
||||||
<path d="M0,6.953l2.521,-1.694a2.649,2.649,0,0,1,2.959,0l2.52,1.694v5.047h-8z" fill="var(--data-color)" />
|
<path d="M0,6.953l2.521,-1.694a2.649,2.649,0,0,1,2.959,0l2.52,1.694v5.047h-8z" fill="var(--data-color)" />
|
||||||
{#if primaryOutputConnectedToLayer(node)}
|
{#if primaryOutputConnectedToLayer(node)}
|
||||||
|
|
@ -712,7 +712,7 @@
|
||||||
bind:this={inputs[nodeIndex + 1][0]}
|
bind:this={inputs[nodeIndex + 1][0]}
|
||||||
>
|
>
|
||||||
{#if node.primaryInput}
|
{#if node.primaryInput}
|
||||||
<title>{`${dataTypeTooltip(node.primaryInput)}\n${validTypesText(node.primaryInput)}\n${inputConnectedToText(node.primaryInput)}`}</title>
|
<title>{`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`}</title>
|
||||||
{/if}
|
{/if}
|
||||||
{#if node.primaryInput?.connectedTo !== undefined}
|
{#if node.primaryInput?.connectedTo !== undefined}
|
||||||
<path d="M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z" fill="var(--data-color)" />
|
<path d="M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z" fill="var(--data-color)" />
|
||||||
|
|
@ -737,7 +737,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${stackDataInput.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${stackDataInput.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={inputs[nodeIndex + 1][1]}
|
bind:this={inputs[nodeIndex + 1][1]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(stackDataInput)}\n${validTypesText(stackDataInput)}\n${inputConnectedToText(stackDataInput)}`}</title>
|
<title>{`${dataTypeTooltip(stackDataInput)}\n\n${validTypesText(stackDataInput)}\n\n${inputConnectedToText(stackDataInput)}`}</title>
|
||||||
{#if stackDataInput.connectedTo !== undefined}
|
{#if stackDataInput.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -810,8 +810,8 @@
|
||||||
bind:this={nodeElements[nodeIndex]}
|
bind:this={nodeElements[nodeIndex]}
|
||||||
>
|
>
|
||||||
{#if node.errors}
|
{#if node.errors}
|
||||||
<span class="node-error faded" transition:fade={FADE_TRANSITION} data-node-error>{node.errors}</span>
|
<span class="node-error faded" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||||
<span class="node-error hover" transition:fade={FADE_TRANSITION} data-node-error>{node.errors}</span>
|
<span class="node-error hover" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- Primary row -->
|
<!-- Primary row -->
|
||||||
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
|
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
|
||||||
|
|
@ -844,7 +844,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${node.primaryInput.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${node.primaryInput.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={inputs[nodeIndex + 1][0]}
|
bind:this={inputs[nodeIndex + 1][0]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(node.primaryInput)}\n${validTypesText(node.primaryInput)}\n${inputConnectedToText(node.primaryInput)}`}</title>
|
<title>{`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`}</title>
|
||||||
{#if node.primaryInput.connectedTo !== undefined}
|
{#if node.primaryInput.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -864,7 +864,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={inputs[nodeIndex + 1][index + (node.primaryInput ? 1 : 0)]}
|
bind:this={inputs[nodeIndex + 1][index + (node.primaryInput ? 1 : 0)]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(secondary)}\n${validTypesText(secondary)}\n${inputConnectedToText(secondary)}`}</title>
|
<title>{`${dataTypeTooltip(secondary)}\n\n${validTypesText(secondary)}\n\n${inputConnectedToText(secondary)}`}</title>
|
||||||
{#if secondary.connectedTo !== undefined}
|
{#if secondary.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -887,7 +887,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={outputs[nodeIndex + 1][0]}
|
bind:this={outputs[nodeIndex + 1][0]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(node.primaryOutput)}\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
<title>{`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
||||||
{#if node.primaryOutput.connectedTo !== undefined}
|
{#if node.primaryOutput.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -906,7 +906,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
||||||
bind:this={outputs[nodeIndex + 1][outputIndex + (node.primaryOutput ? 1 : 0)]}
|
bind:this={outputs[nodeIndex + 1][outputIndex + (node.primaryOutput ? 1 : 0)]}
|
||||||
>
|
>
|
||||||
<title>{`${dataTypeTooltip(secondary)}\n${outputConnectedToText(secondary)}`}</title>
|
<title>{`${dataTypeTooltip(secondary)}\n\n${outputConnectedToText(secondary)}`}</title>
|
||||||
{#if secondary.connectedTo !== undefined}
|
{#if secondary.connectedTo !== undefined}
|
||||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub mod types {
|
||||||
pub type PixelLength = f64;
|
pub type PixelLength = f64;
|
||||||
/// Non negative
|
/// Non negative
|
||||||
pub type Length = f64;
|
pub type Length = f64;
|
||||||
/// 0.- 1.
|
/// 0 to 1
|
||||||
pub type Fraction = f64;
|
pub type Fraction = f64;
|
||||||
pub type IntegerCount = u32;
|
pub type IntegerCount = u32;
|
||||||
/// Int input with randomization button
|
/// Int input with randomization button
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ impl NodeIOTypes {
|
||||||
impl core::fmt::Debug for NodeIOTypes {
|
impl core::fmt::Debug for NodeIOTypes {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!(
|
||||||
"node({}) -> {}",
|
"node({}) → {}",
|
||||||
[&self.call_argument].into_iter().chain(&self.inputs).map(|input| input.to_string()).collect::<Vec<_>>().join(", "),
|
[&self.call_argument].into_iter().chain(&self.inputs).map(|input| input.to_string()).collect::<Vec<_>>().join(", "),
|
||||||
self.return_value
|
self.return_value
|
||||||
))
|
))
|
||||||
|
|
@ -292,13 +292,13 @@ fn format_type(ty: &str) -> String {
|
||||||
impl core::fmt::Debug for Type {
|
impl core::fmt::Debug for Type {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Generic(arg0) => write!(f, "Generic({arg0})"),
|
Self::Generic(arg0) => write!(f, "Generic<{arg0}>"),
|
||||||
#[cfg(feature = "type_id_logging")]
|
#[cfg(feature = "type_id_logging")]
|
||||||
Self::Concrete(arg0) => write!(f, "Concrete({}, {:?})", arg0.name, arg0.id),
|
Self::Concrete(arg0) => write!(f, "Concrete<{}, {:?}>", arg0.name, arg0.id),
|
||||||
#[cfg(not(feature = "type_id_logging"))]
|
#[cfg(not(feature = "type_id_logging"))]
|
||||||
Self::Concrete(arg0) => write!(f, "Concrete({})", format_type(&arg0.name)),
|
Self::Concrete(arg0) => write!(f, "Concrete<{}>", format_type(&arg0.name)),
|
||||||
Self::Fn(arg0, arg1) => write!(f, "({arg0:?} -> {arg1:?})"),
|
Self::Fn(arg0, arg1) => write!(f, "{arg0:?} → {arg1:?}"),
|
||||||
Self::Future(arg0) => write!(f, "Future({arg0:?})"),
|
Self::Future(arg0) => write!(f, "Future<{arg0:?}>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +308,7 @@ impl std::fmt::Display for Type {
|
||||||
match self {
|
match self {
|
||||||
Type::Generic(name) => write!(f, "{name}"),
|
Type::Generic(name) => write!(f, "{name}"),
|
||||||
Type::Concrete(ty) => write!(f, "{}", format_type(&ty.name)),
|
Type::Concrete(ty) => write!(f, "{}", format_type(&ty.name)),
|
||||||
Type::Fn(input, output) => write!(f, "({input} -> {output})"),
|
Type::Fn(input, output) => write!(f, "{input} → {output}"),
|
||||||
Type::Future(ty) => write!(f, "Future<{ty}>"),
|
Type::Future(ty) => write!(f, "Future<{ty}>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -588,7 +588,7 @@ impl ConcatElement for GraphicGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""), path(graphene_core::vector))]
|
||||||
async fn sample_points<F: 'n + Send + Copy>(
|
async fn sample_points<F: 'n + Send + Copy>(
|
||||||
#[implementations(
|
#[implementations(
|
||||||
(),
|
(),
|
||||||
|
|
@ -815,7 +815,7 @@ async fn poisson_disk_points<F: 'n + Send>(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""), path(graphene_core::vector))]
|
||||||
async fn subpath_segment_lengths<F: 'n + Send>(
|
async fn subpath_segment_lengths<F: 'n + Send>(
|
||||||
#[implementations(
|
#[implementations(
|
||||||
(),
|
(),
|
||||||
|
|
@ -979,6 +979,8 @@ async fn morph<F: 'n + Send + Copy>(
|
||||||
let target = target.eval(footprint).await;
|
let target = target.eval(footprint).await;
|
||||||
let mut result = VectorData::empty();
|
let mut result = VectorData::empty();
|
||||||
|
|
||||||
|
let time = time.clamp(0., 1.);
|
||||||
|
|
||||||
// Lerp styles
|
// Lerp styles
|
||||||
result.alpha_blending = if time < 0.5 { source.alpha_blending } else { target.alpha_blending };
|
result.alpha_blending = if time < 0.5 { source.alpha_blending } else { target.alpha_blending };
|
||||||
result.style = source.style.lerp(&target.style, time);
|
result.style = source.style.lerp(&target.style, time);
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ impl ProtoNetwork {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remsove
|
// TODO: Remove
|
||||||
/// Create a hashmap with the list of nodes this proto network depends on/uses as inputs.
|
/// Create a hashmap with the list of nodes this proto network depends on/uses as inputs.
|
||||||
pub fn collect_inwards_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
|
pub fn collect_inwards_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
|
||||||
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||||
|
|
@ -552,27 +552,19 @@ impl core::fmt::Debug for GraphErrorType {
|
||||||
GraphErrorType::NoImplementations => write!(f, "No implementations found"),
|
GraphErrorType::NoImplementations => write!(f, "No implementations found"),
|
||||||
GraphErrorType::NoConstructor => write!(f, "No construct found for node"),
|
GraphErrorType::NoConstructor => write!(f, "No construct found for node"),
|
||||||
GraphErrorType::InvalidImplementations { inputs, error_inputs } => {
|
GraphErrorType::InvalidImplementations { inputs, error_inputs } => {
|
||||||
let ordinal = |x: usize| match x.to_string().as_str() {
|
let format_error = |(index, (_found, expected)): &(usize, (Type, Type))| format!("• Input {}: {expected}", index + 1);
|
||||||
x if x.ends_with('1') && !x.ends_with("11") => format!("{x}st"),
|
|
||||||
x if x.ends_with('2') && !x.ends_with("12") => format!("{x}nd"),
|
|
||||||
x if x.ends_with('3') && !x.ends_with("13") => format!("{x}rd"),
|
|
||||||
x => format!("{x}th"),
|
|
||||||
};
|
|
||||||
let format_index = |index: usize| if index == 0 { "primary".to_string() } else { format!("{} secondary", ordinal(index)) };
|
|
||||||
let format_error = |(index, (real, expected)): &(usize, (Type, Type))| format!("• The {} input expected {} but found {}", format_index(*index), expected, real);
|
|
||||||
let format_error_list = |errors: &Vec<(usize, (Type, Type))>| errors.iter().map(format_error).collect::<Vec<_>>().join("\n");
|
let format_error_list = |errors: &Vec<(usize, (Type, Type))>| errors.iter().map(format_error).collect::<Vec<_>>().join("\n");
|
||||||
let errors = error_inputs.iter().map(format_error_list).collect::<Vec<_>>();
|
let mut errors = error_inputs.iter().map(format_error_list).collect::<Vec<_>>();
|
||||||
|
errors.sort();
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Node graph type error! If this just appeared while editing the graph,\n\
|
"This node isn't compatible with the com-\n\
|
||||||
consider using undo to go back and try another way to connect the nodes.\n\
|
bination of types for the data it is given:\n\
|
||||||
|
{inputs}\n\
|
||||||
\n\
|
\n\
|
||||||
No node implementation exists for type:\n\
|
Each invalid input should be replaced by\n\
|
||||||
({inputs})\n\
|
data with one of these supported types:\n\
|
||||||
\n\
|
|
||||||
Caused by{}:\n\
|
|
||||||
{}",
|
{}",
|
||||||
if errors.len() > 1 { " one of" } else { "" },
|
|
||||||
errors.join("\n")
|
errors.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -679,7 +671,8 @@ impl TypingContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the node input type from the proto node declaration
|
// Get the node input type from the proto node declaration
|
||||||
let input = match node.input {
|
// TODO: When removing automatic composition, rename this to just `call_argument`
|
||||||
|
let primary_input_or_call_argument = match node.input {
|
||||||
ProtoNodeInput::None => concrete!(()),
|
ProtoNodeInput::None => concrete!(()),
|
||||||
ProtoNodeInput::ManualComposition(ref ty) => ty.clone(),
|
ProtoNodeInput::ManualComposition(ref ty) => ty.clone(),
|
||||||
ProtoNodeInput::Node(id) | ProtoNodeInput::NodeLambda(id) => {
|
ProtoNodeInput::Node(id) | ProtoNodeInput::NodeLambda(id) => {
|
||||||
|
|
@ -687,6 +680,7 @@ impl TypingContext {
|
||||||
input.return_value.clone()
|
input.return_value.clone()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let using_manual_composition = matches!(node.input, ProtoNodeInput::ManualComposition(_) | ProtoNodeInput::None);
|
||||||
let impls = self.lookup.get(&node.identifier).ok_or_else(|| vec![GraphError::new(node, GraphErrorType::NoImplementations)])?;
|
let impls = self.lookup.get(&node.identifier).ok_or_else(|| vec![GraphError::new(node, GraphErrorType::NoImplementations)])?;
|
||||||
|
|
||||||
if let Some(index) = inputs.iter().position(|p| {
|
if let Some(index) = inputs.iter().position(|p| {
|
||||||
|
|
@ -724,7 +718,7 @@ impl TypingContext {
|
||||||
// List of all implementations that match the input types
|
// List of all implementations that match the input types
|
||||||
let valid_output_types = impls
|
let valid_output_types = impls
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|node_io| valid_subtype(&node_io.call_argument, &input) && inputs.iter().zip(node_io.inputs.iter()).all(|(p1, p2)| valid_subtype(p1, p2)))
|
.filter(|node_io| valid_subtype(&node_io.call_argument, &primary_input_or_call_argument) && inputs.iter().zip(node_io.inputs.iter()).all(|(p1, p2)| valid_subtype(p1, p2)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Attempt to substitute generic types with concrete types and save the list of results
|
// Attempt to substitute generic types with concrete types and save the list of results
|
||||||
|
|
@ -733,10 +727,10 @@ impl TypingContext {
|
||||||
.map(|node_io| {
|
.map(|node_io| {
|
||||||
collect_generics(node_io)
|
collect_generics(node_io)
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|generic| check_generic(node_io, &input, &inputs, generic).map(|_| ()))
|
.try_for_each(|generic| check_generic(node_io, &primary_input_or_call_argument, &inputs, generic).map(|_| ()))
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
if let Type::Generic(out) = &node_io.return_value {
|
if let Type::Generic(out) = &node_io.return_value {
|
||||||
((*node_io).clone(), check_generic(node_io, &input, &inputs, out).unwrap())
|
((*node_io).clone(), check_generic(node_io, &primary_input_or_call_argument, &inputs, out).unwrap())
|
||||||
} else {
|
} else {
|
||||||
((*node_io).clone(), node_io.return_value.clone())
|
((*node_io).clone(), node_io.return_value.clone())
|
||||||
}
|
}
|
||||||
|
|
@ -752,14 +746,18 @@ impl TypingContext {
|
||||||
let mut best_errors = usize::MAX;
|
let mut best_errors = usize::MAX;
|
||||||
let mut error_inputs = Vec::new();
|
let mut error_inputs = Vec::new();
|
||||||
for node_io in impls.keys() {
|
for node_io in impls.keys() {
|
||||||
let current_errors = [&input]
|
let current_errors = [&primary_input_or_call_argument]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(&inputs)
|
.chain(&inputs)
|
||||||
.cloned()
|
.cloned()
|
||||||
.zip([&node_io.call_argument].into_iter().chain(&node_io.inputs).cloned())
|
.zip([&node_io.call_argument].into_iter().chain(&node_io.inputs).cloned())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, (p1, p2))| !valid_subtype(p1, p2))
|
.filter(|(_, (p1, p2))| !valid_subtype(p1, p2))
|
||||||
.map(|(index, ty)| (node.original_location.inputs(index).min_by_key(|s| s.node.len()).map(|s| s.index).unwrap_or(index), ty))
|
.map(|(index, ty)| {
|
||||||
|
let i = node.original_location.inputs(index).min_by_key(|s| s.node.len()).map(|s| s.index).unwrap_or(index);
|
||||||
|
let i = if using_manual_composition { i } else { i + 1 };
|
||||||
|
(i, ty)
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if current_errors.len() < best_errors {
|
if current_errors.len() < best_errors {
|
||||||
best_errors = current_errors.len();
|
best_errors = current_errors.len();
|
||||||
|
|
@ -769,7 +767,17 @@ impl TypingContext {
|
||||||
error_inputs.push(current_errors);
|
error_inputs.push(current_errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let inputs = [&input].into_iter().chain(&inputs).map(|t| t.to_string()).collect::<Vec<_>>().join(", ");
|
let inputs = [&primary_input_or_call_argument]
|
||||||
|
.into_iter()
|
||||||
|
.chain(&inputs)
|
||||||
|
.enumerate()
|
||||||
|
// TODO: Make the following line's if statement conditional on being a call argument or primary input
|
||||||
|
.filter_map(|(i, t)| {
|
||||||
|
let i = if using_manual_composition { i } else { i + 1 };
|
||||||
|
if i == 0 { None } else { Some(format!("• Input {i}: {t}")) }
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
Err(vec![GraphError::new(node, GraphErrorType::InvalidImplementations { inputs, error_inputs })])
|
Err(vec![GraphError::new(node, GraphErrorType::InvalidImplementations { inputs, error_inputs })])
|
||||||
}
|
}
|
||||||
[(org_nio, _)] => {
|
[(org_nio, _)] => {
|
||||||
|
|
@ -794,13 +802,13 @@ impl TypingContext {
|
||||||
return Ok(org_nio.clone());
|
return Ok(org_nio.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let inputs = [&input].into_iter().chain(&inputs).map(|t| t.to_string()).collect::<Vec<_>>().join(", ");
|
let inputs = [&primary_input_or_call_argument].into_iter().chain(&inputs).map(|t| t.to_string()).collect::<Vec<_>>().join(", ");
|
||||||
let valid = valid_output_types.into_iter().cloned().collect();
|
let valid = valid_output_types.into_iter().cloned().collect();
|
||||||
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let inputs = [&input].into_iter().chain(&inputs).map(|t| t.to_string()).collect::<Vec<_>>().join(", ");
|
let inputs = [&primary_input_or_call_argument].into_iter().chain(&inputs).map(|t| t.to_string()).collect::<Vec<_>>().join(", ");
|
||||||
let valid = valid_output_types.into_iter().cloned().collect();
|
let valid = valid_output_types.into_iter().cloned().collect();
|
||||||
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ fn init_logging() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrations are done in the editor which is unfortunately not available here.
|
// Migrations are done in the editor which is unfortunately not available here.
|
||||||
// TODO: remove this and share migrations between the edtior and the CLI.
|
// TODO: remove this and share migrations between the editor and the CLI.
|
||||||
fn fix_nodes(network: &mut NodeNetwork) {
|
fn fix_nodes(network: &mut NodeNetwork) {
|
||||||
for node in network.nodes.values_mut() {
|
for node in network.nodes.values_mut() {
|
||||||
match &mut node.implementation {
|
match &mut node.implementation {
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Filters
|
// Filters
|
||||||
|
// TODO: Move these filters to the new node macro and put them in `graphene_core::raster::adjustments`, then add them to the document upgrade script which moves many of the adjustment nodes from `graphene_core::raster` to `graphene_core::raster::adjustments`
|
||||||
(
|
(
|
||||||
ProtoNodeIdentifier::new("graphene_core::raster::BrightnessContrastNode"),
|
ProtoNodeIdentifier::new("graphene_core::raster::BrightnessContrastNode"),
|
||||||
|args| {
|
|args| {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ Click a membership level below to pay directly (no account needed). A small fee
|
||||||
**$25 / month**
|
**$25 / month**
|
||||||
|
|
||||||
- Your **personal name** (or handle) **on the Graphite website and GitHub readme**
|
- Your **personal name** (or handle) **on the Graphite website and GitHub readme**
|
||||||
- Option to be mailed a personal **thank-you card with Graphite stickers** (US addresses only)
|
- Option to be mailed a personal **thank-you card with Graphite stickers** (in the US only)
|
||||||
- *Plus the lower-tier rewards*
|
- *Plus the lower-tier rewards*
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue