rive_rs/
draw_target.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::component::Component;
6use crate::component_dirt::ComponentDirt;
7use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property, TryFromU64};
8use crate::drawable::Drawable;
9use crate::dyn_vec::DynVec;
10use crate::option_cell::OptionCell;
11use crate::shapes::ClippingShape;
12use crate::status_code::StatusCode;
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub enum DrawTargetPlacement {
16    Before,
17    After,
18}
19
20impl Default for DrawTargetPlacement {
21    fn default() -> Self {
22        Self::Before
23    }
24}
25
26impl TryFromU64 for DrawTargetPlacement {
27    fn try_from(val: u64) -> Option<Self> {
28        match val {
29            0 => Some(Self::Before),
30            1 => Some(Self::After),
31            _ => None,
32        }
33    }
34}
35
36#[derive(Debug)]
37pub struct DrawTarget {
38    component: Component,
39    drawable_id: Property<u64>,
40    placement: Property<DrawTargetPlacement>,
41    drawable: OptionCell<Object<Drawable>>,
42    pub(crate) first: OptionCell<Object<Drawable>>,
43    pub(crate) last: OptionCell<Object<Drawable>>,
44    clipping_shapes: DynVec<Object<ClippingShape>>,
45}
46
47impl ObjectRef<'_, DrawTarget> {
48    pub fn drawable_id(&self) -> u64 {
49        self.drawable_id.get()
50    }
51
52    pub fn set_drawable_id(&self, drawable_id: u64) {
53        self.drawable_id.set(drawable_id);
54    }
55
56    pub fn placement(&self) -> DrawTargetPlacement {
57        self.placement.get()
58    }
59
60    pub fn set_placement(&self, placement: DrawTargetPlacement) {
61        if self.placement() == placement {
62            return;
63        }
64
65        self.placement.set(placement);
66
67        if let Some(artboard) = self.component.artboard() {
68            artboard.cast::<Component>().as_ref().add_dirt(ComponentDirt::DRAW_ORDER, false);
69        }
70    }
71}
72
73impl ObjectRef<'_, DrawTarget> {
74    pub fn drawable(&self) -> Option<Object<Drawable>> {
75        self.drawable.get()
76    }
77
78    pub fn push_clipping_shape(&self, clipping_shape: Object<ClippingShape>) {
79        self.clipping_shapes.push(clipping_shape);
80    }
81
82    pub fn clipping_shapes(&self) -> impl Iterator<Item = Object<ClippingShape>> + '_ {
83        self.clipping_shapes.iter()
84    }
85}
86
87impl Core for DrawTarget {
88    parent_types![(component, Component)];
89
90    properties![(119, drawable_id, set_drawable_id), (120, placement, set_placement), component];
91}
92
93impl OnAdded for ObjectRef<'_, DrawTarget> {
94    on_added!([on_added_clean, import], Component);
95
96    fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
97        let code = self.cast::<Component>().on_added_dirty(context);
98        if code != StatusCode::Ok {
99            return code;
100        }
101
102        if let Some(drawable) =
103            context.resolve(self.drawable_id() as usize).and_then(|core| core.try_cast())
104        {
105            self.drawable.set(Some(drawable));
106            StatusCode::Ok
107        } else {
108            StatusCode::MissingObject
109        }
110    }
111}
112
113impl Default for DrawTarget {
114    fn default() -> Self {
115        Self {
116            component: Component::default(),
117            drawable_id: Property::new(0),
118            placement: Property::new(DrawTargetPlacement::Before),
119            drawable: OptionCell::new(),
120            first: OptionCell::new(),
121            last: OptionCell::new(),
122            clipping_shapes: DynVec::new(),
123        }
124    }
125}