\ifx\BORDER\relax\endinput\else\let\BORDER=\relax\fi % \input only once % % border.tex: Macros to typeset borders. % version: 1.0 release: 21 October 1991 % % copyright (c) 1991 Marcel R. van der Goot % You can use these macros to typeset documents. You may % distribute this file freely, provided that you also distribute % the accompanying documentation. % You may make changes to this file, or extract portions % of it for inclusion in other files, provided that % (1) you change the name of the file; % (2) you give proper credit and include copyright % information where applicable; % (3) explain how an unchanged version can be obtained; and % (4) document the usage of your macros/changes (if usage % of your macros is not worth documenting, they must not % be worth using). % You are not allowed to use the name ``Midnight Macros'' for % any changed files. % The above rules for making changes do not apply where it % is explicitly noted in this file that something can be changed % to conform to your local installation. % % USAGE: % See the file border.doc % % original: csvax.cs.caltech.edu [131.215.131.131] in pub/tex % (use anonymous ftp). Also in various archives. % % Caltech, Pasadena --- Marcel van der Goot % marcel@cs.caltech.edu % Caltech 256--80 % Pasadena, CA 91125 % USA % (818) 356--4603 % % update history: % version 1.0: This one. % release 21 Oct 1991: The original % %%%%%% CODE: (you don't need to read this to use the macros) \edef\borderelm{\the\catcode`\_} % minor trick to remember the catcode \catcode`\_=11% letter, to make private macros % Note: we use \box0, \box2, \box4, \dimen0, \dimen2, and \count2, rather than % allocating new boxes, dimensions, and counts. That is usually ok because all % assignments are done within \hbox{...} or \vbox{...}, which provides % grouping. %%%%%%% exactly fitting border with overlaps % \border makes a border of the specified dimensions, by overlapping some % of the elements when necessary. % \hborder takes four arguments, the width, and the indices of the left % element, the middle element, and the right element. It makes an horizontal % border of the form \hbox to wd{ l m+ r }, where there is at least one m. % If wd is large enough to set at least {l m r}, all overlap is between % elements of type m. In the unusual case where wd is too small, the overlap % is necessarily with the corner elements. \def\hborder#1#2#3#4% wd, l, m, r {\hbox to#1 {\setbox0=\hbox{\borderelm#3}% \borderelm#2% \hskip0pt minus1fil % \copy0\kern-.5\wd0 % \cleaders\copy0\hskip0pt plus1fil % \kern-.5\wd0\copy0 % \hskip0pt minus1fil % \borderelm#4% }% } % \border does the vertical equivalent of \hborder: the top and bottom % elements are hboxes generated with \hborder, and the middle element is % an \hbox{ l \hss r }. This middle element is again used at least once, % and if possible all overlap will be among middle elements. % The \kern0sp at the end is to get depth 0, rather than the depth of % the last hbox. (\boxmaxdepth is set to the largest possible value to make % sure that the depth is indeed 0, not negative.) \def\border#1#2% ht, wd {\vbox to#1 {\offinterlineskip\boxmaxdepth=\maxdimen \dimen2=#2 \setbox0=\hbox to\dimen2{\borderelm3\hss\borderelm4} \dimen0=\ht0 \advance\dimen0 by\dp0 \hborder{\dimen2}012 \vskip0pt minus1fil \copy0\kern-.5\dimen0 \cleaders\copy0\vskip0pt plus1fil \kern-.5\dimen0\copy0 \vskip0pt minus1fil \hborder{\dimen2}567 \kern0sp }% } %%%%%%% exactly fitting border with spaces % \xborder also makes a border of the specified dimensions, but rather than % overlapping elements, it leaves space between the elements. % \xhborder makes a horizontal border. Unlike \hborder, there are zero (not % one) or more middle elements. The extra space is equally distributed % between all the elements. \def\hxborder#1#2#3#4% wd, l, m, r {\hbox to#1 {\setbox0=\hbox{\borderelm#3}% \borderelm#2% \xleaders\copy0\hskip0pt plus1fil minus1fil % \borderelm#4% }% } % \xborder is to \hxborder as \border is to \hborder. \def\xborder#1#2% ht, wd {\vbox to#1 {\offinterlineskip\boxmaxdepth=\maxdimen \dimen2=#2 \setbox0=\hbox to\dimen2{\borderelm3\hss\borderelm4} \hxborder{\diemn2}012 \xleaders\copy0\vskip0pt plus1fil minus1fil \hxborder{\dimen2}567 \kern0sp }% } %%%%%%% rounded border with abutting elements % \plusborder and \minusborder make borders with abutted elements (no % overlaps, no spaces). To make this possible, the border dimensions are % rounded so that an integral number of elements fits. \plusborder rounds % up, \minusborder rounds down. \plusgray and \minusgray are similiar, except % that \borderelm8 is used as center element (normally the center is white). % \plus_border and \minus_border are used for both, where the 3rd argument % indicates whether there is a center element. % The computation consists of determining the space D that has to be % filled with middle elements. If the width of the middle element is d, % there fit (D div d) middle element in a `minus border.' % To avoid minor inaccuracies in the arithmetic, what we actually do is % (D+100sp) div d. 100sp is so small as to be invisible. \def\hminusborder#1#2#3#4% wd, l, m, r {\hbox {\dimen0=#1\count2=\dimen0 % \setbox0=\hbox{\borderelm#2}\advance\count2 by-\wd0 % \setbox0=\hbox{\borderelm#4}\advance\count2 by-\wd0 % \setbox0=\hbox{\borderelm#3}% \advance\count2 by100 % \divide\count2 by\wd0 % \borderelm#2% \cleaders\copy0\hskip\count2\wd0 % \borderelm#4% }% } \def\minus_border#1#2#3% ht, wd, #3=empty ==> no center element {\vbox {\offinterlineskip\boxmaxdepth=\maxdimen \dimen2=#2\relax \dimen0=#1\count2=\dimen0 \setbox0=\hminusborder{\dimen2}012 \advance\count2 by-\ht0 \advance\count2 by-\dp0 \setbox2=\hminusborder{\dimen2}567 \advance\count2 by-\ht2 \advance\count2 by-\dp2 \if.#3.\setbox4=\hbox to\wd0{\borderelm3\hss\borderelm4} \else \setbox4=\hminusborder{\dimen2}384 \fi \advance\count2 by100 \dimen0=\ht4\advance\dimen0 by\dp4 \divide\count2 by\dimen0 \box0 \cleaders\copy4\vskip\count2\dimen0 \box2 \kern0sp }% } \def\minusborder#1#2{\minus_border{#1}{#2}{}} \def\minusgray#1#2{\minus_border{#1}{#2}{1}} % Rounding upwards is achieved with (D + d - 1) div d, but again, we % actually do (D + d - 100sp) div d. \def\hplusborder#1#2#3#4% wd, l, m, r {\hbox {\dimen0=#1\count2=\dimen0 % \setbox0=\hbox{\borderelm#2}\advance\count2 by-\wd0 % \setbox0=\hbox{\borderelm#4}\advance\count2 by-\wd0 % \setbox0=\hbox{\borderelm#3}% \advance\count2 by\wd0\advance\count2 by-100 % \divide\count2 by\wd0 % \borderelm#2% \cleaders\copy0\hskip\count2\wd0 % \borderelm#4% }% } \def\plus_border#1#2#3% ht, wd, #3=empty ==> no center element {\vbox {\offinterlineskip\boxmaxdepth=\maxdimen \dimen2=#2\relax \dimen0=#1\relax\count2=\dimen0 \setbox0=\hplusborder{\dimen2}012 \advance\count2 by-\ht0 \advance\count2 by-\dp0 \setbox2=\hplusborder{\dimen2}567 \advance\count2 by-\ht2 \advance\count2 by-\dp2 \if.#3.\setbox4=\hbox to\wd0{\borderelm3\hss\borderelm4} \else\setbox4=\hplusborder{\dimen2}384 \fi \dimen0=\ht4\advance\dimen0 by\dp4 \advance\count2 by\dimen0\advance\count2 by-100 \divide\count2 by\dimen0 \box0 \cleaders\copy4\vskip\count2\dimen0 \box2 \kern0sp }% } \def\plusborder#1#2{\plus_border{#1}{#2}{}} \def\plusgray#1#2{\plus_border{#1}{#2}{1}} %%%%%%% border example (rounded corners) % This example creates a border with rounded corners. The corners are taken % from the manfnt font, as described in The TeXbook, p.389. However, we % reposition them in their boxes, as their original position is inconvenient: % We want tight-fitting boxes, because the boxes determine the border width % and height. The original position is described in The TeXbook. % If \manfnt is already defined, we do not redefine it. \ifx\manfnt\UNDEFINED \font\manfnt=manfnt \fi % \roundcorners is a bit messy, but that is not so important. % Just so that you can use \minusgray and \plusgray, we added a center % character (just some random character from the font). That meant that the % left and right character had to be given widths equal to the corner elements. % \roundcorners scales properly with \manfnt. \def\roundcorners#1% use as \borderelm {{\manfnt \setbox2=\hbox{\char'44}% for demonstration purposes \ifcase#1 \setbox0=\hbox{d}% lu \hbox to\ht0{\vbox to\fontdimen8\font{\vss\box0}\hss}% \or\hbox{\vrule width\wd2 height\fontdimen8\font depth0pt\hss}% u=d \or\setbox0=\hbox{a}% ru \hbox to\ht0{\kern\dp0\vbox to\fontdimen8\font{\vss\box0}\hss}% \or\setbox0=\hbox{d}% \hbox to\ht0{\vrule width\fontdimen8\font height\ht2 depth\dp2\hss}% l \or\setbox0=\hbox{d}% \hbox to\ht0{\hss\vrule width\fontdimen8\font height\ht2 depth\dp2}% r \or\setbox0=\hbox{c}% ld \hbox to\ht0{\vbox{\copy0\kern-\dp0}\hss}% \or\hbox{\vrule width\wd2 height\fontdimen8\font depth0pt\hss}% d=u \or\setbox0=\hbox{b}% rd \hbox to\ht0{\kern\dp0\vbox{\copy0\kern-\dp0}\hss}% \or\box2 % center character \fi }} %%%%%%% centering text within a border % \setborder[bwd, hspace, vspace]\bordermacro uses \bordermacro (one of % \border, \xborder, etc.) to typeset a border. The width of the border is bwd, % the height of the border depends on the amount of text within the border. % This text is read and typeset in a vbox, with the hsize set so that the % width has the appropriate value. This is done in a somewhat convoluted way % with \afterassignment to set the hsize, and \aftergroup to create the border. % The reason is that now the text is not read as an argument of \setborder, % which is important, for instance, if the text contains catcode changes. % We did not write \setborder[#1,#2,#3]#4#{ , which would have ensured that a % brace follows: that would have required an explicit brace, whereas now you % can also use \bgroup (useful if you want to put \setborder in some other % macro). \newbox\brd_txt \newbox\brd_box \def\setborder[#1,#2,#3]#4% wd, hspace, vspace, bordermacro {\def\brd_inbox {\hsize=#1 \advance\hsize by-#2 \advance\hsize by-#2 \aftergroup\set_border }% \def\set_border {\setbox\brd_txt=\vbox {\vskip#3 \box\brd_txt \vskip#3 }% \setbox\brd_box=#4{\ht\brd_txt}{#1}% \vbox to\ht\brd_box {\copy\brd_box \kern-\ht\brd_box \vss \hbox to\wd\brd_box{\hss\box\brd_txt\hss} \vss }% }% \afterassignment\brd_inbox \setbox\brd_txt=\vbox } %%%%%%% initialization \catcode`\_=\borderelm % restore catcode \let\borderelm=\roundcorners % only reasonable initialization