Skip to content

Commit 0847d7b

Browse files
authored
Centralize attribute strings in consts and rename "editor:layer" to "editor:layer_path" (#4076)
* Rename "editor:layer" to "editor:layer_path" and centralize it in a const * Centralize "editor:merged_layers" in a const * Centralize all other attributes in consts * Rename consts with ATTR_ prefix * Format
1 parent 5774ec2 commit 0847d7b

25 files changed

Lines changed: 306 additions & 254 deletions

File tree

editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,7 @@ fn table_node_id_path_layout_with_breadcrumb(path: &Table<NodeId>, data: &mut La
993993
/// Mirrors [`dispatch_value_widget`] but routes to [`TableRowLayout::layout_with_breadcrumb`].
994994
/// Returns `None` for unrecognized types.
995995
fn drilldown_attribute_layout(any: &dyn Any, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
996-
// `Table<NodeId>` is interpreted as a path (e.g. the `editor:layer` attribute), so each item's NodeId value
996+
// `Table<NodeId>` is interpreted as a path (e.g. the `editor:layer_path` attribute), so each item's NodeId value
997997
// resolves against the prefix made up of preceding items. Handled before the generic `Table<T>` blanket impl.
998998
if let Some(path) = any.downcast_ref::<Table<NodeId>>() {
999999
return Some(table_node_id_path_layout_with_breadcrumb(path, data));

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,12 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
239239
implementation: DocumentNodeImplementation::ProtoNode(graphic::path_of_subgraph::IDENTIFIER),
240240
..Default::default()
241241
},
242-
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer` attribute,
242+
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer_path` attribute,
243243
// so editor tools (e.g. selection, click target routing) can trace data back to its owning layer.
244244
DocumentNode {
245245
inputs: vec![
246246
NodeInput::node(NodeId(1), 0),
247-
NodeInput::value(TaggedValue::String(String::from("editor:layer")), false),
247+
NodeInput::value(TaggedValue::String(graphene_std::ATTR_EDITOR_LAYER_PATH.to_string()), false),
248248
NodeInput::node(NodeId(2), 0),
249249
],
250250
implementation: DocumentNodeImplementation::ProtoNode(graphic::write_attribute::IDENTIFIER),
@@ -374,12 +374,12 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
374374
implementation: DocumentNodeImplementation::ProtoNode(graphic::path_of_subgraph::IDENTIFIER),
375375
..Default::default()
376376
},
377-
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer` attribute,
377+
// Stamp each item of the content with the parent layer's NodeId via the `editor:layer_path` attribute,
378378
// so editor tools (e.g. selection, click target routing) can trace data back to its owning layer.
379379
DocumentNode {
380380
inputs: vec![
381381
NodeInput::node(NodeId(0), 0),
382-
NodeInput::value(TaggedValue::String(String::from("editor:layer")), false),
382+
NodeInput::value(TaggedValue::String(graphene_std::ATTR_EDITOR_LAYER_PATH.to_string()), false),
383383
NodeInput::node(NodeId(1), 0),
384384
],
385385
implementation: DocumentNodeImplementation::ProtoNode(graphic::write_attribute::IDENTIFIER),

editor/src/messages/portfolio/document/overlays/utility_types_native.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::messages::prelude::ViewportMessageHandler;
1010
use core::borrow::Borrow;
1111
use core::f64::consts::{FRAC_PI_2, PI, TAU};
1212
use glam::{DAffine2, DVec2};
13+
use graphene_std::ATTR_TRANSFORM;
1314
use graphene_std::math::quad::Quad;
1415
use graphene_std::subpath::{self, Subpath};
1516
use graphene_std::table::Table;
@@ -1170,7 +1171,7 @@ impl OverlayContextInternal {
11701171
// Use the existing bezier_to_path infrastructure to convert Vector to BezPath
11711172
let mut path = BezPath::new();
11721173
let mut last_point = None;
1173-
let transform: DAffine2 = text_table.attribute_cloned_or_default("transform", index);
1174+
let transform: DAffine2 = text_table.attribute_cloned_or_default(ATTR_TRANSFORM, index);
11741175

11751176
let Some(element) = text_table.element(index) else { continue };
11761177
for (_, bezier, start_id, end_id) in element.segment_iter() {

node-graph/libraries/core-types/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub use num_traits;
3333
use std::any::TypeId;
3434
use std::future::Future;
3535
use std::pin::Pin;
36+
pub use table::{ATTR_ALPHA_BLENDING, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_END, ATTR_NAME, ATTR_START, ATTR_TRANSFORM, ATTR_TYPE};
3637
#[cfg(feature = "wasm")]
3738
pub use tsify;
3839
pub use types::Cow;

node-graph/libraries/core-types/src/table.rs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,45 @@ use dyn_any::{StaticType, StaticTypeSized};
55
use glam::DAffine2;
66
use std::fmt::Debug;
77

8+
// =====================================================================
9+
// Standard attribute keys used across the data flow
10+
// =====================================================================
11+
12+
/// Attribute key for a row's `DAffine2` transformation, applied when rendering and when accumulating
13+
/// transforms through nested compositions.
14+
pub const ATTR_TRANSFORM: &str = "transform";
15+
16+
/// Attribute key for a row's `AlphaBlending` (blend mode + opacity + fill + clip), composed
17+
/// multiplicatively through nested compositions.
18+
pub const ATTR_ALPHA_BLENDING: &str = "alpha_blending";
19+
20+
/// Attribute key under which each row of an editor-aware layer stores a `Table<NodeId>` describing the
21+
/// path (from the root document network) to the layer node that owns the row. Editor tools use this to
22+
/// route clicks/selection back to the originating layer at any nesting depth.
23+
pub const ATTR_EDITOR_LAYER_PATH: &str = "editor:layer_path";
24+
25+
/// Attribute key under which a row stores a `Table<Graphic>` snapshot of the upstream content that fed
26+
/// into a destructive merge (Boolean Operation, Flatten Path, Morph, Rasterize, etc.). The renderer
27+
/// recurses into this snapshot during metadata collection so the editor can still surface click targets
28+
/// for the original child layers after their content has been collapsed into a single output.
29+
pub const ATTR_EDITOR_MERGED_LAYERS: &str = "editor:merged_layers";
30+
31+
/// Attribute key for the byte offset where a regex match begins in the input string, set by the
32+
/// `regex_find_all` and `regex_capture` text nodes.
33+
pub const ATTR_START: &str = "start";
34+
35+
/// Attribute key for the byte offset where a regex match ends in the input string, set by the
36+
/// `regex_find_all` and `regex_capture` text nodes.
37+
pub const ATTR_END: &str = "end";
38+
39+
/// Attribute key for a regex named-capture-group's name (empty for unnamed groups), set by the
40+
/// `regex_capture` text node.
41+
pub const ATTR_NAME: &str = "name";
42+
43+
/// Attribute key for a JSON value's type (`"string"`, `"number"`, `"object"`, etc.), set by the
44+
/// `json_query_all` text node alongside each extracted value.
45+
pub const ATTR_TYPE: &str = "type";
46+
847
// =====================
948
// TRAIT: AttributeValue
1049
// =====================
@@ -747,7 +786,7 @@ impl<T: BoundingBox> BoundingBox for Table<T> {
747786
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
748787
let mut combined_bounds = None;
749788

750-
for (element, row_transform) in self.iter_element_values().zip(self.iter_attribute_values_or_default::<DAffine2>("transform")) {
789+
for (element, row_transform) in self.iter_element_values().zip(self.iter_attribute_values_or_default::<DAffine2>(ATTR_TRANSFORM)) {
751790
match element.bounding_box(transform * row_transform, include_stroke) {
752791
RenderBoundingBox::None => continue,
753792
RenderBoundingBox::Infinite => return RenderBoundingBox::Infinite,
@@ -793,10 +832,10 @@ impl<T: graphene_hash::CacheHash> graphene_hash::CacheHash for Table<T> {
793832
for element in self.iter_element_values() {
794833
element.cache_hash(state);
795834
}
796-
for transform in self.iter_attribute_values_or_default::<DAffine2>("transform") {
835+
for transform in self.iter_attribute_values_or_default::<DAffine2>(ATTR_TRANSFORM) {
797836
graphene_hash::CacheHash::cache_hash(&transform, state);
798837
}
799-
for alpha_blending in self.iter_attribute_values_or_default::<crate::AlphaBlending>("alpha_blending") {
838+
for alpha_blending in self.iter_attribute_values_or_default::<crate::AlphaBlending>(ATTR_ALPHA_BLENDING) {
800839
alpha_blending.cache_hash(state);
801840
}
802841
}
@@ -811,14 +850,14 @@ impl<T: PartialEq> PartialEq for Table<T> {
811850
impl<T> ApplyTransform for Table<T> {
812851
/// Right-multiplies the modification into each row's transform attribute.
813852
fn apply_transform(&mut self, modification: &DAffine2) {
814-
for transform in self.iter_attribute_values_mut_or_default::<DAffine2>("transform") {
853+
for transform in self.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
815854
*transform *= *modification;
816855
}
817856
}
818857

819858
/// Left-multiplies the modification into each row's transform attribute.
820859
fn left_apply_transform(&mut self, modification: &DAffine2) {
821-
for transform in self.iter_attribute_values_mut_or_default::<DAffine2>("transform") {
860+
for transform in self.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
822861
*transform = *modification * *transform;
823862
}
824863
}

node-graph/libraries/graphic-types/src/artboard.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use crate::graphic::Graphic;
2-
use core_types::Color;
32
use core_types::blending::AlphaBlending;
43
use core_types::bounds::{BoundingBox, RenderBoundingBox};
54
use core_types::math::quad::Quad;
65
use core_types::render_complexity::RenderComplexity;
76
use core_types::table::{Table, TableRow};
87
use core_types::transform::Transform;
98
use core_types::uuid::NodeId;
9+
use core_types::{ATTR_TRANSFORM, Color};
1010
use dyn_any::DynAny;
1111
use glam::{DAffine2, DVec2, IVec2};
1212
use graphene_hash::CacheHash;
@@ -52,7 +52,7 @@ impl BoundingBox for Artboard {
5252

5353
let mut combined_bounds = None;
5454

55-
for (element, row_transform) in self.content.iter_element_values().zip(self.content.iter_attribute_values_or_default::<DAffine2>("transform")) {
55+
for (element, row_transform) in self.content.iter_element_values().zip(self.content.iter_attribute_values_or_default::<DAffine2>(ATTR_TRANSFORM)) {
5656
match element.bounding_box(transform * row_transform, include_stroke) {
5757
RenderBoundingBox::None => continue,
5858
RenderBoundingBox::Infinite => return RenderBoundingBox::Infinite,
@@ -113,7 +113,7 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
113113
alpha_blending: Vec<AlphaBlending>,
114114
}
115115

116-
// Attributes (transform, alpha_blending, editor:layer) are not serialized, so migration only needs
116+
// Attributes (transform, alpha_blending, editor:layer_path) are not serialized, so migration only needs
117117
// to recover the elements. Per-item attribute values are populated at runtime by the node graph.
118118
Ok(match ArtboardFormat::deserialize(deserializer)? {
119119
ArtboardFormat::ArtboardGroup(artboard_group) => artboard_group.artboards.into_iter().map(|(artboard, _)| TableRow::new_from_element(artboard)).collect(),

node-graph/libraries/graphic-types/src/graphic.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use core_types::Color;
21
use core_types::blending::AlphaBlending;
32
use core_types::bounds::{BoundingBox, RenderBoundingBox};
43
use core_types::graphene_hash::CacheHash;
54
use core_types::ops::TableConvert;
65
use core_types::render_complexity::RenderComplexity;
76
use core_types::table::{Table, TableRow};
87
use core_types::uuid::NodeId;
8+
use core_types::{ATTR_ALPHA_BLENDING, ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, Color};
99
use dyn_any::DynAny;
1010
use glam::DAffine2;
1111
use raster_types::{CPU, GPU, Raster};
@@ -141,19 +141,19 @@ fn flatten_graphic_table<T>(content: Table<Graphic>, extract_variant: fn(Graphic
141141

142142
fn flatten_recursive<T>(output: &mut Table<T>, current_graphic_table: Table<Graphic>, extract_variant: fn(Graphic) -> Option<Table<T>>) {
143143
for current_graphic_row in current_graphic_table.into_iter() {
144-
let layer_path: Table<NodeId> = current_graphic_row.attribute_cloned_or_default("editor:layer");
145-
let current_transform: DAffine2 = current_graphic_row.attribute_cloned_or_default("transform");
146-
let current_alpha_blending: AlphaBlending = current_graphic_row.attribute_cloned_or_default("alpha_blending");
144+
let layer_path: Table<NodeId> = current_graphic_row.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH);
145+
let current_transform: DAffine2 = current_graphic_row.attribute_cloned_or_default(ATTR_TRANSFORM);
146+
let current_alpha_blending: AlphaBlending = current_graphic_row.attribute_cloned_or_default(ATTR_ALPHA_BLENDING);
147147

148148
match current_graphic_row.into_element() {
149149
// Recurse into nested `Table<Graphic>` items, composing the parent's transform onto each child
150150
Graphic::Graphic(mut sub_table) => {
151151
for index in 0..sub_table.len() {
152-
let child_transform: DAffine2 = sub_table.attribute_cloned_or_default("transform", index);
153-
let child_alpha_blending: AlphaBlending = sub_table.attribute_cloned_or_default("alpha_blending", index);
152+
let child_transform: DAffine2 = sub_table.attribute_cloned_or_default(ATTR_TRANSFORM, index);
153+
let child_alpha_blending: AlphaBlending = sub_table.attribute_cloned_or_default(ATTR_ALPHA_BLENDING, index);
154154

155-
sub_table.set_attribute("transform", index, current_transform * child_transform);
156-
sub_table.set_attribute("alpha_blending", index, compose_alpha_blending(current_alpha_blending, child_alpha_blending));
155+
sub_table.set_attribute(ATTR_TRANSFORM, index, current_transform * child_transform);
156+
sub_table.set_attribute(ATTR_ALPHA_BLENDING, index, compose_alpha_blending(current_alpha_blending, child_alpha_blending));
157157
}
158158

159159
flatten_recursive(output, sub_table, extract_variant);
@@ -162,13 +162,13 @@ fn flatten_graphic_table<T>(content: Table<Graphic>, extract_variant: fn(Graphic
162162
other => {
163163
if let Some(typed_table) = extract_variant(other) {
164164
for row in typed_table.into_iter() {
165-
let row_transform: DAffine2 = row.attribute_cloned_or_default("transform");
166-
let row_alpha_blending: AlphaBlending = row.attribute_cloned_or_default("alpha_blending");
165+
let row_transform: DAffine2 = row.attribute_cloned_or_default(ATTR_TRANSFORM);
166+
let row_alpha_blending: AlphaBlending = row.attribute_cloned_or_default(ATTR_ALPHA_BLENDING);
167167
let (element, mut attributes) = row.into_parts();
168168

169-
attributes.insert("transform", current_transform * row_transform);
170-
attributes.insert("alpha_blending", compose_alpha_blending(current_alpha_blending, row_alpha_blending));
171-
attributes.insert("editor:layer", layer_path.clone());
169+
attributes.insert(ATTR_TRANSFORM, current_transform * row_transform);
170+
attributes.insert(ATTR_ALPHA_BLENDING, compose_alpha_blending(current_alpha_blending, row_alpha_blending));
171+
attributes.insert(ATTR_EDITOR_LAYER_PATH, layer_path.clone());
172172

173173
output.push(TableRow::from_parts(element, attributes));
174174
}
@@ -321,7 +321,7 @@ impl Graphic {
321321

322322
pub fn had_clip_enabled(&self) -> bool {
323323
fn all_clipped<T>(table: &Table<T>) -> bool {
324-
table.iter_attribute_values_or_default::<AlphaBlending>("alpha_blending").all(|a| a.clip)
324+
table.iter_attribute_values_or_default::<AlphaBlending>(ATTR_ALPHA_BLENDING).all(|a| a.clip)
325325
}
326326
match self {
327327
Graphic::Vector(table) => all_clipped(table),
@@ -337,7 +337,7 @@ impl Graphic {
337337
match self {
338338
Graphic::Vector(vector) => vector
339339
.iter_element_values()
340-
.zip(vector.iter_attribute_values_or_default::<AlphaBlending>("alpha_blending"))
340+
.zip(vector.iter_attribute_values_or_default::<AlphaBlending>(ATTR_ALPHA_BLENDING))
341341
.all(|(element, alpha_blending)| {
342342
(alpha_blending.opacity > 1. - f32::EPSILON) && element.style.fill().is_opaque() && element.style.stroke().is_none_or(|stroke| !stroke.has_renderable_stroke())
343343
}),
@@ -504,7 +504,7 @@ pub fn migrate_graphic<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Res
504504
Table(serde_json::Value),
505505
}
506506

507-
// Attributes (transform, alpha_blending, editor:layer) are not serialized, so migration only needs
507+
// Attributes (transform, alpha_blending, editor:layer_path) are not serialized, so migration only needs
508508
// to recover the elements. Per-item attribute values are populated at runtime by the node graph.
509509
Ok(match GraphicFormat::deserialize(deserializer)? {
510510
GraphicFormat::OldGraphicGroup(old) => old.elements.into_iter().map(|(graphic, _)| TableRow::new_from_element(graphic)).collect(),

node-graph/libraries/graphic-types/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub mod migrations {
7272

7373
Ok(match VectorFormat::deserialize(deserializer)? {
7474
VectorFormat::Vector(vector) => Table::new_from_element(vector),
75-
// Attributes (transform, alpha_blending, editor:layer) are not serialized, so migration only needs
75+
// Attributes (transform, alpha_blending, editor:layer_path) are not serialized, so migration only needs
7676
// to recover the elements. Per-item attribute values are populated at runtime by the node graph.
7777
VectorFormat::OldVectorData(old) => Table::new_from_element(Vector {
7878
style: old.style,

node-graph/libraries/raster-types/src/image.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::raster_types::{CPU, Raster};
22
use crate::{Bitmap, BitmapMut};
3-
use core_types::AlphaBlending;
4-
use core_types::Color;
53
use core_types::color::float_to_srgb_u8;
64
use core_types::table::{Table, TableRow};
5+
use core_types::{ATTR_ALPHA_BLENDING, ATTR_TRANSFORM, AlphaBlending, Color};
76
// use crate::vector::Vector; // TODO: Check if Vector is actually used, if so handle differently
87
use core_types::color::*;
98
use dyn_any::{DynAny, StaticType};
@@ -319,7 +318,7 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
319318
Table::new_from_element(Raster::new_cpu(table.element(0).unwrap().clone()))
320319
}
321320

322-
// Attributes (transform, alpha_blending, editor:layer) are not serialized, so migration only needs
321+
// Attributes (transform, alpha_blending, editor:layer_path) are not serialized, so migration only needs
323322
// to recover the elements. Per-item attribute values are populated at runtime by the node graph.
324323
fn old_table_to_new_table<T>(old_table: OldTable<T>) -> Table<T> {
325324
old_table.element.into_iter().map(TableRow::new_from_element).collect()
@@ -339,8 +338,8 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
339338
FormatVersions::Image(image) => Table::new_from_element(Raster::new_cpu(image)),
340339
FormatVersions::OldImageFrame(OldImageFrame { image, transform, alpha_blending }) => {
341340
let mut image_frame_table = Table::new_from_element(Raster::new_cpu(image));
342-
image_frame_table.set_attribute("transform", 0, transform);
343-
image_frame_table.set_attribute("alpha_blending", 0, alpha_blending);
341+
image_frame_table.set_attribute(ATTR_TRANSFORM, 0, transform);
342+
image_frame_table.set_attribute(ATTR_ALPHA_BLENDING, 0, alpha_blending);
344343
image_frame_table
345344
}
346345
FormatVersions::OlderImageFrameTable(old_table) => from_image_frame_table(older_table_to_new_table(old_table)),
@@ -430,7 +429,7 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
430429
RasterTableRow(TableRow<Raster<CPU>>),
431430
}
432431

433-
// Attributes (transform, alpha_blending, editor:layer) are not serialized, so migration only needs
432+
// Attributes (transform, alpha_blending, editor:layer_path) are not serialized, so migration only needs
434433
// to recover the element. Per-item attribute values are populated at runtime by the node graph.
435434
Ok(match FormatVersions::deserialize(deserializer)? {
436435
FormatVersions::Image(image) => TableRow::new_from_element(Raster::new_cpu(image)),

0 commit comments

Comments
 (0)