\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

