11use crate :: graphic:: Graphic ;
22use core_types:: blending:: BlendMode ;
3+ use core_types:: bounds:: { BoundingBox , RenderBoundingBox } ;
4+ use core_types:: graphene_hash:: CacheHash ;
5+ use core_types:: render_complexity:: RenderComplexity ;
36use core_types:: table:: { Table , TableRow } ;
47use core_types:: uuid:: NodeId ;
58use core_types:: { ATTR_BACKGROUND , ATTR_CLIP , ATTR_DIMENSIONS , ATTR_LOCATION , Color } ;
69use dyn_any:: DynAny ;
710use glam:: { DAffine2 , IVec2 } ;
811
9- // An artboard table is `Table<Table<Graphic>>`: each row's element is the artboard's content
10- // (a `Table<Graphic>`), with the artboard's metadata stored alongside on the row as attributes
11- // (see `ATTR_LOCATION`, `ATTR_DIMENSIONS`, `ATTR_BACKGROUND`, `ATTR_CLIP`).
12- //
13- // The artboard's user-visible name is the parent layer's display name (resolved live from the
14- // network interface via the row's `ATTR_EDITOR_LAYER_PATH` attribute) — not stored here, so it
15- // can never go stale.
16- //
17- // These metadata attributes are populated at runtime by the `Artboard` proto node from its
18- // inputs and therefore aren't persisted in document files; the proto node's input values are
19- // what get serialized.
12+ /// Nominal wrapper around `Table<Graphic>` representing a single artboard's content.
13+ ///
14+ /// Per-artboard metadata (location, dimensions, background, clip) lives as row attributes on the
15+ /// enclosing `Table<Artboard>`, not as fields here. This keeps `Artboard` a pure type-system boundary
16+ /// that prevents arbitrary `Table<Table<...<Graphic>>>` nesting.
17+ #[ derive( Clone , Debug , Default , CacheHash , PartialEq , DynAny ) ]
18+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
19+ pub struct Artboard ( Table < Graphic > ) ;
20+
21+ impl Artboard {
22+ pub fn new ( content : Table < Graphic > ) -> Self {
23+ Self ( content)
24+ }
25+
26+ pub fn as_graphic_table ( & self ) -> & Table < Graphic > {
27+ & self . 0
28+ }
29+
30+ pub fn as_graphic_table_mut ( & mut self ) -> & mut Table < Graphic > {
31+ & mut self . 0
32+ }
33+
34+ pub fn into_graphic_table ( self ) -> Table < Graphic > {
35+ self . 0
36+ }
37+ }
38+
39+ impl From < Table < Graphic > > for Artboard {
40+ fn from ( content : Table < Graphic > ) -> Self {
41+ Self ( content)
42+ }
43+ }
44+
45+ impl From < Artboard > for Table < Graphic > {
46+ fn from ( artboard : Artboard ) -> Self {
47+ artboard. 0
48+ }
49+ }
50+
51+ impl BoundingBox for Artboard {
52+ fn bounding_box ( & self , transform : DAffine2 , include_stroke : bool ) -> RenderBoundingBox {
53+ self . 0 . bounding_box ( transform, include_stroke)
54+ }
55+
56+ fn thumbnail_bounding_box ( & self , transform : DAffine2 , include_stroke : bool ) -> RenderBoundingBox {
57+ self . 0 . thumbnail_bounding_box ( transform, include_stroke)
58+ }
59+ }
60+
61+ impl RenderComplexity for Artboard {
62+ fn render_complexity ( & self ) -> usize {
63+ self . 0 . render_complexity ( )
64+ }
65+ }
2066
2167// TODO: Eventually remove this migration document upgrade code
22- pub fn migrate_artboard < ' de , D : serde:: Deserializer < ' de > > ( deserializer : D ) -> Result < Table < Table < Graphic > > , D :: Error > {
68+ pub fn migrate_artboard < ' de , D : serde:: Deserializer < ' de > > ( deserializer : D ) -> Result < Table < Artboard > , D :: Error > {
2369 use serde:: Deserialize ;
2470
2571 /// Mirrors the removed `AlphaBlending` struct for legacy document deserialization.
@@ -33,9 +79,7 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
3379 pub clip : bool ,
3480 }
3581
36- /// Pre-migration shape of the artboard's stored data: the struct that used to live as the element
37- /// of `Table<Artboard>`. Kept as a private type so we can deserialize legacy documents into the new
38- /// `Table<Table<Graphic>>` (element = `content`, other fields → row attributes).
82+ /// Legacy artboard struct shape, kept for deserializing old documents into `Table<Artboard>`.
3983 #[ derive( Clone , Debug , DynAny ) ]
4084 #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
4185 pub struct LegacyArtboard {
@@ -68,14 +112,14 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
68112 ArtboardGroup ( LegacyArtboardGroup ) ,
69113 OldArtboardTable ( OldTable < LegacyArtboard > ) ,
70114 LegacyArtboardTable ( Table < LegacyArtboard > ) ,
71- // Note: this variant must come last so older formats above are tried first; an empty
72- // `Table<Table<Graphic>>` would otherwise match ( since `Table<T>` has the same shell across `T`) .
73- ArtboardTable ( Table < Table < Graphic > > ) ,
115+ // NOTE: Must come last so older tagged formats above are tried first.
116+ // Also covers the intermediate `Table<Table<Graphic>>` shape since `Artboard` deserializes transparently .
117+ ArtboardTable ( Table < Artboard > ) ,
74118 }
75119
76- fn legacy_to_row ( legacy : LegacyArtboard ) -> TableRow < Table < Graphic > > {
77- // Legacy `label` field is dropped — the artboard's name now comes from its parent layer's display name.
78- TableRow :: new_from_element ( legacy. content )
120+ fn legacy_to_row ( legacy : LegacyArtboard ) -> TableRow < Artboard > {
121+ // Legacy `label` field is dropped ( the artboard's name comes from its parent layer's display name)
122+ TableRow :: new_from_element ( Artboard :: new ( legacy. content ) )
79123 . with_attribute ( ATTR_LOCATION , legacy. location . as_dvec2 ( ) )
80124 . with_attribute ( ATTR_DIMENSIONS , legacy. dimensions . as_dvec2 ( ) )
81125 . with_attribute ( ATTR_BACKGROUND , legacy. background )
0 commit comments