mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Add 'layout' function to obtain the size of the outer container (#557)
This commit is contained in:
parent
5cb226026e
commit
ca71081d05
@ -97,6 +97,7 @@ fn global(math: Module, calc: Module) -> Module {
|
|||||||
global.define("bibliography", meta::BibliographyElem::func());
|
global.define("bibliography", meta::BibliographyElem::func());
|
||||||
global.define("locate", meta::locate);
|
global.define("locate", meta::locate);
|
||||||
global.define("style", meta::style);
|
global.define("style", meta::style);
|
||||||
|
global.define("layout", meta::layout);
|
||||||
global.define("counter", meta::counter);
|
global.define("counter", meta::counter);
|
||||||
global.define("numbering", meta::numbering);
|
global.define("numbering", meta::numbering);
|
||||||
global.define("state", meta::state);
|
global.define("state", meta::state);
|
||||||
|
@ -121,3 +121,101 @@ impl Show for StyleElem {
|
|||||||
Ok(self.func().call_vt(vt, [styles.to_map().into()])?.display())
|
Ok(self.func().call_vt(vt, [styles.to_map().into()])?.display())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides access to the current outer container's (or page's, if none) size (width and height).
|
||||||
|
///
|
||||||
|
/// The given function must accept a single parameter, `size`, which is a dictionary with keys
|
||||||
|
/// `width` and `height`, both having the type [`length`]($type/length).
|
||||||
|
///
|
||||||
|
/// That is, if this `layout` call is done inside (for example) a box of size 800pt (width)
|
||||||
|
/// by 400pt (height), then the specified function will be given the parameter
|
||||||
|
/// `(width: 800pt, height: 400pt)`.
|
||||||
|
///
|
||||||
|
/// If, however, this `layout` call is placed directly on the page, not inside any container,
|
||||||
|
/// then the function will be given `(width: page_width, height: page_height)`, where `page_width`
|
||||||
|
/// and `page_height` correspond to the current page's respective dimensions, minus its margins.
|
||||||
|
///
|
||||||
|
/// This is useful, for example, to convert a [`ratio`]($type/ratio) value (such as `5%`, `100%`
|
||||||
|
/// etc.), which are usually based upon the outer container's dimensions (precisely what this
|
||||||
|
/// function gives), to a fixed length (in `pt`).
|
||||||
|
///
|
||||||
|
/// This is also useful if you're trying to make content fit a certain box, and doing certain
|
||||||
|
/// arithmetic using `pt` (for example, comparing different lengths) is required.
|
||||||
|
///
|
||||||
|
/// Please note: This function may provide a width or height of `infpt` if one of the page
|
||||||
|
/// dimensions is `auto`, under certain circumstances. This should not normally occur for
|
||||||
|
/// usual page sizes, however.
|
||||||
|
///
|
||||||
|
/// ```example
|
||||||
|
/// layout(size => {
|
||||||
|
/// // work with the width and height of the container we're in
|
||||||
|
/// // using size.width and size.height
|
||||||
|
/// })
|
||||||
|
///
|
||||||
|
/// layout(size => {
|
||||||
|
/// // convert 49% (of page width) to 'pt'
|
||||||
|
/// // note that "ratio" values are always relative to a certain, possibly arbitrary length,
|
||||||
|
/// // but it's usually the current container's width or height (e.g., for table columns,
|
||||||
|
/// // 15% would be relative to the width, but, for rows, it would be relative to the height).
|
||||||
|
/// let percentage_of_width = (49% / 1%) * 0.01 * size.width
|
||||||
|
/// // ... use the converted value ...
|
||||||
|
/// })
|
||||||
|
///
|
||||||
|
/// // The following two boxes are equivalent, and will have rectangles sized 200pt and 40pt:
|
||||||
|
///
|
||||||
|
/// #box(width: 200pt, height: 40pt, {
|
||||||
|
/// rect(width: 100%, height: 100%)
|
||||||
|
/// })
|
||||||
|
///
|
||||||
|
/// #box(width: 200pt, height: 40pt, layout(size => {
|
||||||
|
/// rect(width: size.width, height: size.height)
|
||||||
|
/// }))
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Display: Layout
|
||||||
|
/// Category: meta
|
||||||
|
/// Returns: content
|
||||||
|
#[func]
|
||||||
|
pub fn layout(
|
||||||
|
/// A function to call with the outer container's size. Its return value is displayed
|
||||||
|
/// in the document.
|
||||||
|
///
|
||||||
|
/// This function is called once for each time the content returned by
|
||||||
|
/// `layout` appears in the document. That makes it possible to generate
|
||||||
|
/// content that depends on the size of the container it is inside.
|
||||||
|
func: Func,
|
||||||
|
) -> Value {
|
||||||
|
LayoutElem::new(func).pack().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes a `layout` call.
|
||||||
|
///
|
||||||
|
/// Display: Layout
|
||||||
|
/// Category: special
|
||||||
|
#[element(Layout)]
|
||||||
|
struct LayoutElem {
|
||||||
|
/// The function to call with the outer container's (or page's) size.
|
||||||
|
#[required]
|
||||||
|
func: Func,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for LayoutElem {
|
||||||
|
fn layout(
|
||||||
|
&self,
|
||||||
|
vt: &mut Vt,
|
||||||
|
styles: StyleChain,
|
||||||
|
regions: Regions,
|
||||||
|
) -> SourceResult<Fragment> {
|
||||||
|
// Gets the current region's base size, which will be the size of the outer container,
|
||||||
|
// or of the page if there is no such container.
|
||||||
|
let Size { x, y } = regions.base();
|
||||||
|
let size_dict = dict! { "width" => x, "height" => y }.into();
|
||||||
|
|
||||||
|
let result = self
|
||||||
|
.func()
|
||||||
|
.call_vt(vt, [size_dict])? // calls func(size)
|
||||||
|
.display();
|
||||||
|
|
||||||
|
result.layout(vt, styles, regions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 14 KiB |
@ -14,3 +14,11 @@
|
|||||||
fill: aqua,
|
fill: aqua,
|
||||||
lorem(8) + colbreak(),
|
lorem(8) + colbreak(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
---
|
||||||
|
// Layout inside a block with certain dimensions should provide those dimensions.
|
||||||
|
|
||||||
|
#set page(height: 120pt)
|
||||||
|
#block(width: 60pt, height: 80pt, layout(size => [
|
||||||
|
This block has a width of #size.width and height of #size.height
|
||||||
|
]))
|
||||||
|
@ -31,3 +31,12 @@
|
|||||||
// Should result in one forest-colored A11 page and one auto-sized page.
|
// Should result in one forest-colored A11 page and one auto-sized page.
|
||||||
#page("a11", flipped: true, fill: forest)[]
|
#page("a11", flipped: true, fill: forest)[]
|
||||||
#pagebreak()
|
#pagebreak()
|
||||||
|
|
||||||
|
---
|
||||||
|
// Layout without any container should provide the page's dimensions, minus its margins.
|
||||||
|
|
||||||
|
#page(width: 100pt, height: 100pt, {
|
||||||
|
layout(size => [This page has a width of #size.width and height of #size.height ])
|
||||||
|
h(1em)
|
||||||
|
place(left, rect(width: 80pt, stroke: blue))
|
||||||
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user