Refactor the node macro and simply most of the node implementations (#1942)

* Add support structure for new node macro to gcore

* Fix compile issues and code generation

* Implement new node_fn macro

* Implement property translation

* Fix NodeIO type generation

* Start translating math nodes

* Move node implementation to outer scope to allow usage of local imports

* Add expose attribute to allow controlling the parameter exposure

* Add rust analyzer support for #[implementations] attribute

* Migrate logic nodes

* Handle where clause properly

* Implement argument ident pattern preservation

* Implement adjustment layer mapping

* Fix node registry types

* Fix module paths

* Improve demo artwork comptibility

* Improve macro error reporting

* Fix handling of impl node implementations

* Fix nodeio type computation

* Fix opacity node and graph type resolution

* Fix loading of demo artworks

* Fix eslint

* Fix typo in macro test

* Remove node definitions for Adjustment Nodes

* Fix type alias property generation and make adjustments footprint aware

* Convert vector nodes

* Implement path overrides

* Fix stroke node

* Fix painted dreams

* Implement experimental type level specialization

* Fix poisson disk sampling -> all demo artworks should work again

* Port text node + make node macro more robust by implementing lifetime substitution

* Fix vector node tests

* Fix red dress demo + ci

* Fix clippy warnings

* Code review

* Fix primary input issues

* Improve math nodes and audit others

* Set no_properties when no automatic properties are derived

* Port vector generator nodes (could not derive all definitions yet)

* Various QA changes and add min/max/mode_range to number parameters

* Add min and max for f64 and u32

* Convert gpu nodes and clean up unused nodes

* Partially port transform node

* Allow implementations on call arg

* Port path modify node

* Start porting graphic element nodes

* Transform nodes in graphic_element.rs

* Port brush node

* Port nodes in wasm_executior

* Rename node macro

* Fix formatting

* Fix Mandelbrot node

* Formatting

* Fix Load Image and Load Resource nodes, add scope input to node macro

* Remove unnecessary underscores

* Begin attemping to make nodes resolution-aware

* Infer a generic manual compositon type on generic call arg

* Various fixes and work towards merging

* Final changes for merge!

* Fix tests, probably

* More free line removals!

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2024-09-20 12:50:30 +02:00
committed by GitHub
parent ca0d102296
commit e352c7fa71
92 changed files with 4255 additions and 7275 deletions

View File

@@ -311,6 +311,11 @@ impl Default for LayoutGroup {
Self::Row { widgets: Vec::new() }
}
}
impl From<Vec<WidgetHolder>> for LayoutGroup {
fn from(widgets: Vec<WidgetHolder>) -> LayoutGroup {
LayoutGroup::Row { widgets }
}
}
impl LayoutGroup {
/// Applies a tooltip to all widgets in this row or column without a tooltip.

View File

@@ -198,6 +198,7 @@ pub struct NumberInput {
#[derivative(Default(value = "1."))]
pub step: f64,
// TODO: Make this (and range_max) apply to both Range and Increment modes when dragging with the mouse
#[serde(rename = "rangeMin")]
pub range_min: Option<f64>,

View File

@@ -25,11 +25,11 @@ use crate::node_graph_executor::NodeGraphExecutor;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeNetwork, OldNodeNetwork};
use graphene_core::raster::BlendMode;
use graphene_core::raster::ImageFrame;
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::vector::style::ViewMode;
use glam::{DAffine2, DVec2};
pub struct DocumentMessageData<'a> {
pub document_id: DocumentId,
pub ipp: &'a InputPreprocessorMessageHandler,
@@ -726,9 +726,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
let center_in_viewport = DAffine2::from_translation(document_to_viewport.inverse().transform_point2(viewport_location - ipp.viewport_bounds.top_left));
let center_in_viewport_layerspace = center_in_viewport;
// Scale the image to fit into a 512x512 box
let image_size = image_size / DVec2::splat((image_size.max_element() / 512.).max(1.));
// Make layer the size of the image
let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.);

View File

