rive_rs/shapes/paint/
shape_paint.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::RefCell;
use std::rc::Rc;

use crate::container_component::ContainerComponent;
use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
use crate::math::Mat;
use crate::option_cell::OptionCell;
use crate::shapes::paint::shape_paint_mutator::ShapePaintMutator;
use crate::shapes::paint::{BlendMode, Fill, Stroke};
use crate::shapes::{CommandPath, PathSpace, ShapePaintContainer};
use crate::status_code::StatusCode;
use crate::{Component, RenderPaint, Renderer};

#[derive(Debug)]
pub struct ShapePaint {
    container_component: ContainerComponent,
    is_visible: Property<bool>,
    render_paint: OptionCell<Rc<RefCell<RenderPaint>>>,
    shape_paint_mutator: OptionCell<Object<ShapePaintMutator>>,
}

impl ObjectRef<'_, ShapePaint> {
    pub fn is_visible(&self) -> bool {
        self.is_visible.get()
    }

    pub fn set_is_visible(&self, is_visible: bool) {
        self.is_visible.set(is_visible);
    }
}

impl ObjectRef<'_, ShapePaint> {
    pub fn init_render_paint(
        &self,
        mutator: Object<ShapePaintMutator>,
    ) -> Option<Rc<RefCell<RenderPaint>>> {
        self.shape_paint_mutator.set(Some(mutator));
        self.render_paint.set(Some(Rc::new(RefCell::new(RenderPaint::default()))));

        self.render_paint.get()
    }

    pub fn path_space(&self) -> PathSpace {
        if let Some(fill) = self.try_cast::<Fill>() {
            return fill.path_space();
        }

        if let Some(stroke) = self.try_cast::<Stroke>() {
            return stroke.path_space();
        }

        unreachable!()
    }

    pub fn render_paint(&self) -> Rc<RefCell<RenderPaint>> {
        self.render_paint.get().expect("init_render_paint has not been called yet")
    }

    pub fn set_blend_mode(&self, blend_mode: BlendMode) {
        self.render_paint().borrow_mut().blend_mode = blend_mode;
    }

    pub fn set_render_opacity(&self, render_opacity: f32) {
        self.shape_paint_mutator
            .get()
            .expect("init_paint_mutator has not been called yet")
            .as_ref()
            .set_render_opacity(render_opacity);
    }

    pub fn set_is_clipped(&self, is_clipped: bool) {
        self.render_paint().borrow_mut().is_clipped = is_clipped;
    }

    pub fn draw(&self, renderer: &mut impl Renderer, path: &CommandPath, transform: Mat) {
        if let Some(fill) = self.try_cast::<Fill>() {
            return fill.draw(renderer, path, transform);
        }

        if let Some(stroke) = self.try_cast::<Stroke>() {
            return stroke.draw(renderer, path, transform);
        }

        unreachable!()
    }
}

impl Core for ShapePaint {
    parent_types![(container_component, ContainerComponent)];

    properties![(41, is_visible, set_is_visible), container_component];
}

impl OnAdded for ObjectRef<'_, ShapePaint> {
    on_added!([on_added_dirty, import], ContainerComponent);

    fn on_added_clean(&self, _context: &dyn CoreContext) -> StatusCode {
        let container = self.cast::<Component>().parent().and_then(|parent| {
            let object: Object = parent.into();
            object.try_into().ok()
        });

        if let Some(container) = container {
            let container: Object<ShapePaintContainer> = container;
            container.as_ref().push_paint(self.as_object());

            StatusCode::Ok
        } else {
            StatusCode::MissingObject
        }
    }
}

impl Default for ShapePaint {
    fn default() -> Self {
        Self {
            container_component: ContainerComponent::default(),
            is_visible: Property::new(true),
            render_paint: OptionCell::new(),
            shape_paint_mutator: OptionCell::new(),
        }
    }
}