Skip to main content

Extent

Enum Extent 

Source
pub enum Extent {
    Sum {
        px: f64,
        inches: f64,
        percent: f64,
    },
    Min(Box<Extent>, Box<Extent>),
    Max(Box<Extent>, Box<Extent>),
    TrackOf {
        grid: CellId,
        axis: Axis,
        track: u16,
        span: u16,
    },
}
Expand description

A length value. Internally either a linear combination of pixels, inches, and percentage of the containing axis, a deferred min/max of two sub-lengths (because min(absolute, percent) cannot be reduced without knowing the axis size), or a reference to a tagged grid’s resolved track size (which is only known after solve).

Construct via the px / mm / cm / inch / pt / percent associated functions, Extent::min / Extent::max, or Extent::track_of / Extent::tracks_of. Lengths compose with +, -, unary -, * f64, and / f64; addition through Min/Max distributes exactly (min(a, b) + c = min(a+c, b+c)), so arithmetic stays closed without losing structure. TrackOf is opaque to arithmetic — it composes with Min/Max transparently but + / - / * on a tree containing TrackOf panics. Reach a multi-segment sum via Extent::tracks_of’s span parameter.

Physical units (mm, cm, inch, pt) are resolved to pixels via the dpi passed to Grid::solve. percent is taken as a fraction of the relevant axis of the parent’s grid cell area; the constructor argument is 0.0..=1.0 (so Extent::percent(0.5) is “50%”).

Variants§

§

Sum

Linear combination: px + inches * dpi + percent * axis.

Fields

§px: f64

DPI-independent pixel offset.

§inches: f64

Physical inches; multiplied by dpi at resolution.

§percent: f64

Fraction of the containing axis (1.0 = 100%).

§

Min(Box<Extent>, Box<Extent>)

Pointwise minimum of two lengths, evaluated at resolution time.

§

Max(Box<Extent>, Box<Extent>)

Pointwise maximum of two lengths, evaluated at resolution time.

§

TrackOf

Resolves at solve time to the summed resolved size of span consecutive tracks starting at track (1-indexed) on the given axis of the Grid tagged with id == grid. For span > 1 the corresponding gaps between tracks are included.

The solver runs as a damped fixed-point iteration over its width and height passes; on the first iteration TrackOf evaluates to 0 (no prior data); on subsequent iterations it picks up the resolved track size from the previous iteration. Forward references (a track that references a track later in the solve) are handled by iteration; cycles will not converge and exhaust MAX_ITER.

Fields

§grid: CellId

Tag of the target Grid (from Grid::id).

§axis: Axis

Whether to read column widths or row heights.

§track: u16

1-indexed start track within the target grid.

§span: u16

Number of consecutive tracks to sum. Treated as 1 if 0.

Implementations§

Source§

impl Extent

Source

pub const ZERO: Extent

The zero length.

Source

pub const fn px(v: f64) -> Self

Pure pixels (DPI-independent).

Source

pub const fn mm(v: f64) -> Self

Millimeters — v / 25.4 inches.

Source

pub const fn cm(v: f64) -> Self

Centimeters — v / 2.54 inches.

