Оглавление, список иллюстраций и прочее
Автоматическая сборка оглавления — многоэтапный процесс. Сначала материал для оглавления (заглавия разделов и номера соответствующих страниц) записывается в специальный файл с тем же именем, что и у основного файла, и расширением 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
\l@subsection | 2 | 3.8em | 3.2em |
\l@subsubsection | 3 | 7.0em | 4.1em |
\l@paragraph | 4 | 10em | 5em |
\l@subparagraph | 5 | 12em | 6em |
Вот ( в адаптированном виде, как водится) определение команды \l@chapter из стандартного класса book. Чтобы было понятно, о чем идет речь, напомним, что в этом определении на место #1 подставляется информация о номере (если главы нумеруются) и названии главы, а на место #2 — номер страницы.
\newcommand{\l@chapter}[2]% {\pagebreak[3] \vspace{1em plus 1pt}% отбивка перед строкой оглавления \@tempdima=1.5em % место для номера главы {% Дальнейшее происходит внутри группы... \rightskip=\@pnumwidth % см. ниже \parfillskip=-\@pnumwidth \noindent\bfseries % Начать абзац, установить шрифт \addtolength{\leftskip}{\@tempdima}% см. ниже \hspace{-\leftskip}#1\nolinebreak \hfil\nolinebreak \hbox to \@pnumwidth {\hss #2}\par \nopagebreak[3] % лучше бы здесь не рвать страницу... }% конец этой группы }% конец определения Определение, как видите, длинное и сложное, к тому же автору не удалось полностью изгнать из него не упоминавшиеся ранее TeX'овские конструкции. Приведено оно здесь не для того, чтобы вы самостоятельно создавали подобные определения "с нуля", но чтобы вы при необходимости смогли в нем кое-что осторожно изменить. Разберем определение по порядку. В начале встречаются не рассматривавшиеся нами параметры \rightskip и \leftskip. Эти параметры со значением длины (по умолчанию они равны нулю) имеют следующий смысл: все строки абзаца начинаются с отступом \leftskip от левого поля и кончаются с отступом \rightskip от правого поля (если речь идет о последней строке, то в дополнение к отступу \parfillskip). У нас \rightskip устанавливается равным длине, записанной в определении команды \@pnumwidth (именно столько места будет отведено на номер страницы), а \leftskip устанавливается равным значению переменной \@tempdima, определяющей, сколько места будет отведено на номер главы. С другой стороны, параметр \parfillskip устанавливается равным отрицательной величине - \@pnumwidth. Тем самым, если название главы длинное и не поместится в одну строку оглавления, произойдет следующее: все строки, кроме последней, будут заканчиваться на расстоянии \@pnumwidth от правого края, а последняя строка, содержащая номер страницы, закончится на расстоянии
\leftskip + \parfillskip = @pnumwidth - \@pnumwidth =0, от края, так что номер страницы будет все-таки прижат вправо.
Между \@pnumwidth и \@tempdima есть существенная разница. Команда \@pnumwidth всегда определяет только место, отводимое на номер страницы, и эту команду можно переопределять в стилевом пакете. С другой стороны, параметр \@tempdima используется LaTeX'ом для самых разных целей (в основном — для временного хранения различных длин в процессе каких-то вычислений), и он может измениться в процессе выполнения очень многих LaTeX'овских команд, так что присваивать ему какое-то значение в стилевом пакете совершенно бессмысленно — все равно после этого оно сто раз изменится. Как мог заметить читатель, значение этому параметру присваивается в начале исполнения команды \l@chapter, и именно это значение принимается в расчет в дальнейшем. Поэтому, если вы захотите отводить на номер главы, скажем, 2em вместо 1.5em, то вам придется переопределить команду \l@chapter, заменив третью строку на
\@tempdima=2em Нужда в таком переопределении \l@chapter возникает, например, если мы переопределяем команду \thechapter, чтобы номер печатался римскими цифрами (как в книге, которую вы читаете). Далее, #1 - это, как уже было сказано, номер и заглавие главы. Точнее говоря, на месте #1 печатается такой текст (будем считать, что глава называется "Все о слонах"):
\makebox[\@tempdima][l]{\thechapter}Все о слонах Таким образом, величина отступа от левого поля до названия главы всегда равна \@tempdima; если номер занимает больше места, чем \@tempdima, то он наложится на название.
Команда \hfil в двенадцатой строке обеспечивает пробел между названием главы и номером страницы. Если вы хотите заполнить этот пробел лидерами, можете в определении \l@chapter заменить \hfil на, скажем,
\leaders\hbox to .5em{\hss.\hss}\hfil (автор не гарантирует, что именно при таком выборе параметров лидеры будут выглядеть красиво).
Наконец, команды \pagebreak[3] в начале и \nopagebreak[3] в конце играют следующую роль: первая из них призывает LaTeX не печатать, по возможности, строку оглавления, соответствующую главе, внизу страницы, а вторая — не разрывать страницу сразу после строки, посвященной главе (опять же по возможности).
Имейте также в виду, что мы удалили из нашего упрощенного определения \l@chapter проверку значения счетчика tocdepth, так что если вы в какой-то момент решите не включать главы в оглавление, эту команду надо будет переопределить на "ничего не делать" так:
\renewcommand{\l@chapter}[2]{} Команды, определяющие вид записей в списке иллюстраций (соответствующих плавающим иллюстрациям) и списке таблиц (соответствующих плавающим таблицам) называются \l@figure и \l@table соответственно и определяются в стандарте с помощью \@dottedtocline.
До сих пор речь шла о сборке материала для оглавления, списка иллюстраций и т.п. Однако же и у самого оглавления есть заголовок, и его оформление тоже можно менять. Чтобы было понятно, как это делать, опишем, как определена команда \tableofcontents стандартное определение} в стандартном стиле article:
\newcommand{\tableofcontents}% {\section*{\contentsname}\@starttoc{toc}} Здесь \contentsname — это уже знакомая нам команда, которую при работе с русскими текстами приходится переопределять. Как видите, заголовок оглавления оформляется просто как заголовок ненумерованного раздела. Вы можете вместо этого оформить заголовок, скажем, с помощью \subsection, или еще каким-либо образом. Новой для вас будет команда \@starttoc. У этой команды предусмотрен один обязательный аргумент. Этим аргументом должен быть toc (для оглавления), либо lot или lof (для списка таблиц или иллюстраций соответственно). Команда \@starttoc читает toc- (соответственно, lot- или lof-) файл и создает оглавление как таковое.
На самом деле в определении \tableofcontents присутствует еще команда, позволяющая задать текст для включения в колонтитулы (вспомним, что \section* сама по себе никакой информации для колонтитулов не дает). Мы не будем здесь вдаваться в скучные подробности. Когда вы научитесь задавать такие команды, вы сможете соответствующим образом переопределить и \tableofcontents.