Модификация стандартных классов
Оглавление, список иллюстраций и прочее
Автоматическая сборка оглавления — многоэтапный процесс. Сначала материал для оглавления (заглавия разделов и номера соответствующих страниц) записывается в специальный файл с тем же именем, что и у основного файла, и расширением toc (в нормальных условиях эта запись обеспечивается командами \chapter, \section и т.д.); при следующем запуске LaTeX'а этот toc-файл считывается (с помощью команды \input ), команды, записанные в него, исполняются, и в результате происходит фактическая печать оглавления. Аналогичным образом составляются список иллюстраций и список таблиц (при этом информация записывается в файлы с расширениями lof или lot соответственно). Давайте научимся влиять на этот процесс.
Сначала расскажем, как составлять оглавление полностью вручную, игнорируя его автоматическую сборку, обеспечиваемую командами типа \section. Итак, предположим, что все команды \section, \chapter и т.п. даны в исходном тексте в варианте со звездочкой, и посмотрим, как можно самому создать оглавление.
Команда \addtocontents служит для записи в toc- (соответственно,lof - или lot-)- файл любого текста и любых TeX'овских команд. У этой команды два обязательных аргумента. Первый из них должен быть toc, lof или lot, в соответствии с тем, в какой из файлов с оглавлениями вы пишете свой текст. Второй аргумент — то, что вы хотите записать в файл. Если, например, вам взбрело в голову внести в оглавление к вашей книге текст "У попа была собака" (не будем спрашивать, зачем), то можете написать
\addtocontents{toc}{У попа была собака\par}
( \par поставить необходимо, так как до и после выполнения каждой команды, записанной в оглавлении, TeX должен находиться в вертикальном режиме). Если после этого запустить LaTeX два раза, то вы увидите в оглавлении свой текст (после первого раза он только попадет в toc-файл, а при втором запуске toc-файл с этим текстом будет обработан).
С помощью команды \addtocontents можно записывать в оглавление не только всякие глупости. Если, например, вы хотите в каком-то месте оглавления провести горизонтальную линейку шириной во всю страницу, то можно написать
\addtocontents{toc}{\hrule}
и в оглавлении появится линейка. Имейте только в виду, что в аргументе \addtocontents необходимо защищать хрупкие команды с помощью команды \protect. В случае с \hrule мы обошлись без \protect, так как эта команда не хрупка, но если есть сомнения, то лучше команду защитить. Напомним, что \protect действует только на непосредственно следующую команду и что команды для смены шрифта или установки пробелов в защите с помощью \protect не нуждаются. Приведем пример более разумного применения \addtocontents, в котором требуется \protect. Пусть вы не хотите, чтобы какая-то из строк в оглавлении начинала новую страницу. Тогда надо перед командой, порождающей эту строку оглавления (обычно таковой будет команда наподобие \section ), написать в своем файле вот что:
\addtocontents{toc}{\protect\nopagebreak}
В результате в toc-файл запишется команда \nopagebreak, и нежелательный разрыв страницы в оглавлении будет предотвращен. Если опустить \protect, то получится весьма непонятное сообщение об ошибке.
При совместном использовании команд \addtocontents возникает следующий неприятный эффект. Пусть ваш файл имеет вид, скажем,
\documentclass{book} \usepackage{mystyle} \begin{document} \tableofcontents \include{ch1} \addtocontents{\hrule} \include{ch2} \end{document}
Тогда, вопреки всем ожиданиям, в оглавлении линейка окажется не между записями, отвечающими файлам ch1.tex и ch2.tex, а после записей, отвечающих файлу ch2.tex. Чтобы этого избежать, запишите команду \addtocontents в начало файла ch2.tex (самой первой строчкой).
Чтобы составить полноценное оглавление, надо иметь возможность записать в toc - (соответственно, lof- или lot-) файл не только текст, но и номер той страницы, к которой этот текст относится. Это делается с помощью команды \addcontentsline, имеющей такой синтаксис:
\addcontentsline{тип\_файла}{тип\_записи}{текст}
Здесь тип_файла — это toc, lof или lot, текст — тот текст, который будет записан в оглавление (например, команда \section в стандартном стиле article в качестве этого текста передает название раздела и его номер; подробности см. ниже). Наконец, тип_записи определяет, каким образом будет обрабатываться этот текст при чтении файла с оглавлением. Именно, если второй аргумент в команде \addcontentsline был abcd, то, когда при следующем запуске LaTeX'а будет читаться toc- (соответственно, lof- или lot-) файл, будет исполнена команда \l@abcd с двумя аргументами, первый из которых - текст, записанный в третьем аргументе команды \addcontentsline, а второй - номер страницы, на которую попала ваша команда \addcontentsline. Например, если в файле было написано
\leavevmode \hbox to\hsize{\verb"\addcontentsline{toc}{abcd}{О слонах}"\hfill $\displaystyle(*)$
и если эта команда попала на страницу , то при следующем запуске
LaTeX'а в процессе чтения toc-файла будет исполняться команда
\l@abcd{О слонах}{95}
Разумеется, чтобы при этом не получилось сообщения об ошибке,
надо, чтобы команда \l@abcd была определена. Стало быть, в
стилевом пакете должно присутствовать ее определение. Если мы
хотим, чтобы запись в исходном файле порождала в оглавлении
строку
О слонах................................ 95
то в преамбуле надо написать вот что:
\newcommand{\l@abcd}[2]{\hbox to\textwidth{#1\dotfill #2}}
Чтобы при этом страница в оглавлении была указана верно, необходимо команду \addcontentsline разместить непосредственно после команды \section* (иначе есть опасность, что они попадут на разные страницы).
Если в третьем аргументе команды \addcontentsline присутствуют "хрупкие" команды, то их следует, как водится, защитить командой \protect, если, с другой стороны, в нем записана \the -команда, соответствующая какому-то счетчику, то в toc-файл будет записано печатное представление значения этого счетчика по состоянию на тот момент, когда выполнялась \addcontentsline. Таким способом можно, например, записать в оглавление номер текущего раздела документа: достаточно сказать
\addcontentsline{toc}{abcd}{\thesection. О слонах}
Теперь рассмотрим, как именно собирают оглавление стандартные команды наподобие \chapter или \section. Делают они это также с помощью \addcontentsline, при этом ее второй аргумент (" тип записи") будет section для команды \section, subsection для команды \subsection, — одним словом, " внутреннее имя", под которым LaTeX знает тип разделов документа (напомним, что внутреннее имя передается в качестве первого аргумента команде \@startsection ). Стало быть, для модификации стиля оформления строк оглавления, соответствующих \section, надо переопределять команду \l@section, для модификации строк оглавления, соответствующих \subsection, надо переопределять \l@subsection и т.д. Чтобы было понятно, как их переопределять, рассмотрим, как они определены в стандарте.
В классе book команда \l@section определена так:
\newcommand{\l@section}{\@dottedtocline{1}{1.5em}{2.3em}}
Смысл трех выражений, стоящих в фигурных скобках после команды \@dottedtocline, таков. Первое выражение — "уровень вложенности" элемента оглавления. Если этот уровень превышает значение счетчика tocdepth, то команда \@dottedtocline ничего в оглавлении не печатает. Второе выражение — отступ строки оглавления от левого поля. Третье выражение определяет, сколько места в строке оглавления TeX отведет на номер раздела. Результат выглядит на печати так: после отступа, указанного во втором выражении, печатается номер раздела, затем, отступя от начала этого номера столько, сколько сказано в третьем выражении, печатается заглавие раздела. Это сделано для того, чтобы заглавия всех разделов печатались в оглавлении одно под другим. После заглавия идут "лидеры" — ряд точек до завершающего строку номера страницы. Если заглавие в строку не укладывается, то оно обычным образом будет перенесено на следующую строку (если есть какие-то неясности, загляните в оглавление к этой книге). Из сказанного следует, что слишком длинный номер раздела может в оглавлении наложиться на заглавие. Средство борьбы с этим — переопределить команду \l@section (или \l@subsection...), увеличив должным образом второй аргумент команды \@dottedtocline.
Параметры оформления элемента оглавления, задаваемого командами, определенными через \@dottedtocline, можно менять. Именно, размер места, отводимого на номер страницы, задается значением команды \@pnumwidth, которую можно переопределить. В классе book эта команда определена как
\newcommand{\@pnumwidth}{1.55em}
и соответственно на номер страницы отводится 1.55em места. Если мы хотим, чтобы на номер страницы отводилось \2em, надо написать
\renewcommand{\@pnumwidth}{2em}
Еще одна команда, значение которой отвечает за оформление оглавления, — это \@tocrmarg. Если запись в оглавлении занимает более одной строки, то значение этой команды задает отступ от правого поля, который будет у всех строк, кроме той последней, что завершается номером страницы. Если вы хотите, чтобы размер этого отступа равнялся 3em, напишите так:
\renewcommand{\@tocrmarg}{3em}
Хотя \@pnumwidth и \@tocrmarg используются для задания размеров, они не являются параметрами со значением длины; запись наподобие \@tocrmarg=4em приведет к ошибке!
Наконец, регулировать густоту точек-" лидеров" можно, если переопределить команду \@dotsep. В классе book она определена как
\newcommand{\@dotsep}{4.5}
Если вы хотите, чтобы точки шли погуще, попробуйте переопределить ее, заменив 4.5 на число поменьше (число может быть дробным, в нем можно использовать как десятичную запятую, так и десятичную точку):
\renewcommand{\@dotsep}{3,9}
Напрашивающаяся запись \@dotsep=3,9 приведет к ошибке.
Команды \l@subsection и "более мелкие" определяются в классе book так же, как \l@section, отличаются только аргументы команды \@dottedtocline. Мы собрали значения этих параметров в табл. 9.3