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
3 changes: 2 additions & 1 deletion editor/src/messages/frontend/frontend_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::messages::tool::utility_types::HintData;
use graph_craft::document::NodeId;
use graphene_std::raster::Image;
use graphene_std::raster::color::Color;
use graphene_std::text::Font;
use graphene_std::text::{Font, TextAlign};

#[impl_message(Message, Frontend)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
Expand Down Expand Up @@ -38,6 +38,7 @@ pub enum FrontendMessage {
max_width: Option<f64>,
#[serde(rename = "maxHeight")]
max_height: Option<f64>,
align: TextAlign,
},
DisplayEditableTextboxTransform {
transform: [f64; 6],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ impl<'a> ModifyInputsContext<'a> {
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)),
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
]);

let text_id = NodeId::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
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),
NodeInput::value(TaggedValue::TextAlign(text::TextAlign::default()), false),
NodeInput::value(TaggedValue::Bool(false), false),
],
..Default::default()
Expand Down Expand Up @@ -1337,7 +1338,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"TODO",
WidgetOverride::Number(NumberInputSettings {
unit: Some(" px".to_string()),
min: Some(0.),
step: Some(0.1),
..Default::default()
}),
Expand Down Expand Up @@ -1372,6 +1372,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
),
InputMetadata::with_name_description_override("Align", "TODO", WidgetOverride::Custom("text_align".to_string())),
("Per-Glyph Instances", "Splits each text glyph into its own instance, i.e. row in the table of vector data.").into(),
],
output_names: vec!["Vector".to_string()],
Expand Down Expand Up @@ -2404,6 +2405,13 @@ fn static_input_properties() -> InputProperties {
)])
}),
);
map.insert(
"text_align".to_string(),
Box::new(|node_id, index, context| {
let choices = enum_choice::<text::TextAlign>().for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)).property_row();
Ok(vec![choices])
}),
);
map
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use graphene_std::raster::{
SelectiveColorChoice,
};
use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
use graphene_std::text::Font;
use graphene_std::text::{Font, TextAlign};
use graphene_std::transform::{Footprint, ReferencePoint, Transform};
use graphene_std::vector::VectorDataTable;
use graphene_std::vector::misc::GridType;
Expand Down Expand Up @@ -223,6 +223,7 @@ pub(crate) fn property_from_type(
Some(x) if x == TypeId::of::<StrokeAlign>() => enum_choice::<StrokeAlign>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<PaintOrder>() => enum_choice::<PaintOrder>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<ArcType>() => enum_choice::<ArcType>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<TextAlign>() => enum_choice::<TextAlign>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<MergeByDistanceAlgorithm>() => enum_choice::<MergeByDistanceAlgorithm>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<PointSpacingType>() => enum_choice::<PointSpacingType>().for_socket(default_info).property_row(),
Some(x) if x == TypeId::of::<BooleanOperation>() => enum_choice::<BooleanOperation>().for_socket(default_info).property_row(),
Expand Down Expand Up @@ -2018,7 +2019,7 @@ pub mod choice {
let updater = updater_factory();
let committer = committer_factory();
let entry = RadioEntryData::new(var_meta.name).on_update(move |_| updater(item)).on_commit(committer);
match (var_meta.icon.as_deref(), var_meta.docstring.as_deref()) {
match (var_meta.icon, var_meta.docstring) {
(None, None) => entry.label(var_meta.label),
(None, Some(doc)) => entry.label(var_meta.label).tooltip(doc),
(Some(icon), None) => entry.icon(icon).tooltip(var_meta.label),
Expand Down
15 changes: 12 additions & 3 deletions editor/src/messages/portfolio/document_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use glam::IVec2;
use graph_craft::document::DocumentNode;
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
use graphene_std::ProtoNodeIdentifier;
use graphene_std::text::TypesettingConfig;
use graphene_std::text::{TextAlign, TypesettingConfig};
use graphene_std::uuid::NodeId;
use graphene_std::vector::style::{PaintOrder, StrokeAlign};
use graphene_std::vector::{VectorData, VectorDataTable};
Expand Down Expand Up @@ -646,7 +646,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 == "Text" && inputs_count != 10 {
if reference == "Text" && inputs_count != 11 {
let mut template = 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)?;
Expand Down Expand Up @@ -702,8 +702,17 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
);
document.network_interface.set_input(
&InputConnector::node(*node_id, 9),
if inputs_count >= 10 {
if inputs_count >= 11 {
old_inputs[9].clone()
} else {
NodeInput::value(TaggedValue::TextAlign(TextAlign::default()), false)
},
network_path,
);
document.network_interface.set_input(
&InputConnector::node(*node_id, 10),
if inputs_count >= 11 {
old_inputs[10].clone()
} else {
NodeInput::value(TaggedValue::Bool(false), false)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,8 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
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::Bool(per_glyph_instances)) = &inputs[9].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 typesetting = TypesettingConfig {
font_size,
Expand All @@ -379,8 +378,9 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
character_spacing,
max_height,
tilt,
align,
};
Some((text, font, typesetting, *per_glyph_instances))
Some((text, font, typesetting, per_glyph_instances))
}

pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
Expand Down
6 changes: 5 additions & 1 deletion editor/src/messages/tool/tool_messages/brush_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ impl LayoutHolder for BrushTool {

let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
.into_iter()
.map(|draw_mode| RadioEntryData::new(format!("{draw_mode:?}")).on_update(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::DrawMode(draw_mode)).into()))
.map(|draw_mode| {
RadioEntryData::new(format!("{draw_mode:?}"))
.label(format!("{draw_mode:?}"))
.on_update(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::DrawMode(draw_mode)).into())
})
.collect();
widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder());

Expand Down
29 changes: 17 additions & 12 deletions editor/src/messages/tool/tool_messages/text_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,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_font};
use graphene_std::text::{Font, FontCache, TextAlign, TypesettingConfig, lines_clipping, load_font};
use graphene_std::vector::style::Fill;

#[derive(Default, ExtractField)]
Expand All @@ -35,6 +35,7 @@ pub struct TextOptions {
font_style: String,
fill: ToolColorOptions,
tilt: f64,
align: TextAlign,
}

impl Default for TextOptions {
Expand All @@ -47,6 +48,7 @@ impl Default for TextOptions {
font_style: graphene_std::consts::DEFAULT_FONT_STYLE.into(),
fill: ToolColorOptions::new_primary(),
tilt: 0.,
align: TextAlign::default(),
}
}
}
Expand Down Expand Up @@ -78,7 +80,7 @@ pub enum TextOptionsUpdate {
Font { family: String, style: String },
FontSize(f64),
LineHeightRatio(f64),
CharacterSpacing(f64),
Align(TextAlign),
WorkingColors(Option<Color>, Option<Color>),
}

Expand Down Expand Up @@ -131,14 +133,15 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
.step(0.1)
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::LineHeightRatio(number_input.value.unwrap())).into())
.widget_holder();
let character_spacing = NumberInput::new(Some(tool.options.character_spacing))
.label("Char. Spacing")
.int()
.min(0.)
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
.step(0.1)
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::CharacterSpacing(number_input.value.unwrap())).into())
.widget_holder();
let align_entries: Vec<_> = [TextAlign::Left, TextAlign::Center, TextAlign::Right, TextAlign::JustifyLeft]
.into_iter()
.map(|align| {
RadioEntryData::new(format!("{align:?}"))
.label(align.to_string())
.on_update(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::Align(align)).into())
})
.collect();
let align = RadioInput::new(align_entries).selected_index(Some(tool.options.align as u32)).widget_holder();
vec![
font,
Separator::new(SeparatorType::Related).widget_holder(),
Expand All @@ -148,7 +151,7 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
Separator::new(SeparatorType::Related).widget_holder(),
line_height_ratio,
Separator::new(SeparatorType::Related).widget_holder(),
character_spacing,
align,
]
}