Examples found in repository?
examples/layout_demo.rs (line 47)
15fn main() {
16    let (w, h) = (800u32, 600u32);
17    let dpi = 96.0;
18
19    // Outer: 5 columns × 3 rows of fr(1).
20    let mut root = Grid::new(vec![Track::Fr(1.0); 5], vec![Track::Fr(1.0); 3]);
21
22    // Tag every outer cell so we can outline the underlying grid.
23    let mut outer_id = 1u64;
24    for r in 1..=3u16 {
25        for c in 1..=5u16 {
26            root.place_mut(Placement::at(r, c), Grid::cell().id(CellId(outer_id)));
27            outer_id += 1;
28        }
29    }
30
31    // Inner 2×2 in row 2, cols 3..=5, with 1cm left + 25% right insets.
32    let mut inner = Grid::new(
33        [Track::Fr(1.0), Track::Fr(1.0)],
34        [Track::Fr(1.0), Track::Fr(1.0)],
35    );
36    for r in 1..=2u16 {
37        for c in 1..=2u16 {
38            inner.place_mut(
39                Placement::at(r, c),
40                Grid::cell().id(CellId(100 + (r as u64) * 2 + c as u64)),
41            );
42        }
43    }
44    root.place_mut(
45        Placement::at(2, 3).span(1, 3).inset(
46            Inset::default()
47                .left(Extent::cm(1.0))
48                .right(Extent::percent(0.25)),
49        ),
50        inner,
51    );
52
53    // A 2:1 cell in the top-left, expressed via respect + fr weights.
54    root.place_mut(
55        Placement::at(1, 1),
56        Grid::new([Track::Fr(2.0)], [Track::Fr(1.0)])
57            .respect()
58            .id(CellId(200)),
59    );
60
61    let layout = root.solve(hephaestus::Size::new(w as f64, h as f64), dpi);
62
63    // Render.
64    let mut renderer = VelloRenderer::new().expect("vello renderer init");
65    {
66        let scene = renderer.scene();
67        let outer_brush: Brush = rgb8(80, 90, 110).into();
68        let outer_stroke = Stroke::new(1.0);
69        for id in 1..=15u64 {
70            if let Some(rect) = layout.rect(CellId(id)) {
71                let path: Path = rect.to_path(0.1);
72                scene.stroke(
73                    &outer_stroke,
74                    Affine::IDENTITY,
75                    &outer_brush,
76                    None,
77                    &path,
78                    PickId::Skip,
79                );
80            }
81        }
82
83        let inner_brush: Brush = rgb8(240, 180, 60).into();
84        let inner_stroke = Stroke::new(2.0);
85        for id in [103u64, 104, 105, 106] {
86            if let Some(rect) = layout.rect(CellId(id)) {
87                let path: Path = rect.to_path(0.1);
88                scene.fill(
89                    FillRule::NonZero,
90                    Affine::IDENTITY,
91                    &Brush::Solid(rgb8(245, 220, 160)),
92                    None,
93                    &path,
94                    PickId::Skip,
95                );
96                scene.stroke(
97                    &inner_stroke,
98                    Affine::IDENTITY,
99                    &inner_brush,
100                    None,
101                    &path,
102                    PickId::Skip,
103                );
104            }
105        }
106
107        let aspect_brush: Brush = rgb8(60, 160, 220).into();
108        if let Some(rect) = layout.rect(CellId(200)) {
109            let path: Path = rect.to_path(0.1);
110            scene.fill(
111                FillRule::NonZero,
112                Affine::IDENTITY,
113                &aspect_brush,
114                None,
115                &path,
116                PickId::Skip,
117            );
118        }
119    }
120
121    let mut pixels = vec![0u8; (w * h * 4) as usize];
122    let bg: Color = rgb8(20, 22, 28);
123    renderer
124        .render_to_buffer(w, h, bg, &mut pixels)
125        .expect("render");
126
127    let path = std::env::current_dir()
128        .unwrap()
129        .join("examples/layout_demo.png");
130    hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
131    println!("wrote {}", path.display());
132}
Source

pub const fn inch(v: f64) -> Self

Inches.

Source

pub const fn pt(v: f64) -> Self

Points (1pt = 1/72 inch).

Source

pub const fn percent(v: f64) -> Self

A fraction of the containing axis. 0.5 is 50%.

