chiark / gitweb /
a2c390944ccd0571c025fa155fc04fff4ae21a96
[mdwtools] / slowbox.dtx
1 % \begin{meta-comment}
2 %
3 % $Id: slowbox.dtx,v 1.2 2003/09/06 13:08:16 mdw Exp $
4 %
5 % Cop-out for slow things
6 %
7 % (c) 2003 Mark Wooding
8 %
9 % \end{meta-comment}
10 %
11 % \begin{meta-comment} <general public licence>
12 %%
13 %% slowbox package -- skipping of slow boxes
14 %% Copyright (c) 2003 Mark Wooding
15 %%
16 %% This program is free software; you can redistribute it and/or modify
17 %% it under the terms of the GNU General Public License as published by
18 %% the Free Software Foundation; either version 2 of the License, or
19 %% (at your option) any later version.
20 %%
21 %% This program is distributed in the hope that it will be useful,
22 %% but WITHOUT ANY WARRANTY; without even the implied warranty of
23 %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 %% GNU General Public License for more details.
25 %%
26 %% You should have received a copy of the GNU General Public License
27 %% along with this program; if not, write to the Free Software Foundation,
28 %% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 % \end{meta-comment}
30 %
31 % \begin{meta-comment} <Package preambles>
32 %<+package>\NeedsTeXFormat{LaTeX2e}
33 %<+package>\ProvidesPackage{slowbox}
34 %<+package>                [2003/08/27 1.0 skipping of slow boxes]
35 % \end{meta-comment}
36 %
37 % \CheckSum{223}
38 %% \CharacterTable
39 %%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
40 %%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
41 %%   Digits        \0\1\2\3\4\5\6\7\8\9
42 %%   Exclamation   \!     Double quote  \"     Hash (number) \#
43 %%   Dollar        \$     Percent       \%     Ampersand     \&
44 %%   Acute accent  \'     Left paren    \(     Right paren   \)
45 %%   Asterisk      \*     Plus          \+     Comma         \,
46 %%   Minus         \-     Point         \.     Solidus       \/
47 %%   Colon         \:     Semicolon     \;     Less than     \<
48 %%   Equals        \=     Greater than  \>     Question mark \?
49 %%   Commercial at \@     Left bracket  \[     Backslash     \\
50 %%   Right bracket \]     Circumflex    \^     Underscore    \_
51 %%   Grave accent  \`     Left brace    \{     Vertical bar  \|
52 %%   Right brace   \}     Tilde         \~}
53 %%
54 %
55 % \begin{meta-comment}
56 %
57 %<*driver>
58 \input{mdwtools}
59 \describespackage{slowbox}
60 \newcommand\opt[1]{\textsf{#1}}
61 \def\*{\hspace{0pt plus 0.1pt}\ignorespaces}
62 \mdwdoc
63 %</driver>
64 %
65 % \end{meta-comment}
66 %
67 %^^A-------------------------------------------------------------------------
68 % \section{User guide}
69 %
70 % The problem is that some things, e.g., diagrams, can take a while to
71 % typeset, and aren't particularly interesting as far as the global document
72 % layout is concerned.  Once you've got a diagram right, the only thing that
73 % matters as far as general previewing is concerned is its size.
74 %
75 % The solution is \package{slowbox}.  Put things you're usually not
76 % interested in seeing in a \env{slowbox} environment.  Then they get
77 % replaced by a frame saying that there's meant to be something there, and
78 % that's it.
79 %
80 % There are two modes, chosen by package options: \opt{show} and \opt{hide}.
81 % The default is \opt{show} mode, because I had to pick one.  In \opt{show}
82 % mode, everything happens normally; in \opt{hide} mode, slow  boxes are
83 % replaced by frames.  In order for the package to know the sizes of all of
84 % your boxes, you must first run through once in \opt{show} mode.
85 % Thereafter, all should be well.
86 %
87 % \DescribeEnv{slowbox}
88 % In \opt{show} mode, the \env{slowbox} environment typesets its contents in
89 % LR-mode (for \TeX nicians, restricted horizontal mode).\footnote{^^A
90 %   Vertical mode causes all sorts of pain, and makes things way too wide.
91 %   Horizontal mode seems a good `standard currency' for \LaTeX\ things like
92 %   diagrams.} ^^A
93 % In \opt{hide} mode, the boxes are replaced by frames, and \TeX\ will skip
94 % over the contents of the environment at high speed, ignoring it
95 % completely.
96 %
97 % The \env{slowbox} environment needs an argument, a \emph{tag} which is used
98 % to identify this box.  This is needed because otherwise the package has no
99 % way of deciding that you've inserted some new box and need to shunt
100 % everything about.  So the full syntax is
101 % \syntax{"\\begin{slowbox}{"<tag>"}" \ldots "\\end{slowbox}"}.
102 % Tags can be any piece of text.  If you include control sequences in the
103 % tag, then they get expanded.  That might be what you want.
104 %
105 % \DescribeEnv{slowbox$*$}
106 % Adding new slow boxes is best done using the starred version of the
107 % environment.  Stuff in a \env{slowbox$*$} environment is always typset in
108 % \opt{show} mode, regardless of the global mode setting.  The right thing to
109 % do is wrap your new stuff in a \env{slowbox$*$} while you're writing it.
110 % Then remove the \env{$*$} and it will turn into a frame.  The
111 % \env{slowbox$*$} environment takes a tag name, just like \env{slowbox}
112 % does.
113 %
114 % However, if \package{slowbox} sees a slow box \<tag> it's not noticed
115 % before, it always typesets the box contents, and saves the measurements for
116 % later.
117 %
118 % \DescribeMacro\slowboxbegin
119 % \DescribeMacro\slowboxend
120 % It's useful to define your own commands environments which create slow
121 % boxes.  Often, though, what happens is that you want to put some stuff
122 % \emph{inside} the slow box, but that doesn't work properly.  What you must
123 % do instead is say something like
124 %\begin{verbatim}
125 %   \newenvironment{splunt}[1]
126 %     {...\slowboxbegin{#1}{...\startsplunt...}}
127 %     {\slowboxend{...\finishsplunt...}...}
128 %\end{verbatim}
129 % That is, \syntax{"\\slowboxbegin{"<tag>"}{"<stuff>"}"} starts a slow box,
130 % beginning with \<stuff> if we're in \opt{show} mode; and
131 % \syntax{"\\slowboxend{"<stuff>"}"} finishes it, ending with \<stuff>.
132 %
133 % The |\slowboxbegin| command has a |*|-variant, which causes the box to be
134 % typeset regardless of the current mode setting.
135 %
136 % \DescribeMacro\newslowboxenv
137 % Plumbing all of this together is rather tedious, so there's also a
138 % command for building slow box environments.  Say
139 % \syntax{"\\newslowboxenv{"<env-name>"}"\* "["<n-args>"]"\*"["<default>"]"\*
140 % "{"<before-text>"}"\* "{"<start-text>"}"\* "{"<end-text>"}"\*
141 % "{"<after-text>"}"}. This creates a new environment (just like with
142 % |\newenvironment|, taking \<n-args> arguments, maybe with the first one
143 % optional and defaulting to \<default>).  The contents are put in a slow box
144 % with \<start-text> on the front and \<end-text> on the end.  Before the box
145 % is begun, \<before-text> is performed, and \<after-text> is done
146 % afterwards.  The environments so created have \env{$*$}-variants which
147 % ignore the current mode, just like \env{slowbox$*$}.  They also gather an
148 % additional \<tag> argument, which you don't have to bother with.
149 %
150 % \DescribeMacro\doslowbox
151 % Finally, for commands, there's \syntax{"\\doslowbox{"<tag>"}"\*
152 % "{"<stuff>"}"}.  This typesets \<stuff> in a slow box with the given tag.
153 % There's a |*|-variant, of course.
154 %
155 % \DescribeMacro\slowboxshow
156 % \DescribeMacro\slowboxhide
157 % \DescribeMacro\ifslowboxshow
158 % The declarations |\showboxshow| and |\slowboxhide| switch between the
159 % \opt{show} and \opt{hide} modes.  They obey standard scoping rules.
160 % They're probably not very useful.  They twiddle the |\ifslowboxshow| macro,
161 % which is an old-fashioned Plain \TeX\ switch.  If you're the sort of person
162 % who uses \package{ifthen}, then you can test |\boolean{slowboxshow}|.
163 %
164 %^^A-------------------------------------------------------------------------
165 % \implementation
166 %
167 % \section{Implementation of \package{slowbox}}
168 %
169 %    \begin{macrocode}
170 %<*package>
171 %    \end{macrocode}
172 %
173 % \subsection{The mode switch}
174 %
175 % \begin{macro}{\ifslowboxshow}
176 % \begin{macro}{\slowboxshow}
177 % \begin{macro}{\slowboxhide}
178 % The |\if@slowboxshow| switch remembers which mode we're in.  The
179 % |\slowboxshow| and |\slowboxhide| macros flip the switch.  It's really
180 % easy.  The |\relax|es are to annoy people who say |\global\showboxshow|.
181 %    \begin{macrocode}
182 \def\slowboxshow{\relax\let\ifslowboxshow\iftrue}
183 \def\slowboxhide{\relax\let\ifslowboxshow\iffalse}
184 %    \end{macrocode}
185 % \end{macro}
186 % \end{macro}
187 % \end{macro}
188 %
189 % \subsection{Dependencies}
190 %
191 % The skipping-over-stuff-at-high-speed is done by my \package{sverb}
192 % package.
193 %    \begin{macrocode}
194 \RequirePackage{sverb}
195 %    \end{macrocode}
196 %
197 % \subsection{Options}
198 %
199 % Oh, this is obvious.
200 %    \begin{macrocode}
201 \DeclareOption{show}{\slowboxshow}
202 \DeclareOption{hide}{\slowboxhide}
203 \ExecuteOptions{show}
204 \ProcessOptions
205 %    \end{macrocode}
206 %
207 % \subsection{Remembering stuff}
208 %
209 % \begin{macro}{\sb@def}
210 % Box dimensions are recorded in the |.aux| file using
211 % \syntax{"\\sb@def{"<tag>"}"\* "{"<width>"}"\* "{"<height>"}"\*
212 % "{"<depth>"}"}.  This turns into a definition of a strange control
213 % sequence.
214 %    \begin{macrocode}
215 \def\sb@def#1#2#3#4%
216   {\expandafter\gdef\csname sb@box:#1\endcsname{{#2}{#3}{#4}}}
217 %    \end{macrocode}
218 % \end{macro}
219 %
220 % \subsection{The actual work}
221 %
222 % \begin{macro}{\sb@begin}
223 % This is where most of the intelligence is.
224 % \syntax{"\\sb@begin{"<tag>"}{"<stuff>"}"} starts a slow box, putting
225 % \<stuff> at the start if we're in \opt{show} mode.  It doesn't ignore stuff
226 % -- though it sets |\sb@ignore| to be |\relax| in \opt{show} mode and
227 % |\ignore| in \opt{hide} mode.  It also sets |\sb@end| correctly, so that
228 % \syntax{"\\sb@end{"<stuff>"}"} ends the current box, putting \<stuff> in
229 % it.
230 %
231 % Disappointingly, perhaps, this is in fact just a dispatcher to the right
232 % implementation.
233 %    \begin{macrocode}
234 \def\sb@begin{%
235   \ifslowboxshow\expandafter\sb@begin@show%
236   \else\expandafter\sb@begin@hide\fi%
237 }
238 %    \end{macrocode}
239 % \end{macro}
240 %
241 % \begin{macro}{\sb@begin@show}
242 % Now we have the implementation for \opt{show} mode.  This is sometimes
243 % called directly, by |*|-variants.  Needs to be |\long| because \<stuff>
244 % might contain embedded vmode-material which could legitimately have |\par|
245 % tokens in.
246 %    \begin{macrocode}
247 \long\def\sb@begin@show#1#2{%
248   \begingroup%
249   \def\sb@end##1{%
250     ##1%
251     \color@endgroup%
252     \egroup%
253     \immediate\write\@auxout%
254       {\string\sb@def{#1}{\the\wd\z@}{\the\ht\z@}{\the\dp\z@}}%
255     \leavevmode\box\z@%
256     \endgroup%
257   }%
258   \let\sb@ignore\relax%
259   \setbox\z@\hbox\bgroup\color@begingroup#2%
260 }
261 %    \end{macrocode}
262 % \end{macro}
263 %
264 % \begin{macro}{\sb@begin@hide}
265 % Now for something a bit stranger.  If we're in \opt{hide} mode, we need to
266 % find out whether we've saved information about this box before.  We pass
267 % the \emph{control sequence} containing the box dimensions to another
268 % macro.  Needs to be |\long| to collect the \<stuff> argument.
269 %    \begin{macrocode}
270 \long\def\sb@begin@hide#1#2{%
271   \begingroup%
272   \def\sb@end##1{\endgroup}%
273   \let\sb@ignore\ignore%
274   \expandafter\sb@hidden\csname sb@box:#1\endcsname{#1}{#2}%
275 }
276 %    \end{macrocode}
277 % \end{macro}
278 %
279 % \begin{macro}{\sb@hidden}
280 % We're given the control token and the tag name.  If the control sequence is
281 % like |\relax| then |\csname| must have invented it and we should typeset it
282 % anyway in order to measure it.  Otherwise we put the right stuff in a
283 % frame.  Don't forget to write out the box dimensions to the new aux file!
284 %    \begin{macrocode}
285 \def\sb@hidden#1#2#3{%
286   \ifx#1\relax\def\next@{\endgroup\sb@begin@show{#2}{#3}}%
287   \else\edef\next@{\noexpand\sb@hidden@i#1{#2}}\fi%
288   \next@%
289 }
290 \def\sb@hidden@i#1#2#3#4{%
291   \frameonly{#1}{#2}{#3}{Omitted \texttt{#4}}%
292   \immediate\write\@auxout{\string\sb@def{#4}{#1}{#2}{#3}}%
293 }
294 %    \end{macrocode}
295 % \end{macro}
296 %
297 % \subsection{Stuff in frames}
298 %
299 % \begin{macro}{\frameonly}
300 % \syntax{"\\frameonly{"<width>"}{"<height>"}{"<depth>"}{"<stuff>"}"}
301 % typesets \<stuff> in a frame with the given dimensions.  This is a bit
302 % tricky -- we want the \<stuff> in the middle of the box, but the box's
303 % reference point is somewhere else.  We start with a |\vcenter| of the right
304 % height, and then nudge it into position later.
305 %
306 % In case the label is just too big, put shrinky glue all round.  It'll look
307 % horrible, but at least it won't mess everything up.
308 %    \begin{macrocode}
309 \def\frameonly#1#2#3#4{%
310   \dimen\tw@#2\advance\dimen\tw@#3\advance\dimen\tw@-.8\p@%
311   \setbox\z@\hbox{$\vcenter{\hrule\@height\dimen\tw@\@depth\z@}$}%
312   \dimen@#1%
313   \advance\dimen@-.8\p@%
314   \setbox\z@\vbox{%
315     \hrule\vss%
316     \hb@xt@\dimen@{%
317       \vrule\@height\ht\z@\@depth\dp\z@\hss%
318       \advance\dimen@-2em%
319       \parbox\dimen@{\centering#4}%
320       \hss\vrule}%
321     \vss\hrule%
322   }%
323   \dimen@#3\advance\dimen@-\dp\z@%
324   \setbox\z@\hbox{\lower\dimen@\box\z@}%
325   \leavevmode\box\z@%
326 }
327 %    \end{macrocode}
328 % \end{macro}
329 %
330 % \subsection{User commands}
331 %
332 % \begin{macro}{\slowboxbegin}
333 % \begin{macro}{\slowboxend}
334 % This is just a matter of using the machinery we've built already.
335 %    \begin{macrocode}
336 \def\slowboxbegin{\@ifstar{\sb@go\sb@begin}{\sb@go\sb@begin@show}}
337 \long\def\sb@go#1#2#3{#1{#2}{#3}\sb@ignore}
338 \def\slowboxend{\sb@end}
339 %    \end{macrocode}
340 % \end{macro}
341 % \end{macro}
342 %
343 % \begin{macro}{\doslowbox}
344 % And this too.
345 %    \begin{macrocode}
346 \def\doslowbox{\@ifstar{\sb@do\sb@begin}{\sb@do\sb@begin@show}}
347 \long\def\sb@do#1#2#3{#1{#2}{#3}\sb@end}
348 %    \end{macrocode}
349 % \end{macro}
350 %
351 % \begin{macro}{\newslowboxenv}
352 % Something a bit more interesting now.  Gathering the optional arguments for
353 % |\newenvironment| is a bit tedious, but we do it anyway.  Picking up the
354 % arguments for the environment is a bit tricky -- they come in the wrong
355 % order, unfortunately.
356 %    \begin{macrocode}
357 \def\newslowboxenv#1{\@ifnextchar[{\sb@nenv@i{#1}}{\sb@nenv@do{#1}{}}}
358 \def\sb@nenv@i#1[#2]{%
359   \@ifnextchar[{\sb@nenv@ii{#1}{[{#2}]}}{\sb@nenv@do{#1}{[{#2}]}}%
360 }
361 \def\sb@nenv@ii#1#2[#3]{\sb@nenv@do{#1}{#2[{#2}]}}
362 \long\def\sb@nenv@do#1#2#3#4#5#6{%
363   \newenvironment{#1}#2{#3\sb@env\sb@begin{#4}}{\sb@end{#5}#6}%
364   \newenvironment{#1*}#2{#3\sb@env\sb@begin@show{#4}}{\sb@end{#5}#6}%
365 }
366 \def\sb@env#1#2#3{#1{#3}{#2}\sb@ignore}
367 %    \end{macrocode}
368 % \end{macro}
369 %
370 % \begin{environment}{slowbox}
371 % And the \env{slowbox} is built using the above equipment.
372 %    \begin{macrocode}
373 \newslowboxenv{slowbox}{}{}{}{}
374 %    \end{macrocode}
375 % \end{environment}
376 %
377 %    \begin{macrocode}
378 %</package>
379 %    \end{macrocode}
380 %
381 % \Finale
382 \endinput