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("locate", meta::locate);
|
||||
global.define("style", meta::style);
|
||||
global.define("layout", meta::layout);
|
||||
global.define("counter", meta::counter);
|
||||
global.define("numbering", meta::numbering);
|
||||
global.define("state", meta::state);
|
||||
|
@ -121,3 +121,101 @@ impl Show for StyleElem {
|
||||
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,
|
||||
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.
|
||||
#page("a11", flipped: true, fill: forest)[]
|
||||
#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