% \iffalse meta-comment % %% File: l3box.dtx Copyright (C) 2005-2012 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is in the file %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the "l3kernel bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} \GetIdInfo$Id: l3box.dtx 3490 2012-03-04 01:00:53Z bruno $ {L3 Experimental boxes} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3box} package\\ Boxes^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \maketitle % % \begin{documentation} % % There are three kinds of box operations: horizontal mode denoted % with prefix |\hbox_|, vertical mode with prefix |\vbox_|, and the % generic operations working in both modes with prefix |\box_|. % % \section{Creating and initialising boxes} % % \begin{function}{\box_new:N, \box_new:c} % \begin{syntax} % \cs{box_new:N} \meta{box} % \end{syntax} % Creates a new \meta{box} or raises an error if the name is % already taken. The declaration is global. The \meta{box} will % initially be void. % \end{function} % % \begin{function}{\box_clear:N, \box_clear:c, \box_gclear:N, \box_gclear:c} % \begin{syntax} % \cs{box_clear:N} \meta{box} % \end{syntax} % Clears the content of the \meta{box} by setting the box equal to % \cs{c_void_box}. % \end{function} % % \begin{function} % {\box_clear_new:N, \box_clear_new:c, \box_gclear_new:N, \box_gclear_new:c} % \begin{syntax} % \cs{box_clear_new:N} \meta{box} % \end{syntax} % Ensures that the \meta{box} exists globally by applying % \cs{box_new:N} if necessary, then applies \cs{box_(g)clear:N} to leave % the \meta{box} empty. % \end{function} % % \begin{function} % { % \box_set_eq:NN, \box_set_eq:cN, \box_set_eq:Nc, \box_set_eq:cc, % \box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc % } % \begin{syntax} % \cs{box_set_eq:NN} \meta{box1} \meta{box2} % \end{syntax} % Sets the content of \meta{box1} equal to that of \meta{box2}. % \end{function} % % \begin{function} % { % \box_set_eq_clear:NN, \box_set_eq_clear:cN, % \box_set_eq_clear:Nc, \box_set_eq_clear:cc % } % \begin{syntax} % \cs{box_set_eq_clear:NN} \meta{box1} \meta{box2} % \end{syntax} % Sets the content of \meta{box1} within the current \TeX{} group % equal to that of \meta{box2}, then clears \meta{box2} globally. % \end{function} % % \begin{function} % { % \box_gset_eq_clear:NN, \box_gset_eq_clear:cN, % \box_gset_eq_clear:Nc, \box_gset_eq_clear:cc % } % \begin{syntax} % \cs{box_gset_eq_clear:NN} \meta{box1} \meta{box2} % \end{syntax} % Sets the content of \meta{box1} equal to that of \meta{box2}, then % clears \meta{box2}. These assignments are global. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] % {\box_if_exist:N, \box_if_exist:c} % \begin{syntax} % \cs{box_if_exist_p:N} \meta{box} % \cs{box_if_exist:NTF} \meta{box} \Arg{true code} \Arg{false code} % \end{syntax} % Tests whether the \meta{box} is currently defined. This does not % check that the \meta{box} really is a box. % \end{function} % % \section{Using boxes} % % \begin{function}{\box_use:N, \box_use:c} % \begin{syntax} % \cs{box_use:N} \meta{box} % \end{syntax} % Inserts the current content of the \meta{box} onto the current % list for typesetting. % \begin{texnote} % This is the \TeX{} primitive \tn{copy}. % \end{texnote} % \end{function} % % \begin{function}{\box_use_clear:N, \box_use_clear:c} % \begin{syntax} % \cs{box_use_clear:N} \meta{box} % \end{syntax} % Inserts the current content of the \meta{box} onto the current % list for typesetting, then globally clears the content of the % \meta{box}. % \begin{texnote} % This is the \TeX{} primitive \tn{box}. % \end{texnote} % \end{function} % % \begin{function}{\box_move_right:nn, \box_move_left:nn} % \begin{syntax} % \cs{box_move_right:nn} \Arg{dimexpr} \Arg{box function} % \end{syntax} % This function operates in vertical mode, and inserts the % material specified by the \meta{box function} % such that its reference point is displaced horizontally by the given % \meta{dimexpr} from the reference point for typesetting, to the right % or left as appropriate. The \meta{box function} should be % a box operation such as |\box_use:N \| or a \enquote{raw} % box specification such as |\vbox:n { xyz }|. % \end{function} % % \begin{function}{\box_move_up:nn, \box_move_down:nn} % \begin{syntax} % \cs{box_move_up:nn} \Arg{dimexpr} \Arg{box function} % \end{syntax} % This function operates in horizontal mode, and inserts the % material specified by the \meta{box function} % such that its reference point is displaced vertical by the given % \meta{dimexpr} from the reference point for typesetting, up % or down as appropriate. The \meta{box function} should be % a box operation such as |\box_use:N \| or a \enquote{raw} % box specification such as |\vbox:n { xyz }|. % \end{function} % % \section{Measuring and setting box dimensions} % % \begin{function}{\box_dp:N, \box_dp:c} % \begin{syntax} % \cs{box_dp:N} \meta{box} % \end{syntax} % Calculates the depth (below the baseline) of the \meta{box} % in a form suitable for use in a \meta{dimension expression}. % \begin{texnote} % This is the \TeX{} primitive \tn{dp}. % \end{texnote} % \end{function} % % \begin{function}{\box_ht:N, \box_ht:c} % \begin{syntax} % \cs{box_ht:N} \meta{box} % \end{syntax} % Calculates the height (above the baseline) of the \meta{box} % in a form suitable for use in a \meta{dimension expression}. % \begin{texnote} % This is the \TeX{} primitive \tn{ht}. % \end{texnote} % \end{function} % % \begin{function}{\box_wd:N, \box_wd:c} % \begin{syntax} % \cs{box_wd:N} \meta{box} % \end{syntax} % Calculates the width of the \meta{box} in a form % suitable for use in a \meta{dimension expression}. % \begin{texnote} % This is the \TeX{} primitive \tn{wd}. % \end{texnote} % \end{function} % % \begin{function}[updated = 2011-10-22]{\box_set_dp:Nn, \box_set_dp:cn} % \begin{syntax} % \cs{box_set_dp:Nn} \meta{box} \Arg{dimension expression} % \end{syntax} % Set the depth (below the baseline) of the \meta{box} to the value of % the \Arg{dimension expression}. This is a global assignment. % \end{function} % % \begin{function}[updated = 2011-10-22]{\box_set_ht:Nn, \box_set_ht:cn} % \begin{syntax} % \cs{box_set_ht:Nn} \meta{box} \Arg{dimension expression} % \end{syntax} % Set the height (above the baseline) of the \meta{box} to the value of % the \Arg{dimension expression}. This is a global assignment. % \end{function} % % \begin{function}[updated = 2011-10-22]{\box_set_wd:Nn, \box_set_wd:cn} % \begin{syntax} % \cs{box_set_wd:Nn} \meta{box} \Arg{dimension expression} % \end{syntax} % Set the width of the \meta{box} to the value of the % \Arg{dimension expression}. This is a global assignment. % \end{function} % % \section{Affine transformations} % % Affine transformations are changes which (informally) preserve straight % lines. Simple translations are affine transformations, but are better handled % in \TeX{} by doing the translation first, then inserting an unmodified box. % On the other hand, rotation and resizing of boxed material can best be % handled by modifying boxes. These transformations are described here. % % \begin{function}[added = 2011-09-02]{\box_resize:Nnn, \box_resize:cnn} % \begin{syntax} % \cs{box_resize:Nnn} \meta{box} \Arg{x-size} \Arg{y-size} % \end{syntax} % Resize the \meta{box} to \meta{x-size} horizontally and \meta{y-size} % vertically (both of the sizes are dimension expressions). % The \meta{y-size} is the vertical size (height plus depth) of % the box. The updated \meta{box} will be an hbox, irrespective of the nature % of the \meta{box} before the resizing is applied. Negative sizes will % cause the material in the \meta{box} to be reversed in direction, but the % reference point of the \meta{box} will be unchanged. The resizing applies % within the current \TeX{} group level. % % \textbf{This function is experimental} % \end{function} % % \begin{function}[added = 2011-09-02, updated = 2011-10-22] % {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} % \begin{syntax} % \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size} % \end{syntax} % Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal % size by the same amount (\meta{y-size} is a dimension expression). % The \meta{y-size} is the vertical size (height plus depth) of % the box. % The updated \meta{box} will be an hbox, irrespective of the nature % of the \meta{box} before the resizing is applied. A negative size will % cause the material in the \meta{box} to be reversed in direction, but the % reference point of the \meta{box} will be unchanged. The resizing applies % within the current \TeX{} group level. % % \textbf{This function is experimental} % \end{function} % % \begin{function}[added = 2011-09-02, updated = 2011-10-22] % {\box_resize_to_wd:Nn, \box_resize_to_wd:cn} % \begin{syntax} % \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size} % \end{syntax} % Resize the \meta{box} to \meta{x-size} horizontally, scaling the vertical % size by the same amount (\meta{x-size} is a dimension expression). % The updated \meta{box} will be an hbox, irrespective of the nature % of the \meta{box} before the resizing is applied. A negative size will % cause the material in the \meta{box} to be reversed in direction, but the % reference point of the \meta{box} will be unchanged. The resizing applies % within the current \TeX{} group level. % % \textbf{This function is experimental} % \end{function} % % \begin{function}[added = 2011-09-02, updated = 2011-10-22] % {\box_rotate:Nn, \box_rotate:cn} % \begin{syntax} % \cs{box_rotate:Nn} \meta{box} \Arg{angle} % \end{syntax} % Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about % its reference point. The reference point of the updated box will be moved % horizontally such that it is at the left side of the smallest rectangle % enclosing the rotated material. % The updated \meta{box} will be an hbox, irrespective of the nature % of the \meta{box} before the rotation is applied. The rotation applies % within the current \TeX{} group level. % % \textbf{This function is experimental} % \end{function} % % \begin{function}[added = 2011-09-02, updated = 2011-10-22] % {\box_scale:Nnn, \box_scale:cnn} % \begin{syntax} % \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale} % \end{syntax} % Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in % the horizontal and vertical directions, respectively (both scales are % integer expressions). The updated \meta{box} will be an hbox, irrespective % of the nature of the \meta{box} before the scaling is applied. Negative % scalings will cause the material in the \meta{box} to be reversed in % direction, but the reference point of the \meta{box} will be unchanged. % The scaling applies within the current \TeX{} group level. % % \textbf{This function is experimental} % \end{function} % % \section{Viewing part of a box} % % \begin{function}[added = 2011-11-13]{\box_clip:N, \box_clip:c} % \begin{syntax} % \cs{box_clip:N} \meta{box} % \end{syntax} % Clips the \meta{box} in the output so that only material inside the % bounding box is displayed in the output. The updated \meta{box} will be an % hbox, irrespective of the nature of the \meta{box} before the clipping is % applied. The clipping applies within the current \TeX{} group level. % % \textbf{This function is experimental} % \begin{texnote} % Clipping is implemented by the driver, and as such the full content of % the box is places in the output file. Thus clipping does not remove % any information from the raw output, and hidden material can therefore % be viewed by direct examination of the file. % \end{texnote} % \end{function} % % \begin{function}[added = 2011-11-13] % {\box_trim:Nnnnn, \box_trim:cnnnn} % \begin{syntax} % \cs{box_trim:Nnnnn} \meta{box} \Arg{left} \Arg{bottom} \Arg{right} \Arg{top} % \end{syntax} % Adjusts the bounding box of the \meta{box} \meta{left} is removed from % the left-hand edge of the bounding box, \meta{right} from the right-hand % edge and so fourth. All adjustments are \meta{dimension expressions}. % Material output of the bounding box will still be displayed in the output % unless \cs{box_clip:N} is subsequently applied. % The updated \meta{box} will be an % hbox, irrespective of the nature of the \meta{box} before the viewport % operation is applied. The clipping applies within the current \TeX{} % group level. % % \textbf{This function is experimental} % \end{function} % % \begin{function}[added = 2011-11-13] % {\box_viewport:Nnnnn, \box_viewport:cnnnn} % \begin{syntax} % \cs{box_viewport:Nnnnn} \meta{box} \Arg{llx} \Arg{lly} \Arg{urx} \Arg{ury} % \end{syntax} % Adjusts the bounding box of the \meta{box} such that it has lower-left % co-ordinates (\meta{llx}, \meta{lly}) and upper-right co-ordinates % (\meta{urx}, \meta{ury}). All four co-ordinate positions are % \meta{dimension expressions}. Material output of the bounding box will % still be displayed in the output unless \cs{box_clip:N} is % subsequently applied. % The updated \meta{box} will be an % hbox, irrespective of the nature of the \meta{box} before the viewport % operation is applied. The clipping applies within the current \TeX{} % group level. % % \textbf{This function is experimental} % \end{function} % % \section{Box conditionals} % % \begin{function}[EXP,pTF]{\box_if_empty:N, \box_if_empty:c} % \begin{syntax} % \cs{box_if_empty_p:N} \meta{box} % \cs{box_if_empty:NTF} \meta{box} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if \meta{box} is a empty (equal to \cs{c_empty_box}). % \end{function} % % \begin{function}[EXP,pTF]{\box_if_horizontal:N, \box_if_horizontal:c} % \begin{syntax} % \cs{box_if_horizontal_p:N} \meta{box} % \cs{box_if_horizontal:NTF} \meta{box} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if \meta{box} is a horizontal box. % \end{function} % % \begin{function}[EXP,pTF]{\box_if_vertical:N, \box_if_vertical:c} % \begin{syntax} % \cs{box_if_vertical_p:N} \meta{box} % \cs{box_if_vertical:NTF} \meta{box} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if \meta{box} is a vertical box. % \end{function} % % \section{The last box inserted} % % \begin{function} % { % \box_set_to_last:N, \box_set_to_last:c, % \box_gset_to_last:N, \box_gset_to_last:c % } % \begin{syntax} % \cs{box_set_to_last:N} \meta{box} % \end{syntax} % Sets the \meta{box} equal to the last item (box) added to the current % partial list, removing the item from the list at the same time. When % applied to the main vertical list, the \meta{box} will always be void as % it is not possible to recover the last added item. % \end{function} % % \section{Constant boxes} % % \begin{variable}{\c_empty_box} % This is a permanently empty box, which is neither set as horizontal % nor vertical. % \end{variable} % % \section{Scratch boxes} % % \begin{variable}{\l_tmpa_box, \l_tmpb_box} % Scratch boxes for local assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel % code and so should only be used for short-term storage. % \end{variable} % % \section{Viewing box contents} % % \begin{function}{\box_show:N, \box_show:c} % \begin{syntax} % \cs{box_show:N} \meta{box} % \end{syntax} % Writes the contents of \meta{box} to the log file. % \begin{texnote} % This is a wrapper around the \TeX{} primitive \tn{showbox}. % \end{texnote} % \end{function} % % \section{Horizontal mode boxes} % % \begin{function}{\hbox:n} % \begin{syntax} % \cs{hbox:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a horizontal box of natural % width and then includes this box in the current list for typesetting. % \begin{texnote} % This is the \TeX{} primitive \tn{hbox}. % \end{texnote} % \end{function} % % \begin{function}{\hbox_to_wd:nn} % \begin{syntax} % \cs{hbox_to_wd:nn} \Arg{dimexpr} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a horizontal box of width % \meta{dimexpr} and then includes this box in the current list for % typesetting. % \end{function} % % \begin{function}{\hbox_to_zero:n} % \begin{syntax} % \cs{hbox_to_zero:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a horizontal box of zero width % and then includes this box in the current list for typesetting. % \end{function} % % \begin{function}{\hbox_set:Nn, \hbox_set:cn, \hbox_gset:Nn, \hbox_gset:cn} % \begin{syntax} % \cs{hbox_set:Nn} \meta{box} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} at natural width and then stores the % result inside the \meta{box}. % \end{function} % % \begin{function} % { % \hbox_set_to_wd:Nnn, \hbox_set_to_wd:cnn, % \hbox_gset_to_wd:Nnn, \hbox_gset_to_wd:cnn % } % \begin{syntax} % \cs{hbox_set_to_wd:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} to the width given by the \meta{dimexpr} % and then stores the result inside the \meta{box}. % \end{function} % % \begin{function}{\hbox_overlap_right:n} % \begin{syntax} % \cs{hbox_overlap_right:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a horizontal box of zero width % such that material will protrude to the right of the insertion % point. % \end{function} % % \begin{function}{\hbox_overlap_left:n} % \begin{syntax} % \cs{hbox_overlap_left:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a horizontal box of zero width % such that material will protrude to the left of the insertion % point. % \end{function} % % \begin{function} % { % \hbox_set:Nw, \hbox_set:cw, % \hbox_set_end:, % \hbox_gset:Nw, \hbox_gset:cw, % \hbox_gset_end: % } % \begin{syntax} % \cs{hbox_set:Nw} \meta{box} \meta{contents} \cs{hbox_set_end:} % \end{syntax} % Typesets the \meta{contents} at natural width and then stores the % result inside the \meta{box}. In contrast % to \cs{hbox_set:Nn} this function does not absorb the argument % when finding the \meta{content}, and so can be used in circumstances % where the \meta{content} may not be a simple argument. % \end{function} % % \begin{function}{\hbox_unpack:N, \hbox_unpack:c} % \begin{syntax} % \cs{hbox_unpack:N} \meta{box} % \end{syntax} % Unpacks the content of the horizontal \meta{box}, retaining any stretching % or shrinking applied when the \meta{box} was set. % \begin{texnote} % This is the \TeX{} primitive \tn{unhcopy}. % \end{texnote} % \end{function} % % \begin{function}{\hbox_unpack_clear:N, \hbox_unpack_clear:c} % \begin{syntax} % \cs{hbox_unpack_clear:N} \meta{box} % \end{syntax} % Unpacks the content of the horizontal \meta{box}, retaining any stretching % or shrinking applied when the \meta{box} was set. The \meta{box} is % then cleared globally. % \begin{texnote} % This is the \TeX{} primitive \tn{unhbox}. % \end{texnote} % \end{function} % % \section{Vertical mode boxes} % % Vertical boxes inherit their baseline from their contents. The % standard case is that the baseline of the box is at the same position % as that of the last item added to the box. This means that the box % will have no depth unless the last item added to it had depth. As a % result most vertical boxes have a large height value and small or % zero depth. The exception are |_top| boxes, where the reference point % is that of the first item added. These tend to have a large depth and % small height, although the latter will typically be non-zero. % % \begin{function}[updated = 2011-12-18]{\vbox:n} % \begin{syntax} % \cs{vbox:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a vertical box of natural height % and includes this box in the current list for typesetting. % \begin{texnote} % This is the \TeX{} primitive \tn{vbox}. % \end{texnote} % \end{function} % % \begin{function}[updated = 2011-12-18]{\vbox_top:n} % \begin{syntax} % \cs{vbox_top:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a vertical box of natural height % and includes this box in the current list for typesetting. The % baseline of the box will tbe equal to that of the \emph{first} % item added to the box. % \begin{texnote} % This is the \TeX{} primitive \tn{vtop}. % \end{texnote} % \end{function} % % \begin{function}[updated = 2011-12-18]{\vbox_to_ht:nn} % \begin{syntax} % \cs{vbox_to_ht:nn} \Arg{dimexpr} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a vertical box of height % \meta{dimexpr} and then includes this box in the current list for % typesetting. % \end{function} % % \begin{function}[updated = 2011-12-18]{\vbox_to_zero:n} % \begin{syntax} % \cs{vbox_to_zero:n} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} into a vertical box of zero height % and then includes this box in the current list for typesetting. % \end{function} % % \begin{function}[updated = 2011-12-18] % {\vbox_set:Nn, \vbox_set:cn, \vbox_gset:Nn, \vbox_gset:cn} % \begin{syntax} % \cs{vbox_set:Nn} \meta{box} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} at natural height and then stores the % result inside the \meta{box}. % \end{function} % % \begin{function}[updated = 2011-12-18] % {\vbox_set_top:Nn, \vbox_set_top:cn, \vbox_gset_top:Nn, \vbox_gset_top:cn} % \begin{syntax} % \cs{vbox_set_top:Nn} \meta{box} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} at natural height and then stores the % result inside the \meta{box}. The baseline of the box will tbe equal % to that of the \emph{first} item added to the box. % \end{function} % % \begin{function}[updated = 2011-12-18] % { % \vbox_set_to_ht:Nnn, \vbox_set_to_ht:cnn, % \vbox_gset_to_ht:Nnn, \vbox_gset_to_ht:cnn % } % \begin{syntax} % \cs{vbox_set_to_ht:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} % \end{syntax} % Typesets the \meta{contents} to the height given by the % \meta{dimexpr} and then stores the result inside the \meta{box}. % \end{function} % % \begin{function}[updated = 2011-12-18] % { % \vbox_set:Nw, \vbox_set:cw, % \vbox_set_end:, % \vbox_gset:Nw, \vbox_gset:cw, % \vbox_gset_end: % } % \begin{syntax} % \cs{vbox_begin:Nw} \meta{box} \meta{contents} \cs{vbox_set_end:} % \end{syntax} % Typesets the \meta{contents} at natural height and then stores the % result inside the \meta{box}. In contrast % to \cs{vbox_set:Nn} this function does not absorb the argument % when finding the \meta{content}, and so can be used in circumstances % where the \meta{content} may not be a simple argument. % \end{function} % % \begin{function}[updated = 2011-10-22]{\vbox_set_split_to_ht:NNn} % \begin{syntax} % \cs{vbox_set_split_to_ht:NNn} \meta{box1} \meta{box2} \Arg{dimexpr} % \end{syntax} % Sets \meta{box1} to contain material to the height given by the % \meta{dimexpr} by removing content from the top of \meta{box2} % (which must be a vertical box). % \begin{texnote} % This is the \TeX{} primitive \tn{vsplit}. % \end{texnote} % \end{function} % % \begin{function}{\vbox_unpack:N, \vbox_unpack:c} % \begin{syntax} % \cs{vbox_unpack:N} \meta{box} % \end{syntax} % Unpacks the content of the vertical \meta{box}, retaining any stretching % or shrinking applied when the \meta{box} was set. % \begin{texnote} % This is the \TeX{} primitive \tn{unvcopy}. % \end{texnote} % \end{function} % % \begin{function}{\vbox_unpack_clear:N, \vbox_unpack_clear:c} % \begin{syntax} % \cs{vbox_unpack:N} \meta{box} % \end{syntax} % Unpacks the content of the vertical \meta{box}, retaining any stretching % or shrinking applied when the \meta{box} was set. The \meta{box} % is then cleared globally. % \begin{texnote} % This is the \TeX{} primitive \tn{unvbox}. % \end{texnote} % \end{function} % % \section{Primitive box conditionals} % % \begin{function}[EXP]{\if_hbox:N} % \begin{syntax} % \cs{if_hbox:N} \meta{box} % ~~\meta{true code} % \cs{else:} % ~~\meta{false code} % \cs{fi:} % \end{syntax} % Tests is \meta{box} is a horizontal box. % \begin{texnote} % This is the \TeX{} primitive \tn{ifhbox}. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if_vbox:N} % \begin{syntax} % \cs{if_vbox:N} \meta{box} % ~~\meta{true code} % \cs{else:} % ~~\meta{false code} % \cs{fi:} % \end{syntax} % Tests is \meta{box} is a vertical box. % \begin{texnote} % This is the \TeX{} primitive \tn{ifvbox}. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if_box_empty:N} % \begin{syntax} % \cs{if_box_empty:N} \meta{box} % ~~\meta{true code} % \cs{else:} % ~~\meta{false code} % \cs{fi:} % \end{syntax} % Tests is \meta{box} is an empty (void) box. % \begin{texnote} % This is the \TeX{} primitive \tn{ifvoid}. % \end{texnote} % \end{function} % % \section{Experimental box functions} % % \begin{function}[added = 2011-11-21]{\box_show:Nnn, \box_show:cnn} % \begin{syntax} % \cs{box_show:Nnn} \meta{box} \meta{int 1} \meta{int 2} % \end{syntax} % Display the contents of \meta{box} in the terminal, % showing the first \meta{int 1} items of the box, % and descending into \meta{int 1} levels of nesting. % \begin{texnote} % This is a wrapper around the \TeX{} primitives \tn{showbox}, % \tn{showboxbreadth} and \tn{showboxdepth}. % \end{texnote} % \end{function} % % \begin{function}[added = 2011-11-22]{\box_show_full:N, \box_show_full:c} % \begin{syntax} % \cs{box_show_full:N} \meta{box} % \end{syntax} % Display the contents of \meta{box} in the terminal, % showing all items in the box. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3box} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % The code in this module is very straight forward so I'm not going to % comment it very extensively. % % \subsection{Creating and initialising boxes} % % \TestFiles{m3box001.lvt} % % \begin{macro}{\box_new:N,\box_new:c} % Defining a new \meta{box} register: remember that box $255$ is not % generally available. % \begin{macrocode} %<*package> \cs_new_protected:Npn \box_new:N #1 { \chk_if_free_cs:N #1 \newbox #1 } % \cs_generate_variant:Nn \box_new:N { c } % \end{macrocode} % % \begin{macro}{\box_clear:N, \box_clear:c} % \begin{macro}{\box_gclear:N, \box_gclear:c} % \testfile* % Clear a \meta{box} register. % \begin{macrocode} \cs_new_protected:Npn \box_clear:N #1 { \box_set_eq:NN #1 \c_empty_box } \cs_new_protected:Npn \box_gclear:N #1 { \box_gset_eq:NN #1 \c_empty_box } \cs_generate_variant:Nn \box_clear:N { c } \cs_generate_variant:Nn \box_gclear:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\box_clear_new:N, \box_clear_new:c} % \begin{macro}{\box_gclear_new:N, \box_gclear_new:c} % \testfile* % Clear or new. % \begin{macrocode} \cs_new_protected:Npn \box_clear_new:N #1 { \box_if_exist:NTF #1 { \box_clear:N #1 } { \box_new:N #1 } } \cs_new_protected:Npn \box_gclear_new:N #1 { \box_if_exist:NTF #1 { \box_gclear:N #1 } { \box_new:N #1 } } \cs_generate_variant:Nn \box_clear_new:N { c } \cs_generate_variant:Nn \box_gclear_new:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % {\box_set_eq:NN, \box_set_eq:cN, \box_set_eq:Nc, \box_set_eq:cc} % \testfile* % \begin{macro} % {\box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc} % \testfile* % Assigning the contents of a box to be another box. % \begin{macrocode} \cs_new_protected:Npn \box_set_eq:NN #1#2 { \tex_setbox:D #1 \tex_copy:D #2 } \cs_new_protected:Npn \box_gset_eq:NN { \tex_global:D \box_set_eq:NN } \cs_generate_variant:Nn \box_set_eq:NN { cN , Nc , cc } \cs_generate_variant:Nn \box_gset_eq:NN { cN , Nc , cc } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \box_set_eq_clear:NN, \box_set_eq_clear:cN, % \box_set_eq_clear:Nc, \box_set_eq_clear:cc % } % \testfile* % \begin{macro} % { % \box_gset_eq_clear:NN, \box_gset_eq_clear:cN, % \box_gset_eq_clear:Nc, \box_gset_eq_clear:cc % } % \testfile* % Assigning the contents of a box to be another box. % This clears the second box globally (that's how \TeX{} does it). % \begin{macrocode} \cs_new_protected:Npn \box_set_eq_clear:NN #1#2 { \tex_setbox:D #1 \tex_box:D #2 } \cs_new_protected:Npn \box_gset_eq_clear:NN { \tex_global:D \box_set_eq_clear:NN } \cs_generate_variant:Nn \box_set_eq_clear:NN { cN , Nc , cc } \cs_generate_variant:Nn \box_gset_eq_clear:NN { cN , Nc , cc } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\box_if_exist:N, \box_if_exist:c} % Copies of the \texttt{cs} functions defined in \pkg{l3basics}. % \begin{macrocode} \cs_new_eq:NN \box_if_exist:NTF \cs_if_exist:NTF \cs_new_eq:NN \box_if_exist:NT \cs_if_exist:NT \cs_new_eq:NN \box_if_exist:NF \cs_if_exist:NF \cs_new_eq:NN \box_if_exist_p:N \cs_if_exist_p:N \cs_new_eq:NN \box_if_exist:cTF \cs_if_exist:cTF \cs_new_eq:NN \box_if_exist:cT \cs_if_exist:cT \cs_new_eq:NN \box_if_exist:cF \cs_if_exist:cF \cs_new_eq:NN \box_if_exist_p:c \cs_if_exist_p:c % \end{macrocode} % \end{macro} % % \subsection{Measuring and setting box dimensions} % % \begin{macro}{\box_ht:N,\box_ht:c} % \begin{macro}{\box_dp:N,\box_dp:c} % \begin{macro}{\box_wd:N,\box_wd:c} % \testfile* % Accessing the height, depth, and width of a \meta{box} register. % \begin{macrocode} \cs_new_eq:NN \box_ht:N \tex_ht:D \cs_new_eq:NN \box_dp:N \tex_dp:D \cs_new_eq:NN \box_wd:N \tex_wd:D \cs_generate_variant:Nn \box_ht:N { c } \cs_generate_variant:Nn \box_dp:N { c } \cs_generate_variant:Nn \box_wd:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\box_set_ht:Nn, \box_set_ht:cn} % \begin{macro}{\box_set_dp:Nn, \box_set_dp:cn} % \begin{macro}{\box_set_wd:Nn, \box_set_wd:cn} % Measuring is easy: all primitive work. These primitives are not % expandable, so the derived functions are not either. % \begin{macrocode} \cs_new_protected:Npn \box_set_dp:Nn #1#2 { \box_dp:N #1 \dim_eval:w #2 \dim_eval_end: } \cs_new_protected:Npn \box_set_ht:Nn #1#2 { \box_ht:N #1 \dim_eval:w #2 \dim_eval_end: } \cs_new_protected:Npn \box_set_wd:Nn #1#2 { \box_wd:N #1 \dim_eval:w #2 \dim_eval_end: } \cs_generate_variant:Nn \box_set_ht:Nn { c } \cs_generate_variant:Nn \box_set_dp:Nn { c } \cs_generate_variant:Nn \box_set_wd:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Using boxes} % % \begin{macro}{\box_use_clear:N, \box_use_clear:c} % \begin{macro}{\box_use:N, \box_use:c} % Using a \meta{box}. These are just \TeX{} primitives with meaningful % names. % \begin{macrocode} \cs_new_eq:NN \box_use_clear:N \tex_box:D \cs_new_eq:NN \box_use:N \tex_copy:D \cs_generate_variant:Nn \box_use_clear:N { c } \cs_generate_variant:Nn \box_use:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\box_move_left:nn,\box_move_right:nn} % \begin{macro}{\box_move_up:nn,\box_move_down:nn} % \testfile* % Move box material in different directions. % \begin{macrocode} \cs_new_protected:Npn \box_move_left:nn #1#2 { \tex_moveleft:D \dim_eval:w #1 \dim_eval_end: #2 } \cs_new_protected:Npn \box_move_right:nn #1#2 { \tex_moveright:D \dim_eval:w #1 \dim_eval_end: #2 } \cs_new_protected:Npn \box_move_up:nn #1#2 { \tex_raise:D \dim_eval:w #1 \dim_eval_end: #2 } \cs_new_protected:Npn \box_move_down:nn #1#2 { \tex_lower:D \dim_eval:w #1 \dim_eval_end: #2 } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Box conditionals} % % \begin{macro}{\if_hbox:N} % \begin{macro}{\if_vbox:N} % \begin{macro}{\if_box_empty:N} % \testfile* % The primitives for testing if a \meta{box} is empty/void or which % type of box it is. % \begin{macrocode} \cs_new_eq:NN \if_hbox:N \tex_ifhbox:D \cs_new_eq:NN \if_vbox:N \tex_ifvbox:D \cs_new_eq:NN \if_box_empty:N \tex_ifvoid:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\box_if_horizontal:N,\box_if_horizontal:c} % \testfile* % \begin{macro}[pTF]{\box_if_vertical:N,\box_if_vertical:c} % \testfile* % \begin{macrocode} \prg_new_conditional:Npnn \box_if_horizontal:N #1 { p , T , F , TF } { \if_hbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \box_if_vertical:N #1 { p , T , F , TF } { \if_vbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \box_if_horizontal_p:N { c } \cs_generate_variant:Nn \box_if_horizontal:NT { c } \cs_generate_variant:Nn \box_if_horizontal:NF { c } \cs_generate_variant:Nn \box_if_horizontal:NTF { c } \cs_generate_variant:Nn \box_if_vertical_p:N { c } \cs_generate_variant:Nn \box_if_vertical:NT { c } \cs_generate_variant:Nn \box_if_vertical:NF { c } \cs_generate_variant:Nn \box_if_vertical:NTF { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\box_if_empty:N, \box_if_empty:c} % \testfile* % Testing if a \meta{box} is empty/void. % \begin{macrocode} \prg_new_conditional:Npnn \box_if_empty:N #1 { p , T , F , TF } { \if_box_empty:N #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \box_if_empty_p:N { c } \cs_generate_variant:Nn \box_if_empty:NT { c } \cs_generate_variant:Nn \box_if_empty:NF { c } \cs_generate_variant:Nn \box_if_empty:NTF { c } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{The last box inserted} % % \begin{macro}{\box_set_to_last:N, \box_set_to_last:c} % \begin{macro}{\box_gset_to_last:N, \box_gset_to_last:c} % \testfile* % Set a box to the previous box. % \begin{macrocode} \cs_new_protected:Npn \box_set_to_last:N #1 { \tex_setbox:D #1 \tex_lastbox:D } \cs_new_protected:Npn \box_gset_to_last:N { \tex_global:D \box_set_to_last:N } \cs_generate_variant:Nn \box_set_to_last:N { c } \cs_generate_variant:Nn \box_gset_to_last:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Constant boxes} % % \begin{variable}{\c_empty_box} % \begin{macrocode} %<*package> \cs_new_eq:NN \c_empty_box \voidb@x % %<*initex> \box_new:N \c_empty_box % % \end{macrocode} % \end{variable} % % \subsection{Scratch boxes} % % \begin{variable}{\l_tmpa_box, \l_tmpb_box} % \begin{macrocode} %<*package> \cs_new_eq:NN \l_tmpa_box \@tempboxa % %<*initex> \box_new:N \l_tmpa_box % \box_new:N \l_tmpb_box % \end{macrocode} % \end{variable} % % \subsection{Viewing box contents} % % \begin{macro}{\box_show:N, \box_show:c} % \testfile* % Check that the variable exists, then show the contents of the box % and write it into the log file. The spurious \cs{use:n} gives % a nicer output. % \begin{macrocode} \cs_new_protected:Npn \box_show:N #1 { \box_if_exist:NTF #1 { \tex_showbox:D \use:n {#1} } { \msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_generate_variant:Nn \box_show:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\box_show:Nnn, \box_show:cnn} % \begin{macro}{\box_show_full:N, \box_show_full:c} % Show the contents of a box and write it into the log file, % after setting the parameters \tn{showboxbreadth} and \tn{showboxdepth} % to the values provided by the user. % \begin{macrocode} \cs_new_protected:Npn \box_show:Nnn #1#2#3 { \group_begin: \int_set:Nn \tex_showboxbreadth:D {#2} \int_set:Nn \tex_showboxdepth:D {#3} \int_set_eq:NN \tex_tracingonline:D \c_one \box_show:N #1 \group_end: } \cs_generate_variant:Nn \box_show:Nnn { c } \cs_new_protected:Npn \box_show_full:N #1 { \box_show:Nnn #1 { \c_max_int } { \c_max_int } } \cs_generate_variant:Nn \box_show_full:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Horizontal mode boxes} % % \begin{macro}{\hbox:n} % \testfile{m3box002.lvt} % Put a horizontal box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \hbox:n { \tex_hbox:D \scan_stop: } % \end{macrocode} % \end{macro} % % \begin{macro}{\hbox_set:Nn,\hbox_set:cn} % \begin{macro}{\hbox_gset:Nn,\hbox_gset:cn} % \testfile* % \begin{macrocode} \cs_new_protected:Npn \hbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_hbox:D {#2} } \cs_new_protected:Npn \hbox_gset:Nn { \tex_global:D \hbox_set:Nn } \cs_generate_variant:Nn \hbox_set:Nn { c } \cs_generate_variant:Nn \hbox_gset:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hbox_set_to_wd:Nnn,\hbox_set_to_wd:cnn} % \begin{macro}{\hbox_gset_to_wd:Nnn,\hbox_gset_to_wd:cnn} % \testfile* % Storing material in a horizontal box with a specified width. % \begin{macrocode} \cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3 { \tex_setbox:D #1 \tex_hbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } \cs_new_protected:Npn \hbox_gset_to_wd:Nnn { \tex_global:D \hbox_set_to_wd:Nnn } \cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c } \cs_generate_variant:Nn \hbox_gset_to_wd:Nnn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hbox_set:Nw, \hbox_set:cw} % \begin{macro}{\hbox_gset:Nw, \hbox_gset:cw} % \begin{macro}{\hbox_set_end:, \hbox_gset_end:} % \testfile* % Storing material in a horizontal box. This type is useful in % environment definitions. % \begin{macrocode} \cs_new_protected:Npn \hbox_set:Nw #1 { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token } \cs_new_protected:Npn \hbox_gset:Nw { \tex_global:D \hbox_set:Nw } \cs_generate_variant:Nn \hbox_set:Nw { c } \cs_generate_variant:Nn \hbox_gset:Nw { c } \cs_new_eq:NN \hbox_set_end: \c_group_end_token \cs_new_eq:NN \hbox_gset_end: \c_group_end_token % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hbox_set_inline_begin:N, \hbox_set_inline_begin:c} % \begin{macro}{\hbox_gset_inline_begin:N, \hbox_gset_inline_begin:c} % \begin{macro}{\hbox_set_inline_end:,\hbox_gset_inline_end:} % \testfile* % Renamed September 2011. % \begin{macrocode} \cs_new_eq:NN \hbox_set_inline_begin:N \hbox_set:Nw \cs_new_eq:NN \hbox_set_inline_begin:c \hbox_set:cw \cs_new_eq:NN \hbox_set_inline_end: \hbox_set_end: \cs_new_eq:NN \hbox_gset_inline_begin:N \hbox_gset:Nw \cs_new_eq:NN \hbox_gset_inline_begin:c \hbox_gset:cw \cs_new_eq:NN \hbox_gset_inline_end: \hbox_gset_end: % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hbox_to_wd:nn} % \begin{macro}{\hbox_to_zero:n} % \testfile* % Put a horizontal box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \hbox_to_wd:nn #1#2 { \tex_hbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } \cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_skip {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hbox_overlap_left:n, \hbox_overlap_right:n} % Put a zero-sized box with the contents pushed against one side (which % makes it stick out on the other) directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \hbox_overlap_left:n #1 { \hbox_to_zero:n { \tex_hss:D #1 } } \cs_new_protected:Npn \hbox_overlap_right:n #1 { \hbox_to_zero:n { #1 \tex_hss:D } } % \end{macrocode} % \end{macro} % % \begin{macro}{\hbox_unpack:N, \hbox_unpack:c} % \begin{macro}{\hbox_unpack_clear:N, \hbox_unpack_clear:c} % \testfile* % Unpacking a box and if requested also clear it. % \begin{macrocode} \cs_new_eq:NN \hbox_unpack:N \tex_unhcopy:D \cs_new_eq:NN \hbox_unpack_clear:N \tex_unhbox:D \cs_generate_variant:Nn \hbox_unpack:N { c } \cs_generate_variant:Nn \hbox_unpack_clear:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Vertical mode boxes} % % \TeX{} ends these boxes directly with the internal \emph{end_graf} % routine. This means that there is no \cs{par} at the end of vertical % boxes unless we insert one. % % \begin{macro}{\vbox:n} % \TestFiles{m3box003.lvt} % \begin{macro}{\vbox_top:n} % \TestFiles{m3box003.lvt} % Put a vertical box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \vbox:n #1 { \tex_vbox:D { #1 \par } } \cs_new_protected:Npn \vbox_top:n #1 { \tex_vtop:D { #1 \par } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_to_ht:nn,\vbox_to_zero:n} % \begin{macro}{\vbox_to_ht:nn,\vbox_to_zero:n} % \testfile* % Put a vertical box directly into the input stream. % \begin{macrocode} \cs_new_protected:Npn \vbox_to_ht:nn #1#2 { \tex_vbox:D to \dim_eval:w #1 \dim_eval_end: { #2 \par } } \cs_new_protected:Npn \vbox_to_zero:n #1 { \tex_vbox:D to \c_zero_dim { #1 \par } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set:Nn, \vbox_set:cn} % \begin{macro}{\vbox_gset:Nn, \vbox_gset:cn} % \testfile* % Storing material in a vertical box with a natural height. % \begin{macrocode} \cs_new_protected:Npn \vbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_vbox:D { #2 \par } } \cs_new_protected:Npn \vbox_gset:Nn { \tex_global:D \vbox_set:Nn } \cs_generate_variant:Nn \vbox_set:Nn { c } \cs_generate_variant:Nn \vbox_gset:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set_top:Nn, \vbox_set_top:cn} % \begin{macro}{\vbox_gset_top:Nn, \vbox_gset_top:cn} % \testfile* % Storing material in a vertical box with a natural height and reference % point at the baseline of the first object in the box. % \begin{macrocode} \cs_new_protected:Npn \vbox_set_top:Nn #1#2 { \tex_setbox:D #1 \tex_vtop:D { #2 \par } } \cs_new_protected:Npn \vbox_gset_top:Nn { \tex_global:D \vbox_set_top:Nn } \cs_generate_variant:Nn \vbox_set_top:Nn { c } \cs_generate_variant:Nn \vbox_gset_top:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set_to_ht:Nnn,\vbox_set_to_ht:cnn} % \begin{macro}{\vbox_gset_to_ht:Nnn,\vbox_gset_to_ht:cnn} % \testfile* % Storing material in a vertical box with a specified height. % \begin{macrocode} \cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3 { \tex_setbox:D #1 \tex_vbox:D to \dim_eval:w #2 \dim_eval_end: { #3 \par } } \cs_new_protected:Npn \vbox_gset_to_ht:Nnn { \tex_global:D \vbox_set_to_ht:Nnn } \cs_generate_variant:Nn \vbox_set_to_ht:Nnn { c } \cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set:Nw, \vbox_set:cw} % \begin{macro}{\vbox_gset:Nw, \vbox_gset:cw} % \begin{macro}{\vbox_set_end:, \vbox_gset_end:} % \testfile* % Storing material in a vertical box. This type is useful in % environment definitions. % \begin{macrocode} \cs_new_protected:Npn \vbox_set:Nw #1 { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token } \cs_new_protected:Npn \vbox_gset:Nw { \tex_global:D \vbox_set:Nw } \cs_generate_variant:Nn \vbox_set:Nw { c } \cs_generate_variant:Nn \vbox_gset:Nw { c } \cs_new_protected:Npn \vbox_set_end: { \par \c_group_end_token } \cs_new_eq:NN \vbox_gset_end: \vbox_set_end: % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set_inline_begin:N, \vbox_set_inline_begin:c} % \begin{macro}{\vbox_gset_inline_begin:N, \vbox_gset_inline_begin:c} % \begin{macro}{\vbox_set_inline_end:} % \begin{macro}{\vbox_gset_inline_end:} % \testfile* % Renamed September 2011. % \begin{macrocode} \cs_new_eq:NN \vbox_set_inline_begin:N \vbox_set:Nw \cs_new_eq:NN \vbox_set_inline_begin:c \vbox_set:cw \cs_new_eq:NN \vbox_set_inline_end: \vbox_set_end: \cs_new_eq:NN \vbox_gset_inline_begin:N \vbox_gset:Nw \cs_new_eq:NN \vbox_gset_inline_begin:c \vbox_gset:cw \cs_new_eq:NN \vbox_gset_inline_end: \vbox_gset_end: % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_unpack:N, \vbox_unpack:c} % \begin{macro}{\vbox_unpack_clear:N, \vbox_unpack_clear:c} % \testfile* % Unpacking a box and if requested also clear it. % \begin{macrocode} \cs_new_eq:NN \vbox_unpack:N \tex_unvcopy:D \cs_new_eq:NN \vbox_unpack_clear:N \tex_unvbox:D \cs_generate_variant:Nn \vbox_unpack:N { c } \cs_generate_variant:Nn \vbox_unpack_clear:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\vbox_set_split_to_ht:NNn} % \testfile* % Splitting a vertical box in two. % \begin{macrocode} \cs_new_protected:Npn \vbox_set_split_to_ht:NNn #1#2#3 { \tex_setbox:D #1 \tex_vsplit:D #2 to \dim_eval:w #3 \dim_eval_end: } % \end{macrocode} % \end{macro} % % \subsection{Affine transformations} % % \begin{variable}{\l_box_angle_fp} % When rotating boxes, the angle itself may be needed by the % engine-dependent code. This is done using the \pkg{fp} module so % that the value is tidied up properly. % \begin{macrocode} \fp_new:N \l_box_angle_fp % \end{macrocode} % \end{variable} % % \begin{variable}{\l_box_cos_fp, \l_box_sin_fp} % These are used to hold the calculated sine and cosine values while % carrying out a rotation. % \begin{macrocode} \fp_new:N \l_box_cos_fp \fp_new:N \l_box_sin_fp % \end{macrocode} % \end{variable} % % \begin{variable} % {\l_box_top_dim, \l_box_bottom_dim, \l_box_left_dim, \l_box_right_dim} % These are the positions of the four edges of a box before % manipulation. % \begin{macrocode} \dim_new:N \l_box_top_dim \dim_new:N \l_box_bottom_dim \dim_new:N \l_box_left_dim \dim_new:N \l_box_right_dim % \end{macrocode} % \end{variable} % % \begin{variable} % { % \l_box_top_new_dim, \l_box_bottom_new_dim , % \l_box_left_new_dim, \l_box_right_new_dim % } % These are the positions of the four edges of a box after % manipulation. % \begin{macrocode} \dim_new:N \l_box_top_new_dim \dim_new:N \l_box_bottom_new_dim \dim_new:N \l_box_left_new_dim \dim_new:N \l_box_right_new_dim % \end{macrocode} % \end{variable} % % \begin{variable}{\l_box_internal_box, \l_box_internal_fp} % Scratch space. % \begin{macrocode} \box_new:N \l_box_internal_box \fp_new:N \l_box_internal_fp % \end{macrocode} % \end{variable} % % \begin{variable}{\l_box_x_fp, \l_box_y_fp, \l_box_x_new_fp, \l_box_y_new_fp} % Used as the input and output values for a point when manipulation the % location. % \begin{macrocode} \fp_new:N \l_box_x_fp \fp_new:N \l_box_y_fp \fp_new:N \l_box_x_new_fp \fp_new:N \l_box_y_new_fp % \end{macrocode} % \end{variable} % % \begin{macro}{\box_rotate:Nn} % \begin{macro}[aux]{\box_rotate_aux:N} % \begin{macro}[aux]{\box_rotate_set_sin_cos:} % \begin{macro}[aux]{\box_rotate_x:nnN, \box_rotate_y:nnN} % \begin{macro}[aux] % { % \box_rotate_quadrant_one:, \box_rotate_quadrant_two:, % \box_rotate_quadrant_three:, \box_rotate_quadrant_four: % } % Rotation of a box starts with working out the relevant sine and % cosine. There is then a check to avoid doing any real work for the % trivial rotation. % \begin{macrocode} \cs_new_protected:Npn \box_rotate:Nn #1#2 { \hbox_set:Nn #1 { \group_begin: \fp_set:Nn \l_box_angle_fp {#2} \box_rotate_set_sin_cos: \fp_compare:NNNTF \l_box_sin_fp = \c_zero_fp { \fp_compare:NNNTF \l_box_cos_fp = \c_one_fp { \box_use:N #1 } { \box_rotate_aux:N #1 } } { \box_rotate_aux:N #1 } \group_end: } } % \end{macrocode} % The edges of the box are then recorded: the left edge will % always be at zero. Rotation of the four edges then takes place: this is % most efficiently done on a quadrant by quadrant basis. % \begin{macrocode} \cs_new_protected:Npn \box_rotate_aux:N #1 { \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } \dim_zero:N \l_box_left_dim % \end{macrocode} % The next step is to work out the $x$ and $y$ coordinates of vertices of % the rotated box in relation to its original coordinates. The box can be % visualized with vertices $B$, $C$, $D$ and $E$ is illustrated % (Figure~\ref{fig:rotation}). The vertex $O$ is the reference point on the % baseline, and in this implementation is also the centre of rotation. % \begin{figure} % \centering % \setlength{\unitlength}{3pt}^^A % \begin{picture}(34,36)(12,44) % \thicklines % \put(20,52){\dashbox{1}(20,21){}} % \put(20,80){\line(0,-1){36}} % \put(12,58){\line(1, 0){34}} % \put(41,59){A} % \put(40,74){B} % \put(21,74){C} % \put(21,49){D} % \put(40,49){E} % \put(21,59){O} % \end{picture} % \caption{Co-ordinates of a box prior to rotation.} % \label{fig:rotation} % \end{figure} % The formulae are, for a point $P$ and angle $\alpha$: % \[ % \begin{array}{l} % P'_x = P_x - O_x \\ % P'_y = P_y - O_y \\ % P''_x = ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\ % P''_y = ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\ % P'''_x = P''_x + O_x + L_x \\ % P'''_y = P''_y + O_y % \end{array} % \] % The \enquote{extra} horizontal translation $L_x$ at the end is calculated % so that the leftmost point of the resulting box has $x$-coordinate $0$. % This is desirable as \TeX{} boxes must have the reference point at % the left edge of the box. (As $O$ is always $(0,0)$, this part of the % calculation is omitted here.) % \begin{macrocode} \fp_compare:NNNTF \l_box_sin_fp > \c_zero_fp { \fp_compare:NNNTF \l_box_cos_fp > \c_zero_fp { \box_rotate_quadrant_one: } { \box_rotate_quadrant_two: } } { \fp_compare:NNNTF \l_box_cos_fp < \c_zero_fp { \box_rotate_quadrant_three: } { \box_rotate_quadrant_four: } } % \end{macrocode} % The position of the box edges are now known, but the box at this % stage be misplaced relative to the current \TeX{} reference point. So the % content of the box is moved such that the reference point of the % rotated box will be in the same place as the original. % \begin{macrocode} \hbox_set:Nn \l_box_internal_box { \box_use:N #1 } \hbox_set:Nn \l_box_internal_box { \tex_kern:D -\l_box_left_new_dim \hbox:n { \driver_box_rotate_begin: \box_use:N \l_box_internal_box \driver_box_rotate_end: } } % \end{macrocode} % Tidy up the size of the box so that the material is actually inside % the bounding box. The result can then be used to reset the original % box. % \begin{macrocode} \box_set_ht:Nn \l_box_internal_box { \l_box_top_new_dim } \box_set_dp:Nn \l_box_internal_box { -\l_box_bottom_new_dim } \box_set_wd:Nn \l_box_internal_box { \l_box_right_new_dim - \l_box_left_new_dim } \box_use:N \l_box_internal_box } % \end{macrocode} % \end{macro} % \end{macro} % A simple conversion from degrees to radians followed by calculation % of the sine and cosine. % \begin{macrocode} \cs_new_protected:Npn \box_rotate_set_sin_cos: { \fp_set_eq:NN \l_box_internal_fp \l_box_angle_fp \fp_div:Nn \l_box_internal_fp { 180 } \fp_mul:Nn \l_box_internal_fp { \c_pi_fp } \fp_sin:Nn \l_box_sin_fp { \l_box_internal_fp } \fp_cos:Nn \l_box_cos_fp { \l_box_internal_fp } } % \end{macrocode} % These functions take a general point $(|#1|, |#2|)$ and rotate its % location about the origin, using the previously-set sine and cosine % values. Each function gives only one component of the location of the % updated point. This is because for rotation of a box each step needs % only one value, and so performance is gained by avoiding working % out both $x'$ and $y'$ at the same time. Contrast this with % the equivalent function in the \pkg{l3coffins} module, where both parts % are needed. % \begin{macrocode} \cs_new_protected:Npn \box_rotate_x:nnN #1#2#3 { \fp_set_from_dim:Nn \l_box_x_fp {#1} \fp_set_from_dim:Nn \l_box_y_fp {#2} \fp_set_eq:NN \l_box_x_new_fp \l_box_x_fp \fp_set_eq:NN \l_box_internal_fp \l_box_y_fp \fp_mul:Nn \l_box_x_new_fp { \l_box_cos_fp } \fp_mul:Nn \l_box_internal_fp { \l_box_sin_fp } \fp_sub:Nn \l_box_x_new_fp { \l_box_internal_fp } \dim_set:Nn #3 { \fp_to_dim:N \l_box_x_new_fp } } \cs_new_protected:Npn \box_rotate_y:nnN #1#2#3 { \fp_set_from_dim:Nn \l_box_x_fp {#1} \fp_set_from_dim:Nn \l_box_y_fp {#2} \fp_set_eq:NN \l_box_y_new_fp \l_box_y_fp \fp_set_eq:NN \l_box_internal_fp \l_box_x_fp \fp_mul:Nn \l_box_y_new_fp { \l_box_cos_fp } \fp_mul:Nn \l_box_internal_fp { \l_box_sin_fp } \fp_add:Nn \l_box_y_new_fp { \l_box_internal_fp } \dim_set:Nn #3 { \fp_to_dim:N \l_box_y_new_fp } } % \end{macrocode} % Rotation of the edges is done using a different formula for each % quadrant. In every case, the top and bottom edges only need the % resulting $y$-values, whereas the left and right edges need the % $x$-values. Each case is a question of picking out which corner % ends up at with the maximum top, bottom, left and right value. Doing % this by hand means a lot less calculating and avoids lots of % comparisons. % \begin{macrocode} \cs_new_protected:Npn \box_rotate_quadrant_one: { \box_rotate_y:nnN \l_box_right_dim \l_box_top_dim \l_box_top_new_dim \box_rotate_y:nnN \l_box_left_dim \l_box_bottom_dim \l_box_bottom_new_dim \box_rotate_x:nnN \l_box_left_dim \l_box_top_dim \l_box_left_new_dim \box_rotate_x:nnN \l_box_right_dim \l_box_bottom_dim \l_box_right_new_dim } \cs_new_protected:Npn \box_rotate_quadrant_two: { \box_rotate_y:nnN \l_box_right_dim \l_box_bottom_dim \l_box_top_new_dim \box_rotate_y:nnN \l_box_left_dim \l_box_top_dim \l_box_bottom_new_dim \box_rotate_x:nnN \l_box_right_dim \l_box_top_dim \l_box_left_new_dim \box_rotate_x:nnN \l_box_left_dim \l_box_bottom_dim \l_box_right_new_dim } \cs_new_protected:Npn \box_rotate_quadrant_three: { \box_rotate_y:nnN \l_box_left_dim \l_box_bottom_dim \l_box_top_new_dim \box_rotate_y:nnN \l_box_right_dim \l_box_top_dim \l_box_bottom_new_dim \box_rotate_x:nnN \l_box_right_dim \l_box_bottom_dim \l_box_left_new_dim \box_rotate_x:nnN \l_box_left_dim \l_box_top_dim \l_box_right_new_dim } \cs_new_protected:Npn \box_rotate_quadrant_four: { \box_rotate_y:nnN \l_box_left_dim \l_box_top_dim \l_box_top_new_dim \box_rotate_y:nnN \l_box_right_dim \l_box_bottom_dim \l_box_bottom_new_dim \box_rotate_x:nnN \l_box_left_dim \l_box_bottom_dim \l_box_left_new_dim \box_rotate_x:nnN \l_box_right_dim \l_box_top_dim \l_box_right_new_dim } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{variable}{\l_box_scale_x_fp, \l_box_scale_y_fp} % Scaling is potentially-different in the two axes. % \begin{macrocode} \fp_new:N \l_box_scale_x_fp \fp_new:N \l_box_scale_y_fp % \end{macrocode} % \end{variable} % % \begin{macro}{\box_resize:Nnn, \box_resize:cnn} % \begin{macro}[aux]{\box_resize_aux:Nnn} % Resizing a box starts by working out the various dimensions of the % existing box. % \begin{macrocode} \cs_new_protected:Npn \box_resize:Nnn #1#2#3 { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } \dim_zero:N \l_box_left_dim % \end{macrocode} % The $x$-scaling and resulting box size is easy enough to work % out: the dimension is that given as |#2|, and the scale is simply the % new width divided by the old one. % \begin{macrocode} \fp_set_from_dim:Nn \l_box_scale_x_fp {#2} \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_right_dim } \fp_div:Nn \l_box_scale_x_fp { \l_box_internal_fp } % \end{macrocode} % The $y$-scaling needs both the height and the depth of the current box. % \begin{macrocode} \fp_set_from_dim:Nn \l_box_scale_y_fp {#3} \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_top_dim - \l_box_bottom_dim } \fp_div:Nn \l_box_scale_y_fp { \l_box_internal_fp } % \end{macrocode} % At this stage, check for trivial scaling. If both scalings are unity, then % the code does nothing. Otherwise, pass on to the auxiliary function to % find the new dimensions. % \begin{macrocode} \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp { \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp { \box_use:N #1 } { \box_resize_aux:Nnn #1 {#2} {#3} } } { \box_resize_aux:Nnn #1 {#2} {#3} } \group_end: } } \cs_generate_variant:Nn \box_resize:Nnn { c } % \end{macrocode} % With at least one real scaling to do, the next phase is to find the new % edge co-ordinates. In the $x$~direction this is relatively easy: just % scale the right edge. This is done using the absolute value of the % scale so that the new edge is in the correct place. In the $y$~direction, % both dimensions have to be scaled, and this again needs the absolute % scale value. Once that is all done, the common resize/rescale code can % be employed. % \begin{macrocode} \cs_new_protected:Npn \box_resize_aux:Nnn #1#2#3 { \dim_compare:nNnTF {#2} > \c_zero_dim { \dim_set:Nn \l_box_right_new_dim {#2} } { \dim_set:Nn \l_box_right_new_dim { \c_zero_dim - ( #2 ) } } \dim_compare:nNnTF {#3} > \c_zero_dim { \dim_set:Nn \l_box_top_new_dim { \fp_use:N \l_box_scale_y_fp \l_box_top_dim } \dim_set:Nn \l_box_bottom_new_dim { \fp_use:N \l_box_scale_y_fp \l_box_bottom_dim } } { \dim_set:Nn \l_box_top_new_dim { - \fp_use:N \l_box_scale_y_fp \l_box_top_dim } \dim_set:Nn \l_box_bottom_new_dim { - \fp_use:N \l_box_scale_y_fp \l_box_bottom_dim } } \box_resize_common:N #1 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn} % \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn} % Scaling to a total height or to a width is a simplified version of the main % resizing operation, with the scale simply copied between the two parts. The % internal auxiliary is called using the scaling value twice, as the sign for % both parts is needed (as this allows the same internal code to be used as % for the general case). % \begin{macrocode} \cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2 { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } \dim_zero:N \l_box_left_dim \fp_set_from_dim:Nn \l_box_scale_y_fp {#2} \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_top_dim - \l_box_bottom_dim } \fp_div:Nn \l_box_scale_y_fp { \l_box_internal_fp } \fp_set_eq:NN \l_box_scale_x_fp \l_box_scale_y_fp \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp { \box_use:N #1 } { \box_resize_aux:Nnn #1 {#2} {#2} } \group_end: } } \cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c } \cs_new_protected:Npn \box_resize_to_wd:Nn #1#2 { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } \dim_zero:N \l_box_left_dim \fp_set_from_dim:Nn \l_box_scale_x_fp {#2} \fp_set_from_dim:Nn \l_box_internal_fp { \l_box_right_dim } \fp_div:Nn \l_box_scale_x_fp { \l_box_internal_fp } \fp_set_eq:NN \l_box_scale_y_fp \l_box_scale_x_fp \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp { \box_use:N #1 } { \box_resize_aux:Nnn #1 {#2} {#2} } \group_end: } } \cs_generate_variant:Nn \box_resize_to_wd:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\box_scale:Nnn, \box_scale:cnn} % \begin{macro}[aux]{\box_scale_aux:Nnn} % When scaling a box, setting the scaling itself is easy enough. The % new dimensions are also relatively easy to find, allowing only for % the need to keep them positive in all cases. Once that is done then % after a check for the trivial scaling a hand-off can be made to the % common code. The dimension scaling operations are carried out using % the \TeX{} mechanism as it avoids needing to use \texttt{fp} % operations. % \begin{macrocode} \cs_new_protected:Npn \box_scale:Nnn #1#2#3 { \hbox_set:Nn #1 { \group_begin: \fp_set:Nn \l_box_scale_x_fp {#2} \fp_set:Nn \l_box_scale_y_fp {#3} \dim_set:Nn \l_box_top_dim { \box_ht:N #1 } \dim_set:Nn \l_box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l_box_right_dim { \box_wd:N #1 } \dim_zero:N \l_box_left_dim \fp_compare:NNNTF \l_box_scale_x_fp = \c_one_fp { \fp_compare:NNNTF \l_box_scale_y_fp = \c_one_fp { \box_use:N #1 } { \box_scale_aux:Nnn #1 {#2} {#3} } } { \box_scale_aux:Nnn #1 {#2} {#3} } \group_end: } } \cs_generate_variant:Nn \box_scale:Nnn { c } \cs_new_protected:Npn \box_scale_aux:Nnn #1#2#3 { \fp_compare:NNNTF \l_box_scale_y_fp > \c_zero_fp { \dim_set:Nn \l_box_top_new_dim { #3 \l_box_top_dim } \dim_set:Nn \l_box_bottom_new_dim { #3 \l_box_bottom_dim } } { \dim_set:Nn \l_box_top_new_dim { -#3 \l_box_bottom_dim } \dim_set:Nn \l_box_bottom_new_dim { -#3 \l_box_top_dim } } \fp_compare:NNNTF \l_box_scale_x_fp > \c_zero_fp { \l_box_right_new_dim #2 \l_box_right_dim } { \l_box_right_new_dim -#2 \l_box_right_dim } \box_resize_common:N #1 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int]{\box_resize_common:N} % The main resize function places in input into a box which will start % of with zero width, and includes the handles for engine rescaling. % \begin{macrocode} \cs_new_protected:Npn \box_resize_common:N #1 { \hbox_set:Nn \l_box_internal_box { \driver_box_scale_begin: \hbox_overlap_right:n { \box_use:N #1 } \driver_box_scale_end: } % \end{macrocode} % The new height and depth can be applied directly. % \begin{macrocode} \box_set_ht:Nn \l_box_internal_box { \l_box_top_new_dim } \box_set_dp:Nn \l_box_internal_box { \l_box_bottom_new_dim } % \end{macrocode} % Things are not quite as obvious for the width, as the reference point % needs to remain unchanged. For positive scaling factors resizing the % box is all that is needed. However, for case of a negative scaling % the material must be shifted such that the reference point ends up in % the right place. % \begin{macrocode} \fp_compare:NNNTF \l_box_scale_x_fp < \c_zero_fp { \hbox_to_wd:nn { \l_box_right_new_dim } { \tex_kern:D \l_box_right_new_dim \box_use:N \l_box_internal_box \tex_hss:D } } { \box_set_wd:Nn \l_box_internal_box { \l_box_right_new_dim } \box_use:N \l_box_internal_box } } % \end{macrocode} % \end{macro} % % \subsection{Viewing part of a box} % % \begin{macro}{\box_clip:N, \box_clip:c} % A wrapper around the driver-dependent code. % \begin{macrocode} \cs_new_protected:Npn \box_clip:N #1 { \hbox_set:Nn #1 { \driver_box_use_clip:N #1 } } \cs_generate_variant:Nn \box_clip:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\box_trim:Nnnnn, \box_trim:cnnnn} % Trimming from the left- and right-hand edges of the box is easy. The total % width is set to remove from the right, and a skip will shift the material % to remove from the left. % \begin{macrocode} \cs_new_protected:Npn \box_trim:Nnnnn #1#2#3#4#5 { \box_set_wd:Nn #1 { \box_wd:N #1 - \dim_eval:n {#4} - \dim_eval:n {#2} } \hbox_set:Nn #1 { \skip_horizontal:n { - \dim_eval:n {#2} } \box_use:N #1 } % \end{macrocode} % For the height and depth, there is a need to watch the baseline is % respected. Material always has to stay on the correct side, so trimming % has to check that there is enough material to trim. % \begin{macrocode} \dim_compare:nNnTF { \box_dp:N #1 } > {#3} { \box_set_dp:Nn #1 { \box_dp:N #1 - \dim_eval:n {#3} } } { \hbox_set:Nn #1 { \box_move_down:nn { \dim_eval:n {#3} - \box_dp:N #1 } { \box_use:N #1 } } \box_set_dp:Nn #1 \c_zero_dim } \dim_compare:nNnTF { \box_ht:N #1 } > {#5} { \box_set_ht:Nn #1 { \box_ht:N #1 - \dim_eval:n {#5} } } { \hbox_set:Nn #1 { \box_move_up:nn { \dim_eval:n {#5} - \box_ht:N #1 } { \box_use:N #1 } } \box_set_ht:Nn #1 \c_zero_dim } } \cs_generate_variant:Nn \box_trim:Nnnnn { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\box_viewport:Nnnnn, \box_viewport:cnnnn} % The same general logic as for clipping, but with absolute dimensions. % Thus again width is easy and height is harder. % \begin{macrocode} \cs_new_protected:Npn \box_viewport:Nnnnn #1#2#3#4#5 { \box_set_wd:Nn #1 { \dim_eval:n {#4} - \dim_eval:n {#2} } \hbox_set:Nn #1 { \skip_horizontal:n { - \dim_eval:n {#2} } \box_use:N #1 } \dim_compare:nNnTF {#3} > \c_zero_dim { \hbox_set:Nn #1 { \box_move_down:nn {#3} { \box_use:N #1 } } \box_set_dp:Nn #1 \c_zero_dim } { \box_set_dp:Nn #1 { - \dim_eval:n {#3} } } \dim_compare:nNnTF {#5} > \c_zero_dim { \box_set_ht:Nn #1 {#5} } { \hbox_set:Nn #1 { \box_move_up:nn { -\dim_eval:n {#5} } { \box_use:N #1 } } \box_set_ht:Nn #1 \c_zero_dim } } \cs_generate_variant:Nn \box_viewport:Nnnnn { c } % \end{macrocode} % \end{macro} % % \subsection{Deprecated functions} % % \begin{variable}{\l_last_box} % Deprecated 2011-11-13, for removal by 2012-02-28. % \begin{macrocode} \cs_new_eq:NN \l_last_box \tex_lastbox:D % \end{macrocode} % \end{variable} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex