diff --git a/api/sixtyfps-cpp/include/sixtyfps_pathdata.h b/api/sixtyfps-cpp/include/sixtyfps_pathdata.h index f7d47fe97..77789a1be 100644 --- a/api/sixtyfps-cpp/include/sixtyfps_pathdata.h +++ b/api/sixtyfps-cpp/include/sixtyfps_pathdata.h @@ -19,6 +19,8 @@ using cbindgen_private::types::PathElement; using cbindgen_private::types::PathEvent; using cbindgen_private::types::PathLineTo; using cbindgen_private::types::PathMoveTo; +using cbindgen_private::types::PathCubicTo; +using cbindgen_private::types::PathQuadraticTo; using cbindgen_private::types::Point; struct PathData diff --git a/api/sixtyfps-rs/lib.rs b/api/sixtyfps-rs/lib.rs index 28835f61d..1e0ab020f 100644 --- a/api/sixtyfps-rs/lib.rs +++ b/api/sixtyfps-rs/lib.rs @@ -195,7 +195,8 @@ pub mod re_exports { init_component_items, Component, ComponentRefPin, ComponentVTable, }; pub use sixtyfps_corelib::graphics::{ - PathArcTo, PathData, PathElement, PathEvent, PathLineTo, PathMoveTo, Point, Rect, Size, + PathArcTo, PathCubicTo, PathData, PathElement, PathEvent, PathLineTo, PathMoveTo, + PathQuadraticTo, Point, Rect, Size, }; pub use sixtyfps_corelib::input::{ FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyboardModifiers, MouseEvent, diff --git a/docs/builtin_elements.md b/docs/builtin_elements.md index b08f0c411..6d90a5d43 100644 --- a/docs/builtin_elements.md +++ b/docs/builtin_elements.md @@ -280,6 +280,32 @@ or angle. * **`sweep`** (*bool): If the property is true, the arc will be drawn as a clockwise turning arc; anti-clockwise otherwise. +##### `CubicTo` Sub-element for `Path` + +The `CubicTo` sub-element describes a smooth Bézier from the path's current position to the +location specified by the `x` and `y` properties, using two control points specified by their +respective properties. +###### Properties + +* **`x`** (*float): The target x position of the curve. +* **`y`** (*float): The target y position of the curve. +* **`control-1-x`** (*float): The x coordinate of the curve's first control point. +* **`control-1-y`** (*float): The y coordinate of the curve's first control point. +* **`control-2-x`** (*float): The x coordinate of the curve's second control point. +* **`control-2-y`** (*float): The y coordinate of the curve's second control point. + +##### `QuadraticTo` Sub-element for `Path` + +The `QuadraticTo` sub-element describes a smooth Bézier from the path's current position to the +location specified by the `x` and `y` properties, using the control points specified by the +`control-x` and `control-y` properties. +###### Properties + +* **`x`** (*float): The target x position of the curve. +* **`y`** (*float): The target y position of the curve. +* **`control-x`** (*float): The x coordinate of the curve's control point. +* **`control-y`** (*float): The y coordinate of the curve's control point. + ##### `Close` Sub-element for `Path` The `Close` element closes the current sub-path and draws a straight line from the current diff --git a/sixtyfps_compiler/builtins.60 b/sixtyfps_compiler/builtins.60 index f2f99418d..ad64e0a5a 100644 --- a/sixtyfps_compiler/builtins.60 +++ b/sixtyfps_compiler/builtins.60 @@ -234,6 +234,30 @@ ArcTo := _ { //-is_non_item_type } +CubicTo := _ { + property control_1_x; + property control_1_y; + property control_2_x; + property control_2_y; + property x; + property y; + + //-rust_type_constructor:sixtyfps::re_exports::PathElement::CubicTo(PathCubicTo{{}}) + //-cpp_type:sixtyfps::PathCubicTo + //-is_non_item_type +} + +QuadraticTo := _ { + property control_x; + property control_y; + property x; + property y; + + //-rust_type_constructor:sixtyfps::re_exports::PathElement::QuadraticTo(PathQuadraticTo{{}}) + //-cpp_type:sixtyfps::PathQuadraticTo + //-is_non_item_type +} + Close := _ { //-rust_type_constructor:sixtyfps::re_exports::PathElement::Close //-is_non_item_type @@ -254,6 +278,8 @@ export Path := _ { MoveTo {} LineTo {} ArcTo {} + CubicTo {} + QuadraticTo {} Close {} //-default_size_binding:expands_to_parent_geometry @@ -267,8 +293,11 @@ export PathLayout := _ { property commands; property offset; + MoveTo {} LineTo {} ArcTo {} + CubicTo {} + QuadraticTo {} Close {} } diff --git a/sixtyfps_compiler/tests/syntax/basic/path.60 b/sixtyfps_compiler/tests/syntax/basic/path.60 index 58721f19d..179c5c95e 100644 --- a/sixtyfps_compiler/tests/syntax/basic/path.60 +++ b/sixtyfps_compiler/tests/syntax/basic/path.60 @@ -15,7 +15,7 @@ TestCase := Rectangle { LineTo { x: 100; y: 0; } LineTo { x: 100; y: 0; } Rectangle {} -// ^error{Rectangle is not allowed within Path. Only ArcTo Close LineTo MoveTo are valid children} +// ^error{Rectangle is not allowed within Path. Only ArcTo Close CubicTo LineTo MoveTo QuadraticTo are valid children} } LineTo { x: 100; y: 0; } diff --git a/sixtyfps_runtime/corelib/graphics.rs b/sixtyfps_runtime/corelib/graphics.rs index 169a5566d..0513ed140 100644 --- a/sixtyfps_runtime/corelib/graphics.rs +++ b/sixtyfps_runtime/corelib/graphics.rs @@ -361,6 +361,52 @@ pub struct PathArcTo { pub sweep: bool, } +#[repr(C)] +#[derive(FieldOffsets, Default, SixtyFPSElement, Clone, Debug, PartialEq)] +#[pin] +/// PathCubicTo describes a smooth Bézier curve from the path's current position +/// to the specified x/y location, using two control points. +pub struct PathCubicTo { + #[rtti_field] + /// The x coordinate of the curve's end point. + pub x: f32, + #[rtti_field] + /// The y coordinate of the curve's end point. + pub y: f32, + #[rtti_field] + /// The x coordinate of the curve's first control point. + pub control_1_x: f32, + #[rtti_field] + /// The y coordinate of the curve's first control point. + pub control_1_y: f32, + #[rtti_field] + /// The x coordinate of the curve's second control point. + pub control_2_x: f32, + #[rtti_field] + /// The y coordinate of the curve's second control point. + pub control_2_y: f32, +} + +#[repr(C)] +#[derive(FieldOffsets, Default, SixtyFPSElement, Clone, Debug, PartialEq)] +#[pin] +/// PathCubicTo describes a smooth Bézier curve from the path's current position +/// to the specified x/y location, using one control points. +pub struct PathQuadraticTo { + #[rtti_field] + /// The x coordinate of the curve's end point. + pub x: f32, + #[rtti_field] + /// The y coordinate of the curve's end point. + pub y: f32, + #[rtti_field] + /// The x coordinate of the curve's control point. + pub control_x: f32, + #[rtti_field] + /// The y coordinate of the curve's control point. + pub control_y: f32, +} + #[repr(C)] #[derive(Clone, Debug, PartialEq)] /// PathElement describes a single element on a path, such as move-to, line-to, etc. @@ -371,6 +417,10 @@ pub enum PathElement { LineTo(PathLineTo), /// The PathArcTo variant describes an arc. ArcTo(PathArcTo), + /// The CubicTo variant describes a Bézier curve with two control points. + CubicTo(PathCubicTo), + /// The QuadraticTo variant describes a Bézier curve with one control point. + QuadraticTo(PathQuadraticTo), /// Indicates that the path should be closed now by connecting to the starting point. Close, } @@ -608,6 +658,26 @@ impl PathData { path_builder.arc_to(radii, x_rotation, flags, to) } } + PathElement::CubicTo(PathCubicTo { + x, + y, + control_1_x, + control_1_y, + control_2_x, + control_2_y, + }) => { + path_builder.cubic_bezier_to( + Point::new(*control_1_x, *control_1_y), + Point::new(*control_2_x, *control_2_y), + Point::new(*x, *y), + ); + } + PathElement::QuadraticTo(PathQuadraticTo { x, y, control_x, control_y }) => { + path_builder.quadratic_bezier_to( + Point::new(*control_x, *control_y), + Point::new(*x, *y), + ); + } PathElement::Close => path_builder.close(), } } diff --git a/sixtyfps_runtime/interpreter/eval.rs b/sixtyfps_runtime/interpreter/eval.rs index 17fd76d01..a6159a084 100644 --- a/sixtyfps_runtime/interpreter/eval.rs +++ b/sixtyfps_runtime/interpreter/eval.rs @@ -998,6 +998,13 @@ fn convert_path_element( "ArcTo" => { PathElement::ArcTo(new_struct_with_bindings(&expr_element.bindings, local_context)) } + "CubicTo" => { + PathElement::CubicTo(new_struct_with_bindings(&expr_element.bindings, local_context)) + } + "QuadraticTo" => PathElement::QuadraticTo(new_struct_with_bindings( + &expr_element.bindings, + local_context, + )), "Close" => PathElement::Close, _ => panic!( "Cannot create unsupported path element {}", diff --git a/tests/cases/examples/hello.60 b/tests/cases/examples/hello.60 index 0354120cb..eaabb086a 100644 --- a/tests/cases/examples/hello.60 +++ b/tests/cases/examples/hello.60 @@ -142,6 +142,23 @@ Hello := Rectangle { radius_y: 10; } +// M 0 0 C 15.3333 3.6667 92 1 48 46 Q -25 54 0 0 + CubicTo { + x: 48; + y: 46; + control-1-x: 15; + control-1-y: 3; + control-2-x: 92; + control-2-y: 1; + } + + QuadraticTo { + x: 0; + y: 0; + control-x: -25; + control-y: 54; + } + Close {} }