@@ -7,8 +7,10 @@ use crate::messages::prelude::*;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
use graph_craft::imaginate_input::{ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus};
use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus};
use graph_craft::Type;
use graphene_core::memo::IORecord;
use graphene_core::raster::curve::Curve;
use graphene_core::raster::{
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
SelectiveColorChoice,
@@ -16,13 +18,14 @@ use graphene_core::raster::{
use graphene_core::text::Font;
use graphene_core::vector::misc::CentroidType;
use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
use graphene_std::vector::style::{Fill, FillChoice};
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
use glam::{DAffine2, DVec2, IVec2, UVec2};
use graphene_std::transform::Footprint;
use graphene_std::vector::misc::BooleanOperation;
use graphene_std::vector::VectorData;
pub fn string_properties(text: impl Into<String>) -> Vec<LayoutGroup> {
pub(crate) fn string_properties(text: impl Into<String>) -> Vec<LayoutGroup> {
let widget = TextLabel::new(text).widget_holder();
vec![LayoutGroup::Row { widgets: vec![widget] }]
}
@@ -84,6 +87,158 @@ fn start_widgets(document_node: &DocumentNode, node_id: NodeId, index: usize, na
widgets
}
pub(crate) fn property_from_type(
document_node: &DocumentNode,
node_id: NodeId,
index: usize,
name: &str,
ty: &Type,
_context: &mut NodePropertiesContext,
number_options: (Option<f64>, Option<f64>, Option<(f64, f64)>),
) -> Vec<LayoutGroup> {
let (mut number_min, mut number_max, range) = number_options;
let mut number_input = NumberInput::default();
if let Some((range_start, range_end)) = range {
number_min = Some(range_start);
number_max = Some(range_end);
number_input = number_input.mode_range().min(range_start).max(range_end);
}
let min = |x: f64| number_min.unwrap_or(x);
let max = |x: f64| number_max.unwrap_or(x);
let mut extra_widgets = vec![];
let widgets = match ty {
Type::Concrete(concrete_type) => {
match concrete_type.alias.as_ref().map(|x| x.as_ref()) {
// Aliased types (ambiguous values)
Some("Percentage") => number_widget(document_node, node_id, index, name, number_input.percentage().min(min(0.)).max(max(100.)), true).into(),
Some("SignedPercentage") => number_widget(document_node, node_id, index, name, number_input.percentage().min(min(-100.)).max(max(100.)), true).into(),
Some("Angle") => number_widget(document_node, node_id, index, name, number_input.mode_range().min(min(-180.)).max(max(180.)).unit("°"), true).into(),
Some("PixelLength") => number_widget(document_node, node_id, index, name, number_input.min(min(0.)).unit("px"), true).into(),
Some("Length") => number_widget(document_node, node_id, index, name, number_input.min(min(0.)), true).into(),
Some("Fraction") => number_widget(document_node, node_id, index, name, number_input.min(min(0.)).max(max(1.)), true).into(),
Some("IntegerCount") => number_widget(document_node, node_id, index, name, number_input.int().min(min(1.)), true).into(),
Some("SeedValue") => number_widget(document_node, node_id, index, name, number_input.int().min(min(0.)), true).into(),
Some("Resolution") => vec2_widget(document_node, node_id, index, name, "W", "H", "px", Some(64.), add_blank_assist),
// For all other types, use TypeId-based matching
_ => {
if let Some(internal_id) = concrete_type.id {
use std::any::TypeId;
match internal_id {
x if x == TypeId::of::<bool>() => bool_widget(document_node, node_id, index, name, CheckboxInput::default(), true).into(),
x if x == TypeId::of::<f64>() => number_widget(document_node, node_id, index, name, number_input.min(min(f64::NEG_INFINITY)).max(max(f64::INFINITY)), true).into(),
x if x == TypeId::of::<u32>() => number_widget(document_node, node_id, index, name, number_input.int().min(min(0.)).max(max(f64::from(u32::MAX))), true).into(),
x if x == TypeId::of::<u64>() => number_widget(document_node, node_id, index, name, number_input.int().min(min(0.)), true).into(),
x if x == TypeId::of::<String>() => text_widget(document_node, node_id, index, name, true).into(),
x if x == TypeId::of::<Color>() => color_widget(document_node, node_id, index, name, ColorButton::default(), true),
x if x == TypeId::of::<Option<Color>>() => color_widget(document_node, node_id, index, name, ColorButton::default().allow_none(true), true),
x if x == TypeId::of::<DVec2>() => vec2_widget(document_node, node_id, index, name, "X", "Y", "", None, add_blank_assist),
x if x == TypeId::of::<UVec2>() => vec2_widget(document_node, node_id, index, name, "X", "Y", "", Some(0.), add_blank_assist),
x if x == TypeId::of::<IVec2>() => vec2_widget(document_node, node_id, index, name, "X", "Y", "", None, add_blank_assist),
x if x == TypeId::of::<Vec<f64>>() => vec_f64_input(document_node, node_id, index, name, TextInput::default(), true).into(),
x if x == TypeId::of::<Vec<DVec2>>() => vec_dvec2_input(document_node, node_id, index, name, TextInput::default(), true).into(),
x if x == TypeId::of::<Font>() => {
let (font_widgets, style_widgets) = font_inputs(document_node, node_id, index, name, false);
font_widgets.into_iter().chain(style_widgets.unwrap_or_default()).collect::<Vec<_>>().into()
}
x if x == TypeId::of::<Curve>() => curves_widget(document_node, node_id, index, name, true),
x if x == TypeId::of::<GradientStops>() => color_widget(document_node, node_id, index, name, ColorButton::default().allow_none(false), true),
x if x == TypeId::of::<VectorData>() => vector_widget(document_node, node_id, index, name, true).into(),
x if x == TypeId::of::<Footprint>() => {
let widgets = footprint_widget(document_node, node_id, index);
let (last, rest) = widgets.split_last().expect("Footprint widget should return multiple rows");
extra_widgets = rest.to_vec();
last.clone()
}
x if x == TypeId::of::<BlendMode>() => blend_mode(document_node, node_id, index, name, true),
x if x == TypeId::of::<RedGreenBlue>() => color_channel(document_node, node_id, index, name, true),
x if x == TypeId::of::<RedGreenBlueAlpha>() => rgba_channel(document_node, node_id, index, name, true),
x if x == TypeId::of::<NoiseType>() => noise_type(document_node, node_id, index, name, true),
x if x == TypeId::of::<FractalType>() => fractal_type(document_node, node_id, index, name, true, false),
x if x == TypeId::of::<CellularDistanceFunction>() => cellular_distance_function(document_node, node_id, index, name, true, false),
x if x == TypeId::of::<CellularReturnType>() => cellular_return_type(document_node, node_id, index, name, true, false),
x if x == TypeId::of::<DomainWarpType>() => domain_warp_type(document_node, node_id, index, name, true, false),
x if x == TypeId::of::<RelativeAbsolute>() => vec![DropdownInput::new(vec![vec![
MenuListEntry::new("Relative")
.label("Relative")
.on_update(update_value(|_| TaggedValue::RelativeAbsolute(RelativeAbsolute::Relative), node_id, index)),
MenuListEntry::new("Absolute")
.label("Absolute")
.on_update(update_value(|_| TaggedValue::RelativeAbsolute(RelativeAbsolute::Absolute), node_id, index)),
]])
.widget_holder()]
.into(),
x if x == TypeId::of::<LineCap>() => line_cap_widget(document_node, node_id, index, name, true),
x if x == TypeId::of::<LineJoin>() => line_join_widget(document_node, node_id, index, name, true),
x if x == TypeId::of::<FillType>() => vec![DropdownInput::new(vec![vec![
MenuListEntry::new("Solid")
.label("Solid")
.on_update(update_value(|_| TaggedValue::FillType(FillType::Solid), node_id, index)),
MenuListEntry::new("Gradient")
.label("Gradient")
.on_update(update_value(|_| TaggedValue::FillType(FillType::Gradient), node_id, index)),
]])
.widget_holder()]
.into(),
x if x == TypeId::of::<GradientType>() => vec![DropdownInput::new(vec![vec![
MenuListEntry::new("Linear")
.label("Linear")
.on_update(update_value(|_| TaggedValue::GradientType(GradientType::Linear), node_id, index)),
MenuListEntry::new("Radial")
.label("Radial")
.on_update(update_value(|_| TaggedValue::GradientType(GradientType::Radial), node_id, index)),
]])
.widget_holder()]
.into(),
x if x == TypeId::of::<BooleanOperation>() => boolean_operation_radio_buttons(document_node, node_id, index, name, true),
x if x == TypeId::of::<CentroidType>() => centroid_widget(document_node, node_id, index),
x if x == TypeId::of::<LuminanceCalculation>() => luminance_calculation(document_node, node_id, index, name, true),
x if x == TypeId::of::<ImaginateSamplingMethod>() => vec![DropdownInput::new(
ImaginateSamplingMethod::list()
.into_iter()
.map(|method| {
vec![MenuListEntry::new(format!("{:?}", method)).label(method.to_string()).on_update(update_value(
move |_| TaggedValue::ImaginateSamplingMethod(method),
node_id,
index,
))]
})
.collect(),
)
.widget_holder()]
.into(),
x if x == TypeId::of::<ImaginateMaskStartingFill>() => vec![DropdownInput::new(
ImaginateMaskStartingFill::list()
.into_iter()
.map(|fill| {
vec![MenuListEntry::new(format!("{:?}", fill)).label(fill.to_string()).on_update(update_value(
move |_| TaggedValue::ImaginateMaskStartingFill(fill),
node_id,
index,
))]
})
.collect(),
)
.widget_holder()]
.into(),
_ => vec![TextLabel::new(format!("Unsupported type: {}", concrete_type.name)).widget_holder()].into(),
}
} else {
vec![TextLabel::new(format!("Unsupported type: {}", concrete_type.name)).widget_holder()].into()
}
}
}
}
Type::Generic(_) => vec![TextLabel::new("Generic type (not supported)").widget_holder()].into(),
Type::Fn(_, out) => return property_from_type(document_node, node_id, index, name, out, _context, number_options),
Type::Future(_) => vec![TextLabel::new("Future type (not supported)").widget_holder()].into(),
};
extra_widgets.push(widgets);
extra_widgets
}
fn text_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec<WidgetHolder> {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
@@ -498,6 +653,14 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na
.on_commit(commit_value)
.widget_holder(),
]),
Some(&TaggedValue::U64(x)) => widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
number_props
.value(Some(x as f64))
.on_update(update_value(move |x: &NumberInput| TaggedValue::U64((x.value.unwrap()) as u64), node_id, index))
.on_commit(commit_value)
.widget_holder(),
]),
_ => {}
}
@@ -930,137 +1093,27 @@ fn centroid_widget(document_node: &DocumentNode, node_id: NodeId, index: usize)
LayoutGroup::Row { widgets }
}
pub fn levels_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let input_shadows = number_widget(document_node, node_id, 1, "Shadows", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let input_midtones = number_widget(document_node, node_id, 2, "Midtones", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let input_highlights = number_widget(document_node, node_id, 3, "Highlights", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let output_minimums = number_widget(document_node, node_id, 4, "Output Minimums", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let output_maximums = number_widget(document_node, node_id, 5, "Output Maximums", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
vec![
LayoutGroup::Row { widgets: input_shadows },
LayoutGroup::Row { widgets: input_midtones },
LayoutGroup::Row { widgets: input_highlights },
LayoutGroup::Row { widgets: output_minimums },
LayoutGroup::Row { widgets: output_maximums },
]
}
pub fn black_and_white_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
const MIN: f64 = -200.;
const MAX: f64 = 300.;
// TODO: Add tint color (blended above using the "Color" blend mode)
let tint = color_widget(document_node, node_id, 1, "Tint", ColorButton::default(), true);
let r_weight = number_widget(document_node, node_id, 2, "Reds", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
let y_weight = number_widget(document_node, node_id, 3, "Yellows", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
let g_weight = number_widget(document_node, node_id, 4, "Greens", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
let c_weight = number_widget(document_node, node_id, 5, "Cyans", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
let b_weight = number_widget(document_node, node_id, 6, "Blues", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
let m_weight = number_widget(document_node, node_id, 7, "Magentas", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true);
vec![
tint,
LayoutGroup::Row { widgets: r_weight },
LayoutGroup::Row { widgets: y_weight },
LayoutGroup::Row { widgets: g_weight },
LayoutGroup::Row { widgets: c_weight },
LayoutGroup::Row { widgets: b_weight },
LayoutGroup::Row { widgets: m_weight },
]
}
pub fn blend_color_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let under = color_widget(document_node, node_id, 1, "Under", ColorButton::default(), true);
let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true);
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
vec![under, blend_mode, LayoutGroup::Row { widgets: opacity }]
}
pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let backdrop = color_widget(document_node, node_id, 1, "Backdrop", ColorButton::default(), true);
let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true);
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }]
}
pub fn number_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 0, "Number", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn percentage_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 0, "Percentage", NumberInput::default().min(0.).max(100.).mode_range(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn vector2_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let x = number_widget(document_node, node_id, 1, "X", NumberInput::default(), true);
let y = number_widget(document_node, node_id, 2, "Y", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets: x }, LayoutGroup::Row { widgets: y }]
}
pub fn boolean_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = bool_widget(document_node, node_id, 0, "Bool", CheckboxInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn color_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![color_widget(document_node, node_id, 0, "Color", ColorButton::default(), true)]
}
pub fn gradient_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![color_widget(document_node, node_id, 0, "Gradient", ColorButton::default().allow_none(false), true)]
}
pub fn load_image_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn load_image_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let url = text_widget(document_node, node_id, 1, "URL", true);
vec![LayoutGroup::Row { widgets: url }]
}
pub fn output_properties(_document_node: &DocumentNode, _node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let label = TextLabel::new("Graphics fed into the Output are drawn in the viewport").widget_holder();
vec![LayoutGroup::Row { widgets: vec![label] }]
}
pub fn mask_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn mask_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let mask = color_widget(document_node, node_id, 1, "Stencil", ColorButton::default(), true);
vec![mask]
}
pub fn color_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![color_channel(document_node, node_id, 0, "Channel", true)]
}
pub fn luminance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let luminance_calc = luminance_calculation(document_node, node_id, 1, "Luminance Calc", true);
vec![luminance_calc]
}
pub fn insert_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn insert_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_channel = color_channel(document_node, node_id, 2, "Into", true);
vec![color_channel]
}
pub fn extract_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_channel = rgba_channel(document_node, node_id, 1, "From", true);
vec![color_channel]
}
// Noise Type is commented out for now as there is only one type of noise (White Noise).
// As soon as there are more types of noise, this should be uncommented.
pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
// Get the current values of the inputs of interest so they can set whether certain inputs are disabled based on various conditions.
let current_noise_type = match &document_node.inputs[3].as_value() {
Some(&TaggedValue::NoiseType(noise_type)) => Some(noise_type),
@@ -1208,62 +1261,52 @@ pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _
]
}
pub fn hue_saturation_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let hue_shift = number_widget(document_node, node_id, 1, "Hue Shift", NumberInput::default().min(-180.).max(180.).unit("°"), true);
let saturation_shift = number_widget(document_node, node_id, 2, "Saturation Shift", NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true);
let lightness_shift = number_widget(document_node, node_id, 3, "Lightness Shift", NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true);
pub(crate) fn brightness_contrast_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let is_use_classic = match &document_node.inputs[3].as_value() {
Some(&TaggedValue::Bool(value)) => value,
_ => false,
};
let ((b_min, b_max), (c_min, c_max)) = if is_use_classic { ((-100., 100.), (-100., 100.)) } else { ((-100., 150.), (-50., 100.)) };
vec![
LayoutGroup::Row { widgets: hue_shift },
LayoutGroup::Row { widgets: saturation_shift },
LayoutGroup::Row { widgets: lightness_shift },
]
}
pub fn brightness_contrast_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let brightness = number_widget(document_node, node_id, 1, "Brightness", NumberInput::default().min(-150.).max(150.), true);
let contrast = number_widget(document_node, node_id, 2, "Contrast", NumberInput::default().min(-100.).max(100.), true);
let use_legacy = bool_widget(document_node, node_id, 3, "Use Legacy", CheckboxInput::default(), true);
let brightness = number_widget(
document_node,
node_id,
1,
"Brightness",
NumberInput::default().mode_range().range_min(Some(b_min)).range_max(Some(b_max)).unit("%").display_decimal_places(2),
true,
);
let contrast = number_widget(
document_node,
node_id,
2,
"Contrast",
NumberInput::default().mode_range().range_min(Some(c_min)).range_max(Some(c_max)).unit("%").display_decimal_places(2),
true,
);
let use_classic = bool_widget(document_node, node_id, 3, "Use Classic", CheckboxInput::default(), true);
vec![
LayoutGroup::Row { widgets: brightness },
LayoutGroup::Row { widgets: contrast },
LayoutGroup::Row { widgets: use_legacy },
LayoutGroup::Row { widgets: use_classic },
]
}
pub fn curves_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn curves_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let curves = curves_widget(document_node, node_id, 1, "Curve", true);
vec![curves]
}
pub fn _blur_image_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn _blur_image_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let radius = number_widget(document_node, node_id, 1, "Radius", NumberInput::default().min(0.).max(20.).int(), true);
let sigma = number_widget(document_node, node_id, 2, "Sigma", NumberInput::default().min(0.).max(10000.), true);
vec![LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: sigma }]
}
pub fn threshold_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let thereshold_min = number_widget(document_node, node_id, 1, "Min Luminance", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let thereshold_max = number_widget(document_node, node_id, 2, "Max Luminance", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
let luminance_calc = luminance_calculation(document_node, node_id, 3, "Luminance Calc", true);
vec![LayoutGroup::Row { widgets: thereshold_min }, LayoutGroup::Row { widgets: thereshold_max }, luminance_calc]
}
pub fn gradient_map_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let gradient_index = 1;
let reverse_index = 2;
let gradient_row = color_widget(document_node, node_id, gradient_index, "Gradient", ColorButton::default().allow_none(false), true);
let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", CheckboxInput::default(), true);
vec![gradient_row, LayoutGroup::Row { widgets: reverse_row }]
}
pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let fill_index = 1;
let stroke_index = 2;
let gradient_index = 3;
@@ -1303,22 +1346,7 @@ pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _
]
}
pub fn vibrance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let vibrance_index = 1;
let vibrance = number_widget(
document_node,
node_id,
vibrance_index,
"Vibrance",
NumberInput::default().mode_range().min(-100.).max(100.).unit("%"),
true,
);
vec![LayoutGroup::Row { widgets: vibrance }]
}
pub fn channel_mixer_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn channel_mixer_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
// Monochrome
let monochrome_index = 1;
let monochrome = bool_widget(document_node, node_id, monochrome_index, "Monochrome", CheckboxInput::default(), true);
@@ -1418,7 +1446,7 @@ pub fn channel_mixer_properties(document_node: &DocumentNode, node_id: NodeId, _
layout
}
pub fn selective_color_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn selective_color_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
// Colors choice
let colors_index = 38;
let mut colors = vec![TextLabel::new("Colors").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()];
@@ -1508,40 +1536,13 @@ pub fn selective_color_properties(document_node: &DocumentNode, node_id: NodeId,
}
#[cfg(feature = "gpu")]
pub fn _gpu_map_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn _gpu_map_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let map = text_widget(document_node, node_id, 1, "Map", true);
vec![LayoutGroup::Row { widgets: map }]
}
pub fn opacity_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let gamma = number_widget(document_node, node_id, 1, "Factor", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true);
vec![LayoutGroup::Row { widgets: gamma }]
}
pub fn blend_mode_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![blend_mode(document_node, node_id, 1, "Blend Mode", true)]
}
pub fn blend_mode_value_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![blend_mode(document_node, node_id, 0, "Blend Mode", true)]
}
pub fn posterize_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let value = number_widget(document_node, node_id, 1, "Levels", NumberInput::default().min(2.).max(255.).int(), true);
vec![LayoutGroup::Row { widgets: value }]
}
#[cfg(feature = "quantization")]
pub fn quantize_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let value = number_widget(document_node, node_id, 1, "Levels", NumberInput::default().min(1.).max(1000.).int(), true);
let index = number_widget(document_node, node_id, 1, "Fit Fn Index", NumberInput::default().min(0.).max(2.).int(), true);
vec![LayoutGroup::Row { widgets: value }, LayoutGroup::Row { widgets: index }]
}
pub fn exposure_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn exposure_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let exposure = number_widget(document_node, node_id, 1, "Exposure", NumberInput::default().min(-20.).max(20.), true);
let offset = number_widget(document_node, node_id, 2, "Offset", NumberInput::default().min(-0.5).max(0.5), true);
let gamma_input = NumberInput::default().min(0.01).max(9.99).increment_step(0.1);
@@ -1554,82 +1555,7 @@ pub fn exposure_properties(document_node: &DocumentNode, node_id: NodeId, _conte
]
}
pub fn add_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Addend", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn subtract_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Subtrahend", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn divide_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Divisor", NumberInput::new(Some(1.)), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn multiply_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Multiplicand", NumberInput::new(Some(1.)), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn exponent_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Power", NumberInput::new(Some(2.)), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn log_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Base", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn max_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Maximum", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn min_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Minimum", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn eq_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Equals", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn modulo_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = number_widget(document_node, node_id, 1, "Modulo", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn circle_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![LayoutGroup::Row {
widgets: number_widget(document_node, node_id, 1, "Radius", NumberInput::default(), true),
}]
}
pub fn ellipse_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let operand = |name: &str, index| {
let widgets = number_widget(document_node, node_id, index, name, NumberInput::default(), true);
LayoutGroup::Row { widgets }
};
vec![operand("Radius X", 1), operand("Radius Y", 2)]
}
pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let size_x_index = 1;
let size_y_index = 2;
let corner_rounding_type_index = 3;
@@ -1754,37 +1680,17 @@ pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _cont
]
}
pub fn regular_polygon_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let points = number_widget(document_node, node_id, 1, "Points", NumberInput::default().min(3.), true);
let radius = number_widget(document_node, node_id, 2, "Radius", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets: points }, LayoutGroup::Row { widgets: radius }]
}
pub fn star_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let points = number_widget(document_node, node_id, 1, "Points", NumberInput::default().min(2.), true);
let radius = number_widget(document_node, node_id, 2, "Radius", NumberInput::default(), true);
let inner_radius = number_widget(document_node, node_id, 3, "Inner Radius", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets: points }, LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: inner_radius }]
}
pub fn line_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn line_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let operand = |name: &str, index| vec2_widget(document_node, node_id, index, name, "X", "Y", "px", None, add_blank_assist);
vec![operand("Start", 1), operand("End", 2)]
}
pub fn spline_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn spline_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![LayoutGroup::Row {
widgets: vec_dvec2_input(document_node, node_id, 1, "Points", TextInput::default().centered(true), true),
}]
}
pub fn logic_operator_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = bool_widget(document_node, node_id, 0, "Operand B", CheckboxInput::default(), true);
vec![LayoutGroup::Row { widgets }]
}
pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let translation = vec2_widget(document_node, node_id, 1, "Translation", "X", "Y", " px", None, add_blank_assist);
let rotation = {
@@ -1817,11 +1723,11 @@ pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _cont
vec![translation, rotation, scale]
}
pub fn rasterize_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn rasterize_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
footprint_widget(document_node, node_id, 1)
}
pub fn text_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn text_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let text = text_area_widget(document_node, node_id, 1, "Text", true);
let (font, style) = font_inputs(document_node, node_id, 2, "Font", true);
let size = number_widget(document_node, node_id, 3, "Size", NumberInput::default().unit(" px").min(1.), true);
@@ -1834,7 +1740,7 @@ pub fn text_properties(document_node: &DocumentNode, node_id: NodeId, _context:
result
}
pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let imaginate_node = [context.selection_network_path, &[node_id]].concat();
let resolve_input = |name: &str| {
@@ -2328,7 +2234,7 @@ fn unknown_node_properties(reference: &String) -> Vec<LayoutGroup> {
string_properties(format!("Node '{}' cannot be found in library", reference))
}
pub fn node_no_properties(_document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn node_no_properties(_document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
string_properties(if context.network_interface.is_layer(&node_id, context.selection_network_path) {
"Layer has no properties"
} else {
@@ -2336,13 +2242,13 @@ pub fn node_no_properties(_document_node: &DocumentNode, node_id: NodeId, contex
})
}
pub fn index_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn index_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let index = number_widget(document_node, node_id, 1, "Index", NumberInput::default().min(0.), true);
vec![LayoutGroup::Row { widgets: index }]
}
pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup {
pub(crate) fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup {
let reference = context.network_interface.reference(&node_id, context.selection_network_path).clone();
let layout = if let Some(ref reference) = reference {
match super::document_node_definitions::resolve_document_node_type(reference) {
@@ -2361,66 +2267,7 @@ pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, c
}
}
pub fn stroke_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_index = 1;
let weight_index = 2;
let dash_lengths_index = 3;
let dash_offset_index = 4;
let line_cap_index = 5;
let line_join_index = 6;
let miter_limit_index = 7;
let color = color_widget(document_node, node_id, color_index, "Color", ColorButton::default(), true);
let weight = number_widget(document_node, node_id, weight_index, "Weight", NumberInput::default().unit("px").min(0.), true);
let dash_lengths_val = match &document_node.inputs[dash_lengths_index].as_value() {
Some(TaggedValue::VecF64(x)) => x,
_ => &vec![],
};
let dash_lengths = vec_f64_input(document_node, node_id, dash_lengths_index, "Dash Lengths", TextInput::default().centered(true), true);
let number_input = NumberInput::default().unit("px").disabled(dash_lengths_val.is_empty());
let dash_offset = number_widget(document_node, node_id, dash_offset_index, "Dash Offset", number_input, true);
let line_cap = line_cap_widget(document_node, node_id, line_cap_index, "Line Cap", true);
let line_join = line_join_widget(document_node, node_id, line_join_index, "Line Join", true);
let line_join_val = match &document_node.inputs[line_join_index].as_value() {
Some(TaggedValue::LineJoin(x)) => x,
_ => &LineJoin::Miter,
};
let number_input = NumberInput::default().min(0.).disabled(line_join_val != &LineJoin::Miter);
let miter_limit = number_widget(document_node, node_id, miter_limit_index, "Miter Limit", number_input, true);
vec![
color,
LayoutGroup::Row { widgets: weight },
LayoutGroup::Row { widgets: dash_lengths },
LayoutGroup::Row { widgets: dash_offset },
line_cap,
line_join,
LayoutGroup::Row { widgets: miter_limit },
]
}
pub fn repeat_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let direction = vec2_widget(document_node, node_id, 1, "Direction", "X", "Y", " px", None, add_blank_assist);
let angle = number_widget(document_node, node_id, 2, "Angle", NumberInput::default().unit("°"), true);
let instances = number_widget(document_node, node_id, 3, "Instances", NumberInput::default().min(1.).is_integer(true), true);
vec![direction, LayoutGroup::Row { widgets: angle }, LayoutGroup::Row { widgets: instances }]
}
pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let angle_offset = number_widget(document_node, node_id, 1, "Angle Offset", NumberInput::default().unit("°"), true);
let radius = number_widget(document_node, node_id, 2, "Radius", NumberInput::default(), true); // TODO: What units?
let instances = number_widget(document_node, node_id, 3, "Instances", NumberInput::default().min(1.).is_integer(true), true);
vec![
LayoutGroup::Row { widgets: angle_offset },
LayoutGroup::Row { widgets: radius },
LayoutGroup::Row { widgets: instances },
]
}
pub fn boolean_operation_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn boolean_operation_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let group_of_paths_index = 0;
let operation_index = 1;
@@ -2434,7 +2281,7 @@ pub fn boolean_operation_properties(document_node: &DocumentNode, node_id: NodeI
vec![LayoutGroup::Row { widgets }, operation]
}
pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let instance_index = 1;
let random_scale_min_index = 2;
let random_scale_max_index = 3;
@@ -2493,7 +2340,7 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
]
}
pub fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.).unit(" px"), true);
let start_offset = number_widget(document_node, node_id, 2, "Start Offset", NumberInput::default().min(0.).unit(" px"), true);
let stop_offset = number_widget(document_node, node_id, 3, "Stop Offset", NumberInput::default().min(0.).unit(" px"), true);
@@ -2507,7 +2354,7 @@ pub fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _
]
}
pub fn poisson_disk_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn poisson_disk_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let separation_disk_diameter_index = 1;
let seed_index = 2;
@@ -2525,18 +2372,8 @@ pub fn poisson_disk_points_properties(document_node: &DocumentNode, node_id: Nod
vec![LayoutGroup::Row { widgets: spacing }, LayoutGroup::Row { widgets: seed }]
}
pub fn morph_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let start_index = number_widget(document_node, node_id, 2, "Start Index", NumberInput::default().min(0.), true);
let time = number_widget(document_node, node_id, 3, "Time", NumberInput::default().min(0.).max(1.).mode_range(), true);
vec![
LayoutGroup::Row { widgets: start_index }.with_tooltip("The index of point on the target that morphs to the first point of the source"),
LayoutGroup::Row { widgets: time }.with_tooltip("Linear time of transition - 0. is source, 1. is target"),
]
}
/// Fill Node Widgets LayoutGroup
pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let fill_index = 1;
let backup_color_index = 2;
let backup_gradient_index = 3;
@@ -2711,7 +2548,46 @@ pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context:
widgets
}
pub fn artboard_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub fn stroke_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color_index = 1;
let weight_index = 2;
let dash_lengths_index = 3;
let dash_offset_index = 4;
let line_cap_index = 5;
let line_join_index = 6;
let miter_limit_index = 7;
let color = color_widget(document_node, node_id, color_index, "Color", ColorButton::default(), true);
let weight = number_widget(document_node, node_id, weight_index, "Weight", NumberInput::default().unit("px").min(0.), true);
let dash_lengths_val = match &document_node.inputs[dash_lengths_index].as_value() {
Some(TaggedValue::VecF64(x)) => x,
_ => &vec![],
};
let dash_lengths = vec_f64_input(document_node, node_id, dash_lengths_index, "Dash Lengths", TextInput::default().centered(true), true);
let number_input = NumberInput::default().unit("px").disabled(dash_lengths_val.is_empty());
let dash_offset = number_widget(document_node, node_id, dash_offset_index, "Dash Offset", number_input, true);
let line_cap = line_cap_widget(document_node, node_id, line_cap_index, "Line Cap", true);
let line_join = line_join_widget(document_node, node_id, line_join_index, "Line Join", true);
let line_join_val = match &document_node.inputs[line_join_index].as_value() {
Some(TaggedValue::LineJoin(x)) => x,
_ => &LineJoin::Miter,
};
let number_input = NumberInput::default().min(0.).disabled(line_join_val != &LineJoin::Miter);
let miter_limit = number_widget(document_node, node_id, miter_limit_index, "Miter Limit", number_input, true);
vec![
color,
LayoutGroup::Row { widgets: weight },
LayoutGroup::Row { widgets: dash_lengths },
LayoutGroup::Row { widgets: dash_offset },
line_cap,
line_join,
LayoutGroup::Row { widgets: miter_limit },
]
}
pub(crate) fn artboard_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let location = vec2_widget(document_node, node_id, 2, "Location", "X", "Y", " px", None, add_blank_assist);
let dimensions = vec2_widget(document_node, node_id, 3, "Dimensions", "W", "H", " px", None, add_blank_assist);
let background = color_widget(document_node, node_id, 4, "Background", ColorButton::default().allow_none(false), true);
@@ -2722,27 +2598,7 @@ pub fn artboard_properties(document_node: &DocumentNode, node_id: NodeId, _conte
vec![location, dimensions, background, clip_row]
}
pub fn color_fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
pub(crate) fn color_fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color = color_widget(document_node, node_id, 1, "Color", ColorButton::default(), true);
vec![color]
}
pub fn color_overlay_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let color = color_widget(document_node, node_id, 1, "Color", ColorButton::default(), true);
let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true);
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().percentage(), true);
vec![color, blend_mode, LayoutGroup::Row { widgets: opacity }]
}
pub fn image_color_palette(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let size = number_widget(document_node, node_id, 1, "Max Size", NumberInput::default().int().min(1.).max(28.), true);
vec![LayoutGroup::Row { widgets: size }]
}
pub fn centroid_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let centroid_type = centroid_widget(document_node, node_id, 1);
vec![centroid_type]
}

