Added ArcTo element for paths

This commit is contained in:
Simon Hausmann 2020-07-07 14:11:19 +02:00
parent a83127ace8
commit f646809ff4
8 changed files with 124 additions and 11 deletions

View file

@ -5,6 +5,7 @@
namespace sixtyfps { namespace sixtyfps {
using internal::types::PathArcTo;
using internal::types::PathElement; using internal::types::PathElement;
using internal::types::PathLineTo; using internal::types::PathLineTo;

View file

@ -1,7 +1,7 @@
use core::cell::RefCell; use core::cell::RefCell;
use neon::prelude::*; use neon::prelude::*;
use sixtyfps_compilerlib::typeregister::Type; use sixtyfps_compilerlib::typeregister::Type;
use sixtyfps_corelib::abi::datastructures::{PathElement, PathLineTo, Resource}; use sixtyfps_corelib::abi::datastructures::{PathArcTo, PathElement, PathLineTo, Resource};
use sixtyfps_corelib::{ComponentRefPin, EvaluationContext}; use sixtyfps_corelib::{ComponentRefPin, EvaluationContext};
use std::rc::Rc; use std::rc::Rc;
@ -122,6 +122,30 @@ fn to_eval_value<'cx>(
} }
} }
fn set_float_property<'cx>(
cx: &mut impl Context<'cx>,
object: &Handle<JsObject>,
name: &str,
value: f32,
) -> NeonResult<()> {
let value = JsNumber::new(cx, value);
let value = value.as_value(cx);
object.set(cx, name, value)?;
Ok(())
}
fn set_bool_property<'cx>(
cx: &mut impl Context<'cx>,
object: &Handle<JsObject>,
name: &str,
value: bool,
) -> NeonResult<()> {
let value = JsBoolean::new(cx, value);
let value = value.as_value(cx);
object.set(cx, name, value)?;
Ok(())
}
fn to_js_value<'cx>( fn to_js_value<'cx>(
val: sixtyfps_interpreter::Value, val: sixtyfps_interpreter::Value,
cx: &mut impl Context<'cx>, cx: &mut impl Context<'cx>,
@ -162,13 +186,28 @@ fn to_js_value<'cx>(
match element { match element {
PathElement::LineTo(PathLineTo { x, y }) => { PathElement::LineTo(PathLineTo { x, y }) => {
let x = JsNumber::new(cx, *x); set_float_property(cx, &element_object, "x", *x)?;
let x = x.as_value(cx); set_float_property(cx, &element_object, "y", *y)?;
element_object.set(cx, "x", x)?; }
PathElement::ArcTo(PathArcTo {
x,
y,
radius_x,
radius_y,
x_rotation,
large_arc,
sweep,
}) => {
set_float_property(cx, &element_object, "x", *x)?;
set_float_property(cx, &element_object, "y", *y)?;
let y = JsNumber::new(cx, *y); set_float_property(cx, &element_object, "radius_x", *radius_x)?;
let y = y.as_value(cx); set_float_property(cx, &element_object, "radius_y", *radius_y)?;
element_object.set(cx, "y", y)?;
set_float_property(cx, &element_object, "x_rotation", *x_rotation)?;
set_bool_property(cx, &element_object, "large_arc", *large_arc)?;
set_bool_property(cx, &element_object, "sweep", *sweep)?;
} }
} }

View file

@ -6,7 +6,7 @@ TestCase := Rectangle {
LineTo { x: 100; y: 0; } LineTo { x: 100; y: 0; }
LineTo { x: 100; y: 0; } LineTo { x: 100; y: 0; }
Rectangle {} Rectangle {}
// ^error{Rectangle is not allowed within Path. Only LineTo are valid children} // ^error{Rectangle is not allowed within Path. Only LineTo ArcTo are valid children}
} }
LineTo { x: 100; y: 0; } LineTo { x: 100; y: 0; }

View file

@ -289,6 +289,20 @@ impl TypeRegister {
path.additional_accepted_child_types path.additional_accepted_child_types
.insert("LineTo".to_owned(), Type::Builtin(Rc::new(line_to))); .insert("LineTo".to_owned(), Type::Builtin(Rc::new(line_to)));
let mut arc_to = BuiltinElement::new("ArcTo");
arc_to.properties.insert("x".to_owned(), Type::Float32);
arc_to.properties.insert("y".to_owned(), Type::Float32);
arc_to.properties.insert("radius_x".to_owned(), Type::Float32);
arc_to.properties.insert("radius_y".to_owned(), Type::Float32);
arc_to.properties.insert("x_rotation".to_owned(), Type::Float32);
arc_to.properties.insert("large_arc".to_owned(), Type::Bool);
arc_to.properties.insert("sweep".to_owned(), Type::Bool);
arc_to.rust_type_constructor =
Some("sixtyfps::re_exports::PathElement::ArcTo(PathArcTo{{}})".into());
arc_to.cpp_type = Some("sixtyfps::PathArcTo".into());
path.additional_accepted_child_types
.insert("ArcTo".to_owned(), Type::Builtin(Rc::new(arc_to)));
r.types.insert("Path".to_owned(), Type::Builtin(Rc::new(path))); r.types.insert("Path".to_owned(), Type::Builtin(Rc::new(path)));
let mut property_animation = let mut property_animation =

View file

@ -266,12 +266,44 @@ pub struct PathLineTo {
pub y: f32, pub y: f32,
} }
#[repr(C)]
#[derive(FieldOffsets, Default, BuiltinItem, Clone, Debug, PartialEq)]
#[pin]
/// PathArcTo describes the event of moving the cursor on the path across an arc to the specified
/// x/y coordinates, with the specified x/y radius and additional properties.
pub struct PathArcTo {
#[rtti_field]
/// The x coordinate where the arc should end up.
pub x: f32,
#[rtti_field]
/// The y coordinate where the arc should end up.
pub y: f32,
#[rtti_field]
/// The radius on the x-axis of the arc.
pub radius_x: f32,
#[rtti_field]
/// The radius on the y-axis of the arc.
pub radius_y: f32,
#[rtti_field]
/// The rotation along the x-axis of the arc in degress.
pub x_rotation: f32,
#[rtti_field]
/// large_arc indicates whether to take the long or the shorter path to complete the arc.
pub large_arc: bool,
#[rtti_field]
/// sweep indicates the direction of the arc. If true, a clockwise direction is chosen,
/// otherwise counter-clockwise.
pub sweep: bool,
}
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// PathElement describes a single element on a path, such as move-to, line-to, etc. /// PathElement describes a single element on a path, such as move-to, line-to, etc.
pub enum PathElement { pub enum PathElement {
/// The LineTo variant describes a line. /// The LineTo variant describes a line.
LineTo(PathLineTo), LineTo(PathLineTo),
/// The PathArcTo variant describes an arc.
ArcTo(PathArcTo),
} }
#[repr(C)] #[repr(C)]

View file

@ -377,6 +377,9 @@ fn convert_path_element(
"LineTo" => sixtyfps_corelib::abi::datastructures::PathElement::LineTo( "LineTo" => sixtyfps_corelib::abi::datastructures::PathElement::LineTo(
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context), new_struct_with_bindings(&expr_element.bindings, component_type, eval_context),
), ),
"ArcTo" => sixtyfps_corelib::abi::datastructures::PathElement::ArcTo(
new_struct_with_bindings(&expr_element.bindings, component_type, eval_context),
),
_ => panic!( _ => panic!(
"Cannot create unsupported path element {}", "Cannot create unsupported path element {}",
expr_element.element_type.class_name expr_element.element_type.class_name

View file

@ -5,7 +5,7 @@ use itertools::Itertools;
use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers}; use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers};
use lyon::tessellation::{FillAttributes, FillOptions, FillTessellator}; use lyon::tessellation::{FillAttributes, FillOptions, FillTessellator};
use sixtyfps_corelib::abi::datastructures::{ use sixtyfps_corelib::abi::datastructures::{
Color, ComponentWindow, ComponentWindowOpaque, PathElement, PathLineTo, Point, Rect, Color, ComponentWindow, ComponentWindowOpaque, PathArcTo, PathElement, PathLineTo, Point, Rect,
RenderingPrimitive, Resource, Size, RenderingPrimitive, Resource, Size,
}; };
use sixtyfps_corelib::graphics::{ use sixtyfps_corelib::graphics::{
@ -336,8 +336,11 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
Some(self.create_glyph_runs(text, font_family, pixel_size, *color)) Some(self.create_glyph_runs(text, font_family, pixel_size, *color))
} }
RenderingPrimitive::Path { x: _, y: _, elements, fill_color } => { RenderingPrimitive::Path { x: _, y: _, elements, fill_color } => {
use lyon::math::Point; use lyon::math::{Angle, Point, Vector};
use lyon::path::builder::{Build, FlatPathBuilder}; use lyon::path::{
builder::{Build, FlatPathBuilder, SvgBuilder},
ArcFlags,
};
let mut path_builder = lyon::path::Path::builder().with_svg(); let mut path_builder = lyon::path::Path::builder().with_svg();
for element in elements.iter() { for element in elements.iter() {
@ -345,6 +348,20 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
PathElement::LineTo(PathLineTo { x, y }) => { PathElement::LineTo(PathLineTo { x, y }) => {
path_builder.line_to(Point::new(*x, *y)) path_builder.line_to(Point::new(*x, *y))
} }
PathElement::ArcTo(PathArcTo {
x,
y,
radius_x,
radius_y,
x_rotation,
large_arc,
sweep,
}) => path_builder.arc_to(
Vector::new(*radius_x, *radius_y),
Angle::degrees(*x_rotation),
ArcFlags { large_arc: *large_arc, sweep: *sweep },
Point::new(*x, *y),
),
} }
} }

View file

@ -114,6 +114,13 @@ Hello := Rectangle {
x: 0; x: 0;
y: 100; y: 100;
} }
ArcTo {
x: 0;
y: 0;
radius_x: 10;
radius_y: 10;
}
} }
} }