Add support for exposing node parameter inputs (#866)
* Add exposing inputs to graph * Use uuids and better node positioning * Fix accidentally refering to the wrong grid spacing * Secondary input without primary input * Cleanup document node types * Rename to input and addend
This commit is contained in:
parent
0a78ebda25
commit
3dd9e88655
|
|
@ -14,7 +14,7 @@ pub enum NodeGraphMessage {
|
||||||
},
|
},
|
||||||
CreateNode {
|
CreateNode {
|
||||||
// Having the caller generate the id means that we don't have to return it. This can be a random u64.
|
// Having the caller generate the id means that we don't have to return it. This can be a random u64.
|
||||||
node_id: NodeId,
|
node_id: Option<NodeId>,
|
||||||
// I don't really know what this is for (perhaps a user identifiable name).
|
// I don't really know what this is for (perhaps a user identifiable name).
|
||||||
node_type: String,
|
node_type: String,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ pub struct FrontendNode {
|
||||||
pub id: graph_craft::document::NodeId,
|
pub id: graph_craft::document::NodeId,
|
||||||
#[serde(rename = "displayName")]
|
#[serde(rename = "displayName")]
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
#[serde(rename = "primaryInput")]
|
||||||
|
pub primary_input: Option<FrontendGraphDataType>,
|
||||||
#[serde(rename = "exposedInputs")]
|
#[serde(rename = "exposedInputs")]
|
||||||
pub exposed_inputs: Vec<NodeGraphInput>,
|
pub exposed_inputs: Vec<NodeGraphInput>,
|
||||||
pub outputs: Vec<FrontendGraphDataType>,
|
pub outputs: Vec<FrontendGraphDataType>,
|
||||||
|
|
@ -122,10 +124,17 @@ impl NodeGraphMessageHandler {
|
||||||
nodes.push(FrontendNode {
|
nodes.push(FrontendNode {
|
||||||
id: *id,
|
id: *id,
|
||||||
display_name: node.name.clone(),
|
display_name: node.name.clone(),
|
||||||
|
primary_input: node
|
||||||
|
.inputs
|
||||||
|
.first()
|
||||||
|
.filter(|input| input.is_exposed())
|
||||||
|
.and_then(|_| node_type.inputs.get(0))
|
||||||
|
.map(|input_type| input_type.data_type),
|
||||||
exposed_inputs: node
|
exposed_inputs: node
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.zip(node_type.inputs)
|
.zip(node_type.inputs)
|
||||||
|
.skip(1)
|
||||||
.filter(|(input, _)| input.is_exposed())
|
.filter(|(input, _)| input.is_exposed())
|
||||||
.map(|(_, input_type)| NodeGraphInput {
|
.map(|(_, input_type)| NodeGraphInput {
|
||||||
data_type: input_type.data_type,
|
data_type: input_type.data_type,
|
||||||
|
|
@ -180,6 +189,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
|
||||||
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
|
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
|
||||||
}
|
}
|
||||||
NodeGraphMessage::CreateNode { node_id, node_type } => {
|
NodeGraphMessage::CreateNode { node_id, node_type } => {
|
||||||
|
let node_id = node_id.unwrap_or_else(crate::application::generate_uuid);
|
||||||
let Some(network) = self.get_active_network_mut(document) else{
|
let Some(network) = self.get_active_network_mut(document) else{
|
||||||
warn!("No network");
|
warn!("No network");
|
||||||
return;
|
return;
|
||||||
|
|
@ -208,6 +218,8 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
let far_right_node = network.nodes.iter().map(|node| node.1.metadata.position).max_by_key(|pos| pos.0).unwrap_or_default();
|
||||||
|
|
||||||
network.nodes.insert(
|
network.nodes.insert(
|
||||||
node_id,
|
node_id,
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
|
|
@ -217,7 +229,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
|
||||||
implementation: DocumentNodeImplementation::Network(inner_network),
|
implementation: DocumentNodeImplementation::Network(inner_network),
|
||||||
metadata: graph_craft::document::DocumentNodeMetadata {
|
metadata: graph_craft::document::DocumentNodeMetadata {
|
||||||
// TODO: Better position default
|
// TODO: Better position default
|
||||||
position: (node_id as i32 * 7 - 41, node_id as i32 * 2 - 10),
|
position: (far_right_node.0 + 7, far_right_node.1 + 2),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -243,8 +255,16 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
|
||||||
|
|
||||||
if let NodeInput::Value { exposed, .. } = &mut node.inputs[input_index] {
|
if let NodeInput::Value { exposed, .. } = &mut node.inputs[input_index] {
|
||||||
*exposed = new_exposed;
|
*exposed = new_exposed;
|
||||||
|
} else if let Some(node_type) = document_node_types::resolve_document_node_type(&node.name) {
|
||||||
|
if let NodeInput::Value { tagged_value, .. } = &node_type.inputs[input_index].default {
|
||||||
|
node.inputs[input_index] = NodeInput::Value {
|
||||||
|
tagged_value: tagged_value.clone(),
|
||||||
|
exposed: new_exposed,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Self::send_graph(network, responses);
|
Self::send_graph(network, responses);
|
||||||
|
responses.push_back(PropertiesPanelMessage::ResendActiveProperties.into());
|
||||||
}
|
}
|
||||||
NodeGraphMessage::MoveSelectedNodes { displacement_x, displacement_y } => {
|
NodeGraphMessage::MoveSelectedNodes { displacement_x, displacement_y } => {
|
||||||
let Some(network) = self.get_active_network_mut(document) else{
|
let Some(network) = self.get_active_network_mut(document) else{
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
properties: |_document_node, _node_id| {
|
properties: |_document_node, _node_id| {
|
||||||
vec![LayoutGroup::Row {
|
vec![LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: format!("The identity node simply returns the input"),
|
value: "The identity node simply returns the input".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))],
|
}))],
|
||||||
}]
|
}]
|
||||||
|
|
@ -46,12 +46,16 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Input",
|
name: "Input",
|
||||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Concrete(Cow::Borrowed("Any<'_>"))]),
|
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Concrete(Cow::Borrowed("Any<'_>"))]),
|
||||||
inputs: &[],
|
inputs: &[DocumentInputType {
|
||||||
|
name: "In",
|
||||||
|
data_type: FrontendGraphDataType::Raster,
|
||||||
|
default: NodeInput::Network,
|
||||||
|
}],
|
||||||
outputs: &[FrontendGraphDataType::Raster],
|
outputs: &[FrontendGraphDataType::Raster],
|
||||||
properties: |_document_node, _node_id| {
|
properties: |_document_node, _node_id| {
|
||||||
vec![LayoutGroup::Row {
|
vec![LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: format!("The input to the graph is the bitmap under the frame"),
|
value: "The input to the graph is the bitmap under the frame".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))],
|
}))],
|
||||||
}]
|
}]
|
||||||
|
|
@ -72,7 +76,7 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
properties: |_document_node, _node_id| {
|
properties: |_document_node, _node_id| {
|
||||||
vec![LayoutGroup::Row {
|
vec![LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: format!("The output to the graph is rendered in the frame"),
|
value: "The output to the graph is rendered in the frame".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))],
|
}))],
|
||||||
}]
|
}]
|
||||||
|
|
@ -93,7 +97,7 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
properties: |_document_node, _node_id| {
|
properties: |_document_node, _node_id| {
|
||||||
vec![LayoutGroup::Row {
|
vec![LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: format!("The output to the graph is rendered in the frame"),
|
value: "The output to the graph is rendered in the frame".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))],
|
}))],
|
||||||
}]
|
}]
|
||||||
|
|
@ -152,7 +156,7 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|
||||||
inputs: &[
|
inputs: &[
|
||||||
DocumentInputType {
|
DocumentInputType {
|
||||||
name: "Left",
|
name: "Input",
|
||||||
data_type: FrontendGraphDataType::Number,
|
data_type: FrontendGraphDataType::Number,
|
||||||
default: NodeInput::Value {
|
default: NodeInput::Value {
|
||||||
tagged_value: TaggedValue::F32(0.),
|
tagged_value: TaggedValue::F32(0.),
|
||||||
|
|
@ -160,7 +164,7 @@ static DOCUMENT_NODE_TYPES: [DocumentNodeType; 7] = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DocumentInputType {
|
DocumentInputType {
|
||||||
name: "Right",
|
name: "Addend",
|
||||||
data_type: FrontendGraphDataType::Number,
|
data_type: FrontendGraphDataType::Number,
|
||||||
default: NodeInput::Value {
|
default: NodeInput::Value {
|
||||||
tagged_value: TaggedValue::F32(0.),
|
tagged_value: TaggedValue::F32(0.),
|
||||||
|
|
@ -178,5 +182,9 @@ pub fn resolve_document_node_type(name: &str) -> Option<&DocumentNodeType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
||||||
DOCUMENT_NODE_TYPES.iter().map(|node_type| FrontendNodeType { name: node_type.name.to_string() }).collect()
|
DOCUMENT_NODE_TYPES
|
||||||
|
.iter()
|
||||||
|
.filter(|node_type| !matches!(node_type.name, "Input" | "Output"))
|
||||||
|
.map(|node_type| FrontendNodeType { name: node_type.name.to_string() })
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,33 +10,46 @@ use graph_craft::document::{DocumentNode, NodeId, NodeInput};
|
||||||
use super::FrontendGraphDataType;
|
use super::FrontendGraphDataType;
|
||||||
|
|
||||||
pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
||||||
vec![LayoutGroup::Row {
|
let index = 1;
|
||||||
widgets: vec![
|
let input: &NodeInput = document_node.inputs.get(index).unwrap();
|
||||||
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
let exposed = input.is_exposed();
|
||||||
exposed: true,
|
|
||||||
data_type: FrontendGraphDataType::Number,
|
let mut widgets = vec![
|
||||||
tooltip: "Expose input parameter in node graph".into(),
|
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
||||||
..Default::default()
|
exposed,
|
||||||
})),
|
data_type: FrontendGraphDataType::Number,
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
tooltip: "Expose input parameter in node graph".into(),
|
||||||
separator_type: SeparatorType::Unrelated,
|
on_update: WidgetCallback::new(move |_parameter| {
|
||||||
direction: SeparatorDirection::Horizontal,
|
NodeGraphMessage::ExposeInput {
|
||||||
})),
|
node_id,
|
||||||
WidgetHolder::new(Widget::TextLabel(TextLabel {
|
input_index: index,
|
||||||
value: "Shift Degrees".into(),
|
new_exposed: !exposed,
|
||||||
..Default::default()
|
}
|
||||||
})),
|
.into()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
|
separator_type: SeparatorType::Unrelated,
|
||||||
|
direction: SeparatorDirection::Horizontal,
|
||||||
|
})),
|
||||||
|
WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
|
value: "Shift Degrees".into(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
if let NodeInput::Value {
|
||||||
|
tagged_value: TaggedValue::F32(x),
|
||||||
|
exposed: false,
|
||||||
|
} = document_node.inputs[index]
|
||||||
|
{
|
||||||
|
widgets.extend_from_slice(&[
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
separator_type: SeparatorType::Unrelated,
|
separator_type: SeparatorType::Unrelated,
|
||||||
direction: SeparatorDirection::Horizontal,
|
direction: SeparatorDirection::Horizontal,
|
||||||
})),
|
})),
|
||||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||||
value: Some({
|
value: Some(x as f64),
|
||||||
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[1] else {
|
|
||||||
panic!("Hue rotate should be f32")
|
|
||||||
};
|
|
||||||
x as f64
|
|
||||||
}),
|
|
||||||
unit: "°".into(),
|
unit: "°".into(),
|
||||||
mode: NumberInputMode::Range,
|
mode: NumberInputMode::Range,
|
||||||
range_min: Some(-180.),
|
range_min: Some(-180.),
|
||||||
|
|
@ -51,38 +64,54 @@ pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId)
|
||||||
}),
|
}),
|
||||||
..NumberInput::default()
|
..NumberInput::default()
|
||||||
})),
|
})),
|
||||||
],
|
])
|
||||||
}]
|
}
|
||||||
|
|
||||||
|
vec![LayoutGroup::Row { widgets }]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
||||||
vec![LayoutGroup::Row {
|
let index = 1;
|
||||||
widgets: vec![
|
let input: &NodeInput = document_node.inputs.get(index).unwrap();
|
||||||
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
let exposed = input.is_exposed();
|
||||||
exposed: true,
|
|
||||||
data_type: FrontendGraphDataType::Number,
|
let mut widgets = vec![
|
||||||
tooltip: "Expose input parameter in node graph".into(),
|
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
||||||
..Default::default()
|
exposed,
|
||||||
})),
|
data_type: FrontendGraphDataType::Number,
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
tooltip: "Expose input parameter in node graph".into(),
|
||||||
separator_type: SeparatorType::Unrelated,
|
on_update: WidgetCallback::new(move |_parameter| {
|
||||||
direction: SeparatorDirection::Horizontal,
|
NodeGraphMessage::ExposeInput {
|
||||||
})),
|
node_id,
|
||||||
WidgetHolder::new(Widget::TextLabel(TextLabel {
|
input_index: index,
|
||||||
value: "Brighten Amount".into(),
|
new_exposed: !exposed,
|
||||||
..Default::default()
|
}
|
||||||
})),
|
.into()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
|
separator_type: SeparatorType::Unrelated,
|
||||||
|
direction: SeparatorDirection::Horizontal,
|
||||||
|
})),
|
||||||
|
WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
|
value: "Brighten Amount".into(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let NodeInput::Value {
|
||||||
|
tagged_value: TaggedValue::F32(x),
|
||||||
|
exposed: false,
|
||||||
|
} = document_node.inputs[index]
|
||||||
|
{
|
||||||
|
widgets.extend_from_slice(&[
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
separator_type: SeparatorType::Unrelated,
|
separator_type: SeparatorType::Unrelated,
|
||||||
direction: SeparatorDirection::Horizontal,
|
direction: SeparatorDirection::Horizontal,
|
||||||
})),
|
})),
|
||||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||||
value: Some({
|
value: Some(x as f64),
|
||||||
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[1] else {
|
|
||||||
panic!("Brighten amount should be f32")
|
|
||||||
};
|
|
||||||
x as f64
|
|
||||||
}),
|
|
||||||
mode: NumberInputMode::Range,
|
mode: NumberInputMode::Range,
|
||||||
range_min: Some(-255.),
|
range_min: Some(-255.),
|
||||||
range_max: Some(255.),
|
range_max: Some(255.),
|
||||||
|
|
@ -96,17 +125,29 @@ pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId)
|
||||||
}),
|
}),
|
||||||
..NumberInput::default()
|
..NumberInput::default()
|
||||||
})),
|
})),
|
||||||
],
|
])
|
||||||
}]
|
}
|
||||||
|
|
||||||
|
vec![LayoutGroup::Row { widgets }]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
pub fn add_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
|
||||||
let operand = |name: &str, index| LayoutGroup::Row {
|
let operand = |name: &str, index| {
|
||||||
widgets: vec![
|
let input: &NodeInput = document_node.inputs.get(index).unwrap();
|
||||||
|
let exposed = input.is_exposed();
|
||||||
|
let mut widgets = vec![
|
||||||
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
|
||||||
exposed: true,
|
exposed,
|
||||||
data_type: FrontendGraphDataType::Number,
|
data_type: FrontendGraphDataType::Number,
|
||||||
tooltip: "Expose input parameter in node graph".into(),
|
tooltip: "Expose input parameter in node graph".into(),
|
||||||
|
on_update: WidgetCallback::new(move |_parameter| {
|
||||||
|
NodeGraphMessage::ExposeInput {
|
||||||
|
node_id,
|
||||||
|
input_index: index,
|
||||||
|
new_exposed: !exposed,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
|
|
@ -117,32 +158,37 @@ pub fn add_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<Layo
|
||||||
value: name.into(),
|
value: name.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
WidgetHolder::new(Widget::Separator(Separator {
|
];
|
||||||
separator_type: SeparatorType::Unrelated,
|
|
||||||
direction: SeparatorDirection::Horizontal,
|
|
||||||
})),
|
|
||||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
|
||||||
value: Some({
|
|
||||||
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[index] else {
|
|
||||||
panic!("Add input should be f32")
|
|
||||||
};
|
|
||||||
|
|
||||||
x as f64
|
if let NodeInput::Value {
|
||||||
}),
|
tagged_value: TaggedValue::F32(x),
|
||||||
mode: NumberInputMode::Increment,
|
exposed: false,
|
||||||
on_update: WidgetCallback::new(move |number_input: &NumberInput| {
|
} = document_node.inputs[index]
|
||||||
NodeGraphMessage::SetInputValue {
|
{
|
||||||
node: node_id,
|
widgets.extend_from_slice(&[
|
||||||
input_index: index,
|
WidgetHolder::new(Widget::Separator(Separator {
|
||||||
value: TaggedValue::F32(number_input.value.unwrap() as f32),
|
separator_type: SeparatorType::Unrelated,
|
||||||
}
|
direction: SeparatorDirection::Horizontal,
|
||||||
.into()
|
})),
|
||||||
}),
|
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||||
..NumberInput::default()
|
value: Some(x as f64),
|
||||||
})),
|
mode: NumberInputMode::Increment,
|
||||||
],
|
on_update: WidgetCallback::new(move |number_input: &NumberInput| {
|
||||||
|
NodeGraphMessage::SetInputValue {
|
||||||
|
node: node_id,
|
||||||
|
input_index: index,
|
||||||
|
value: TaggedValue::F32(number_input.value.unwrap() as f32),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
..NumberInput::default()
|
||||||
|
})),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutGroup::Row { widgets }
|
||||||
};
|
};
|
||||||
vec![operand("Left", 0), operand("Right", 1)]
|
vec![operand("Input", 0), operand("Addend", 1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unknown_node_properties(document_node: &DocumentNode) -> Vec<LayoutGroup> {
|
fn unknown_node_properties(document_node: &DocumentNode) -> Vec<LayoutGroup> {
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@
|
||||||
<div class="primary">
|
<div class="primary">
|
||||||
<div class="ports">
|
<div class="ports">
|
||||||
<div
|
<div
|
||||||
v-if="node.exposedInputs.length > 0"
|
v-if="node.primaryInput"
|
||||||
class="input port"
|
class="input port"
|
||||||
data-port="input"
|
data-port="input"
|
||||||
:data-datatype="node.exposedInputs[0].dataType"
|
:data-datatype="node.primaryInput"
|
||||||
:style="{ '--data-color': `var(--color-data-${node.exposedInputs[0].dataType})`, '--data-color-dim': `var(--color-data-${node.exposedInputs[0].dataType}-dim)` }"
|
:style="{ '--data-color': `var(--color-data-${node.primaryInput})`, '--data-color-dim': `var(--color-data-${node.primaryInput}-dim)` }"
|
||||||
>
|
>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -66,8 +66,8 @@
|
||||||
<IconLabel :icon="nodeIcon(node.displayName)" />
|
<IconLabel :icon="nodeIcon(node.displayName)" />
|
||||||
<TextLabel>{{ node.displayName }}</TextLabel>
|
<TextLabel>{{ node.displayName }}</TextLabel>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="node.exposedInputs.length > 1" class="arguments">
|
<div v-if="node.exposedInputs.length > 0" class="arguments">
|
||||||
<div v-for="(argument, index) in node.exposedInputs.slice(1)" :key="index" class="argument">
|
<div v-for="(argument, index) in node.exposedInputs" :key="index" class="argument">
|
||||||
<div class="ports">
|
<div class="ports">
|
||||||
<div
|
<div
|
||||||
class="input port"
|
class="input port"
|
||||||
|
|
@ -366,7 +366,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const links = this.nodeGraph.state.links;
|
const links = this.nodeGraph.state.links;
|
||||||
this.nodeLinkPaths = links.flatMap((link) => {
|
this.nodeLinkPaths = links.flatMap((link) => {
|
||||||
const connectorIndex = 0;
|
const connectorIndex = Number(link.linkEndInputIndex);
|
||||||
|
|
||||||
const nodePrimaryOutput = (containerBounds.querySelector(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined) as HTMLDivElement | undefined;
|
const nodePrimaryOutput = (containerBounds.querySelector(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined) as HTMLDivElement | undefined;
|
||||||
|
|
||||||
|
|
@ -511,8 +511,8 @@ export default defineComponent({
|
||||||
this.linkInProgressToConnector = new DOMRect(e.x, e.y);
|
this.linkInProgressToConnector = new DOMRect(e.x, e.y);
|
||||||
}
|
}
|
||||||
} else if (this.draggingNodes) {
|
} else if (this.draggingNodes) {
|
||||||
const deltaX = Math.round((e.x - this.draggingNodes.startX) / this.transform.scale / this.gridSpacing);
|
const deltaX = Math.round((e.x - this.draggingNodes.startX) / this.transform.scale / GRID_SIZE);
|
||||||
const deltaY = Math.round((e.y - this.draggingNodes.startY) / this.transform.scale / this.gridSpacing);
|
const deltaY = Math.round((e.y - this.draggingNodes.startY) / this.transform.scale / GRID_SIZE);
|
||||||
if (this.draggingNodes.roundX !== deltaX || this.draggingNodes.roundY !== deltaY) {
|
if (this.draggingNodes.roundX !== deltaX || this.draggingNodes.roundY !== deltaY) {
|
||||||
this.draggingNodes.roundX = deltaX;
|
this.draggingNodes.roundX = deltaX;
|
||||||
this.draggingNodes.roundY = deltaY;
|
this.draggingNodes.roundY = deltaY;
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@ export class FrontendNode {
|
||||||
|
|
||||||
readonly displayName!: string;
|
readonly displayName!: string;
|
||||||
|
|
||||||
|
readonly primaryInput!: FrontendGraphDataType | undefined;
|
||||||
|
|
||||||
readonly exposedInputs!: NodeGraphInput[];
|
readonly exposedInputs!: NodeGraphInput[];
|
||||||
|
|
||||||
readonly outputs!: FrontendGraphDataType[];
|
readonly outputs!: FrontendGraphDataType[];
|
||||||
|
|
|
||||||
|
|
@ -553,18 +553,7 @@ impl JsEditorHandle {
|
||||||
/// Creates a new document node in the node graph
|
/// Creates a new document node in the node graph
|
||||||
#[wasm_bindgen(js_name = createNode)]
|
#[wasm_bindgen(js_name = createNode)]
|
||||||
pub fn create_node(&self, node_type: String) {
|
pub fn create_node(&self, node_type: String) {
|
||||||
fn generate_node_id() -> u64 {
|
let message = NodeGraphMessage::CreateNode { node_id: None, node_type };
|
||||||
static mut NODE_ID: u64 = 10;
|
|
||||||
unsafe {
|
|
||||||
NODE_ID += 1;
|
|
||||||
NODE_ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = NodeGraphMessage::CreateNode {
|
|
||||||
node_id: generate_node_id(),
|
|
||||||
node_type,
|
|
||||||
};
|
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,10 +108,10 @@ impl NodeInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_exposed(&self) -> bool {
|
pub fn is_exposed(&self) -> bool {
|
||||||
if let NodeInput::Value { exposed, .. } = self {
|
match self {
|
||||||
*exposed
|
NodeInput::Node(_) => true,
|
||||||
} else {
|
NodeInput::Value { exposed, .. } => *exposed,
|
||||||
true
|
NodeInput::Network => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue