Merge branch 'master' into spiral-node

This commit is contained in:
0SlowPoke0
2025-07-01 18:07:20 +05:30
committed by GitHub
28 changed files with 702 additions and 373 deletions

View File

@@ -190,6 +190,7 @@ impl<'a> ModifyInputsContext<'a> {
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::F64(typesetting.tilt), false)),
]);
let text_id = NodeId::new();

View File

@@ -1556,6 +1556,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false),
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false),
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false),
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false),
],
..Default::default()
},
@@ -1577,6 +1578,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Line Height",
"TODO",
WidgetOverride::Number(NumberInputSettings {
unit: Some("x".to_string()),
min: Some(0.),
step: Some(0.1),
..Default::default()
@@ -1586,6 +1588,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Character Spacing",
"TODO",
WidgetOverride::Number(NumberInputSettings {
unit: Some(" px".to_string()),
min: Some(0.),
step: Some(0.1),
..Default::default()
@@ -1595,6 +1598,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Max Width",
"TODO",
WidgetOverride::Number(NumberInputSettings {
unit: Some(" px".to_string()),
min: Some(1.),
blank_assist: false,
..Default::default()
@@ -1604,11 +1608,22 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Max Height",
"TODO",
WidgetOverride::Number(NumberInputSettings {
unit: Some(" px".to_string()),
min: Some(1.),
blank_assist: false,
..Default::default()
}),
),
PropertiesRow::with_override(
"Tilt",
"Faux italic",
WidgetOverride::Number(NumberInputSettings {
min: Some(-85.),
max: Some(85.),
unit: Some("°".to_string()),
..Default::default()
}),
),
],
output_names: vec!["Vector".to_string()],
..Default::default()

View File

@@ -1161,8 +1161,7 @@ impl NodeNetworkInterface {
.and_then(|node_metadata| node_metadata.persistent_metadata.input_properties.get(index))
}
pub fn insert_input_properties_row(&mut self, node_id: &NodeId, index: usize, network_path: &[NodeId]) {
let row = ("", "TODO").into();
pub fn insert_input_properties_row(&mut self, node_id: &NodeId, index: usize, network_path: &[NodeId], row: PropertiesRow) {
let _ = self
.node_metadata_mut(node_id, network_path)
.map(|node_metadata| node_metadata.persistent_metadata.input_properties.insert(index - 1, row));

View File

@@ -1,6 +1,7 @@
// TODO: Eventually remove this document upgrade code
// This file contains lots of hacky code for upgrading old documents to the new format
use super::document::utility_types::network_interface::{NumberInputSettings, PropertiesRow, WidgetOverride};
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector};
@@ -308,8 +309,8 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
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, network_path, document_node.implementation.clone());
document.network_interface.insert_input_properties_row(node_id, 8, network_path);
document.network_interface.insert_input_properties_row(node_id, 9, network_path);
document.network_interface.insert_input_properties_row(node_id, 8, network_path, ("", "TODO").into());
document.network_interface.insert_input_properties_row(node_id, 9, network_path, ("", "TODO").into());
let old_inputs = document.network_interface.replace_inputs(node_id, document_node.inputs.clone(), network_path);
let align_input = NodeInput::value(TaggedValue::StrokeAlign(StrokeAlign::Center), false);
@@ -402,7 +403,7 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
}
// 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 == "Text" && inputs_count != 8 {
if reference == "Text" && inputs_count != 9 {
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, network_path, document_node.implementation.clone());
@@ -433,12 +434,44 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
);
document.network_interface.set_input(
&InputConnector::node(*node_id, 6),
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false),
if inputs_count >= 7 {
old_inputs[6].clone()
} else {
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false)
},
network_path,
);
document.network_interface.set_input(
&InputConnector::node(*node_id, 7),
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false),
if inputs_count >= 8 {
old_inputs[7].clone()
} else {
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false)
},
network_path,
);
document.network_interface.insert_input_properties_row(
node_id,
9,
network_path,
PropertiesRow::with_override(
"Tilt",
"Faux italic",
WidgetOverride::Number(NumberInputSettings {
min: Some(-85.),
max: Some(85.),
unit: Some("°".to_string()),
..Default::default()
}),
),
);
document.network_interface.set_input(
&InputConnector::node(*node_id, 8),
if inputs_count >= 9 {
old_inputs[8].clone()
} else {
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false)
},
network_path,
);
}

View File

@@ -924,11 +924,11 @@ impl PortfolioMessageHandler {
let result = self.executor.poll_node_graph_evaluation(active_document, responses);
if result.is_err() {
let error = r#"
<rect x="50%" y="50%" width="480" height="100" transform="translate(-240 -50)" rx="4" fill="var(--color-error-red)" />
<rect x="50%" y="50%" width="460" height="100" transform="translate(-230 -50)" rx="4" fill="var(--color-warning-yellow)" />
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-size="18" fill="var(--color-2-mildblack)">
<tspan x="50%" dy="-24" font-weight="bold">The document cannot be rendered in its current state.</tspan>
<tspan x="50%" dy="24">Check for error details in the node graph, which can be</tspan>
<tspan x="50%" dy="24">opened with the viewport's top right <tspan font-style="italic">Node Graph</tspan> button.</tspan>
<tspan x="50%" dy="-24" font-weight="bold">The document cannot render in its current state.</tspan>
<tspan x="50%" dy="24">Undo to go back, if available, or check for error details</tspan>
<tspan x="50%" dy="24">by clicking the <tspan font-style="italic">Node Graph</tspan> button up at the top right.</tspan>
/text>"#
// It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed.
.to_string();

View File

@@ -361,6 +361,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
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 typesetting = TypesettingConfig {
font_size,
@@ -368,6 +369,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
max_width,
character_spacing,
max_height,
tilt,
};
Some((text, font, typesetting))
}

View File

@@ -11,7 +11,7 @@ use crate::messages::tool::utility_types::ToolType;
use bezier_rs::{Bezier, BezierHandles};
use glam::{DAffine2, DVec2};
use graphene_std::renderer::Quad;
use graphene_std::text::{FontCache, load_face};
use graphene_std::text::{FontCache, load_font};
use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModificationType};
use kurbo::{CubicBez, Line, ParamCurveExtrema, PathSeg, Point, QuadBez};
@@ -70,8 +70,8 @@ pub fn text_bounding_box(layer: LayerNodeIdentifier, document: &DocumentMessageH
return Quad::from_box([DVec2::ZERO, DVec2::ZERO]);
};
let buzz_face = font_cache.get(font).map(|data| load_face(data));
let far = graphene_std::text::bounding_box(text, buzz_face.as_ref(), typesetting, false);
let font_data = font_cache.get(font).map(|data| load_font(data));
let far = graphene_std::text::bounding_box(text, font_data, typesetting, false);
Quad::from_box([DVec2::ZERO, far])
}

View File

@@ -18,7 +18,7 @@ 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, TypesettingConfig, lines_clipping, load_face};
use graphene_std::text::{Font, FontCache, TypesettingConfig, lines_clipping, load_font};
use graphene_std::vector::style::Fill;
#[derive(Default)]
@@ -35,6 +35,7 @@ pub struct TextOptions {
font_name: String,
font_style: String,
fill: ToolColorOptions,
tilt: f64,
}
impl Default for TextOptions {
@@ -42,10 +43,11 @@ impl Default for TextOptions {
Self {
font_size: 24.,
line_height_ratio: 1.2,
character_spacing: 1.,
character_spacing: 0.,
font_name: graphene_std::consts::DEFAULT_FONT_FAMILY.into(),
font_style: graphene_std::consts::DEFAULT_FONT_STYLE.into(),
fill: ToolColorOptions::new_primary(),
tilt: 0.,
}
}
}
@@ -468,8 +470,8 @@ impl Fsm for TextToolFsmState {
transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(),
});
if let Some(editing_text) = tool_data.editing_text.as_mut() {
let buzz_face = font_cache.get(&editing_text.font).map(|data| load_face(data));
let far = graphene_std::text::bounding_box(&tool_data.new_text, buzz_face.as_ref(), editing_text.typesetting, false);
let font_data = font_cache.get(&editing_text.font).map(|data| load_font(data));
let far = graphene_std::text::bounding_box(&tool_data.new_text, font_data, editing_text.typesetting, false);
if far.x != 0. && far.y != 0. {
let quad = Quad::from_box([DVec2::ZERO, far]);
let transformed_quad = document.metadata().transform_to_viewport(tool_data.layer) * quad;
@@ -517,8 +519,8 @@ impl Fsm for TextToolFsmState {
// Draw red overlay if text is clipped
let transformed_quad = layer_transform * bounds;
if let Some((text, font, typesetting)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) {
let buzz_face = font_cache.get(font).map(|data| load_face(data));
if lines_clipping(text.as_str(), buzz_face, typesetting) {
let font_data = font_cache.get(font).map(|data| load_font(data));
if lines_clipping(text.as_str(), font_data, typesetting) {
overlay_context.line(transformed_quad.0[2], transformed_quad.0[3], Some(COLOR_OVERLAY_RED), Some(3.));
}
}
@@ -784,6 +786,7 @@ impl Fsm for TextToolFsmState {
max_width: constraint_size.map(|size| size.x),
character_spacing: tool_options.character_spacing,
max_height: constraint_size.map(|size| size.y),
tilt: tool_options.tilt,
},
font: Font::new(tool_options.font_name.clone(), tool_options.font_style.clone()),
color: tool_options.fill.active_color(),