diff options
| author | Martin Haug <mhaug@live.de> | 2022-05-01 13:21:07 +0200 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-05-01 14:56:07 +0200 |
| commit | 84a4961a5dd03072b0e94c715957475d4ae21e4f (patch) | |
| tree | f23f7b2917943079c12a218de3dd649ef6e590b7 /src | |
| parent | 5f1499d380e223e7e1b2a8a96eb99e3ec95a56ac (diff) | |
Outset; fix folding
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.rs | 2 | ||||
| -rw-r--r-- | src/geom/sides.rs | 4 | ||||
| -rw-r--r-- | src/library/graphics/shape.rs | 90 | ||||
| -rw-r--r-- | src/model/styles.rs | 23 |
4 files changed, 79 insertions, 40 deletions
diff --git a/src/frame.rs b/src/frame.rs index f889601e..2cf584d8 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -478,7 +478,7 @@ pub fn rect_paths( ]; for (side, radius) in sides.into_iter().zip(radius.windows(2)) { - let stroke_continuity = strokes.get(side) == strokes.get(side.clockwise()); + let stroke_continuity = strokes.get(side) == strokes.get(side.next_cw()); connection = connection.advance(stroke_continuity && side != Side::Left); always_continuous &= stroke_continuity; diff --git a/src/geom/sides.rs b/src/geom/sides.rs index 255c21ee..f214a1bf 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -128,7 +128,7 @@ impl Side { } /// The next side, clockwise. - pub fn clockwise(self) -> Self { + pub fn next_cw(self) -> Self { match self { Self::Left => Self::Top, Self::Top => Self::Right, @@ -138,7 +138,7 @@ impl Side { } /// The next side, counter-clockwise. - pub fn counter_clockwise(self) -> Self { + pub fn next_ccw(self) -> Self { match self { Self::Left => Self::Bottom, Self::Top => Self::Left, diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index 7a1bfb1f..640c879b 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -102,6 +102,7 @@ castable! { } }, Value::Length(l) => Sides::splat(Some(l.into())), + Value::Ratio(r) => Sides::splat(Some(r.into())), Value::Relative(r) => Sides::splat(Some(r)), } @@ -117,40 +118,44 @@ impl<const S: ShapeKind> Layout for AngularNode<S> { let inset = styles.get(Self::INSET); // Pad the child. - let child = child - .clone() - .padded(inset.map(|side| side.map(|abs| RawLength::from(abs)))); + let child = child.clone().padded(inset.map(|side| side.map(RawLength::from))); let mut pod = Regions::one(regions.first, regions.base, regions.expand); frames = child.layout(ctx, &pod, styles)?; // Relayout with full expansion into square region to make sure // the result is really a square or circle. - let length = if regions.expand.x || regions.expand.y { - let target = regions.expand.select(regions.first, Size::zero()); - target.x.max(target.y) - } else { - let size = frames[0].size; - let desired = size.x.max(size.y); - desired.min(regions.first.x).min(regions.first.y) - }; - - pod.first = Size::splat(length); - pod.expand = Spec::splat(true); - frames = child.layout(ctx, &pod, styles)?; + if is_quadratic(S) { + let length = if regions.expand.x || regions.expand.y { + let target = regions.expand.select(regions.first, Size::zero()); + target.x.max(target.y) + } else { + let size = frames[0].size; + let desired = size.x.max(size.y); + desired.min(regions.first.x).min(regions.first.y) + }; + + pod.first = Size::splat(length); + pod.expand = Spec::splat(true); + frames = child.layout(ctx, &pod, styles)?; + } } else { // The default size that a shape takes on if it has no child and // enough space. let mut size = Size::new(Length::pt(45.0), Length::pt(30.0)).min(regions.first); - let length = if regions.expand.x || regions.expand.y { - let target = regions.expand.select(regions.first, Size::zero()); - target.x.max(target.y) + if is_quadratic(S) { + let length = if regions.expand.x || regions.expand.y { + let target = regions.expand.select(regions.first, Size::zero()); + target.x.max(target.y) + } else { + size.x.min(size.y) + }; + size = Size::splat(length); } else { - size.x.min(size.y) - }; - size = Size::splat(length); + size = regions.expand.select(regions.first, size); + } frames = vec![Arc::new(Frame::new(size))]; } @@ -162,27 +167,38 @@ impl<const S: ShapeKind> Layout for AngularNode<S> { let stroke = match styles.get(Self::STROKE) { Smart::Auto if fill.is_none() => Sides::splat(Some(Stroke::default())), Smart::Auto => Sides::splat(None), - Smart::Custom(strokes) => strokes.map(|s| Some(s.unwrap_or_default())), + Smart::Custom(strokes) => strokes.map(|s| s.map(|s| s.unwrap_or_default())), }; - let radius = { - let radius = styles.get(Self::RADIUS); + let outset = styles.get(Self::OUTSET); + let outset = Sides { + left: outset.left.relative_to(frame.size.x), + top: outset.top.relative_to(frame.size.y), + right: outset.right.relative_to(frame.size.x), + bottom: outset.bottom.relative_to(frame.size.y), + }; - Sides { - left: radius.left.relative_to(frame.size.x / 2.0), - top: radius.top.relative_to(frame.size.y / 2.0), - right: radius.right.relative_to(frame.size.x / 2.0), - bottom: radius.bottom.relative_to(frame.size.y / 2.0), - } + let size = Spec::new( + frame.size.x + outset.left + outset.right, + frame.size.y + outset.top + outset.bottom, + ); + + let radius = styles.get(Self::RADIUS); + let radius = Sides { + left: radius.left.relative_to(size.x / 2.0), + top: radius.top.relative_to(size.y / 2.0), + right: radius.right.relative_to(size.x / 2.0), + bottom: radius.bottom.relative_to(size.y / 2.0), }; + if fill.is_some() || stroke.iter().any(Option::is_some) { let shape = Shape { - geometry: Geometry::Rect(frame.size, radius), + geometry: Geometry::Rect(size, radius), fill, stroke, }; - frame.prepend(Point::zero(), Element::Shape(shape)); + frame.prepend(Point::new(-outset.left, -outset.top), Element::Shape(shape)); } // Apply link if it exists. @@ -208,3 +224,13 @@ const CIRCLE: ShapeKind = 2; /// A curve around two focal points. const ELLIPSE: ShapeKind = 3; + +/// Whether a shape kind is curvy. +fn is_round(kind: ShapeKind) -> bool { + matches!(kind, CIRCLE | ELLIPSE) +} + +/// Whether a shape kind has equal side length. +fn is_quadratic(kind: ShapeKind) -> bool { + matches!(kind, SQUARE | CIRCLE) +} diff --git a/src/model/styles.rs b/src/model/styles.rs index 2e752625..00d1df0f 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use super::{Content, Show, ShowNode}; use crate::diag::{At, TypResult}; use crate::eval::{Args, Func, Node, Smart, Value}; -use crate::geom::{Numeric, Relative, Sides, Spec}; +use crate::geom::{Length, Numeric, Relative, Sides, Spec}; use crate::library::layout::PageNode; use crate::library::structure::{EnumNode, ListNode}; use crate::library::text::{FontFamily, ParNode, TextNode}; @@ -459,17 +459,30 @@ where } } -impl<T> Fold for Sides<Option<T>> +impl<T> Fold for Sides<T> where - T: Default, + T: Fold, { - type Output = Sides<T>; + type Output = Sides<T::Output>; + + fn fold(self, outer: Self::Output) -> Self::Output { + Sides { + left: self.left.fold(outer.left), + top: self.top.fold(outer.top), + right: self.right.fold(outer.right), + bottom: self.bottom.fold(outer.bottom), + } + } +} + +impl Fold for Sides<Option<Relative<Length>>> { + type Output = Sides<Relative<Length>>; fn fold(self, outer: Self::Output) -> Self::Output { Sides { left: self.left.unwrap_or(outer.left), - right: self.right.unwrap_or(outer.right), top: self.top.unwrap_or(outer.top), + right: self.right.unwrap_or(outer.right), bottom: self.bottom.unwrap_or(outer.bottom), } } |
