Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions node-graph/graph-craft/src/document/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,21 +618,13 @@ impl TaggedValue {
}

fn to_color(input: &str) -> Option<Color> {
// String syntax (e.g. "000000ff")
if input.starts_with('"') && input.ends_with('"') {
let hex = input.trim().trim_matches('"').trim().trim_start_matches('#');
let color = SRGBA8::from_hex_str(hex).map(Color::from);
if color.is_none() {
log::error!("Invalid default value color string: {input}");
}
return color;
}

// Color constant syntax (e.g. Color::BLACK)
let mut choices = input.split("::");
let (first, second) = (choices.next()?.trim(), choices.next()?.trim());
if first == "Color" {
return Some(match second {
if let Some((first, second)) = input.split_once("::") {
if first.trim() != "Color" {
log::error!("Invalid default value color: {input}");
return None;
}
return Some(match second.trim() {
"BLACK" => Color::BLACK,
"WHITE" => Color::WHITE,
"RED" => Color::RED,
Expand All @@ -649,8 +641,13 @@ impl TaggedValue {
});
}

log::error!("Invalid default value color: {input}");
None
// Hex syntax (e.g. "000000ff"), which a string literal default reaches here without its quotes
let hex = input.trim().trim_matches('"').trim().trim_start_matches('#');
let color = SRGBA8::from_hex_str(hex).map(Color::from);
Comment thread
Keavon marked this conversation as resolved.
if color.is_none() {
log::error!("Invalid default value color string: {input}");
}
color
}

fn to_gradient(input: &str) -> Option<Gradient> {
Expand Down Expand Up @@ -1039,6 +1036,18 @@ mod paint_default_parsing {
);
}

/// A hex string default reaches the parser without the quotes its literal had in the node signature, and must still parse.
#[test]
fn hex_string_color_default_parses_without_quotes() {
let tint = Some(TaggedValue::Color(Color::from(SRGBA8::new(225, 211, 179, 255))));
assert_eq!(TaggedValue::from_primitive_string("e1d3b3", &item!(Color)), tint, "a bare hex default should resolve");
assert_eq!(
TaggedValue::from_primitive_string("\"#e1d3b3\"", &item!(Color)),
tint,
"a quoted, hash-prefixed hex default should resolve"
);
}

/// Table-era documents stored the red-slash "no paint" fill as an empty color table, which must keep
/// deserializing to [`TaggedValue::no_paint`] rather than collapsing to a transparent color.
#[test]
Expand Down
7 changes: 4 additions & 3 deletions node-graph/node-macro/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,9 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
quote!(Some(concrete!(#implementation_ty)))
}
}
// A concrete ranked `Item<T>` param's scalar `#[default]` parses as a bare `T` literal (unranked, promoted at resolution);
// without one it keeps the structural `Type::Item` wire type with the element's alias on its descriptor (so the rank-0 Properties widget still dispatches, e.g. `Progression`), and `node_inputs` peels to `T` if no `Item` type default exists
// A concrete ranked `Item<T>` param's scalar `#[default]` parses as a bare `T` literal (unranked, promoted at resolution); without one it keeps
// the structural `Type::Item` wire type, and `node_inputs` peels to `T` if no `Item` type default exists. Either way the element's alias stays
// on its descriptor so the rank-0 Properties widget still dispatches, e.g. `Progression`.
None => match &field.ty {
ParsedFieldType::Item {
field: RegularParsedField { value_source, .. },
Expand All @@ -241,7 +242,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
// The fn's lifetimes are elided since the metadata registration fn declares none of them
let element = substitute_lifetimes(element.clone(), "_");
match value_source {
ParsedValueSource::Default(_) => quote!(Some(concrete!(#element))),
ParsedValueSource::Default(_) => quote!(Some(concrete!(#element, #element))),
_ => quote!(Some(#core_types::item!(#element, #element))),
}
}
Expand Down
Loading