diff options
| author | Martin Haug <mhaug@live.de> | 2022-05-02 16:51:14 +0200 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-05-02 17:20:47 +0200 |
| commit | f07395f9a47502c50f767f78a233d0e2a6e4445f (patch) | |
| tree | c54fe2afeaaf265780279c893c272f1abfd12393 /src/frame.rs | |
| parent | 7b6f3a0ab9ae0dac19f62b62b9ecc96ea942a89e (diff) | |
Move rounding logic out of exporters
Diffstat (limited to 'src/frame.rs')
| -rw-r--r-- | src/frame.rs | 211 |
1 files changed, 1 insertions, 210 deletions
diff --git a/src/frame.rs b/src/frame.rs index 2cf584d8..dcaa7581 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,13 +1,11 @@ //! Finished layouts. use std::fmt::{self, Debug, Formatter, Write}; -use std::mem; use std::sync::Arc; use crate::font::FaceId; use crate::geom::{ - Align, Angle, Em, Get, Length, Numeric, Paint, Path, Point, Side, Sides, Size, Spec, - Stroke, Transform, + Align, Em, Length, Numeric, Paint, Point, Shape, Size, Spec, Transform, }; use crate::image::ImageId; use crate::util::{EcoString, MaybeShared}; @@ -299,210 +297,3 @@ pub struct Glyph { /// The first character of the glyph's cluster. pub c: char, } - -/// A geometric shape with optional fill and stroke. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Shape { - /// The shape's geometry. - pub geometry: Geometry, - /// The shape's background fill. - pub fill: Option<Paint>, - /// The shape's border stroke. - pub stroke: Sides<Option<Stroke>>, -} - -/// A shape's geometry. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Geometry { - /// A line to a point (relative to its position). - Line(Point), - /// A rectangle with its origin in the topleft corner and a border radius. - Rect(Size, Sides<Length>), - /// A ellipse with its origin in the topleft corner. - Ellipse(Size), - /// A bezier path. - Path(Path), -} - -impl Geometry { - /// Fill the geometry without a stroke. - pub fn filled(self, fill: Paint) -> Shape { - Shape { - geometry: self, - fill: Some(fill), - stroke: Sides::splat(None), - } - } - - /// Stroke the geometry without a fill. - pub fn stroked(self, stroke: Stroke) -> Shape { - Shape { - geometry: self, - fill: None, - stroke: Sides::splat(Some(stroke)), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum Connection { - None, - Left, - Right, - Both, -} - -impl Connection { - pub fn advance(self, right: bool) -> Self { - match self { - Self::Right | Self::Both => { - if right { - Self::Both - } else { - Self::Left - } - } - Self::Left | Self::None => { - if right { - Self::Right - } else { - Self::None - } - } - } - } - - fn left(self) -> bool { - matches!(self, Self::Left | Self::Both) - } - - fn right(self) -> bool { - matches!(self, Self::Right | Self::Both) - } -} - -/// Draws one side of the rounded rectangle. Will always draw the left arc. The -/// right arc will be drawn halfway iff there is no connection. -fn draw_side( - path: &mut Path, - side: Side, - size: Size, - radius_left: Length, - radius_right: Length, - connection: Connection, -) { - let reversed = |angle: Angle, radius, rotate, mirror_x, mirror_y| { - let [a, b, c, d] = angle.bezier_arc(radius, rotate, mirror_x, mirror_y); - [d, c, b, a] - }; - - let angle_left = Angle::deg(if connection.left() { 90.0 } else { 45.0 }); - let angle_right = Angle::deg(if connection.right() { 90.0 } else { 45.0 }); - - let (arc1, arc2) = match side { - Side::Top => { - let arc1 = reversed(angle_left, radius_left, true, true, false) - .map(|x| x + Point::with_x(radius_left)); - let arc2 = (-angle_right) - .bezier_arc(radius_right, true, true, false) - .map(|x| x + Point::with_x(size.x - radius_right)); - - (arc1, arc2) - } - Side::Right => { - let arc1 = reversed(-angle_left, radius_left, false, false, false) - .map(|x| x + Point::new(size.x, radius_left)); - - let arc2 = angle_right - .bezier_arc(radius_right, false, false, false) - .map(|x| x + Point::new(size.x, size.y - radius_right)); - - (arc1, arc2) - } - Side::Bottom => { - let arc1 = reversed(-angle_left, radius_left, true, false, false) - .map(|x| x + Point::new(size.x - radius_left, size.y)); - - let arc2 = angle_right - .bezier_arc(radius_right, true, false, false) - .map(|x| x + Point::new(radius_right, size.y)); - - (arc1, arc2) - } - Side::Left => { - let arc1 = reversed(angle_left, radius_left, false, false, true) - .map(|x| x + Point::with_y(size.y - radius_left)); - - let arc2 = (-angle_right) - .bezier_arc(radius_right, false, false, true) - .map(|x| x + Point::with_y(radius_right)); - - (arc1, arc2) - } - }; - - if !connection.left() { - path.move_to(if radius_left.is_zero() { arc1[3] } else { arc1[0] }); - } - - if !radius_left.is_zero() { - path.cubic_to(arc1[1], arc1[2], arc1[3]); - } - - path.line_to(arc2[0]); - - if !connection.right() && !radius_right.is_zero() { - path.cubic_to(arc2[1], arc2[2], arc2[3]); - } -} - -pub fn rect_paths( - size: Size, - radius: Sides<Length>, - strokes: Option<Sides<Option<Stroke>>>, -) -> Vec<(Path, Option<Stroke>)> { - let strokes = strokes.unwrap_or_else(|| Sides::splat(None)); - let mut res = vec![]; - - let mut connection = Connection::None; - let mut path = Path::new(); - let sides = [Side::Top, Side::Right, Side::Bottom, Side::Left]; - let mut always_continuous = true; - - let radius = [ - radius.left, - radius.top, - radius.right, - radius.bottom, - radius.left, - ]; - - for (side, radius) in sides.into_iter().zip(radius.windows(2)) { - let stroke_continuity = strokes.get(side) == strokes.get(side.next_cw()); - connection = connection.advance(stroke_continuity && side != Side::Left); - always_continuous &= stroke_continuity; - - draw_side(&mut path, side, size, radius[0], radius[1], connection); - - if !stroke_continuity { - res.push((mem::take(&mut path), strokes.get(side))); - } - } - - if always_continuous { - path.close_path(); - } - - if !path.0.is_empty() { - res.push((path, strokes.left)); - } - - res -} - -pub fn rect_path(size: Size, radius: Sides<Length>) -> Path { - let mut paths = rect_paths(size, radius, None); - assert_eq!(paths.len(), 1); - - paths.pop().unwrap().0 -} |
