Skip to content

Commit 7704586

Browse files
committed
Route Text tool through Text to Vector with fill, fixing editing-preview placement
1 parent bf82817 commit 7704586

2 files changed

Lines changed: 38 additions & 6 deletions

File tree

editor/src/messages/portfolio/document/graph_operation/utility_types.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,19 +267,34 @@ impl<'a> ModifyInputsContext<'a> {
267267
Some(NodeInput::value(TaggedValue::F64(typesetting.max_height.unwrap_or(100.)), false)),
268268
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
269269
]);
270+
let text_to_vector = resolve_proto_node_type(graphene_std::text::text_to_vector::IDENTIFIER)
271+
.expect("Text to Vector node does not exist")
272+
.default_node_template();
270273
let transform = resolve_proto_node_type(graphene_std::transform_nodes::transform::IDENTIFIER)
271274
.expect("Transform node does not exist")
272275
.default_node_template();
276+
let fill = resolve_proto_node_type(graphene_std::vector_nodes::fill::IDENTIFIER)
277+
.expect("Fill node does not exist")
278+
.default_node_template();
273279

280+
// Build the chain `Text -> Text to Vector -> Transform -> Fill -> layer`
274281
let text_id = NodeId::new();
275282
self.network_interface.insert_node(text_id, text, &[]);
276283
self.network_interface.move_node_to_chain_start(&text_id, layer, &[], self.import);
277284

278285
self.responses.add(DocumentMessage::Resource(ResourceMessage::AddFont { resource_id: font_resource_id, font }));
279286

287+
let text_to_vector_id = NodeId::new();
288+
self.network_interface.insert_node(text_to_vector_id, text_to_vector, &[]);
289+
self.network_interface.move_node_to_chain_start(&text_to_vector_id, layer, &[], self.import);
290+
280291
let transform_id = NodeId::new();
281292
self.network_interface.insert_node(transform_id, transform, &[]);
282293
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[], self.import);
294+
295+
let fill_id = NodeId::new();
296+
self.network_interface.insert_node(fill_id, fill, &[]);
297+
self.network_interface.move_node_to_chain_start(&fill_id, layer, &[], self.import);
283298
}
284299

285300
pub fn insert_color_value(&mut self, color: Color, layer: LayerNodeIdentifier) {

editor/src/messages/tool/tool_messages/text_tool.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use graphene_std::choice_type::ChoiceTypeStatic;
2424
use graphene_std::color::SRGBA8;
2525
use graphene_std::renderer::Quad;
2626
use graphene_std::text::{Font, TextAlign, TypesettingConfig, lines_clipping};
27-
use graphene_std::vector::style::{FillChoice, FillChoiceUI};
27+
use graphene_std::vector::style::{Fill, FillChoice, FillChoiceUI};
2828
use graphene_std::{Color, NodeInputDecleration};
2929

3030
#[derive(Default, ExtractField)]
@@ -571,6 +571,10 @@ impl TextToolData {
571571
parent: document.new_layer_parent(true),
572572
insert_index: 0,
573573
});
574+
responses.add(GraphOperationMessage::FillSet {
575+
layer: self.layer,
576+
fill: editing_text.color.map_or(Fill::None, Fill::Solid),
577+
});
574578
let transform = editing_text.transform;
575579
self.editing_text = Some(editing_text);
576580

@@ -650,14 +654,21 @@ impl Fsm for TextToolFsmState {
650654
let ToolMessage::Text(event) = event else { return self };
651655
match (self, event) {
652656
(TextToolFsmState::Editing, TextToolMessage::Overlays { context: mut overlay_context }) => {
653-
let transform = document.metadata().transform_to_viewport(tool_data.layer).to_cols_array();
657+
// While editing, the text is blanked, so the layer's rendered transform metadata is absent; read the Transform node so the overlay tracks placement
658+
let transform = document
659+
.metadata()
660+
.transform_to_viewport_with_first_transform_node_if_group(tool_data.layer, &document.network_interface)
661+
.to_cols_array();
654662
responses.add(FrontendMessage::DisplayEditableTextboxTransform { transform });
655663
if let Some(editing_text) = tool_data.editing_text.as_mut() {
656664
let font_resource = fonts.get_resource_or_queue_load(&editing_text.font, responses);
657665
let far = graphene_std::text::bounding_box(&tool_data.new_text, &font_resource, editing_text.typesetting, false);
658666
if far.x != 0. && far.y != 0. {
659667
let quad = Quad::from_box([DVec2::ZERO, far]);
660-
let transformed_quad = document.metadata().transform_to_viewport(tool_data.layer) * quad;
668+
let transformed_quad = document
669+
.metadata()
670+
.transform_to_viewport_with_first_transform_node_if_group(tool_data.layer, &document.network_interface)
671+
* quad;
661672
overlay_context.quad(transformed_quad, None, Some(fill_color));
662673
}
663674
}
@@ -960,11 +971,17 @@ impl Fsm for TextToolFsmState {
960971
return TextToolFsmState::Editing;
961972
}
962973

963-
// Otherwise create some new text
964-
let constraint_size = has_dragged.then_some((start - end).abs());
974+
// Otherwise create some new text. The drag bounds are in viewport space; map them into document space for the text's
975+
// transform and wrapping size, then compose with document-to-viewport so the editing overlay (a screen-space CSS matrix) carries the zoom.
976+
let document_to_viewport = document.metadata().document_to_viewport;
977+
let viewport_to_document = document_to_viewport.inverse();
978+
let document_start = viewport_to_document.transform_point2(start);
979+
let document_end = viewport_to_document.transform_point2(end);
980+
981+
let constraint_size = has_dragged.then_some((document_start - document_end).abs());
965982
let editing_text = EditingText {
966983
text: String::new(),
967-
transform: DAffine2::from_translation(start),
984+
transform: document_to_viewport * DAffine2::from_translation(document_start),
968985
typesetting: TypesettingConfig {
969986
font_size: tool_options.font_size,
970987
letter_spacing: tool_options.letter_spacing,

0 commit comments

Comments
 (0)