use kurbo::{Rect, Shape};
use pax_engine::*;
use pax_runtime::api::{use_RefCell, Stroke};
use pax_runtime::api::{Fill, Layer, RenderContext};
use pax_runtime::BaseInstance;
use pax_runtime::{ExpandedNode, InstanceFlags, InstanceNode, InstantiationArgs, RuntimeContext};
use_RefCell!();
use std::rc::Rc;
#[pax]
#[engine_import_path("pax_engine")]
#[primitive("pax_std::drawing::ellipse::EllipseInstance")]
pub struct Ellipse {
pub stroke: Property<Stroke>,
pub fill: Property<Fill>,
}
pub struct EllipseInstance {
base: BaseInstance,
changed: Property<()>,
}
impl InstanceNode for EllipseInstance {
fn instantiate(args: InstantiationArgs) -> Rc<Self>
where
Self: Sized,
{
Rc::new(EllipseInstance {
base: BaseInstance::new(
args,
InstanceFlags {
invisible_to_slot: false,
invisible_to_raycasting: false,
layer: Layer::Canvas,
is_component: false,
is_slot: false,
},
),
changed: Property::new(()),
})
}
fn handle_mount(
self: Rc<Self>,
expanded_node: &Rc<ExpandedNode>,
context: &Rc<RuntimeContext>,
) {
let tab = expanded_node.transform_and_bounds.clone();
let (stroke, fill) = expanded_node.with_properties_unwrapped(|properties: &mut Ellipse| {
(properties.stroke.clone(), properties.fill.clone())
});
let deps = &[tab.untyped(), stroke.untyped(), fill.untyped()];
let cloned_expanded_node = expanded_node.clone();
let cloned_context = context.clone();
self.changed.replace_with(Property::computed(
move || {
cloned_context
.set_canvas_dirty(cloned_expanded_node.occlusion.get().occlusion_layer_id);
()
},
deps,
));
}
fn update(self: Rc<Self>, _expanded_node: &Rc<ExpandedNode>, _context: &Rc<RuntimeContext>) {
self.changed.get();
}
fn render(
&self,
expanded_node: &ExpandedNode,
rtc: &Rc<RuntimeContext>,
rc: &mut dyn RenderContext,
) {
let layer_id = expanded_node.occlusion.get().occlusion_layer_id;
if !rtc.is_canvas_dirty(&layer_id) {
return;
}
let tab = expanded_node.transform_and_bounds.get();
let (width, height) = tab.bounds;
expanded_node.with_properties_unwrapped(|properties: &mut Ellipse| {
let rect = Rect::from_points((0.0, 0.0), (width, height));
let ellipse = kurbo::Ellipse::from_rect(rect);
let accuracy = 0.1;
let bez_path = ellipse.to_path(accuracy);
let transformed_bez_path = Into::<kurbo::Affine>::into(tab.transform) * bez_path;
let duplicate_transformed_bez_path = transformed_bez_path.clone();
let color = if let Fill::Solid(properties_color) = properties.fill.get() {
properties_color.to_piet_color()
} else {
unimplemented!("gradients not supported on ellipse")
};
rc.fill(layer_id, transformed_bez_path, &color.into());
let width: f64 = properties
.stroke
.get()
.width
.get()
.expect_pixels()
.to_float();
if width > f64::EPSILON {
rc.stroke(
layer_id,
duplicate_transformed_bez_path,
&properties.stroke.get().color.get().to_piet_color().into(),
width,
);
}
});
}
fn resolve_debug(
&self,
f: &mut std::fmt::Formatter,
expanded_node: Option<&ExpandedNode>,
) -> std::fmt::Result {
match expanded_node {
Some(expanded_node) => expanded_node
.with_properties_unwrapped(|_e: &mut Ellipse| f.debug_struct("Ellipse").finish()),
None => f.debug_struct("Ellipse").finish_non_exhaustive(),
}
}
fn base(&self) -> &BaseInstance {
&self.base
}
}