mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Properly track the Text node's text frame via the attribute system to fix misalignment (#4097)
* Compensate for upstream row-0 transform absorption in viewport-space 'TransformSet' * Add 'editor:text_frame' row attribute so the Text tool's drag cage tracks multi-row text * "Separate Glyph Elements" -> "Separate Glyphs" * Improve artboard migration robustness from older documents * Code review * Make the tools visualize the text frame based on attribute not upstream node
This commit is contained in:
@@ -11,8 +11,8 @@ use core_types::table::{Table, TableRow};
|
||||
use core_types::transform::Footprint;
|
||||
use core_types::uuid::{NodeId, generate_uuid};
|
||||
use core_types::{
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_GRADIENT_TYPE, ATTR_LOCATION,
|
||||
ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_TRANSFORM,
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME,
|
||||
ATTR_GRADIENT_TYPE, ATTR_LOCATION, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_TRANSFORM,
|
||||
};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
@@ -327,6 +327,9 @@ pub struct RenderMetadata {
|
||||
/// Source-geometry outlines for hover/selection overlays, separate from `click_targets` so
|
||||
/// nodes with an `editor:click_target` override still outline the precise geometry.
|
||||
pub outlines: HashMap<NodeId, Vec<Arc<ClickTarget>>>,
|
||||
/// Per-layer text frame from row 0's `editor:text_frame` attribute.
|
||||
/// The Text tool composes this with `transform_to_viewport(layer)` to position its drag cage.
|
||||
pub text_frames: HashMap<NodeId, DAffine2>,
|
||||
pub clip_targets: HashSet<NodeId>,
|
||||
pub vector_data: HashMap<NodeId, Arc<Vector>>,
|
||||
pub backgrounds: Vec<Background>,
|
||||
@@ -349,6 +352,7 @@ impl RenderMetadata {
|
||||
first_element_source_id,
|
||||
click_targets,
|
||||
outlines,
|
||||
text_frames,
|
||||
clip_targets,
|
||||
vector_data,
|
||||
backgrounds,
|
||||
@@ -358,6 +362,7 @@ impl RenderMetadata {
|
||||
first_element_source_id.extend(other.first_element_source_id.iter());
|
||||
click_targets.extend(other.click_targets.iter().map(|(k, v)| (*k, v.clone())));
|
||||
outlines.extend(other.outlines.iter().map(|(k, v)| (*k, v.clone())));
|
||||
text_frames.extend(other.text_frames.iter());
|
||||
clip_targets.extend(other.clip_targets.iter());
|
||||
vector_data.extend(other.vector_data.iter().map(|(id, data)| (*id, data.clone())));
|
||||
|
||||
@@ -1366,7 +1371,7 @@ impl Render for Table<Vector> {
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, caller_element_id: Option<NodeId>) {
|
||||
// Aggregate all items' targets per element_id so multi-item tables (e.g. 'Text' node with "Separate Glyph Elements" active) produce hit areas for every glyph.
|
||||
// Aggregate all items' targets per element_id so multi-item tables (e.g. 'Text' node with "Separate Glyphs" active) produce hit areas for every glyph.
|
||||
// Targets are baked relative to item 0's transform since `Graphic::collect_metadata` records that as `local_transforms[element_id]`.
|
||||
let item_zero_transform: DAffine2 = if !self.is_empty() {
|
||||
self.attribute_cloned_or_default(ATTR_TRANSFORM, 0)
|
||||
@@ -1414,6 +1419,11 @@ impl Render for Table<Vector> {
|
||||
// Source geometry (not the click-target override) so editing tools work on letterforms.
|
||||
// Only item 0 is recorded since editing tools can only target a single item currently.
|
||||
metadata.vector_data.entry(element_id).or_insert_with(|| Arc::new(source.clone()));
|
||||
|
||||
// Surface `editor:text_frame` for the Text tool's drag cage
|
||||
if let Some(&frame) = self.attribute::<DAffine2>(ATTR_EDITOR_TEXT_FRAME, index) {
|
||||
metadata.text_frames.entry(element_id).or_insert(frame);
|
||||
}
|
||||
}
|
||||
|
||||
// If this item carries a snapshot of upstream graphic content (e.g. it was produced by Boolean Operation,
|
||||
|
||||
Reference in New Issue
Block a user