Add support for clip on Path elements

This allows clipping the viewbox conveniently.
This commit is contained in:
Simon Hausmann 2021-05-21 09:11:19 +02:00 committed by Simon Hausmann
parent 7de783bbe1
commit cc9d5e09f0
7 changed files with 131 additions and 11 deletions

View file

@ -124,7 +124,7 @@ All notable changes to this project will be documented in this file.
- Signals can have return a value - Signals can have return a value
- `has_hover` property in `TouchArea` - `has_hover` property in `TouchArea`
- `font-weight` property on Text - `font-weight` property on Text
- `viewbox-x/y/width/height` properties for `Path` - `viewbox-x/y/width/height` and `clip` properties for `Path`
## [0.0.2] - 2020-10-22 ## [0.0.2] - 2020-10-22

View file

@ -231,6 +231,9 @@ accordingly.
defining the position and size of the viewport of the path in path coordinates. In the rendered output, the defining the position and size of the viewport of the path in path coordinates. In the rendered output, the
If the `viewbox-width` or `viewbox-height` is less or equal than zero, the viewbox properties are ignored If the `viewbox-width` or `viewbox-height` is less or equal than zero, the viewbox properties are ignored
and instead the bounding rectangle of all path elements are used to define the view port. and instead the bounding rectangle of all path elements are used to define the view port.
* **`clip`** (*bool*): By default, when a path has a view box defined and the elements render outside of it, they are still
rendered. When this property is set to true, then rendering will be clipped at the boundaries of the view box.
This property must be a literal `true` or `false` (default: false)
#### Path Using SVG commands #### Path Using SVG commands

View file

@ -323,6 +323,7 @@ export Path := _ {
property <float> viewbox_y; property <float> viewbox_y;
property <float> viewbox_width; property <float> viewbox_width;
property <float> viewbox_height; property <float> viewbox_height;
property <bool> clip;
//-disallow_global_types_as_child_elements //-disallow_global_types_as_child_elements
MoveTo {} MoveTo {}

View file

@ -31,13 +31,22 @@ pub fn handle_clip(
&mut |elem_rc: &ElementRc, _| { &mut |elem_rc: &ElementRc, _| {
let mut elem = elem_rc.borrow_mut(); let mut elem = elem_rc.borrow_mut();
if let Some(clip_prop) = elem.bindings.remove("clip") { if let Some(clip_prop) = elem.bindings.remove("clip") {
if !elem.builtin_type().map_or(false, |bt| bt.name == "Rectangle") { match elem.builtin_type().as_ref().map(|ty| ty.name.as_str()) {
diag.push_error( Some("Rectangle") => {}
"The 'clip' property can only be applied to a Rectangle for now".into(), Some("Path") => {
&clip_prop.span, // it's an actual property, so keep the binding
); elem.bindings.insert("clip".into(), clip_prop);
return; return;
}; }
_ => {
diag.push_error(
"The 'clip' property can only be applied to a Rectangle or a Path for now"
.into(),
&clip_prop.span,
);
return;
}
}
// Was added by the meterialier_fake_properties pass // Was added by the meterialier_fake_properties pass
elem.property_declarations.remove("clip"); elem.property_declarations.remove("clip");
match &clip_prop.expression { match &clip_prop.expression {

View file

@ -17,7 +17,7 @@ SubElements := Rectangle {
} }
Image { Image {
clip: false; clip: false;
// ^error{The 'clip' property can only be applied to a Rectangle for now} // ^error{The 'clip' property can only be applied to a Rectangle or a Path for now}
} }
for a in 12 : Rectangle { for a in 12 : Rectangle {
clip: true || true; clip: true || true;

View file

@ -776,6 +776,7 @@ pub struct Path {
pub viewbox_y: Property<f32>, pub viewbox_y: Property<f32>,
pub viewbox_width: Property<f32>, pub viewbox_width: Property<f32>,
pub viewbox_height: Property<f32>, pub viewbox_height: Property<f32>,
pub clip: Property<bool>,
pub cached_rendering_data: CachedRenderingData, pub cached_rendering_data: CachedRenderingData,
} }
@ -783,7 +784,7 @@ impl Item for Path {
fn init(self: Pin<&Self>, _window: &ComponentWindow) {} fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
fn geometry(self: Pin<&Self>) -> Rect { fn geometry(self: Pin<&Self>) -> Rect {
euclid::rect(self.x(), self.y(), 0., 0.) euclid::rect(self.x(), self.y(), self.width(), self.height())
} }
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo { fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
@ -815,7 +816,15 @@ impl Item for Path {
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {} fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
fn render(self: Pin<&Self>, backend: &mut ItemRendererRef) { fn render(self: Pin<&Self>, backend: &mut ItemRendererRef) {
(*backend).draw_path(self) let clip = self.clip();
if clip {
(*backend).save_state();
(*backend).combine_clip(self.geometry(), 0., 0.)
}
(*backend).draw_path(self);
if clip {
(*backend).restore_state();
}
} }
} }

View file

@ -0,0 +1,98 @@
/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
RectPath := Path {
MoveTo {
x: 0;
y: 0;
}
LineTo {
x: 100;
y: 0;
}
LineTo {
x: 100;
y: 100;
}
LineTo {
x: 0;
y: 100;
}
Close {}
}
PathViewBox := Window {
preferred-width: 600px;
preferred-height: 600px;
// This is the reference path rectangle
RectPath {
x: 100px;
y: 100px;
width: 100px;
height: 100px;
stroke-width: 1px;
stroke: black;
}
// This path rectangle uses an unclipped viewbox and therefore
// draws outside the boundaries of the underlying green rectangle.
Rectangle {
background: #26e115da;
x: 300px;
y: 100px;
width: 100px;
height: 100px;
RectPath {
width: 100px;
height: 100px;
stroke-width: 1px;
stroke: black;
viewbox-x: 50;
viewbox-y: 0;
viewbox-width: 100;
viewbox-height: 100;
}
}
// This path rectangle uses an clipped viewbox and therefore
// draws only inside the boundaries of the underlying green rectangle.
Rectangle {
background: #26e115da;
x: 100px;
y: 300px;
width: 100px;
height: 100px;
RectPath {
width: 100px;
height: 100px;
stroke-width: 1px;
stroke: black;
clip: true;
viewbox-x: 50;
viewbox-y: 0;
viewbox-width: 100;
viewbox-height: 100;
}
}
}