blob: 2d6a82277f2377f4ead133ad7e27bd364771a8c7 [file] [log] [blame]
// 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, rc::Rc};
use crate::{
container_component::ContainerComponent,
core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property},
math::Mat,
option_cell::OptionCell,
shapes::{
paint::{shape_paint_mutator::ShapePaintMutator, BlendMode, Fill, Stroke},
CommandPath, PathSpace, ShapePaintContainer,
},
status_code::StatusCode,
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(),
}
}
}