mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Fraction layout
This commit is contained in:
parent
57a636b370
commit
203d5779f8
@ -25,7 +25,7 @@ use super::*;
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[capable(LayoutMath)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct FracNode {
|
||||
/// The numerator.
|
||||
@ -43,14 +43,9 @@ impl FracNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for FracNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\frac{");
|
||||
self.num.texify_unparen(t)?;
|
||||
t.push_str("}{");
|
||||
self.denom.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
impl LayoutMath for FracNode {
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.num, &self.denom, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +67,7 @@ impl Texify for FracNode {
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[capable(LayoutMath)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct BinomNode {
|
||||
/// The upper index.
|
||||
@ -90,13 +85,83 @@ impl BinomNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for BinomNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\binom{");
|
||||
self.upper.texify(t)?;
|
||||
t.push_str("}{");
|
||||
self.lower.texify(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
impl LayoutMath for BinomNode {
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.upper, &self.lower, true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Layout a fraction or binomial.
|
||||
fn layout(
|
||||
ctx: &mut MathContext,
|
||||
num: &Content,
|
||||
denom: &Content,
|
||||
binom: bool,
|
||||
) -> SourceResult<()> {
|
||||
let axis = scaled!(ctx, axis_height);
|
||||
let thickness = scaled!(ctx, fraction_rule_thickness);
|
||||
let shift_up = scaled!(
|
||||
ctx,
|
||||
text: fraction_numerator_shift_up,
|
||||
display: fraction_numerator_display_style_shift_up,
|
||||
);
|
||||
let shift_down = scaled!(
|
||||
ctx,
|
||||
text: fraction_denominator_shift_down,
|
||||
display: fraction_denominator_display_style_shift_down,
|
||||
);
|
||||
let num_min = scaled!(
|
||||
ctx,
|
||||
text: fraction_numerator_gap_min,
|
||||
display: fraction_num_display_style_gap_min,
|
||||
);
|
||||
let denom_min = scaled!(
|
||||
ctx,
|
||||
text: fraction_denominator_gap_min,
|
||||
display: fraction_denom_display_style_gap_min,
|
||||
);
|
||||
|
||||
ctx.style(ctx.style.for_numerator());
|
||||
let num = ctx.layout_frame(num)?;
|
||||
ctx.unstyle();
|
||||
|
||||
ctx.style(ctx.style.for_denominator());
|
||||
let denom = ctx.layout_frame(denom)?;
|
||||
ctx.unstyle();
|
||||
|
||||
let around = Em::new(0.1).scaled(ctx);
|
||||
let num_gap = (shift_up - axis - num.descent()).max(num_min + thickness / 2.0);
|
||||
let denom_gap = (shift_down + axis - denom.ascent()).max(denom_min + thickness / 2.0);
|
||||
|
||||
let line_width = num.width().max(denom.width());
|
||||
let width = line_width + 2.0 * around;
|
||||
let height = num.height() + num_gap + thickness + denom_gap + denom.height();
|
||||
let size = Size::new(width, height);
|
||||
let num_pos = Point::with_x((width - num.width()) / 2.0);
|
||||
let line_pos =
|
||||
Point::new((width - line_width) / 2.0, num.height() + num_gap + thickness / 2.0);
|
||||
let denom_pos = Point::new((width - denom.width()) / 2.0, height - denom.height());
|
||||
let baseline = line_pos.y + axis;
|
||||
|
||||
let mut frame = Frame::new(size);
|
||||
frame.set_baseline(baseline);
|
||||
frame.push_frame(num_pos, num);
|
||||
frame.push_frame(denom_pos, denom);
|
||||
|
||||
if binom {
|
||||
ctx.push(GlyphFragment::new(ctx, '('));
|
||||
ctx.push(frame);
|
||||
ctx.push(GlyphFragment::new(ctx, ')'));
|
||||
} else {
|
||||
frame.push(
|
||||
line_pos,
|
||||
Element::Shape(
|
||||
Geometry::Line(Point::with_x(line_width))
|
||||
.stroked(Stroke { paint: ctx.fill, thickness }),
|
||||
),
|
||||
);
|
||||
ctx.push(frame);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ use crate::text::{families, variant, FallbackList, FontFamily, SpaceNode, Symbol
|
||||
pub fn define(scope: &mut Scope) {
|
||||
scope.def_func::<MathNode>("math");
|
||||
scope.def_func::<FracNode>("frac");
|
||||
scope.def_func::<BinomNode>("binom");
|
||||
scope.def_func::<ScriptNode>("script");
|
||||
scope.def_func::<SqrtNode>("sqrt");
|
||||
scope.def_func::<RootNode>("root");
|
||||
|
Loading…
x
Reference in New Issue
Block a user