Fix path fitting

Include the stroke width in the boundaries when fitting a path into the
size of a `Path` element.
This commit is contained in:
Simon Hausmann 2021-02-04 09:06:33 +01:00
parent fd3c8bf9fa
commit d92c8cab23
3 changed files with 28 additions and 4 deletions

View file

@ -25,6 +25,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
#![allow(missing_docs)] // because documenting each property of items is redundent
use crate::component::ComponentVTable;
use crate::graphics::PathDataIterator;
use crate::graphics::{Brush, Color, PathData, Point, Rect, Size};
use crate::input::{
FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyEventType, MouseEvent,
@ -600,6 +601,22 @@ impl Item for Path {
}
}
impl Path {
/// Returns an iterator of the events of the path and an offset, so that the
/// shape fits into the width/height of the path while respecting the stroke
/// width.
pub fn fitted_path_events(
self: Pin<&Self>,
) -> (euclid::default::Vector2D<f32>, PathDataIterator) {
let stroke_width = self.stroke_width();
let bounds_width = (self.width() - stroke_width).max(0.);
let bounds_height = (self.height() - stroke_width).max(0.);
let offset = euclid::default::Vector2D::new(stroke_width / 2., stroke_width / 2.);
let event_iterator = self.elements().iter_fitted(bounds_width, bounds_height);
(offset, event_iterator)
}
}
impl ItemConsts for Path {
const cached_rendering_data_offset: const_field_offset::FieldOffset<Path, CachedRenderingData> =
Path::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();

View file

@ -954,8 +954,11 @@ impl ItemRenderer for GLItemRenderer {
if matches!(elements, sixtyfps_corelib::PathData::None) {
return;
}
let (offset, path_events) = path.fitted_path_events();
let mut fpath = femtovg::Path::new();
for x in elements.iter_fitted(path.width(), path.height()).iter() {
for x in path_events.iter() {
match x {
lyon_path::Event::Begin { at } => {
fpath.move_to(at.x, at.y);
@ -983,7 +986,7 @@ impl ItemRenderer for GLItemRenderer {
border_paint.set_line_width(path.stroke_width());
self.shared_data.canvas.borrow_mut().save_with(|canvas| {
canvas.translate(pos.x + path.x(), pos.y + path.y());
canvas.translate(pos.x + path.x() + offset.x, pos.y + path.y() + offset.y);
canvas.fill_path(&mut fpath, fill_paint);
canvas.stroke_path(&mut fpath, border_paint);
})

View file

@ -372,12 +372,16 @@ impl ItemRenderer for QtItemRenderer<'_> {
}
// FIXME: handle width/height
//let rect: qttypes::QRectF = get_geometry!(pos, items::Path, path);
let pos = qttypes::QPoint { x: (pos.x + path.x()) as _, y: (pos.y + path.y()) as _ };
let fill_brush: qttypes::QBrush = path.fill().into();
let stroke_brush: qttypes::QBrush = path.stroke().into();
let stroke_width: f32 = path.stroke_width();
let (offset, path_events) = path.fitted_path_events();
let pos = qttypes::QPoint {
x: (pos.x + path.x() + offset.x) as _,
y: (pos.y + path.y() + offset.y) as _,
};
let mut painter_path = QPainterPath::default();
for x in elements.iter_fitted(path.width(), path.height()).iter() {
for x in path_events.iter() {
impl From<Point> for qttypes::QPointF {
fn from(p: Point) -> Self {
qttypes::QPointF { x: p.x as _, y: p.y as _ }