\def\stackengineversionnumber{v4.11} \ProvidesPackage{stackengine} [2021/07/22 \stackengineversionnumber\ Stacking text and objects in convenient ways] % 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.3c or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Steven B. Segletes. % % V1.0 -Initial release. % V2.0 -Revised syntax, making \Sstackgap=len, \Lstackgap=len syntax % obsolete. New syntax is \setstackgap{S}{len} and % \setstackgap{L}{len} % -Condensed several routines % -Revised documentation for clarity and to eliminate typos. % -Added \toplap and \bottomlap. % -Disallowed \quietstack for lapping. % -added \abovebaseline % V3.0 -Added \stackMath and \stackText macros to treat arguments, % by default, in math mode or not. % V3.1 -Added \hsmash, for zero-width, center-aligned argument (note: % other alignments can be achieved with \llap and \rlap) % -Eliminated need for \usepackage{readarray} through the % implementation of \@readMANYrows and \@processROW % -Added [usestackEOL] package option to use \\ separator, rather % than space separator in \Shortstack, \Longstack, % \Shortunderstack, and \Longunderstack % -Implemented \setstackEOL to define new separator in \Shortstack, % \Longstack, \Shortunderstack, and \Longunderstack % -Renamed some package internal variables with @... % -Added \addstackgap to place vertical gap above and below an % existing stack. Negative gaps have no effect. % -Added \stackinset, deprecates \topinset & \bottominset. % -allow c \stackalignment on \stackinset, \topinset, and % \bottominset to have meaning (rightward offset relative to % centerline, can be positive or negative). % -Forced \useanchorwidth{T} for insets, since otherwise the % stackwidth could vary for reasons not obvious to user. % -Added \strutlongstacks{} mode for auto-adding a strut to % each row of a long stack % -Recommend \strutshortanchors{} mode in preference to % \def\usestackstrut{} definition (now deprecated). % V3.11 -Corrected bug in \stackinset which did not condition the % anchor when using vertical centering in \stackMath mode % V3.2 -Incorporated changes suggested by E. Gregorio to make robust % the supporting macro \@readMANYrows % -Introduced routines: \Centerstack, \Vectorstack, \parenVectorstack % \bracketVectorstack, \braceVectorstack, \vertvectorstack, % and \ensurestackMath % V3.21 -Corrected a bug in \stackinset introduced in V3.11 % V3.22 -Removed \usepackage{calc} % -Corrected \@STRT placement to not inadvertantly force a \mathop % on rows beginning with a minus sign. % V3.23 -Made EOL-separated stacks (i.e., \Longstack, \Shortstack, % \Centerstack, \Vectorstack, etc.) work properly when a single % (unstacked) row is input. % -Noted in documentation that while EOL-separated stacks % ignore leading/trailing spaces in their arguments (unless the % EOL itself is a space token), the \stackon / \stackunder % family of macros do not ignore spaces in their arguments. % -Reinstated \usepackage{calc} (Oops!) % V3.24 -Replaced references to \roman with \romannumeral, since \roman % is redefined by packages like spanish babel. % V3.25 -Default longstack gap is now \normalbaselineskip, so as to % automatically work in tabular environments. % V3.26 -V3.25 on partially fixed the problem of \normalbaselineskip. % V4.00 -Incorporate listofitems package methodology for parsing, requiring % some package rewrite, primarily macro \@readMANYrows. % -Eliminated all uses of \protected@edef.fxf % V4.01 -Removed unnecessary\global specifiers from \newlength and % \setlength, which could also cause potential problems with the % calc package. % -Changed \global\def to \gdef and \global\edef to \xdef. % V4.1 -Removed \widthof type measurements in \stackinset and % \stackengine, instead setting things in saveboxes from the % outset and using \wd, thereby only setting stacked content % once. This is helpful for speed and also if counters are % present in arguments, which are now incremented only once. % -Save and restore counter entering/exiting \@stack, which % favorably resolves issue of nesting for multi-row stacks. % -Introduce \lstackMath and \lstackText as local versions of % \stackMath and \stackText (which are global). % -Eliminated \usestackstrut (became internal \@usestackstrut) % V4.11 -Renamed \@backgroundbox to \se@backgroundbox, to avoid % conflict with adjustbox package. Thanks to % samuel.wein AT uni-tuebingen.de for the tip. \RequirePackage{etoolbox} \RequirePackage{listofitems}% REQUIRES listofitems.sty AND listofitems.tex \usepackage{calc} \newtoggle{@doneROWreads} \newtoggle{stackloop@done} \newcounter{@stackindex} \newlength\@boxshift \newlength\stack@tmplength \newlength\temp@stkl \newlength\@stackedboxwidth \newsavebox\@addedbox \newsavebox\@anchorbox \newsavebox\@insetbox \newsavebox\se@backgroundbox \newsavebox\stackedbox \newsavebox{\@centerbox} \newcounter{ROWcellindex@} %% Following 3 lines thanks to Prof. Enrico Gregorio, from: %% http://tex.stackexchange.com/questions/42318/ \begingroup\lccode`\|=`\\ \lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}} \newcommand{\stack@macro@name}[1]{\expandafter\removebs\string#1} %% Following macro was, in V3.2, made robust with the help of %% Prof. Enrico Gregorio. See: %% http://tex.stackexchange.com/questions/137298/ \newcommand\setstackEOL[1]{% \ifstrempty{#1}{\def\SEP@char{ }}{\def\SEP@char{#1}}% } % FOR PROCESSING A GROUP OF STACK ROWS SEPARATED BY \SEP@char % EMPLOYS listofitems PACKAGE, AS OF V4.0 \newcommand\@readMANYrows[1]{% \expandafter\setsepchar\expandafter{\SEP@char}% \readlist*\stack@arg{#1}% \edef\stackengine@args{\stack@arglen}% } %%%%% % PROCESS PACKAGE OPTIONS \newif\ifstackengine@oldsyntax \newif\ifstackengine@usestackEOL \DeclareOption{oldsyntax}{\stackengine@oldsyntaxtrue} \DeclareOption{usestackEOL}{\stackengine@usestackEOLtrue} \ProcessOptions\relax \ifstackengine@oldsyntax% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%% THIS VERSION 1.0 SYNTAX WAS PHASED OUT %%%%%%%%%%%%%%%%%%% %%%%% (but can invoke with \usepackage[oldsyntax]{stackengine} ) \newlength\Sstackgap\newlength\Lstackgap \newcommand\stackgap{\if S\stacktype\the\Sstackgap\else\the\Lstackgap\fi} \setlength{\Sstackgap}{3pt} \setlength{\Lstackgap}{\normalbaselineskip} \else% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%% AND REPLACED WITH THE FOLLOWING %%%%%%%%%%%%%%%%%%%%%%%%%% % Again, thanks to Prof. Gregorio for his lucid explanation that helped % improve this package. See: % http://tex.stackexchange.com/questions/123443/ % defining-a-length-that-scales-with-fontsize-changes/123470#123470 \newcommand{\setstackgap}[2]{\@namedef{#1stackgap}{#2}} \newcommand\stackgap{\@nameuse{\if S\stacktype S\else L\fi stackgap}\relax} \setstackgap{S}{3pt}% SHORTSTACKING GAP BETWEEN ITEMS (SAME AS \shortstack) \setstackgap{L}{\normalbaselineskip}% LONGSTACKING BASELINESKIP (\normalbaselineskip) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi \ifstackengine@usestackEOL% % USE \\ AS SEPERATOR IN \Shortstack, \Longstack, % \Shortunderstack, and \Longunderstack \setstackEOL{\\} \else % USE SPACE TOKEN AS SEPERATOR IN \Shortstack, \Longstack, % \Shortunderstack, and \Longunderstack \setstackEOL{ } \fi %%%%% PACKAGE DEFAULT DEFINITIONS \def\useanchorwidth{F}% T= FORCE BOX WIDTH TO ANCHOR-WIDTH \def\quietstack{F}% T = SUPPRESS OUTPUT OF ALL COMMANDS % (USE \usebox{\stackedbox} TO RETRIEVE) \def\stackalignment{c}% l, c, or r for left, center or right alignment \def\stacktype{S}% S for constant gap shortstack; % L for constant baselineskip longstack %%%%% MODES \newcommand\stackMath{\gdef\stack@delim{$}} \newcommand\stackText{\gdef\stack@delim{}} \newcommand\lstackMath{\def\stack@delim{$}} \newcommand\lstackText{\def\stack@delim{}} \stackText \newcommand\strutlongstacks[1]{\def\@strutlongstacks{#1}} \strutlongstacks{F} \newcommand\strutshortanchors[1]{\def\@usestackstrut{#1}} \strutshortanchors{T} %%%%% MACROS %\stackengine{\Sstackgap or \Lstackgap or \stackgap or stacklength} % {anchor} % {item} % {O or U} % {\stackalignment or l or c or r} % {\quietstack or T or F} % {\useanchorwidth or T or F} % {\stacktype or S or L} \newcommand*\stackengine[8]{% \def\@STRT{}% \if T\@strutlongstacks\if L#8\def\@STRT{\strut}\fi\fi% \sbox{\stackedbox}{% \sbox{\@anchorbox}{\@STRT\stack@delim#2\stack@delim}% \sbox{\@addedbox}{\@STRT\stack@delim#3\stack@delim}% \setlength{\@stackedboxwidth}{\wd\@anchorbox}% \if F#7% \ifdim\wd\@addedbox>\@stackedboxwidth% \setlength{\@stackedboxwidth}{\wd\@addedbox}% \fi% \fi% \setlength{\@boxshift}{#1}% \if L#8% \if U#4% \setlength{\@boxshift}{-\@boxshift}% \fi% \else% \if U#4% \setlength{\@boxshift}{-\dp\@anchorbox -\ht\@addedbox -\@boxshift}% \else% \setlength{\@boxshift}{\ht\@anchorbox +\dp\@addedbox +\@boxshift}% \fi% \fi% \if c#5% \hspace{.5\@stackedboxwidth}% \hspace{-.5\wd\@anchorbox}% \usebox{\@anchorbox}% \hspace{-.5\wd\@anchorbox}% \hspace{-.5\wd\@addedbox}% \raisebox{\@boxshift}{\usebox{\@addedbox}}% \hspace{-.5\wd\@addedbox}% \hspace{.5\@stackedboxwidth}% \else% \if l#5% \usebox{\@anchorbox}% \hspace{-\wd\@anchorbox}% \raisebox{\@boxshift}{\usebox{\@addedbox}}% \hspace{-\wd\@addedbox}% \hspace{\@stackedboxwidth}% \else% \if r#5% \hspace{\@stackedboxwidth}% \hspace{-\wd\@anchorbox}% \usebox{\@anchorbox}% \hspace{-\wd\@addedbox}% \raisebox{\@boxshift}{\usebox{\@addedbox}}% \fi% \fi% \fi% }% \if F#6\usebox{\stackedbox}\fi% } \newcommand*\stackunder[3][\stackgap]{\stackengine% {#1}{#2}{#3}{U}{\stackalignment}{\quietstack}{\useanchorwidth}{\stacktype}} \newcommand*\stackon[3][\stackgap]{\stackengine% {#1}{#2}{#3}{O}{\stackalignment}{\quietstack}{\useanchorwidth}{\stacktype}} \newcommand*\Shortstack[2][\stackalignment]{\@stack{#1}{#2}{O}{S}} \newcommand*\Longstack[2][\stackalignment]{\@stack{#1}{#2}{O}{L}} \newcommand*\Shortunderstack[2][\stackalignment]{\@stack{#1}{#2}{U}{S}} \newcommand*\Longunderstack[2][\stackalignment]{\@stack{#1}{#2}{U}{L}} \newcommand*\@stack[4]{% \edef\sv@stackindex{\the@stackindex}% \bgroup% SO AS NOT TO INTERFERE WITH loi's \setsepchar \@readMANYrows{#2}% \if U#3% \setcounter{@stackindex}{\stackengine@args}% \def\@stacksign{-}% \def\@stackcondition{\the@stackindex > 1}% \else% \setcounter{@stackindex}{1}% \def\@stacksign{}% \def\@stackcondition{\the@stackindex < \stackengine@args}% \fi% \def\@STRT{}% \if T\@strutlongstacks\if L#4\def\@STRT{\strut}\fi\fi% \sbox{\stackedbox}{% \@STRT\stack@delim\ignorespaces% \stack@arg[\the@stackindex]% \unskip\stack@delim}% \ifnum\stackengine@args>1% \togglefalse{stackloop@done}% \else% \toggletrue{stackloop@done}% \fi% \whileboolexpr{test {\nottoggle{stackloop@done}}}{% \addtocounter{@stackindex}{\@stacksign 1}% \stackengine{\csname#4stackgap\endcsname}% {\stack@arg[\the@stackindex]}% {\usebox{\stackedbox}}{#3}{#1}{T}{\useanchorwidth}{#4}% \ifnum\@stackcondition\else\toggletrue{stackloop@done}\fi% }% \if F\quietstack\usebox{\stackedbox}\fi% \egroup% \setcounter{@stackindex}{\sv@stackindex}% } % PERHAPS THESE SIX MACROS CAN BE REPLACED BY \toplap AND \bottomlap \newcommand*\tllap[2][\Lstackgap]{\@stacklap{#1}{l}{#2}{O}} \newcommand*\tclap[2][\Lstackgap]{\@stacklap{#1}{c}{#2}{O}} \newcommand*\trlap[2][\Lstackgap]{\@stacklap{#1}{r}{#2}{O}} \newcommand*\bllap[2][\Lstackgap]{\@stacklap{#1}{l}{#2}{U}} \newcommand*\bclap[2][\Lstackgap]{\@stacklap{#1}{c}{#2}{U}} \newcommand*\brlap[2][\Lstackgap]{\@stacklap{#1}{r}{#2}{U}} \newcommand*\toplap[3][\Lstackgap]{\@stacklap{#1}{#2}{#3}{O}} \newcommand*\bottomlap[3][\Lstackgap]{\@stacklap{#1}{#2}{#3}{U}} \newcommand*\@stacklap[4]{% \if l#2\stackengine{#1}{}{#3}{#4}{r}{F}{T}{L}\else% \if r#2\stackengine{#1}{}{#3}{#4}{l}{F}{T}{L}\else% \stackengine{#1}{}{#3}{#4}{c}{F}{T}{L}% \fi% \fi } \newcommand*\hsmash[1]{\stackengine{0pt}{}{#1}{O}{c}{F}{T}{L}} \newcommand*\stackanchor[3][\stackgap]{% \setlength{\stack@tmplength}{#1}% \setlength{\stack@tmplength}{.5\stack@tmplength}% \if T\@usestackstrut% \if S\stacktype\addtolength{\stack@tmplength}% {.5\ht\strutbox-.5\dp\strutbox}\fi% \fi% \stackengine{\stack@tmplength}{}{#2}{O}{\stackalignment}{T}{F}{\stacktype}% \if T\@usestackstrut% \if S\stacktype\addtolength{\stack@tmplength}% {-\ht\strutbox+\dp\strutbox}\fi% \fi% \stackengine{\stack@tmplength}{\usebox{\stackedbox}}{#3}{U}% {\stackalignment}{\quietstack}{F}{\stacktype}% } \newcommand*\abovebaseline[2][\stackgap]{% \stackengine{#1}{}{#2}{O}{\stackalignment}{\quietstack}{F}{\stacktype}} \newcommand*\belowbaseline[2][\stackgap]{% \stackengine{#1}{}{#2}{U}{\stackalignment}{\quietstack}{F}{\stacktype}} \newcommand*\savestack[2]{% \xdef\sv@name{\stack@macro@name{#1}}% \@ifundefined{\sv@name content}{% \expandafter\newsavebox\expandafter{\csname\sv@name content\endcsname}% }{}% \expandafter\sbox\csname\sv@name content\endcsname{#2}% \expandafter\def\expandafter#1\expandafter{\expandafter\usebox\expandafter% {\csname\sv@name content\endcsname}}% } \newcommand*\addstackgap[2][\Sstackgap]{\stackengine{#1}{% \stackengine{#1}{#2}{}{O}{c}{\quietstack}{T}{S}}{}{U}{c}{\quietstack}{T}{S}} \newcommand*\topinset[4]{\stackinset{\stackalignment}{#4}{t}{#3}{#1}{#2}}% DEPRECATED \newcommand*\bottominset[4]{\stackinset{\stackalignment}{#4}{b}{#3}{#1}{#2}}% DEPRECATED %\stackinset{l/c/r}{x}{b/c/t}{y}{inset}{anchor} \newcommand*\stackinset[6]{% \sbox\se@backgroundbox{\stack@delim#6\stack@delim}% \sbox\@insetbox{\stack@delim#5\stack@delim}% \ifstrequal{#4}{}% {\setlength{\stack@tmplength}{0pt}}% {\setlength{\stack@tmplength}{#4}}% \if c#3% \setlength{\temp@stkl}{\ht\se@backgroundbox+\dp\se@backgroundbox% -\ht\@insetbox-\dp\@insetbox}% \addtolength{\stack@tmplength}{.5\temp@stkl}% \fi% \ifstrequal{#2}{}{\def\stack@tmp{0pt}}{\def\stack@tmp{#2}}% \def\stack@lroffset{\rule{\stack@tmp}{0pt}}% \addtolength{\stack@tmplength}{\ht\@insetbox+\dp\@insetbox}% \if c#1% \def\conditioned@inset{\stack@lroffset\stack@lroffset\usebox{\@insetbox}}% \else% \def\conditioned@inset{\stack@lroffset\usebox{\@insetbox}\stack@lroffset}% \fi% \stackengine{-\stack@tmplength}{\usebox{\se@backgroundbox}}% {\conditioned@inset}{\inset@valign{#3}}{#1}{\quietstack}{T}{S}% } \def\inset@valign#1{\if t#1O\else U\fi} \newcommand\Centerstack[2][\stackalignment]{% \sbox{\@centerbox}{\strutlongstacks{T}\Longstack[#1]{#2}}% \raisebox{-.5\ht\@centerbox+.5\ht\strutbox}{\usebox{\@centerbox}}} \newcommand\Vectorstack[2][\stackalignment]{% \ensurestackMath{\Centerstack[#1]{#2}}} \newcommand\parenVectorstack[2][\stackalignment]{% \ensurestackMath{\left(\Centerstack[#1]{#2}\right)}} \newcommand\bracketVectorstack[2][\stackalignment]{% \ensurestackMath{\left[\Centerstack[#1]{#2}\right]}} \newcommand\braceVectorstack[2][\stackalignment]{% \ensurestackMath{\left\{\Centerstack[#1]{#2}\right\}}} \newcommand\vertVectorstack[2][\stackalignment]{% \ensurestackMath{\left|\Centerstack[#1]{#2}\right|}} \newcommand\ensurestackMath[1]{% \let\sv@stackmode\stack@delim\stackMath% #1\global\let\stack@delim\sv@stackmode} \endinput