rive_rs/
component.rs
1use std::any::TypeId;
6use std::cell::Cell;
7use std::hash::{Hash, Hasher};
8use std::iter;
9
10use crate::artboard::Artboard;
11use crate::bones::Skin;
12use crate::component_dirt::ComponentDirt;
13use crate::container_component::ContainerComponent;
14use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
15use crate::dyn_vec::DynVec;
16use crate::importers::{ArtboardImporter, ImportStack};
17use crate::option_cell::OptionCell;
18use crate::shapes::paint::LinearGradient;
19use crate::shapes::{
20 ClippingShape, Ellipse, Path, PathComposer, PointsPath, Polygon, Rectangle, Shape, Triangle,
21};
22use crate::status_code::StatusCode;
23use crate::TransformComponent;
24
25#[derive(Debug)]
26pub struct Component {
27 name: Property<String>,
28 parent_id: Property<u64>,
29 parent: OptionCell<Object<ContainerComponent>>,
30 depdenents: DynVec<Object<Self>>,
31 artboard: OptionCell<Object<Artboard>>,
32 pub(crate) graph_order: Cell<usize>,
33 pub(crate) dirt: Cell<ComponentDirt>,
34}
35
36impl<'a> ObjectRef<'a, Component> {
37 pub fn name(&self) -> String {
38 self.name.get()
39 }
40
41 pub fn set_name(&self, name: String) {
42 self.name.set(name);
43 }
44
45 pub fn parent_id(&'a self) -> u64 {
46 self.parent_id.get()
47 }
48
49 pub fn set_parent_id(&self, parent_id: u64) {
50 self.parent_id.set(parent_id);
51 }
52}
53
54impl Component {
55 pub fn artboard(&self) -> Option<Object<Artboard>> {
56 self.artboard.get()
57 }
58
59 pub fn value_has_dirt(value: ComponentDirt, flags: ComponentDirt) -> bool {
60 !(value & flags).is_empty()
61 }
62}
63
64impl ObjectRef<'_, Component> {
65 pub fn parent(&self) -> Option<Object<ContainerComponent>> {
66 self.parent.get()
67 }
68
69 pub fn parents(&self) -> impl Iterator<Item = Object<ContainerComponent>> {
70 iter::successors(self.parent(), |component| component.cast::<Component>().as_ref().parent())
71 }
72
73 pub fn depdenents(&self) -> impl Iterator<Item = Object<Component>> + '_ {
74 self.depdenents.iter()
75 }
76
77 pub fn push_dependent(&self, dependent: Object<Component>) {
78 self.depdenents.push(dependent);
79 }
80
81 pub fn has_dirt(&self, flags: ComponentDirt) -> bool {
82 self.dirt.get() & flags == flags
83 }
84
85 pub fn add_dirt(&self, value: ComponentDirt, recurse: bool) -> bool {
86 if self.has_dirt(value) {
87 return false;
88 }
89
90 self.dirt.set(self.dirt.get() | value);
91 self.on_dirty(self.dirt.get());
92
93 if let Some(artboard) = self.artboard.get() {
94 artboard.as_ref().on_component_dirty(self);
95 }
96
97 if !recurse {
98 return true;
99 }
100
101 for dependent in self.depdenents() {
102 dependent.as_ref().add_dirt(value, recurse);
103 }
104
105 true
106 }
107
108 pub fn build_dependencies(&self) {
109 match_cast!(self, {
110 ClippingShape(clipping_shape) => clipping_shape.build_dependencies(),
111 Shape(shape) => shape.build_dependencies(),
112 PointsPath(points_path) => points_path.build_dependencies(),
113 Path(path) => path.build_dependencies(),
114 PathComposer(path_composer) => path_composer.build_dependencies(),
115 Skin(skin) => skin.build_dependencies(),
116 LinearGradient(linear_gradient) => linear_gradient.build_dependencies(),
117 TransformComponent(transform_component) => transform_component.build_dependencies(),
118 })
119 }
120
121 pub fn on_dirty(&self, dirt: ComponentDirt) {
122 match_cast!(self, {
123 Path(path) => path.on_dirty(dirt),
124 Skin(skin) => skin.on_dirty(dirt),
125 Artboard(artboard) => artboard.on_dirty(dirt),
126 })
127 }
128
129 pub fn update(&self, value: ComponentDirt) {
130 match_cast!(self, {
131 Ellipse(ellipse) => ellipse.update(value),
132 Rectangle(rectangle) => rectangle.update(value),
133 Triangle(triangle) => triangle.update(value),
134 Polygon(polygon) => polygon.update(value),
135 ClippingShape(clipping_shape) => clipping_shape.update(value),
136 Shape(shape) => shape.update(value),
137 PointsPath(points_path) => points_path.update(value),
138 Path(path) => path.update(value),
139 PathComposer(path_composer) => path_composer.update(value),
140 Skin(skin) => skin.update(value),
141 LinearGradient(linear_gradient) => linear_gradient.update(value),
142 TransformComponent(transform_component) => transform_component.update(value),
143 Artboard(artboard) => artboard.update(value),
144 })
145 }
146}
147
148impl Hash for Component {
149 fn hash<H: Hasher>(&self, state: &mut H) {
150 self.name.get().hash(state);
151 self.parent_id.get().hash(state);
152 }
153}
154
155impl Core for Component {
156 properties![(4, name, set_name), (5, parent_id, set_parent_id)];
157}
158
159impl OnAdded for ObjectRef<'_, Component> {
160 on_added!([on_added_clean]);
161
162 fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
163 let artboard = context.artboard();
164 self.artboard.set(Some(artboard.clone()));
165
166 if let Some(self_artboard) = self.as_object().try_cast() {
167 if artboard == self_artboard {
168 return StatusCode::Ok;
169 }
170 }
171
172 if let Some(parent) =
173 context.resolve(self.parent_id() as usize).and_then(|core| core.try_cast())
174 {
175 self.parent.set(Some(parent));
176 StatusCode::Ok
177 } else {
178 StatusCode::MissingObject
179 }
180 }
181
182 fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode {
183 if let Some(importer) = import_stack.latest::<ArtboardImporter>(TypeId::of::<Artboard>()) {
184 importer.push_object(object);
185 StatusCode::Ok
186 } else {
187 StatusCode::MissingObject
188 }
189 }
190}
191
192impl Default for Component {
193 fn default() -> Self {
194 Self {
195 name: Property::new(String::new()),
196 parent_id: Property::new(0),
197 parent: OptionCell::new(),
198 depdenents: DynVec::new(),
199 artboard: OptionCell::new(),
200 graph_order: Cell::new(0),
201 dirt: Cell::new(ComponentDirt::all()),
202 }
203 }
204}