Expand Down Expand Up @@ -186,7 +189,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Text
}
TextOptionsUpdate::FontSize(font_size) => self.options.font_size = font_size,
TextOptionsUpdate::LineHeightRatio(line_height_ratio) => self.options.line_height_ratio = line_height_ratio,
TextOptionsUpdate::CharacterSpacing(character_spacing) => self.options.character_spacing = character_spacing,
TextOptionsUpdate::Align(align) => self.options.align = align,
TextOptionsUpdate::FillColor(color) => {
self.options.fill.custom_color = color;
self.options.fill.color_type = ToolColorType::Custom;
Expand Down Expand Up @@ -314,6 +317,7 @@ impl TextToolData {
transform: editing_text.transform.to_cols_array(),
max_width: editing_text.typesetting.max_width,
max_height: editing_text.typesetting.max_height,
align: editing_text.typesetting.align,
});
} else {
// Check if DisplayRemoveEditableTextbox is already in the responses queue
Expand Down Expand Up @@ -792,6 +796,7 @@ impl Fsm for TextToolFsmState {
character_spacing: tool_options.character_spacing,
max_height: constraint_size.map(|size| size.y),
tilt: tool_options.tilt,
align: tool_options.align,
},
font: Font::new(tool_options.font_name.clone(), tool_options.font_style.clone()),
color: tool_options.fill.active_color(),
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/panels/Document.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@
textInput.style.lineHeight = `${displayEditableTextbox.lineHeightRatio}`;
textInput.style.fontSize = `${displayEditableTextbox.fontSize}px`;
textInput.style.color = displayEditableTextbox.color.toHexOptionalAlpha() || "transparent";
textInput.style.textAlign = displayEditableTextbox.align;

textInput.oninput = () => {
if (!textInput) return;
Expand Down Expand Up @@ -774,7 +775,6 @@
.text-input {
word-break: break-all;
unicode-bidi: plaintext;
text-align: left;
}

.text-input div {
Expand All @@ -789,7 +789,6 @@
white-space: pre-wrap;
word-break: normal;
unicode-bidi: plaintext;
text-align: left;
display: inline-block;
// Workaround to force Chrome to display the flashing text entry cursor when text is empty
padding-left: 1px;
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,8 @@ export class UpdateDocumentLayerStructureJs extends JsMessage {
readonly dataBuffer!: DataBuffer;
}

export type TextAlign = "Left" | "Center" | "Right" | "JustifyLeft";

export class DisplayEditableTextbox extends JsMessage {
readonly text!: string;

Expand All @@ -831,6 +833,8 @@ export class DisplayEditableTextbox extends JsMessage {
readonly maxWidth!: undefined | number;

readonly maxHeight!: undefined | number;

readonly align!: TextAlign;
}

export class DisplayEditableTextboxTransform extends JsMessage {
Expand Down
26 changes: 26 additions & 0 deletions node-graph/gcore/src/text.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
mod font_cache;
mod to_path;

use dyn_any::DynAny;
pub use font_cache::*;
pub use to_path::*;

/// Alignment of lines of type within a text block.
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
#[widget(Radio)]
pub enum TextAlign {
#[default]
Left,
Center,
Right,
#[label("Justify")]
JustifyLeft,
// TODO: JustifyCenter, JustifyRight, JustifyAll
}

impl From<TextAlign> for parley::Alignment {
fn from(val: TextAlign) -> Self {
match val {
TextAlign::Left => parley::Alignment::Left,
TextAlign::Center => parley::Alignment::Middle,
TextAlign::Right => parley::Alignment::Right,
TextAlign::JustifyLeft => parley::Alignment::Justified,
}
}
}
7 changes: 5 additions & 2 deletions node-graph/gcore/src/text/to_path.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::TextAlign;
use crate::instances::Instance;
use crate::vector::{PointId, VectorData, VectorDataTable};
use bezier_rs::{ManipulatorGroup, Subpath};
use core::cell::RefCell;
use glam::{DAffine2, DVec2};
use parley::fontique::Blob;
use parley::{Alignment, AlignmentOptions, FontContext, GlyphRun, Layout, LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty};
use parley::{AlignmentOptions, FontContext, GlyphRun, Layout, LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty};
use skrifa::GlyphId;
use skrifa::instance::{LocationRef, NormalizedCoord, Size};
use skrifa::outline::{DrawSettings, OutlinePen};
Expand Down Expand Up @@ -103,6 +104,7 @@ pub struct TypesettingConfig {
pub max_width: Option<f64>,
pub max_height: Option<f64>,
pub tilt: f64,
pub align: TextAlign,
}

impl Default for TypesettingConfig {
Expand All @@ -114,6 +116,7 @@ impl Default for TypesettingConfig {
max_width: None,
max_height: None,
tilt: 0.,
align: TextAlign::default(),
}
}
}
Expand Down Expand Up @@ -197,7 +200,7 @@ fn layout_text(str: &str, font_data: Option<Blob<u8>>, typesetting: TypesettingC
let mut layout: Layout<()> = builder.build(str);

layout.break_all_lines(typesetting.max_width.map(|mw| mw as f32));
layout.align(typesetting.max_width.map(|max_w| max_w as f32), Alignment::Left, AlignmentOptions::default());
layout.align(typesetting.max_width.map(|max_w| max_w as f32), typesetting.align.into(), AlignmentOptions::default());

Some(layout)
}
Expand Down
1 change: 1 addition & 0 deletions node-graph/graph-craft/src/document/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ tagged_value! {
ReferencePoint(graphene_core::transform::ReferencePoint),
CentroidType(graphene_core::vector::misc::CentroidType),
BooleanOperation(graphene_path_bool::BooleanOperation),
TextAlign(graphene_core::text::TextAlign),
}

impl TaggedValue {
Expand Down
2 changes: 2 additions & 0 deletions node-graph/gstd/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn text<'i: 'n>(
#[unit("°")]
#[default(0.)]
tilt: f64,
align: TextAlign,
/// Splits each text glyph into its own instance, i.e. row in the table of vector data.
#[default(false)]
per_glyph_instances: bool,
Expand All @@ -39,6 +40,7 @@ fn text<'i: 'n>(
max_width,
max_height,
tilt,
align,
};

let font_data = editor.font_cache.get(&font_name).map(|f| load_font(f));
Expand Down
Loading