diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/doc.rs | 35 | ||||
| -rw-r--r-- | src/export/pdf/page.rs | 4 | ||||
| -rw-r--r-- | src/export/render.rs | 4 | ||||
| -rw-r--r-- | src/ide/jump.rs | 107 |
4 files changed, 91 insertions, 59 deletions
@@ -288,7 +288,7 @@ impl Frame { pub fn fill(&mut self, fill: Paint) { self.prepend( Point::zero(), - Element::Shape(Geometry::Rect(self.size()).filled(fill)), + Element::Shape(Geometry::Rect(self.size()).filled(fill), Span::detached()), ); } @@ -299,6 +299,7 @@ impl Frame { stroke: Sides<Option<Stroke>>, outset: Sides<Rel<Abs>>, radius: Corners<Rel<Abs>>, + span: Span, ) { let outset = outset.relative_to(self.size()); let size = self.size() + outset.sum_by_axis(); @@ -307,7 +308,7 @@ impl Frame { self.prepend_multiple( rounded_rect(size, radius, fill, stroke) .into_iter() - .map(|x| (pos, Element::Shape(x))), + .map(|x| (pos, Element::Shape(x, span))), ) } @@ -349,6 +350,7 @@ impl Frame { Element::Shape( Geometry::Rect(self.size) .filled(RgbaColor { a: 100, ..Color::TEAL.to_rgba() }.into()), + Span::detached(), ), ); self.insert( @@ -359,6 +361,7 @@ impl Frame { paint: Color::RED.into(), thickness: Abs::pt(1.0), }), + Span::detached(), ), ); self @@ -369,11 +372,10 @@ impl Frame { let radius = Abs::pt(2.0); self.push( pos - Point::splat(radius), - Element::Shape(geom::ellipse( - Size::splat(2.0 * radius), - Some(Color::GREEN.into()), - None, - )), + Element::Shape( + geom::ellipse(Size::splat(2.0 * radius), Some(Color::GREEN.into()), None), + Span::detached(), + ), ); } @@ -381,10 +383,13 @@ impl Frame { pub fn mark_line(&mut self, y: Abs) { self.push( Point::with_y(y), - Element::Shape(Geometry::Line(Point::with_x(self.size.x)).stroked(Stroke { - paint: Color::GREEN.into(), - thickness: Abs::pt(1.0), - })), + Element::Shape( + Geometry::Line(Point::with_x(self.size.x)).stroked(Stroke { + paint: Color::GREEN.into(), + thickness: Abs::pt(1.0), + }), + Span::detached(), + ), ); } } @@ -406,9 +411,9 @@ pub enum Element { /// A run of shaped text. Text(Text), /// A geometric shape with optional fill and stroke. - Shape(Shape), + Shape(Shape, Span), /// An image and its size. - Image(Image, Size), + Image(Image, Size, Span), /// Meta information and the region it applies to. Meta(Meta, Size), } @@ -418,8 +423,8 @@ impl Debug for Element { match self { Self::Group(group) => group.fmt(f), Self::Text(text) => write!(f, "{text:?}"), - Self::Shape(shape) => write!(f, "{shape:?}"), - Self::Image(image, _) => write!(f, "{image:?}"), + Self::Shape(shape, _) => write!(f, "{shape:?}"), + Self::Image(image, _, _) => write!(f, "{image:?}"), Self::Meta(meta, _) => write!(f, "{meta:?}"), } } diff --git a/src/export/pdf/page.rs b/src/export/pdf/page.rs index 7f8c20ef..df7b517f 100644 --- a/src/export/pdf/page.rs +++ b/src/export/pdf/page.rs @@ -293,8 +293,8 @@ fn write_frame(ctx: &mut PageContext, frame: &Frame) { match element { Element::Group(group) => write_group(ctx, pos, group), Element::Text(text) => write_text(ctx, x, y, text), - Element::Shape(shape) => write_shape(ctx, x, y, shape), - Element::Image(image, size) => write_image(ctx, x, y, image, *size), + Element::Shape(shape, _) => write_shape(ctx, x, y, shape), + Element::Image(image, size, _) => write_image(ctx, x, y, image, *size), Element::Meta(meta, size) => match meta { Meta::Link(link) => write_link(ctx, pos, link, *size), Meta::Node(_) => {} diff --git a/src/export/render.rs b/src/export/render.rs index bf183ebe..58659b98 100644 --- a/src/export/render.rs +++ b/src/export/render.rs @@ -52,10 +52,10 @@ fn render_frame( Element::Text(text) => { render_text(canvas, ts, mask, text); } - Element::Shape(shape) => { + Element::Shape(shape, _) => { render_shape(canvas, ts, mask, shape); } - Element::Image(image, size) => { + Element::Image(image, size, _) => { render_image(canvas, ts, mask, image, *size); } Element::Meta(meta, _) => match meta { diff --git a/src/ide/jump.rs b/src/ide/jump.rs index 95f2fa02..0aa97b56 100644 --- a/src/ide/jump.rs +++ b/src/ide/jump.rs @@ -1,7 +1,7 @@ use std::num::NonZeroUsize; use crate::doc::{Destination, Element, Frame, Location, Meta}; -use crate::geom::{Point, Size}; +use crate::geom::{Geometry, Point, Size}; use crate::model::Introspector; use crate::syntax::{LinkedNode, Source, SourceId, Span, SyntaxKind}; use crate::World; @@ -15,6 +15,14 @@ pub enum Jump { Dest(Destination), } +impl Jump { + fn from_span(world: &dyn World, span: Span) -> Self { + let source = world.source(span.source()); + let node = source.find(span); + Self::Source(source.id(), node.offset()) + } +} + /// Determine where to jump to based on a click in a frame. pub fn jump_from_click( world: &dyn World, @@ -24,55 +32,74 @@ pub fn jump_from_click( ) -> Option<Jump> { let mut introspector = None; - for (mut pos, element) in frame.elements() { - if let Element::Group(group) = element { - // TODO: Handle transformation. - if let Some(span) = jump_from_click(world, frames, &group.frame, click - pos) - { - return Some(span); + // Prefer metadata. + for (pos, element) in frame.elements() { + if let Element::Meta(Meta::Link(link), size) = element { + if is_in_rect(*pos, *size, click) { + let dest = link.resolve(|| { + introspector.get_or_insert_with(|| Introspector::new(frames)) + }); + + let Some(dest) = dest else { continue }; + return Some(Jump::Dest(dest)); } } + } - if let Element::Text(text) = element { - for glyph in &text.glyphs { - if glyph.span.is_detached() { - continue; + for (mut pos, element) in frame.elements().rev() { + match element { + Element::Group(group) => { + // TODO: Handle transformation. + if let Some(span) = + jump_from_click(world, frames, &group.frame, click - pos) + { + return Some(span); } + } - let width = glyph.x_advance.at(text.size); - if is_in_rect( - Point::new(pos.x, pos.y - text.size), - Size::new(width, text.size), - click, - ) { - let source = world.source(glyph.span.source()); - let node = source.find(glyph.span); - let pos = if node.kind() == SyntaxKind::Text { - let range = node.range(); - let mut offset = range.start + usize::from(glyph.offset); - if (click.x - pos.x) > width / 2.0 { - offset += glyph.c.len_utf8(); - } - offset.min(range.end) - } else { - node.offset() - }; - return Some(Jump::Source(source.id(), pos)); + Element::Text(text) => { + for glyph in &text.glyphs { + if glyph.span.is_detached() { + continue; + } + + let width = glyph.x_advance.at(text.size); + if is_in_rect( + Point::new(pos.x, pos.y - text.size), + Size::new(width, text.size), + click, + ) { + let source = world.source(glyph.span.source()); + let node = source.find(glyph.span); + let pos = if node.kind() == SyntaxKind::Text { + let range = node.range(); + let mut offset = range.start + usize::from(glyph.offset); + if (click.x - pos.x) > width / 2.0 { + offset += glyph.c.len_utf8(); + } + offset.min(range.end) + } else { + node.offset() + }; + return Some(Jump::Source(source.id(), pos)); + } + + pos.x += width; } - - pos.x += width; } - } - if let Element::Meta(Meta::Link(link), size) = element { - if is_in_rect(pos, *size, click) { - let dest = link.resolve(|| { - introspector.get_or_insert_with(|| Introspector::new(frames)) - }); + Element::Shape(shape, span) => { + let Geometry::Rect(size) = shape.geometry else { continue }; + if is_in_rect(pos, size, click) { + return Some(Jump::from_span(world, *span)); + } + } - let Some(dest) = dest else { continue }; - return Some(Jump::Dest(dest)); + Element::Image(_, size, span) if is_in_rect(pos, *size, click) => { + return Some(Jump::from_span(world, *span)); } + + _ => {} } } |
