%--------------------------------------------------------------------------- % 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{}{} \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}{}{} % -------------------------------------------------------- \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}% }}% }