rive_rs/shapes/paint/
shape_paint.rs
1use std::cell::RefCell;
6use std::rc::Rc;
7
8use crate::container_component::ContainerComponent;
9use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
10use crate::math::Mat;
11use crate::option_cell::OptionCell;
12use crate::shapes::paint::shape_paint_mutator::ShapePaintMutator;
13use crate::shapes::paint::{BlendMode, Fill, Stroke};
14use crate::shapes::{CommandPath, PathSpace, ShapePaintContainer};
15use crate::status_code::StatusCode;
16use crate::{Component, RenderPaint, Renderer};
17
18#[derive(Debug)]
19pub struct ShapePaint {
20 container_component: ContainerComponent,
21 is_visible: Property<bool>,
22 render_paint: OptionCell<Rc<RefCell<RenderPaint>>>,
23 shape_paint_mutator: OptionCell<Object<ShapePaintMutator>>,
24}
25
26impl ObjectRef<'_, ShapePaint> {
27 pub fn is_visible(&self) -> bool {
28 self.is_visible.get()
29 }
30
31 pub fn set_is_visible(&self, is_visible: bool) {
32 self.is_visible.set(is_visible);
33 }
34}
35
36impl ObjectRef<'_, ShapePaint> {
37 pub fn init_render_paint(
38 &self,
39 mutator: Object<ShapePaintMutator>,
40 ) -> Option<Rc<RefCell<RenderPaint>>> {
41 self.shape_paint_mutator.set(Some(mutator));
42 self.render_paint.set(Some(Rc::new(RefCell::new(RenderPaint::default()))));
43
44 self.render_paint.get()
45 }
46
47 pub fn path_space(&self) -> PathSpace {
48 if let Some(fill) = self.try_cast::<Fill>() {
49 return fill.path_space();
50 }
51
52 if let Some(stroke) = self.try_cast::<Stroke>() {
53 return stroke.path_space();
54 }
55
56 unreachable!()
57 }
58
59 pub fn render_paint(&self) -> Rc<RefCell<RenderPaint>> {
60 self.render_paint.get().expect("init_render_paint has not been called yet")
61 }
62
63 pub fn set_blend_mode(&self, blend_mode: BlendMode) {
64 self.render_paint().borrow_mut().blend_mode = blend_mode;
65 }
66
67 pub fn set_render_opacity(&self, render_opacity: f32) {
68 self.shape_paint_mutator
69 .get()
70 .expect("init_paint_mutator has not been called yet")
71 .as_ref()
72 .set_render_opacity(render_opacity);
73 }
74
75 pub fn set_is_clipped(&self, is_clipped: bool) {
76 self.render_paint().borrow_mut().is_clipped = is_clipped;
77 }
78
79 pub fn draw(&self, renderer: &mut impl Renderer, path: &CommandPath, transform: Mat) {
80 if let Some(fill) = self.try_cast::<Fill>() {
81 return fill.draw(renderer, path, transform);
82 }
83
84 if let Some(stroke) = self.try_cast::<Stroke>() {
85 return stroke.draw(renderer, path, transform);
86 }
87
88 unreachable!()
89 }
90}
91
92impl Core for ShapePaint {
93 parent_types![(container_component, ContainerComponent)];
94
95 properties![(41, is_visible, set_is_visible), container_component];
96}
97
98impl OnAdded for ObjectRef<'_, ShapePaint> {
99 on_added!([on_added_dirty, import], ContainerComponent);
100
101 fn on_added_clean(&self, _context: &dyn CoreContext) -> StatusCode {
102 let container = self.cast::<Component>().parent().and_then(|parent| {
103 let object: Object = parent.into();
104 object.try_into().ok()
105 });
106
107 if let Some(container) = container {
108 let container: Object<ShapePaintContainer> = container;
109 container.as_ref().push_paint(self.as_object());
110
111 StatusCode::Ok
112 } else {
113 StatusCode::MissingObject
114 }
115 }
116}
117
118impl Default for ShapePaint {
119 fn default() -> Self {
120 Self {
121 container_component: ContainerComponent::default(),
122 is_visible: Property::new(true),
123 render_paint: OptionCell::new(),
124 shape_paint_mutator: OptionCell::new(),
125 }
126 }
127}