diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index b0c8760073..d364a78774 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -206,8 +206,10 @@ impl<'a> ModifyInputsContext<'a> { Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)), Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)), Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)), - Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)), - Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)), + Some(NodeInput::value(TaggedValue::Bool(typesetting.max_width.is_some()), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.max_width.unwrap_or(100.)), false)), + Some(NodeInput::value(TaggedValue::Bool(typesetting.max_width.is_some()), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.max_width.unwrap_or(100.)), false)), Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)), Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)), ]); diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 3f0171e83b..bb90f2c946 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -21,7 +21,6 @@ use graphene_std::extract_xy::XY; use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; use graphene_std::raster_types::{CPU, Raster}; use graphene_std::table::Table; -use graphene_std::text::{Font, TypesettingConfig}; #[allow(unused_imports)] use graphene_std::transform::Footprint; use graphene_std::vector::Vector; @@ -1653,103 +1652,6 @@ fn document_node_definitions() -> HashMap InputProperties { }]) }), ); + map.insert( + // The custom number input settings are only available on proto nodes + "optional_f64".to_string(), + Box::new(|node_id, index, context| { + let node_metadata = registry::NODE_METADATA.lock().unwrap(); + let mut number_input = NumberInput::default(); + if let Some(field) = context + .network_interface + .implementation(&node_id, context.selection_network_path) + .and_then(|implementation| if let DocumentNodeImplementation::ProtoNode(id) = implementation { Some(id) } else { None }) + .and_then(|proto_node_identifier| node_metadata.get(proto_node_identifier)) + .and_then(|metadata| metadata.fields.get(index)) + { + if let Some(unit) = field.unit { + number_input = number_input.unit(unit); + } + if let Some(number_min) = field.number_min { + number_input = number_input.min(number_min); + } + if let Some(number_max) = field.number_max { + number_input = number_input.max(number_max); + } + if let Some((range_min, range_max)) = field.number_mode_range { + number_input = number_input.range_min(Some(range_min)); + number_input = number_input.range_max(Some(range_max)); + } + number_input = number_input.is_integer(false); + if let Some(number_step) = field.number_step { + number_input = number_input.step(number_step); + } + }; + Ok(vec![LayoutGroup::Row { + // NOTE: The bool input MUST be at the input index directly before the f64 input! + widgets: node_properties::optional_f64_widget(ParameterWidgetsInfo::new(node_id, index, false, context), index - 1, number_input), + }]) + }), + ); map.insert( "vec2".to_string(), Box::new(|node_id, index, context| { diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 661215ee11..c644a34f14 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -939,6 +939,49 @@ pub fn progression_widget(parameter_widgets_info: ParameterWidgetsInfo, number_p widgets } +/// `parameter_widgets_info` is for the f64 parameter. `bool_input_index` is the input index of the bool parameter for the checkbox. +pub fn optional_f64_widget(parameter_widgets_info: ParameterWidgetsInfo, bool_input_index: usize, number_props: NumberInput) -> Vec { + let ParameterWidgetsInfo { + document_node, + node_id, + index: number_input_index, + .. + } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(number_input) = document_node.inputs.get(number_input_index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + let Some(bool_input) = document_node.inputs.get(bool_input_index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let (Some(&TaggedValue::Bool(enabled)), Some(&TaggedValue::F64(number))) = (bool_input.as_non_exposed_value(), number_input.as_non_exposed_value()) { + widgets.extend_from_slice(&[ + Separator::new(SeparatorStyle::Unrelated).widget_instance(), + Separator::new(SeparatorStyle::Related).widget_instance(), + // The checkbox toggles if the value is Some or None + CheckboxInput::new(enabled) + .on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, bool_input_index)) + .on_commit(commit_value) + .widget_instance(), + Separator::new(SeparatorStyle::Related).widget_instance(), + Separator::new(SeparatorStyle::Unrelated).widget_instance(), + number_props + .value(Some(number)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap_or_default()), node_id, number_input_index)) + .disabled(!enabled) + .on_commit(commit_value) + .widget_instance(), + ]); + } + + widgets +} + pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec { let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; @@ -982,27 +1025,6 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: .on_commit(commit_value) .widget_instance(), ]), - Some(&TaggedValue::OptionalF64(x)) => { - // TODO: Don't wipe out the previously set value (setting it back to the default of 100) when reenabling this checkbox back to Some from None - let toggle_enabled = move |checkbox_input: &CheckboxInput| TaggedValue::OptionalF64(if checkbox_input.checked { Some(100.) } else { None }); - widgets.extend_from_slice(&[ - Separator::new(SeparatorStyle::Unrelated).widget_instance(), - Separator::new(SeparatorStyle::Related).widget_instance(), - // The checkbox toggles if the value is Some or None - CheckboxInput::new(x.is_some()) - .on_update(update_value(toggle_enabled, node_id, index)) - .on_commit(commit_value) - .widget_instance(), - Separator::new(SeparatorStyle::Related).widget_instance(), - Separator::new(SeparatorStyle::Unrelated).widget_instance(), - number_props - .value(x) - .on_update(update_value(move |x: &NumberInput| TaggedValue::OptionalF64(x.value), node_id, index)) - .disabled(x.is_none()) - .on_commit(commit_value) - .widget_instance(), - ]); - } Some(&TaggedValue::DVec2(dvec2)) => widgets.extend_from_slice(&[ Separator::new(SeparatorStyle::Unrelated).widget_instance(), number_props @@ -1087,14 +1109,6 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button: .on_commit(commit_value) .widget_instance(), ), - TaggedValue::OptionalColorNotInTable(color) => widgets.push( - color_button - .value(color.map_or(FillChoice::None, FillChoice::Solid)) - .allow_none(true) - .on_update(update_value(|input: &ColorInput| TaggedValue::OptionalColorNotInTable(input.value.as_solid()), node_id, index)) - .on_commit(commit_value) - .widget_instance(), - ), TaggedValue::Color(color_table) => widgets.push( color_button .value(match color_table.iter().next() { diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index c19c187dc3..aa4ccaa174 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -27,6 +27,7 @@ const TEXT_REPLACEMENTS: &[(&str, &str)] = &[ "core::option::Option>", ), ("graphene_core::transform::Footprint", "graphene_core::transform::Footprint"), + ("\"OptionalF64\":", "\"F64\":"), ]; pub struct NodeReplacement<'a> { @@ -961,11 +962,48 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ const REPLACEMENTS: &[(&str, &str)] = &[]; pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String { + let document_serialized_content = replace_optional_f64_null(&document_serialized_content); + TEXT_REPLACEMENTS .iter() .fold(document_serialized_content, |document_serialized_content, (old, new)| document_serialized_content.replace(old, new)) } +fn replace_optional_f64_null(input: &str) -> String { + let mut result = String::new(); + let mut last_end = 0; + let key = "\"OptionalF64\":"; + + for (start, _) in input.match_indices(key) { + let search_start = start + key.len(); + if search_start >= input.len() { + continue; + } + + let mut after_key_start = search_start; + for (i, c) in input[search_start..].char_indices() { + if !c.is_whitespace() { + after_key_start = search_start + i; + break; + } + // If we reach the end and it's all whitespace, update after_key_start + if search_start + i + c.len_utf8() == input.len() { + after_key_start = input.len(); + } + } + + if input[after_key_start..].starts_with("null") { + result.push_str(&input[last_end..start]); + result.push_str(key); + result.push_str("0.0"); + last_end = after_key_start + "null".len(); + } + } + + result.push_str(&input[last_end..]); + result +} + pub fn document_migration_reset_node_definition(document_serialized_content: &str) -> bool { // Upgrade a document being opened to use fresh copies of all nodes if document_serialized_content.contains("node_output_index") { @@ -1035,7 +1073,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // Only nodes that have not been modified and still refer to a definition can be updated let reference = document.network_interface.reference(node_id, network_path)?; - let inputs_count = node.inputs.len(); + let mut inputs_count = node.inputs.len(); // Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644) if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER) && inputs_count == 8 { @@ -1134,7 +1172,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016 - if reference == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER) && inputs_count != 11 { + if reference == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER) && inputs_count == 8 { let mut template: NodeTemplate = resolve_document_node_type(&reference)?.default_node_template(); document.network_interface.replace_implementation(node_id, network_path, &mut template); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?; @@ -1166,7 +1204,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], if inputs_count >= 7 { old_inputs[6].clone() } else { - NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false) + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().max_width.unwrap_or_default()), false) }, network_path, ); @@ -1175,7 +1213,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], if inputs_count >= 8 { old_inputs[7].clone() } else { - NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false) + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().max_width.unwrap_or_default()), false) }, network_path, ); @@ -1190,7 +1228,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], ); document.network_interface.set_input( &InputConnector::node(*node_id, 9), - if inputs_count >= 11 { + if inputs_count >= 10 { old_inputs[9].clone() } else { NodeInput::value(TaggedValue::TextAlign(TextAlign::default()), false) @@ -1206,6 +1244,49 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], }, network_path, ); + inputs_count = 11 + } + + // Insert bool parameters for `has_max_width` and `has_max_height`: + // https://github.com/GraphiteEditor/Graphite/pull/3643 + if reference == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER) && inputs_count == 11 { + let mut template: NodeTemplate = resolve_document_node_type(&reference)?.default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut template); + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?; + + // Copy over old inputs + #[allow(clippy::needless_range_loop)] + for i in 0..=5 { + document.network_interface.set_input(&InputConnector::node(*node_id, i), old_inputs[i].clone(), network_path); + } + + // Max Width + let Some(&TaggedValue::F64(old_max_width)) = old_inputs[6].as_value() else { return None }; + document + .network_interface + .set_input(&InputConnector::node(*node_id, 6), NodeInput::value(TaggedValue::Bool(old_max_width != 0.), false), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 7), + NodeInput::value(TaggedValue::F64(if old_max_width == 0. { 100. } else { old_max_width }), false), + network_path, + ); + + // Max Height + let Some(&TaggedValue::F64(old_max_height)) = old_inputs[7].as_value() else { return None }; + document + .network_interface + .set_input(&InputConnector::node(*node_id, 8), NodeInput::value(TaggedValue::Bool(old_max_height != 0.), false), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 9), + NodeInput::value(TaggedValue::F64(if old_max_height == 0. { 100. } else { old_max_height }), false), + network_path, + ); + + // Copy over old inputs + #[allow(clippy::needless_range_loop)] + for i in 10..=12 { + document.network_interface.set_input(&InputConnector::node(*node_id, i), old_inputs[i - 2].clone(), network_path); + } } // Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 98386bb0ad..a0d4cf1dbd 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -388,23 +388,49 @@ pub fn get_grid_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig, bool)> { let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER))?; - let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None }; - let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None }; - let Some(&TaggedValue::F64(font_size)) = inputs[3].as_value() else { return None }; - let Some(&TaggedValue::F64(line_height_ratio)) = inputs[4].as_value() else { return None }; - let Some(&TaggedValue::F64(character_spacing)) = inputs[5].as_value() else { return None }; - let Some(&TaggedValue::OptionalF64(max_width)) = inputs[6].as_value() else { return None }; - let Some(&TaggedValue::OptionalF64(max_height)) = inputs[7].as_value() else { return None }; - let Some(&TaggedValue::F64(tilt)) = inputs[8].as_value() else { return None }; - let Some(&TaggedValue::TextAlign(align)) = inputs[9].as_value() else { return None }; - let Some(&TaggedValue::Bool(per_glyph_instances)) = inputs[10].as_value() else { return None }; + let Some(TaggedValue::String(text)) = &inputs[graphene_std::text::text::TextInput::INDEX].as_value() else { + return None; + }; + let Some(TaggedValue::Font(font)) = &inputs[graphene_std::text::text::FontInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(font_size)) = inputs[graphene_std::text::text::SizeInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(line_height_ratio)) = inputs[graphene_std::text::text::LineHeightInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(character_spacing)) = inputs[graphene_std::text::text::CharacterSpacingInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::Bool(has_max_width)) = inputs[graphene_std::text::text::HasMaxWidthInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(max_width)) = inputs[graphene_std::text::text::MaxWidthInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::Bool(has_max_height)) = inputs[graphene_std::text::text::HasMaxHeightInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(max_height)) = inputs[graphene_std::text::text::MaxHeightInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::F64(tilt)) = inputs[graphene_std::text::text::TiltInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::TextAlign(align)) = inputs[graphene_std::text::text::AlignInput::INDEX].as_value() else { + return None; + }; + let Some(&TaggedValue::Bool(per_glyph_instances)) = inputs[graphene_std::text::text::SeparateGlyphElementsInput::INDEX].as_value() else { + return None; + }; let typesetting = TypesettingConfig { font_size, line_height_ratio, - max_width, + max_width: has_max_width.then_some(max_width), + max_height: has_max_height.then_some(max_height), character_spacing, - max_height, tilt, align, }; diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 49a7bdfd5f..1bd12b61ac 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -18,10 +18,10 @@ use crate::messages::tool::common_functionality::utility_functions::text_boundin use crate::messages::tool::utility_types::ToolRefreshOptions; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; -use graphene_std::Color; use graphene_std::renderer::Quad; use graphene_std::text::{Font, FontCache, TextAlign, TypesettingConfig, lines_clipping}; use graphene_std::vector::style::Fill; +use graphene_std::{Color, NodeInputDecleration}; #[derive(Default, ExtractField)] pub struct TextTool { @@ -800,13 +800,22 @@ impl Fsm for TextToolFsmState { // Find the translation necessary from the original position in viewport space let translation_viewport = bounds.original_bound_transform.transform_vector2(translation_bounds_space); + // TODO: Don't set both max_width and max_height to true at the same time, only do one based on which edge is being dragged (or both if a corner is being dragged) responses.add(NodeGraphMessage::SetInput { - input_connector: InputConnector::node(node_id, 6), - input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.x)), false), + input_connector: InputConnector::node(node_id, graphene_std::text::text::HasMaxWidthInput::INDEX), + input: NodeInput::value(TaggedValue::Bool(true), false), }); responses.add(NodeGraphMessage::SetInput { - input_connector: InputConnector::node(node_id, 7), - input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.y)), false), + input_connector: InputConnector::node(node_id, graphene_std::text::text::MaxWidthInput::INDEX), + input: NodeInput::value(TaggedValue::F64(size_layer.x), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, graphene_std::text::text::HasMaxHeightInput::INDEX), + input: NodeInput::value(TaggedValue::Bool(true), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, graphene_std::text::text::MaxHeightInput::INDEX), + input: NodeInput::value(TaggedValue::F64(size_layer.y), false), }); responses.add(GraphOperationMessage::TransformSet { layer: dragging_layer.id, diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 16827f1926..72e81f874d 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -173,9 +173,7 @@ tagged_value! { U64(u64), Bool(bool), String(String), - OptionalF64(Option), ColorNotInTable(Color), - OptionalColorNotInTable(Option), // ======================== // LISTS OF PRIMITIVE TYPES // ======================== @@ -366,9 +364,9 @@ impl TaggedValue { x if x == TypeId::of::() => FromStr::from_str(string).map(TaggedValue::U32).ok()?, x if x == TypeId::of::() => to_dvec2(string).map(TaggedValue::DVec2)?, x if x == TypeId::of::() => FromStr::from_str(string).map(TaggedValue::Bool).ok()?, - x if x == TypeId::of::>() => to_color(string).map(|color| TaggedValue::Color(Table::new_from_element(color)))?, x if x == TypeId::of::() => to_color(string).map(TaggedValue::ColorNotInTable)?, x if x == TypeId::of::>() => TaggedValue::ColorNotInTable(to_color(string)?), + x if x == TypeId::of::>() => to_color(string).map(|color| TaggedValue::Color(Table::new_from_element(color)))?, x if x == TypeId::of::() => to_color(string).map(|color| TaggedValue::Fill(Fill::solid(color)))?, x if x == TypeId::of::() => to_reference_point(string).map(TaggedValue::ReferencePoint)?, _ => return None, diff --git a/node-graph/libraries/graphic-types/src/graphic.rs b/node-graph/libraries/graphic-types/src/graphic.rs index d5db099745..c535ed461a 100644 --- a/node-graph/libraries/graphic-types/src/graphic.rs +++ b/node-graph/libraries/graphic-types/src/graphic.rs @@ -90,18 +90,6 @@ impl From> for Graphic { } } // Note: Table conversions handled by blanket impl in gcore - -// Option -impl From> for Graphic { - fn from(color: Option) -> Self { - if let Some(color) = color { - Graphic::Color(Table::new_from_element(color)) - } else { - Graphic::default() - } - } -} -// Note: Table conversions handled by blanket impl in gcore // Note: Table -> Option is in gcore (Color is defined there) // GradientStops diff --git a/node-graph/nodes/blending/src/lib.rs b/node-graph/nodes/blending/src/lib.rs index 6c07eb5490..a770c85b5e 100644 --- a/node-graph/nodes/blending/src/lib.rs +++ b/node-graph/nodes/blending/src/lib.rs @@ -244,7 +244,6 @@ fn blending( #[default(100.)] fill: Percentage, /// Whether the content inherits the alpha of the content beneath it. - #[default(false)] clip: bool, ) -> T { // TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or TableRow) rather than applying to each row in its own table, which produces the undesired result diff --git a/node-graph/nodes/gstd/src/text.rs b/node-graph/nodes/gstd/src/text.rs index 9dfe656351..ff8bf0e8e3 100644 --- a/node-graph/nodes/gstd/src/text.rs +++ b/node-graph/nodes/gstd/src/text.rs @@ -3,41 +3,52 @@ use graph_craft::wasm_application_io::WasmEditorApi; use graphic_types::Vector; pub use text_nodes::*; -#[node_macro::node(category(""))] +#[node_macro::node(category("Text"))] fn text<'i: 'n>( _: impl Ctx, - editor: &'i WasmEditorApi, + #[scope("editor-api")] editor_resources: &'i WasmEditorApi, + #[widget(ParsedWidgetOverride::Custom = "text_area")] + #[default("Lorem ipsum")] text: String, - font: Font, + #[widget(ParsedWidgetOverride::Custom = "text_font")] font: Font, #[unit(" px")] #[default(24.)] - font_size: f64, + #[hard_min(1.)] + size: f64, #[unit("x")] + #[hard_min(0.)] + #[step(0.1)] #[default(1.2)] - line_height_ratio: f64, + line_height: f64, #[unit(" px")] - #[default(0.)] + #[step(0.1)] character_spacing: f64, - #[unit(" px")] max_width: Option, - #[unit(" px")] max_height: Option, - /// Faux italic. + #[widget(ParsedWidgetOverride::Hidden)] has_max_width: bool, + #[unit(" px")] + #[hard_min(1.)] + #[widget(ParsedWidgetOverride::Custom = "optional_f64")] + max_width: f64, + #[widget(ParsedWidgetOverride::Hidden)] has_max_height: bool, + #[unit(" px")] + #[hard_min(1.)] + #[widget(ParsedWidgetOverride::Custom = "optional_f64")] + max_height: f64, #[unit("°")] - #[default(0.)] + #[hard_min(-85.)] + #[hard_max(85.)] tilt: f64, - align: TextAlign, - /// Splits each text glyph into its own row in the table of vector geometry. - #[default(false)] - per_glyph_instances: bool, + #[widget(ParsedWidgetOverride::Custom = "text_align")] align: TextAlign, + separate_glyph_elements: bool, ) -> Table { let typesetting = TypesettingConfig { - font_size, - line_height_ratio, + font_size: size, + line_height_ratio: line_height, character_spacing, - max_width, - max_height, + max_width: has_max_width.then_some(max_width), + max_height: has_max_height.then_some(max_height), tilt, align, }; - to_path(&text, &font, &editor.font_cache, typesetting, per_glyph_instances) + to_path(&text, &font, &editor_resources.font_cache, typesetting, separate_glyph_elements) } diff --git a/node-graph/nodes/gstd/src/wasm_application_io.rs b/node-graph/nodes/gstd/src/wasm_application_io.rs index 3fd0dd13dd..df5d2b1955 100644 --- a/node-graph/nodes/gstd/src/wasm_application_io.rs +++ b/node-graph/nodes/gstd/src/wasm_application_io.rs @@ -131,7 +131,7 @@ fn image_to_bytes(_: impl Ctx, image: Table>) -> Vec { image.element.data.iter().flat_map(|color| color.to_rgb8_srgb().into_iter()).collect::>() } -/// Loads binary from URLs and local asset paths. Returns a transparent placeholder if the resource fails to load, allowing workflows to continue. +/// Loads binary from URLs and local asset paths. Returns a transparent placeholder if the resource fails to load, allowing rendering to continue. #[node_macro::node(category("Web Request"))] async fn load_resource<'a: 'n>(_: impl Ctx, _primary: (), #[scope("editor-api")] editor_resources: &'a WasmEditorApi, #[name("URL")] url: String) -> Arc<[u8]> { let Some(api) = editor_resources.application_io.as_ref() else { diff --git a/node-graph/nodes/math/src/lib.rs b/node-graph/nodes/math/src/lib.rs index 93c4fc2950..ef8bee97d3 100644 --- a/node-graph/nodes/math/src/lib.rs +++ b/node-graph/nodes/math/src/lib.rs @@ -405,7 +405,6 @@ fn random( /// Seed to determine the unique variation of which number is generated. seed: u64, /// The smaller end of the range within which the random number is generated. - #[default(0.)] min: f64, /// The larger end of the range within which the random number is generated. #[default(1.)]