Examples found in repository?
examples/layout_demo.rs (line 48)
15fn main() {
16    let (w, h) = (800u32, 600u32);
17    let dpi = 96.0;
18
19    // Outer: 5 columns × 3 rows of fr(1).
20    let mut root = Grid::new(vec![Track::Fr(1.0); 5], vec![Track::Fr(1.0); 3]);
21
22    // Tag every outer cell so we can outline the underlying grid.
23    let mut outer_id = 1u64;
24    for r in 1..=3u16 {
25        for c in 1..=5u16 {
26            root.place_mut(Placement::at(r, c), Grid::cell().id(CellId(outer_id)));
27            outer_id += 1;
28        }
29    }
30
31    // Inner 2×2 in row 2, cols 3..=5, with 1cm left + 25% right insets.
32    let mut inner = Grid::new(
33        [Track::Fr(1.0), Track::Fr(1.0)],
34        [Track::Fr(1.0), Track::Fr(1.0)],
35    );
36    for r in 1..=2u16 {
37        for c in 1..=2u16 {
38            inner.place_mut(
39                Placement::at(r, c),
40                Grid::cell().id(CellId(100 + (r as u64) * 2 + c as u64)),
41            );
42        }
43    }
44    root.place_mut(
45        Placement::at(2, 3).span(1, 3).inset(
46            Inset::default()
47                .left(Extent::cm(1.0))
48                .right(Extent::percent(0.25)),
49        ),
50        inner,
51    );
52
53    // A 2:1 cell in the top-left, expressed via respect + fr weights.
54    root.place_mut(
55        Placement::at(1, 1),
56        Grid::new([Track::Fr(2.0)], [Track::Fr(1.0)])
57            .respect()
58            .id(CellId(200)),
59    );
60
61    let layout = root.solve(hephaestus::Size::new(w as f64, h as f64), dpi);
62
63    // Render.
64    let mut renderer = VelloRenderer::new().expect("vello renderer init");
65    {
66        let scene = renderer.scene();
67        let outer_brush: Brush = rgb8(80, 90, 110).into();
68        let outer_stroke = Stroke::new(1.0);
69        for id in 1..=15u64 {
70            if let Some(rect) = layout.rect(CellId(id)) {
71                let path: Path = rect.to_path(0.1);
72                scene.stroke(
73                    &outer_stroke,
74                    Affine::IDENTITY,
75                    &outer_brush,
76                    None,
77                    &path,
78                    PickId::Skip,
79                );
80            }
81        }
82
83        let inner_brush: Brush = rgb8(240, 180, 60).into();
84        let inner_stroke = Stroke::new(2.0);
85        for id in [103u64, 104, 105, 106] {
86            if let Some(rect) = layout.rect(CellId(id)) {
87                let path: Path = rect.to_path(0.1);
88                scene.fill(
89                    FillRule::NonZero,
90                    Affine::IDENTITY,
91                    &Brush::Solid(rgb8(245, 220, 160)),
92                    None,
93                    &path,
94                    PickId::Skip,
95                );
96                scene.stroke(
97                    &inner_stroke,
98                    Affine::IDENTITY,
99                    &inner_brush,
100                    None,
101                    &path,
102                    PickId::Skip,
103                );
104            }
105        }
106
107        let aspect_brush: Brush = rgb8(60, 160, 220).into();
108        if let Some(rect) = layout.rect(CellId(200)) {
109            let path: Path = rect.to_path(0.1);
110            scene.fill(
111                FillRule::NonZero,
112                Affine::IDENTITY,
113                &aspect_brush,
114                None,
115                &path,
116                PickId::Skip,
117            );
118        }
119    }
120
121    let mut pixels = vec![0u8; (w * h * 4) as usize];
122    let bg: Color = rgb8(20, 22, 28);
123    renderer
124        .render_to_buffer(w, h, bg, &mut pixels)
125        .expect("render");
126
127    let path = std::env::current_dir()
128        .unwrap()
129        .join("examples/layout_demo.png");
130    hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
131    println!("wrote {}", path.display());
132}
Source

pub fn min(a: Extent, b: Extent) -> Self

Pointwise minimum of two lengths.

Source

pub fn max(a: Extent, b: Extent) -> Self

Pointwise maximum of two lengths.

Source

pub const fn track_of(grid: CellId, axis: Axis, track: u16) -> Self

Reference the resolved size of a single track in a tagged grid. track is 1-indexed. See Extent::TrackOf.

Source

pub const fn tracks_of(grid: CellId, axis: Axis, start: u16, span: u16) -> Self

Reference the resolved summed size of span consecutive tracks in a tagged grid, starting at start (1-indexed). Gaps between tracks are included. See Extent::TrackOf.

Source

pub fn is_absolute(&self) -> bool

True if this length has no percent term anywhere in its tree and no Extent::TrackOf reference (whose value isn’t known without a prior solve pass). Lengths that are absolute can be resolved to pixels without an axis size or prior resolved tracks (used for intrinsic-size computation in Track::Auto).

Trait Implementations§

Source§

impl Add for Extent

Source§

type Output = Extent

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Extent) -> Extent

Performs the + operation. Read more
Source§

impl Clone for Extent

Source§

fn clone(&self) -> Extent

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Extent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Extent

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Div<f64> for Extent

Source§

type Output = Extent

The resulting type after applying the / operator.
Source§

fn div(self, k: f64) -> Extent

Performs the / operation. Read more
Source§

impl Mul<Extent> for f64

Source§

type Output = Extent

The resulting type after applying the * operator.
Source§

fn mul(self, l: Extent) -> Extent

Performs the * operation. Read more
Source§

impl Mul<f64> for Extent

Source§

type Output = Extent

The resulting type after applying the * operator.
Source§

fn mul(self, k: f64) -> Extent

Performs the * operation. Read more
Source§

impl Neg for Extent

Source§

type Output = Extent

The resulting type after applying the - operator.
Source§

fn neg(self) -> Extent

Performs the unary - operation. Read more
Source§

impl PartialEq for Extent

Source§

fn eq(&self, other: &Extent) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Extent

Source§

impl Sub for Extent

Source§

type Output = Extent

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Extent) -> Extent

Performs the - operation. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Brush for T
where T: Clone + PartialEq + Default + Debug,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

Source§

fn simd_from(_simd: S, value: T) -> T

Source§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

Source§

fn simd_into(self, simd: S) -> T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more