Add rounded corners and strokes to highlight (#3526)
This commit is contained in:
parent
030041466b
commit
67ba8d6c0e
@ -5,12 +5,14 @@ use ttf_parser::{GlyphId, OutlineBuilder};
|
||||
use crate::diag::SourceResult;
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{elem, Content, Packed, Show, Smart, StyleChain};
|
||||
use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size};
|
||||
use crate::layout::{
|
||||
Abs, Corners, Em, Frame, FrameItem, Length, Point, Rel, Sides, Size,
|
||||
};
|
||||
use crate::syntax::Span;
|
||||
use crate::text::{
|
||||
BottomEdge, BottomEdgeMetric, TextElem, TextItem, TopEdge, TopEdgeMetric,
|
||||
};
|
||||
use crate::visualize::{Color, FixedStroke, Geometry, Paint, Stroke};
|
||||
use crate::visualize::{styled_rect, Color, FixedStroke, Geometry, Paint, Stroke};
|
||||
|
||||
/// Underlines text.
|
||||
///
|
||||
@ -283,6 +285,12 @@ pub struct HighlightElem {
|
||||
#[default(Color::from_u8(0xFF, 0xFD, 0x11, 0xA1).into())]
|
||||
pub fill: Paint,
|
||||
|
||||
/// The highlight's border color. See the
|
||||
/// [rectangle's documentation]($rect.stroke) for more details.
|
||||
#[resolve]
|
||||
#[fold]
|
||||
pub stroke: Sides<Option<Option<Stroke>>>,
|
||||
|
||||
/// The top end of the background rectangle.
|
||||
///
|
||||
/// ```example
|
||||
@ -316,6 +324,12 @@ pub struct HighlightElem {
|
||||
#[resolve]
|
||||
pub extent: Length,
|
||||
|
||||
/// How much to round the highlight's corners. See the
|
||||
/// [rectangle's documentation]($rect.radius) for more details.
|
||||
#[resolve]
|
||||
#[fold]
|
||||
pub radius: Corners<Option<Rel<Length>>>,
|
||||
|
||||
/// The content that should be highlighted.
|
||||
#[required]
|
||||
pub body: Content,
|
||||
@ -327,8 +341,13 @@ impl Show for Packed<HighlightElem> {
|
||||
Ok(self.body().clone().styled(TextElem::set_deco(smallvec![Decoration {
|
||||
line: DecoLine::Highlight {
|
||||
fill: self.fill(styles),
|
||||
stroke: self
|
||||
.stroke(styles)
|
||||
.unwrap_or_default()
|
||||
.map(|stroke| stroke.map(Stroke::unwrap_or_default)),
|
||||
top_edge: self.top_edge(styles),
|
||||
bottom_edge: self.bottom_edge(styles),
|
||||
radius: self.radius(styles).unwrap_or_default(),
|
||||
},
|
||||
extent: self.extent(styles),
|
||||
}])))
|
||||
@ -348,10 +367,30 @@ pub struct Decoration {
|
||||
/// A kind of decorative line.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
enum DecoLine {
|
||||
Underline { stroke: Stroke<Abs>, offset: Smart<Abs>, evade: bool, background: bool },
|
||||
Strikethrough { stroke: Stroke<Abs>, offset: Smart<Abs>, background: bool },
|
||||
Overline { stroke: Stroke<Abs>, offset: Smart<Abs>, evade: bool, background: bool },
|
||||
Highlight { fill: Paint, top_edge: TopEdge, bottom_edge: BottomEdge },
|
||||
Underline {
|
||||
stroke: Stroke<Abs>,
|
||||
offset: Smart<Abs>,
|
||||
evade: bool,
|
||||
background: bool,
|
||||
},
|
||||
Strikethrough {
|
||||
stroke: Stroke<Abs>,
|
||||
offset: Smart<Abs>,
|
||||
background: bool,
|
||||
},
|
||||
Overline {
|
||||
stroke: Stroke<Abs>,
|
||||
offset: Smart<Abs>,
|
||||
evade: bool,
|
||||
background: bool,
|
||||
},
|
||||
Highlight {
|
||||
fill: Paint,
|
||||
stroke: Sides<Option<FixedStroke>>,
|
||||
top_edge: TopEdge,
|
||||
bottom_edge: BottomEdge,
|
||||
radius: Corners<Rel<Abs>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Add line decorations to a single run of shaped text.
|
||||
@ -365,12 +404,18 @@ pub(crate) fn decorate(
|
||||
) {
|
||||
let font_metrics = text.font.metrics();
|
||||
|
||||
if let DecoLine::Highlight { fill, top_edge, bottom_edge } = &deco.line {
|
||||
if let DecoLine::Highlight { fill, stroke, top_edge, bottom_edge, radius } =
|
||||
&deco.line
|
||||
{
|
||||
let (top, bottom) = determine_edges(text, *top_edge, *bottom_edge);
|
||||
let rect = Geometry::Rect(Size::new(width + 2.0 * deco.extent, top - bottom))
|
||||
.filled(fill.clone());
|
||||
let size = Size::new(width + 2.0 * deco.extent, top - bottom);
|
||||
let rects = styled_rect(size, *radius, Some(fill.clone()), stroke.clone());
|
||||
let origin = Point::new(pos.x - deco.extent, pos.y - top - shift);
|
||||
frame.prepend(origin, FrameItem::Shape(rect, Span::detached()));
|
||||
frame.prepend_multiple(
|
||||
rects
|
||||
.into_iter()
|
||||
.map(|shape| (origin, FrameItem::Shape(shape, Span::detached()))),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 63 KiB |
@ -58,6 +58,17 @@ We can also specify a customized value
|
||||
#highlight[abc]
|
||||
#highlight[abc #sym.integral]
|
||||
|
||||
---
|
||||
// Test highlight radius
|
||||
#highlight(radius: 3pt)[abc],
|
||||
#highlight(radius: 1em)[#lorem(5)]
|
||||
|
||||
---
|
||||
// Test highlight stroke
|
||||
#highlight(stroke: 2pt + blue)[abc]
|
||||
#highlight(stroke: (top: blue, left: red, bottom: green, right: orange))[abc]
|
||||
#highlight(stroke: 1pt, radius: 3pt)[#lorem(5)]
|
||||
|
||||
---
|
||||
// Test underline background
|
||||
#set underline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round"))
|
||||
@ -68,7 +79,6 @@ We can also specify a customized value
|
||||
#set overline(background: true, stroke: (thickness: 0.5em, paint: red, cap: "round"))
|
||||
#overline[This is in the background]
|
||||
|
||||
|
||||
---
|
||||
// Test strike background
|
||||
#set strike(background: true, stroke: 5pt + red)
|
||||
|
Loading…
Reference in New Issue
Block a user