diff options
author | Karl Berry <karl@freefriends.org> | 2015-12-06 23:50:41 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2015-12-06 23:50:41 +0000 |
commit | cf5dbf70c6bd40b1959580618f178b3f3fee09a0 (patch) | |
tree | 38650bf9d9145a14d82b9166d119b4cf49bea5a1 /Master/texmf-dist/tex/latex/longfbox/longbox.sty | |
parent | 8b958843c92e1dc188620b20cd04a85abe4f7fbc (diff) |
longfbox (6dec15)
git-svn-id: svn://tug.org/texlive/trunk@39028 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/longfbox/longbox.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/longfbox/longbox.sty | 853 |
1 files changed, 853 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/longfbox/longbox.sty b/Master/texmf-dist/tex/latex/longfbox/longbox.sty new file mode 100644 index 00000000000..9d373895f2b --- /dev/null +++ b/Master/texmf-dist/tex/latex/longfbox/longbox.sty @@ -0,0 +1,853 @@ +%--------------------------------------------------------------------------- +% Copyright 2015 Daan Leijen, Microsoft Corporation. +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +%--------------------------------------------------------------------------- +\NeedsTeXFormat{LaTeX2e}[1995/12/01] + +\ProvidesPackage{longbox}[2015/12/01, Daan Leijen, Provides basic longbox that can break over pages] +\RequirePackage{options} + +\@ifclassloaded{beamer}{% + \newcommand\lb@savefootnotes{}% + \newcommand\lb@restorefootnotes{}% +}% +{\RequirePackage{footnote}% + \newcommand\lb@savefootnotes{\savenotes}% + \newcommand\lb@restorefootnotes{\spewnotes}% +} + + +% -------------------------------------------------------- +% Debugging +% -------------------------------------------------------- + +\newcommand*\lb@debug[1]{% + \ontoggle{lb@debug}{\typeout{longbox debug: #1}}% +} +\newcommand*\lb@typeout[1]{% + \ontoggle{lb@verbose}{\typeout{longbox: #1}}% +} +\newcommand*\lb@warncannotsplit{% + \PackageWarning{longbox}{Cannot split box; it seems you are using a non-splittable contents}% +} +\newcommand*\lb@warnbadsplit[1]{% + \PackageWarning{longbox}{Bad split (underful vbox by \the#1)}% +} + + +% -------------------------------------------------------- +% Utilities for LaTeX internals +% -------------------------------------------------------- + +% Suppress the indentation on the following paragraph +\providecommand\nofirstindent{\@afterindentfalse\@afterheading} + +% Suppress the paragraph skip on the following paragraph +\providecommand\nofirstparskip{\addvskip{-\parskip}} + +% In contrast to addvspace, addvskip is not suppressed in a minipage +\providecommand\addvskip[1]{% + \ifvmode + \ifdim\lastskip=\z@ + \vskip #1\relax + \else + \@tempskipb#1\relax\@xaddvskip + \fi + \else\@noitemerr\fi +} + + +% Skip to 0.3\baselineskip multiple taking prevdepth into account. +\newskip\lb@prevdepth +\newcommand\lb@skiptobaseline{% + \global\lb@prevdepth=-\@m\p@\relax + \ifvmode + \ifdim\lastskip=\z@\relax + \ifdim\prevdepth=-\@m\p@\else + \dimen@\prevdepth + % Calculate the modulus of the previous depth with 0.3|\baselineskip| in |\dimen@|. + \@tempcnta\prevdepth + \@tempskipa=0.3\baselineskip\relax + \@tempcntb=\@tempskipa\relax + \divide \@tempcnta by \@tempcntb + \dimen@\prevdepth + \advance\dimen@ -\@tempcnta\@tempskipa + % Skip back by that amount, and then skip by 0.3|\baselineskip|. + \vskip -\dimen@ + \vskip \@tempskipa\relax + \global\lb@prevdepth=\@tempskipa\relax + \fi + \fi + \fi +} + +% unvbox a box, and return a vbox with a given background color +% \unvcolorbox{<colorspec>}{<vboxname>} +\newcommand\unvcolorbox[2]{% + \ifoptionblank{#1}{\vbox{\unvbox#2}}{% + \lb@debug{vcolorbox: #1}% + \vbox{\offinterlineskip + \hbox to \z@{\vbox to \z@{\optioncolor{#1}\hrule\@width\wd#2\@height\ht#2\@depth\dp#2\vss}\hss}% + \unvbox#2% + }% + }% +} + +% create a vbox with a given background color +\newcommand\vcolorbox[2]{% + \eifblank{#1}{\vbox{#2}}{% + \setbox\z@=\vbox{#2}\relax + \unvcolorbox{#1}{\z@}% + }% +}% + +% -------------------------------------------------------- +% The following macros come from mdframed +% -------------------------------------------------------- + +% Determine the amount of free space left on the current page +\newlength\lb@freevspace +\newcommand*\lb@setfreevspace@page{% + \lb@debug{ determine free space}% + \bgroup\@nobreakfalse\addpenalty\z@\egroup% + \penalty\@M\relax\vskip 2\baselineskip\relax% + \penalty9999\relax\vskip -2\baselineskip\relax% + \penalty9999% + \ifdim\pagegoal=\maxdimen\relax% + \lb@freevspace=\vsize% + \else + \lb@freevspace=\dimexpr\pagegoal-\pagetotal-\parskip\relax% + \fi + \lb@debug{free space: \the\lb@freevspace, in page: \the\textheight, vsize=\the\vsize}% +} + +\newcommand*\lb@shiftdim[2]{% + %\letoption{#1}\lb@list + \expandafter\lb@setheadtail@#1,\relax + \eifblank{\lb@head}{}{\option@invoke{/longbox/@breakat-previous}{\lb@head}}% + #2\option{/longbox/@breakat-previous}% + \eifblank{\lb@tail}{}{\let#1\lb@tail}% push back tail +} +\def\lb@comma{,}% +\def\lb@setheadtail@#1,#2\relax{% + \def\lb@head{#1}% + \def\lb@tail{#2}% adds commas! +} + +\newcommand*\lb@setfreevspace{% + \eifblank{\lb@breakat}{\lb@setfreevspace@page}{% + \def\lb@eject{\par}%no eject + \lb@extrasplit=\z@\relax% + \lb@shiftdim{\lb@breakat}\lb@freevspace + \ifdim\lb@freevspace>\z@\else\lb@setfreevspace@page\fi + }% +} + + +% Suppress overfull-underfull vbox messages +\newcommand*\lb@ignorevbadness{% + \edef\lb@currentvbadness{\the\vbadness}% + \edef\lb@currentvfuzz{\the\vfuzz}% + \vbadness=\@M\relax% + \vfuzz=\maxdimen\relax% + \afterassignment\lb@restorevbadness +} +\newcommand*\lb@restorevbadness{% + \vbadness=\lb@currentvbadness\relax + \vfuzz=\lb@currentvfuzz\relax +} + + +% -------------------------------------------------------- +% The 'long vbox' (lvbox) environment collects long material +% into a long \vbox, instead of a \hbox like a lrbox in latex. +% The collected box can contain any box, minipage, lrbox, fbox etc, +% but not outer-par material like a figure. Footnotes can be +% dealt with useing lb@savefootnotes. +% +% The material is typeset in a \vbox according to a given width. +% inside the environment, the boolean 'inlvbox' is true. +% +% \begin{lvbox}{<boxname>}{<width>} +% -------------------------------------------------------- + +\newif\ifinlvbox +\newcommand\lvbox[4]{% + \setbox#1\vbox\bgroup + \begingroup + \inlvboxtrue + % reset defaults + \let\if@nobreak\iffalse + \let\if@noskipsec\iffalse + \let\par\@@par + \let\-\@dischyph + \let\'\@acci\let\`\@accii\let\=\@acciii + % set margin and linewidth + \leftmargin=#2\relax\rightmargin=#4\relax + \@totalleftmargin=\leftmargin% + %\leftskip=#2\relax\rightskip=#4\relax\@rightskip=#4\relax + \linewidth=#3\relax + % set primitive tex margins + \leftskip=\@totalleftmargin% + \rightskip=\rightmargin% + \@rightskip=\rightmargin% + \hsize=\dimexpr\@totalleftmargin+\linewidth+\rightmargin\relax + \columnwidth\hsize + \textwidth\hsize + \nofirstindent + %\nofirstparskip +} +\def\endlvbox{\endgroup\egroup} + + + +% -------------------------------------------------------- +% +% -------------------------------------------------------- + + +\newsavebox\lb@headbox +\newsavebox\lb@savebox +\newsavebox\lb@mainbox + +% -------------------------------------------------------- +% +% -------------------------------------------------------- + +\newcommand\lb@setbaseline[1]{% + %\typeout{ set baseline, \the\dp#1,\the\ht#1}% + \ifcase\lb@baseline% + \relax%bottom + \or%middle + \setbox#1=\vbox{\hbox{\lower \dimexpr(\dp#1 + \ht#1)/2 - \dp#1\relax\vbox{\unvbox#1}}}% + \or%top + \setbox#1=\vtop{\unvbox#1}% + \fi + %\typeout{ .new dim: \the\dp#1, \the\ht#1}% +} + + +\@ifundefined{define@key}{}% + {\define@key{longbox}{options}{\options{#1}\option{/longbox/adjust-options}}}% + +\newcommand*\lb@render@breakbox{% + %\typeout{render breakbox entry (in output routine), height=\the\bb@height}% + \bb@restorekeys{longbox}% + \lb@skiptop=\ifbb@isfirst\option{/longbox/skip-top}\else\option{/longbox/skip-break-top}\fi\relax + \lb@skipbottom=\ifbb@islast\option{/longbox/skip-bottom}\else\option{/longbox/skip-break-bottom}\fi\relax + \lb@skipbreaktop=\ifbb@isfirst 0pt\else\option{/longbox/skip-break-top}\fi + \lb@skipbreakbottom=\ifbb@islast 0pt\else\option{/longbox/skip-break-bottom}\fi + %\typeout{ render: skip top=\the\lb@skiptop, bottom=\the\lb@skipbottom, break-top=\the\dimexpr\option{/longbox/skip-bottom}}% + \options{% + /longbox/@part-height=\bb@height + \lb@skipbreaktop + \lb@skipbreakbottom, + /longbox/@part-width=\option{/longbox/width} + \option{/longbox/skip-left} + \option{/longbox/skip-right},%\bb@width, + /longbox/@part-depth=0pt, + /longbox/@part-needtop=\ifbb@isfirst true\else false\fi, + /longbox/@part-needbottom=\ifbb@islast true\else false\fi, + /longbox/@content-box-height=\option{/longbox/@part-height} - \lb@skiptop - \lb@skipbottom, + /longbox/@content-box-width=\option{/longbox/width}, + /longbox/@content-box-depth=\option{/longbox/@part-depth}, + }% + %\typeout{breakbox: width=\expandafter\the\option{/longbox/width}, \the\bb@width, \the\dimexpr\option{/longbox/@part-width}}% + \vbox{% + \kern -\lb@skipbreaktop% todo: move to breakbox? + \option{/longbox/render}% + \kern -\lb@skipbreakbottom + }% +} + +\newcommand*\lb@render@vbox[1]{% + \lb@debug{render vbox entry}% + \lb@restoreoptions + \lb@skiptop=\dimexpr\iftoggle{/longbox/@part-needtop}{\option{/longbox/skip-top}}{\option{/longbox/skip-break-top}}\relax + \lb@skipbottom=\dimexpr\iftoggle{/longbox/@part-needbottom}{\option{/longbox/skip-bottom}}{\option{/longbox/skip-break-bottom}}\relax + %\typeout{ skip top=\the\lb@skiptop, bottom=\the\lb@skipbottom}% + % add top skip while maintaining the baseline. + \ifdim\lb@skiptop=\z@\relax\else + \setbox\z@=\vtop{\unvcopy#1}% + \dimen@=\ht\z@ + \setbox#1=\vbox{\offinterlineskip + \hrule width \z@ height \dimexpr\dimen@ + \lb@skiptop\relax depth -\dimen@ + \unvbox#1% + }% + \fi + % add bottom skip while maintaining the baseline. + \ifdim\lb@skipbottom=\z@\relax\else + \dimen@=\dp#1% + \setbox#1=\vbox{\offinterlineskip\unvbox#1\hrule width \z@ height -\dimen@ depth \dimexpr\dimen@ + \lb@skipbottom\relax}% + \fi + \lb@setbaseline{#1}% + \options{% + /longbox/@part-height=\dimexpr\ht#1 + \dp#1\relax, + /longbox/@part-width=\dimexpr\wd#1 + \option{/longbox/skip-left} + \option{/longbox/skip-right}\relax, + /longbox/@part-depth=\dp#1, + /longbox/@content-box-width=\option{/longbox/width}, + /longbox/@content-box-height=\option{/longbox/@part-height} - \lb@skiptop - \lb@skipbottom, + /longbox/@content-box-depth=\option{/longbox/@part-depth} - \lb@skipbottom, + }% + %\typeout{ longbox: height=\the\dimexpr\option{/longbox/@content-box-height}, outer height=\the\dimexpr\option{/longbox/@part-height}\relax}% + % lower the box depending on vertical alignment + \ifcase\option{/longbox/vertical-align/@ord}\relax + \@tempdima\z@ + \or + %bottom + \@tempdima\dimexpr0.3\baselineskip - \option{/longbox/@part-depth}\relax + \or%middle + \@tempdima\dimexpr0.5\option{/longbox/@part-height} - \option{/longbox/@part-depth}\relax + \or%top + \@tempdima\dimexpr\option{/longbox/@part-height}-\option{/longbox/@part-depth}-0.7\baselineskip\relax + \or%text-bottom + \@tempdima\dimexpr0.3\baselineskip - \option{/longbox/@part-depth}\relax + \or%text-top + \@tempdima\dimexpr\option{/longbox/@part-height}-\option{/longbox/@part-depth}-0.7\baselineskip\relax + \or%super + \@tempdima=-0.9ex% + \or%sub + \@tempdima=0.7ex% + \else + \@tempdima\z@ + \fi + \advance\@tempdima by -\option{/longbox/raise}% + \option@invoke{/longbox/@lower}{\@tempdima}% + \noindent\hbox{\lower \@tempdima\vbox{\offinterlineskip + \hbox to \z@{% + \vbox to \z@{% + \hbox{\lower \option{/longbox/@part-height}\vbox{\offinterlineskip{\option{/longbox/render}}}}% + \vss}% + \hss + }% + \hbox{% + \ifdim\option{/longbox/skip-left}=\z@\else\hskip\option{/longbox/skip-left}\fi + \box#1% + \ifdim\option{/longbox/skip-right}=\z@\else\hskip\option{/longbox/skip-right}\fi + %$\box#1% + }% + }}% +} + +\newcommand*\lb@single@[1]{% + \begingroup + \toggletrue{/longbox/@part-needtop}% + \toggletrue{/longbox/@part-needbottom}% + \lb@render@vbox{#1}% + \endgroup +} +\newcommand*\lb@first@[1]{% + \begingroup + \toggletrue{/longbox/@part-needtop}% + \togglefalse{/longbox/@part-needbottom}% + \lb@render@vbox{#1}% + \lb@eject + \endgroup +} +\newcommand*\lb@middle@[1]{% + \begingroup + \togglefalse{/longbox/@part-needtop}% + \togglefalse{/longbox/@part-needbottom}% + \lb@render@vbox{#1}% + \lb@eject + \endgroup +} +\newcommand*\lb@last@[1]{% + \begingroup + \togglefalse{/longbox/@part-needtop}% + \toggletrue{/longbox/@part-needbottom}% + \lb@render@vbox{#1}% + \endgroup +} + +% -------------------------------------------------------- +% +% -------------------------------------------------------- + +\newcommand*\lb@env@start{% + \ifcase\lb@textalign\relax + %default + \or\raggedright + \or\centering + \or\raggedleft + \else\relax% justify=default + \fi + \lb@insertbefore +} + +\newcount\lb@usevbox +\newlength\lb@width +\newlength\lb@height +\newlength\lb@skiptop +\newlength\lb@skipright +\newlength\lb@skipbottom +\newlength\lb@skipleft +\newlength\lb@skipbreaktop +\newlength\lb@skipbreakbottom +\newlength\lb@outerwidth +\newlength\lb@extrasplit +\newcount\lb@textalign +\newcount\lb@baseline +\newtoggle{lb@baselineskip}% +\newtoggle{lb@breakable}% +\newtoggle{lb@debug}% +\newtoggle{lb@verbose}% +\def\lb@breakat{}% +\def\lb@halign{}% +\def\lb@eject{}% +\def\lb@insertafter{} +\def\lb@insertbefore{} + +\newcommand*\lb@peekoptions[1]{% + % process options inside a group and just set necessary parameters + % this way, nested boxes don't influence each other's parameters + \begingroup + \options{#1}% + \option{/longbox/adjust-options}% + \protected@edef\lb@temp{\endgroup + \lb@width=\the\dimexpr\option{/longbox/width}\relax + \lb@height=\the\dimexpr\option{/longbox/height}\relax + \lb@textalign=\the\numexpr\option{/longbox/text-align/@ord}\relax + \lb@baseline=\the\numexpr\option{/longbox/baseline/@ord}\relax + \lb@skiptop=\the\dimexpr\option{/longbox/skip-top}\relax + \lb@skipright=\the\dimexpr\option{/longbox/skip-right}\relax + \lb@skipbottom=\the\dimexpr\option{/longbox/skip-bottom}\relax + \lb@skipleft=\the\dimexpr\option{/longbox/skip-left}\relax + \lb@skipbreaktop=\the\dimexpr\option{/longbox/skip-break-top}\relax + \lb@skipbreakbottom=\the\dimexpr\option{/longbox/skip-break-bottom}\relax + \lb@usevbox=\iftoggle{/longbox/use-vbox}{1}{0}\relax + \lb@outerwidth=\the\dimexpr\option{/longbox/outer-width}\relax + \lb@extrasplit=\the\dimexpr\option{/longbox/split-minimum}\relax + \def\noexpand\lb@insertafter{\option{/longbox/insert-after}}% + \def\noexpand\lb@insertbefore{\option{/longbox/insert-before}}% + \def\noexpand\lb@breakat{\option{/longbox/breakat}}% + \def\noexpand\lb@halign{\option{/longbox/height-align}}% + \def\noexpand\lb@eject{\option{/longbox/eject}}% + \noexpand\csname toggle\iftoggle{/longbox/baseline-skip}{true}{false}\endcsname{lb@baselineskip}% + \noexpand\csname toggle\iftoggle{/longbox/breakable}{true}{false}\endcsname{lb@breakable}% + \noexpand\csname toggle\iftoggle{/longbox/debug}{true}{false}\endcsname{lb@debug}% + \noexpand\csname toggle\iftoggle{/longbox/verbose}{true}{false}\endcsname{lb@verbose}% + }% + \lb@temp +} + +\newenvironment{longbox@env}[2]{% + % save options + \lb@peekoptions{#1,#2}% + % + \ifnum\lb@usevbox=0\relax + \lb@debug{start breakbox}% + \let\bb@render\lb@render@breakbox + \bb@savekeys{longbox}{options={#1,#2,outer-width=\the\lb@outerwidth}}% + \iftoggle{lb@baselineskip}{\typeout{**insert bskip}}{\typeout{**suppress bskip}\vskip 1pt}% + \begin{breakbox}% + \ifdim\lb@skiptop=\z@\relax\else\vspace{\lb@skiptop}\fi% + \dimen@=\dimexpr\linewidth-\lb@skipleft-\lb@width\relax + \begin{bb@margins}{\lb@skipleft}{\dimen@}% + \else + \lb@debug{start vbox}% + \def\lb@restoreoptions{\options{#1,#2}\option{/longbox/adjust-options}}% + \lb@savefootnotes + \dimen@=\dimexpr\linewidth-\lb@skipleft-\lb@width\relax + \lb@debug{ width=\the\lb@width, linewidth=\the\linewidth, skipleft=\the\lb@skipleft, right=\the\lb@skipright, total right=\the\dimen@}% + \iftoggle{lb@baselineskip}{\lb@skiptobaseline}{\lb@prevdepth=-\@m pt}% + \lvbox{\lb@mainbox}{0pt}{\lb@width}{0pt}%{\lb@skipleft}{\lb@width}{\lb@skipright}% + \prevdepth=\lb@prevdepth + \fi + \ifcase\lb@textalign\relax + %default + \or\raggedright + \or\centering + \or\raggedleft + \else\relax% justify=default + \fi + \lb@insertbefore + \begingroup +}{% + \par\unskip + \endgroup + \lb@insertafter + %\ifdim\lb@skipbottom=\z@\relax\else\vskip\lb@skipbottom\fi% + \ifnum\lb@usevbox=0\relax + \end{bb@margins}% + \ifdim\lb@skipbottom=\z@\relax\else\hrule width \z@ height \lb@skipbottom\fi%\vspace{\lb@skipbottom}\fi% + \iftoggle{lb@baselineskip}{}{\vskip 1sp}% + \end{breakbox}% + \lb@debug{end breakbox}% + \else + \ontoggle{lb@baselineskip}{\lb@skiptobaseline}% + \endlvbox% + \lb@debug{initial lvbox: \the\dp\lb@mainbox, \the\ht\lb@mainbox, \the\wd\lb@mainbox}% + \lb@processbox + %\setbox\lb@mainbox=\hbox{\lower \lb@skipbottom\vbox{\offinterlineskip\unvbox\lb@mainbox}}% + \lb@restorefootnotes + \lb@debug{end vbox}% + \fi +} + +\newcommand\longbox@cmd[3]{% + \begingroup + %\options{/options/collectunknown,/longbox/scoped,#2}% set scoped options first + %\option{/longbox/scoped/@adjust-options}% + \lb@peekoptions{#1,#2}% + \leavevmode + %\setbox\lb@mainbox=\hbox{% + % \begingroup + % #3% + % \endgroup + %}% + \setbox\lb@mainbox=\hbox{% + \begingroup + \ifcase\lb@textalign\relax + %default=left + \or%left + \or\hss%center + \or\hss%right + \else%justify + \fi + \lb@insertbefore + #3% + \lb@insertafter + \ifnum\lb@textalign<3\relax\hss\fi% default,left,center + \endgroup + }% + \options{#1,#2}% + \ifdim\option{/longbox/width}=-1sp\relax + \options{/longbox/width=\wd\lb@mainbox}%set to natural width + \fi + \option{/longbox/adjust-options}% + % make it a vbox + \setbox\lb@mainbox=\vbox{\offinterlineskip% + \hbox to \option{/longbox/width}{% + \unhbox\lb@mainbox + }% + }% + \def\lb@restoreoptions{}% + \letoption{/longbox/height-align}\lb@halign + \lb@height=\option{/longbox/height}\relax + \lb@baseline=\option{/longbox/baseline/@ord}\relax + \lb@processbox + \endgroup +} + +\newcommand\lb@processbox{% + \ifdim\lb@height<0pt\relax + \lb@setbaseline{\lb@mainbox}% + \else + \lb@restrictheight + \fi + \lb@typesetbox +} + +\newcommand\lb@typesetbox{% + \ifinlvbox + \iftoggle{lb@breakable}{% + %\lb@debug{disable breakable due to nesting of long-boxes}% + \togglefalse{lb@breakable}% + }{}% + \fi + \ifhmode\lb@single@{\lb@mainbox}\else\lb@typeset\fi +} + +% -------------------------------------------------------- +% +% -------------------------------------------------------- + +\newcommand\lb@restrictheight{% + \lb@typeout{restrict height to \the\lb@height}% + \lb@splitheight=\lb@height% + %lb@debug{before height split: \the\dp\lb@mainbox, \the\ht\lb@mainbox, \the\wd\lb@mainbox}% + \lb@splitbox + \ifdim\ht\lb@headbox=0pt\relax + %split failed.. do nothing + \lb@debug{could not restrict height}% + \else + % store splitted off content in the mainbox (and discard the rest) + \setbox\lb@mainbox\vbox{\unvbox\lb@headbox}% + \lb@debug{restricted height to \the\ht\lb@mainbox}% + \fi + % set baseline + \lb@setbaseline{\lb@mainbox}% + % height align + %\letoption{/longbox/height-align}\lb@halign + \eifstrequal{\lb@halign}{bottom}% + {\setbox\lb@mainbox=\vbox{\hbox{\vbox to \lb@splitheight{\vss\unvbox\lb@mainbox}}}}% + {\eifstrequal{\lb@halign}{middle}% + {\dimen@=\dimexpr\lb@splitheight-\ht\lb@mainbox-\dp\lb@mainbox\relax + \setbox\lb@mainbox=\vbox{\hbox{% + \lower \dimexpr0.5\dimen@ + \dp\lb@mainbox\relax% + \vbox to \lb@splitheight{\vss\unvbox\lb@mainbox\vss}}}}% + {% default is top + \dimen@=\dimexpr\lb@splitheight-\ht\lb@mainbox-\dp\lb@mainbox\relax + \setbox\lb@mainbox=\vbox{\vtop to \lb@splitheight{\box\lb@mainbox\vss}}% + }% + }% +} + +% -------------------------------------------------------- +% +% -------------------------------------------------------- + +\newlength\lb@neededvspace +\newcommand\lb@typeset[1][0pt]{% + \iftoggle{lb@breakable}{% + \lb@setfreevspace + \setlength\lb@neededvspace{\dimexpr\ht\lb@mainbox+\dp\lb@mainbox+\lb@skiptop+\lb@skipbottom\relax}% + \lb@debug{needed: \the\lb@neededvspace, available: \the\lb@freevspace}% + \ifdim\lb@neededvspace<\lb@freevspace\relax + \lb@single@{\lb@mainbox}% + \else + \lb@typeout{longbox needs splitting}% + \setlength\lb@splitheight{\dimexpr\lb@freevspace-\lb@skiptop-\lb@skipbreakbottom\relax}% + \lb@splitbox + \ifdim\ht\lb@headbox=0pt\relax + % failed to split + \ifdim\dimexpr\lb@freevspace + #1\relax<\textheight\relax % test if we were at a fresh page.. (and prevent infinite recursion) + \lb@debug{failed to split the box, inserting a page break}% + \hrule \@height\z@ \@width\hsize + \lb@eject% + \lb@typeset[\textheight]% try again, but pass \textheight to guard against infinite recursion + \else + % on a fresh page we should not fail anymore.. just output as is.. + % lb@warncannotsplit + \lb@single@{\lb@mainbox}% + \fi + \else + % first part success + \lb@typeout{first part splitted}% + \lb@first@{\lb@headbox}% + \expandafter\expandafter\expandafter\lb@typesetrest + \fi + \fi + }{%\else + \lb@debug{unbreakable box}% + \lb@single@{\lb@mainbox}% always directly output an unbreakable box + }% +} + +\newcommand\lb@typesetrest{% + \lb@setfreevspace% + \setlength\lb@neededvspace{\dimexpr\ht\lb@mainbox+\dp\lb@mainbox+\lb@skipbottom+\lb@skipbreaktop\relax}% + \ifdim\lb@neededvspace<\lb@freevspace\relax + \lb@typeout{output last part of box}% + \lb@last@{\lb@mainbox}% + \else + \lb@debug{split box further}% + \setlength\lb@splitheight{\dimexpr\lb@freevspace-\lb@skipbreaktop-\lb@skipbreakbottom\relax}% + \lb@splitbox + \ifdim\ht\lb@headbox=0pt\relax + % failed to split + \lb@typeout{failed to split box!}% + \lb@last@{\lb@mainbox}% + \else + % middle part success + \lb@typeout{output middle part of box}% + \lb@middle@{\lb@headbox}% + \expandafter\expandafter\expandafter\lb@typesetrest% continue the iteration... + \fi + \fi +} + +% -------------------------------------------------------- +% Split a long vbox over multiple pages. +% This code is based on similar code in the mdframed package +% -------------------------------------------------------- + +\newlength\lb@splitheight +\newlength\lb@insurance % tiny extra space to ensure our box will really fit +\setlength\lb@insurance{1pt} + +% expects split target height in lb@splitheight, and splits off the start of lb@mainbox to lb@headbox +\newcommand\lb@splitbox{% + \ifdim\dimexpr\ht\lb@mainbox + \dp\lb@mainbox\relax>\lb@splitheight\relax + % the main box is larger than our target split height.. + \ifdim\lb@extrasplit>\lb@splitheight\relax + % not enough space to bother + \lb@typeout{not enough space on page for a split}% + \setbox\lb@headbox=\vbox{}% empty head + \else + % try a split; lower the split height a bit so we are sure to fit + \advance\lb@splitheight -\lb@insurance\relax + \lb@debug{split: \the\lb@splitheight, from \the\dimexpr\ht\lb@mainbox + \dp\lb@mainbox\relax}% + \setbox\lb@savebox=\vbox{\unvcopy\lb@mainbox}% save original + \lb@trysplit{\lb@splitheight}% + \ifdim\dimexpr\ht\lb@headbox + \dp\lb@headbox>\lb@splitheight\relax + % too big, bad split. Try other splits.. iterate N times with 1 or 5pt less before giving up + \dimen@=\lb@splitheight\relax + \@tempcnta=\z@\relax + \loop + \ifdim\dimexpr\ht\lb@headbox+\dp\lb@headbox\relax>\lb@splitheight\relax + \ifnum\@tempcnta<50% + \advance\dimen@ by -\p@\relax% try a slightly smaller height.. + \else + \advance\dimen@ by -5\p@\relax% try larger increase after 50pt.. + \fi + \advance\@tempcnta by \@ne\relax + \lb@ignorevbadness + \setbox\lb@mainbox=\vbox{\unvcopy\lb@savebox}% restore + \lb@trysplit{\dimen@}% + \ifdim\lb@extrasplit<\dimen@\relax\else\lb@splitstop\fi % don't try to split too small + \ifnum\@tempcnta<100\relax\else\lb@splitstop\fi % and not more than N attempts + \repeat% + \ifnum\@tempcnta<100\relax + \dimen@=\dimexpr\lb@splitheight - \ht\lb@headbox - \dp\lb@headbox\relax + \ifdim\dimen@>\option{/longbox/split-badness}\relax + \lb@warnbadsplit{\dimen@}% + \fi + \fi + \fi + \fi + \else + % mainbox fits in our target lb@splitheight + \setbox\lb@headbox=\vbox{\unvbox\lb@mainbox}% + \setbox\lb@mainbox=\vbox{}% + \fi +} + +\newcommand\lb@splitstop{% + \lb@typeout{cannot find a good split}% + \let\iterate\relax + \lb@warncannotsplit + \setbox\lb@mainbox=\vbox{\unvcopy\lb@savebox}% restore + \setbox\lb@headbox=\vbox{}% empty head + \@tempcnta=\@M\relax +} + +\newcommand\lb@trysplit[1]{% try to split at given height + \lb@typeout{try to split at: \the\dimexpr #1\relax}% + \lb@ignorevbadness + \setbox\lb@headbox=\vsplit\lb@mainbox to #1\relax% + \setbox\lb@headbox=\vbox{\unvbox\lb@headbox}% + \setbox\lb@mainbox=\vbox{\unvbox\lb@mainbox}% +} + +% -------------------------------------------------------- +% The longbox environment uses options to set its options +% -------------------------------------------------------- + + +% keys and styles that can be set once globally +\options{% + /longbox/.new family, +}% + +\options{/longbox,% + % computed + @part-needtop/.new toggle, + @part-needbottom/.new toggle, + @part-height/.new length, + @part-width/.new length, + @part-depth/.new length, + @content-box-height/.new length, + @content-box-width/.new length, + @content-box-depth/.new length, + @breakat-previous/.new length, + @lower/.new length, + % + debug/.new toggle, + verbose/.new toggle, + render/.new value =\lb@render@fbox, + adjust-options/.new value = {\longbox@adjustoptions}, + eject/.new value = {\protect\vfill\protect\eject}, + use-vbox/.new toggle = true, + split-minimum/.new length = {1.5\baselineskip}, + split-badness/.new length = \baselineskip, + % + height-align/.new choice= {top,middle,bottom}, + baseline/.new choice = {bottom,middle,top}, + text-align/.new choice = {default,left,center,right,justify}, + vertical-align/.new choice = {baseline,bottom,middle,top,text-bottom,text-top,super,sub}, + raise/.new length = {0pt}, + baseline-skip/.new toggle =true, + % + height/.new length = -1sp, + width/.new length = -1sp, + outer-height/.new length= -1sp, + outer-width/.new length = -1sp, + insert-before/.new value= {}, + insert-after/.new value = {}, + breakat/.new value = {}, + breakable/.new toggle = false, + skip/.new style = {skip-top=#1,skip-right=#1,skip-bottom=#1,skip-left=#1}, + skip-top/.new length, + skip-right/.new length, + skip-bottom/.new length, + skip-left/.new length, + skip-break-bottom/.new length, + skip-break-top/.new length, +} + +\newcommand\longbox@adjustoptions{% + %\typeout{ standard longbox adjustoptions}% + \lb@debug{ current width=\the\dimexpr\option{/longbox/width}, outer=\the\dimexpr\option{/longbox/outer-width}, linewidth=\the\linewidth}% + \ontoggle{/longbox/debug}{\option@invoke{/longbox/verbose}{true}}% + % adjust height + \ifdim\option{/longbox/height}=-1sp\relax + \ifdim\option{/longbox/outer-height}=-1sp\else + \option@invoke{/longbox/height}% + {\option{/longbox/outer-height}-\option{/longbox/skip-top}-\option{/longbox/skip-bottom}}% + \fi + \fi + % set width + \ifdim\option{/longbox/width}=-1sp\relax + \ifdim\option{/longbox/outer-width}=-1sp\relax + \option@invoke{/longbox/outer-width}{\linewidth}% + \fi + \dimen@=\dimexpr\option{/longbox/outer-width}-\option{/longbox/skip-left}-\option{/longbox/skip-right}\relax + \ifdim\dimen@<\z@\relax\dimen@=\z@\fi + \option@invoke{/longbox/width}{\dimen@}% + \fi + % use a breakbox whenever we are in external vertical mode and not width or height restricted. + \iftoggle{/longbox/use-vbox}{}{% + \ifinner\toggletrue{/longbox/use-vbox}\else + \ifhmode\toggletrue{/longbox/use-vbox}\else + \ifdim\option{/longbox/height}>-1sp\toggletrue{/longbox/use-vbox}\else + \iftoggle{/longbox/breakable}{}{\toggletrue{/longbox/use-vbox}}% + \ifoptionblank{/longbox/breakat}{}{\toggletrue{/longbox/use-vbox}}% + \fi\fi\fi + }% +} + +\newenvironment{longbox}[1][]{% + %\bb@savekeys{bfbox}{fboxrule=\the\fboxrule,fboxsep=\the\fboxsep,bgcolor={\bb@bgcolor},rulecolor={\bb@rulecolor},stickout={\bb@stickout}}% + \begin{longbox@env}{/longbox}{#1}% +}{\end{longbox@env}} + +\newcommand\lbox[1][]{% + %\bb@savekeys{bfbox}{fboxrule=\the\fboxrule,fboxsep=\the\fboxsep,bgcolor={\bb@bgcolor},rulecolor={\bb@rulecolor},stickout={\bb@stickout}}% + \longbox@cmd{/longbox}{#1}% +} + +\newcommand*\lb@render@fbox{% + %\typeout{render defaultbox: bgcolor=\bb@bgcolor, needtop=\iftoggle{/longbox/@part-needtop}{true}{false}}% + \@ovdx=\dimexpr\option{/longbox/@part-width} - 2\fboxrule\relax% + \@ovdy=\dimexpr\option{/longbox/@part-height}\relax% + \iftoggle{/longbox/@part-needbottom}% + {\@tempdima=0pt\relax\advance\@ovdy by -\fboxrule}% + {\@tempdima=\dimexpr\fboxrule + \bb@stickout\relax + \advance\bb@height by \@tempdima + \advance\@ovdy by \@tempdima}% + \iftoggle{/longbox/@part-needtop}% + {\@tempdimb=0pt\relax\advance\@ovdy by -\fboxrule}% + {\@tempdimb=\dimexpr\bb@stickout\relax + \advance\bb@height by \@tempdimb + \advance\@ovdy by \@tempdimb}% + % + \hbox{\lower \@tempdima\vbox{% + \vskip -\@tempdimb + \ontoggle{/longbox/@part-needtop}{\lb@debug{toprule wd=\expandafter\the\option{/longbox/width}}\hrule width \option{/longbox/@part-width} height \fboxrule}% + \hbox{% + \vrule width \fboxrule height \@ovdy% + \ifx\bb@bgcolor\@empty + \vrule width \@ovdx height \z@\relax + \else + {\color{\bb@bgcolor}\vrule width \@ovdx height \@ovdy}% + \fi + \vrule width \fboxrule height \@ovdy% + }% + \ontoggle{/longbox/@part-needbottom}{\hrule width \option{/longbox/@part-width} height \fboxrule}% + }}% +}
\ No newline at end of file |