Add text alignment to the Text node (#2920)

* Add text alignment to Text node

* Lots of renames and improvements

* Add text alignment to the Text tool

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Salman Abuhaimed
2025-07-25 22:04:12 -07:00
committed by GitHub
co-authored by Keavon Chambers
parent 91156d295c
commit 85021fd9e0
14 changed files with 92 additions and 28 deletions
@@ -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,
@@ -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> {
@@ -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());
@@ -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)]
@@ -35,6 +35,7 @@ pub struct TextOptions {
font_style: String,
fill: ToolColorOptions,
tilt: f64,
align: TextAlign,
}
impl Default for TextOptions {
@@ -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(),
}
}
}
@@ -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>),
}
@@ -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(),
@@ -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,
]
}
@@ -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;
@@ -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
@@ -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(),