View File

@@ -17,7 +17,7 @@ pub enum FrontendGraphDataType {
impl FrontendGraphDataType {
pub fn with_type(input: &Type) -> Self {
match TaggedValue::from_type(input) {
match TaggedValue::from_type_or_none(input) {
TaggedValue::Image(_) | TaggedValue::ImageFrame(_) => Self::Raster,
TaggedValue::Subpaths(_) | TaggedValue::VectorData(_) => Self::VectorData,
TaggedValue::U32(_)

View File

@@ -426,12 +426,12 @@ impl NodeNetworkInterface {
};
} else {
// Disconnect node input if it is not connected to another node in new_ids
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
let tagged_value = TaggedValue::from_type_or_none(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
*input = NodeInput::value(tagged_value, true);
}
} else if let &mut NodeInput::Network { .. } = input {
// Always disconnect network node input
let tagged_value = TaggedValue::from_type(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
let tagged_value = TaggedValue::from_type_or_none(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0);
*input = NodeInput::value(tagged_value, true);
}
}
@@ -1445,7 +1445,12 @@ impl NodeNetworkInterface {
/// Gets the type for a random protonode implementation (used if there is no type from the compiled network)
fn random_protonode_implementation(protonode: &graph_craft::ProtoNodeIdentifier) -> Option<&graphene_std::NodeIOTypes> {
let Some(node_io_hashmap) = NODE_REGISTRY.get(protonode) else {
let mut protonode = protonode.clone();
// TODO: Remove
if let Some((path, _generics)) = protonode.name.split_once('<') {
protonode = path.to_string().to_string().into();
}
let Some(node_io_hashmap) = NODE_REGISTRY.get(&protonode) else {
log::error!("Could not get hashmap for proto node: {protonode:?}");
return None;
};
@@ -3120,6 +3125,19 @@ impl NodeNetworkInterface {
node_metadata.persistent_metadata.network_metadata = metadata.network_metadata;
}
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
pub fn set_manual_compostion(&mut self, node_id: &NodeId, network_path: &[NodeId], manual_composition: Option<Type>) {
let Some(network) = self.network_mut(network_path) else {
log::error!("Could not get nested network in set_implementation");
return;
};
let Some(node) = network.nodes.get_mut(node_id) else {
log::error!("Could not get node in set_implementation");
return;
};
node.manual_composition = manual_composition;
}
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
pub fn replace_inputs(&mut self, node_id: &NodeId, inputs: Vec<NodeInput>, network_path: &[NodeId]) -> Vec<NodeInput> {
let Some(network) = self.network_mut(network_path) else {
@@ -3386,7 +3404,7 @@ impl NodeNetworkInterface {
}
}
let tagged_value = TaggedValue::from_type(&self.input_type(input_connector, network_path).0);
let tagged_value = TaggedValue::from_type_or_none(&self.input_type(input_connector, network_path).0);
let value_input = NodeInput::value(tagged_value, true);

View File

@@ -6,6 +6,7 @@ use crate::consts::DEFAULT_DOCUMENT_NAME;
use crate::messages::dialog::simple_dialogs;
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
use crate::messages::layout::utility_types::widget_prelude::*;
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::DocumentMessageData;
use crate::messages::prelude::*;
@@ -423,7 +424,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
.get(node_id)
.and_then(|node| node.persistent_metadata.reference.as_ref())
{
let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type(reference).unwrap();
let node_definition = resolve_document_node_type(reference).unwrap();
let default_definition_node = node_definition.default_node_template();
document.network_interface.replace_implementation(node_id, &[], default_definition_node.document_node.implementation);
document
@@ -447,10 +448,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
let node_ids = document.network_interface.network(&[]).unwrap().nodes.keys().cloned().collect::<Vec<_>>();
for node_id in &node_ids {
let Some(node) = document.network_interface.network(&[]).unwrap().nodes.get(node_id) else {
log::error!("could not get node in deserialize_document");
continue;
};
let Some(node_metadata) = document.network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata.get(node_id) else {
log::error!("could not get node metadata for node {node_id} in deserialize_document");
continue;
@@ -461,8 +458,24 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
let Some(ref reference) = node_metadata.persistent_metadata.reference.clone() else {
continue;
};
if let Some(node_definition) = resolve_document_node_type(reference) {
let document_node = node_definition.default_node_template().document_node;
document.network_interface.set_manual_compostion(node_id, &[], document_node.manual_composition);
// if ["Fill", "Stroke", "Splines from Points", "Sample Subpaths", "Sample Points", "Copy to Points", "Path", "Scatter Points"].contains(&reference.as_str()) {
// document.network_interface.set_implementation(node_id, &[], document_node.implementation);
// }
document.network_interface.replace_implementation(node_id, &[], document_node.implementation);
document
.network_interface
.replace_implementation_metadata(node_id, &[], node_definition.default_node_template().persistent_node_metadata);
}
let Some(node) = document.network_interface.network(&[]).unwrap().nodes.get(node_id) else {
log::error!("could not get node in deserialize_document");
continue;
};
if reference == "Fill" && node.inputs.len() == 8 {
let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::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;
document.network_interface.replace_implementation(node_id, &[], document_node.implementation.clone());
@@ -518,7 +531,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
}
}
// Upgrade construct layer implementation from https://github.com/GraphiteEditor/Graphite/pull/1946
// 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();

View File

@@ -13,7 +13,7 @@ use crate::messages::prelude::*;
use crate::node_graph_executor::NodeGraphExecutor;
use graphene_core::raster::color::Color;
use graphene_std::text::FontCache;
use graphene_core::text::FontCache;
use std::fmt::{self, Debug};

View File

@@ -230,7 +230,7 @@ impl NodeRuntime {
self.monitor_nodes = proto_network
.nodes
.iter()
.filter(|(_, node)| node.identifier == "graphene_core::memo::MonitorNode<_, _, _>".into())
.filter(|(_, node)| node.identifier == "graphene_core::memo::MonitorNode".into())
.map(|(_, node)| node.original_location.path.clone().unwrap_or_default())
.collect::<Vec<_>>();
@@ -576,7 +576,7 @@ impl NodeGraphExecutor {
});
responses.add(NodeGraphMessage::SendGraph);
return Err("Node graph evaluation failed".to_string());
return Err(format!("Node graph evaluation failed:\n{e}"));
}
Ok(result) => result,
};