diff --git a/polylux.typ b/polylux.typ index 25cfea1..d01b5c1 100644 --- a/polylux.typ +++ b/polylux.typ @@ -2,4 +2,4 @@ #import "logic.typ" #import "logic.typ": polylux-slide, uncover, only, alternatives, alternatives-match, alternatives-fn, alternatives-cases, one-by-one, line-by-line, list-one-by-one, enum-one-by-one, terms-one-by-one, pause, enable-handout-mode #import "utils/utils.typ" -#import "utils/utils.typ": polylux-outline, fit-to-height, side-by-side, pdfpc +#import "utils/utils.typ": polylux-outline, fit-to-height, fit-to-width, side-by-side, pdfpc diff --git a/utils/utils.typ b/utils/utils.typ index ba2690b..66dd825 100644 --- a/utils/utils.typ +++ b/utils/utils.typ @@ -40,7 +40,7 @@ #let last-slide-number = locate(loc => logic.logical-slide.final(loc).first()) -// HEIGHT FITTING +// HEIGHT/WIDTH FITTING #let _size-to-pt(size, styles, container-dimension) = { let to-convert = size @@ -60,7 +60,9 @@ box(width: mutable-width, body) } -#let fit-to-height(height, width: none, prescale-width: none, body) = { +#let fit-to-height( + width: none, prescale-width: none, grow: true, shrink: true, height, body +) = { // Place two labels with the requested vertical separation to be able to // measure their vertical distance in pt. // Using this approach instead of using `measure` allows us to accept fractions @@ -113,22 +115,54 @@ let w-ratio = mutable-width / size.width let ratio = calc.min(h-ratio, w-ratio) * 100% - let new-width = size.width * ratio - v(-available-height) - // If not boxed, the content can overflow to the next page even though it will fit. - // This is because scale doesn't update the layout information. - // Boxing in a container without clipping will inform typst that content - // will indeed fit in the remaining space - box( - width: new-width, - height: available-height, - scale(x: ratio, y: ratio, origin: top + left, boxed-content) - ) + if ( + (shrink and (ratio < 100%)) + or (grow and (ratio > 100%)) + ) { + let new-width = size.width * ratio + v(-available-height) + // If not boxed, the content can overflow to the next page even though it will + // fit. This is because scale doesn't update the layout information. + // Boxing in a container without clipping will inform typst that content + // will indeed fit in the remaining space + box( + width: new-width, + height: available-height, + scale(x: ratio, y: ratio, origin: top + left, boxed-content) + ) + } else { + body + } }) }) }) } +#let fit-to-width(grow: true, shrink: true, width, content) = { + style(styles => { + layout(layout-size => { + let content-size = measure(content, styles) + let content-width = content-size.width + let width = _size-to-pt(width, styles, layout-size.width) + if ( + (shrink and (width < content-width)) + or (grow and (width > content-width)) + ) { + let ratio = width / content-width * 100% + // The first box keeps content from prematurely wrapping + let scaled = scale( + box(content, width: content-width), origin: top + left, x: ratio, y: ratio + ) + // The second box lets typst know the post-scaled dimensions, since `scale` + // doesn't update layout information + box(scaled, width: width, height: content-size.height * ratio) + } else { + content + } + }) + }) +} + // SIDE BY SIDE #let side-by-side(columns: none, gutter: 1em, ..bodies) = {