今日もの話で、目次のデザインについて。
なお、とは区別せずに扱ってる。
参考にしたのは以下:
LaTeX2ε辞典 増補改訂版 (DESKTOP REFERENCE)
- 作者: 吉永徹美
- 出版社/メーカー: 翔泳社
- 発売日: 2018/08/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Before / After
まずは変更前と変更後でどう変わったのかを示しておきたい。
変更前はこちら:
なお、昨日の見出しデザインの変更が入ってるので、目次の見出しは章見出しと同じデザインになってる。
あと、目次にリンクをはる変更が入ってる。
変更後はこちら:
以下が変わってることが分かると思う:
- 目次の見出しデザインが変わってる
- 小節まで見出しが出るようになっている
- 章番号がない章のタイトルの先頭が章番号がある章のタイトルの先頭に揃っている
- メインコンテンツでは章の上に線が引かれている
- 節は章のタイトルの先頭にインデントされ、小節は節のタイトルの先頭にインデントされている
- 「はじめに」の上に大きくスペースが入っている
「メインコンテンツでは・・・」というのは、「はじめに」や「プロローグ」も章なんだけど、これらの非メインコンテンツでは章の上に線が引かれず、「第1章」「第2章」のようなメインコンテンツでは章の上に線が引かれているということ。
ちなみに、これも『数学ガール』のデザインをマネたものとなっている。
目次の見出しデザインの変更
まずは目次の見出しデザインの変更から。
目次は\tableofcontents
命令で出力するのだけど、これで見出しなどもまるまる出力され、目次の場合は「目次」という章見出しが出力される定義になっている。
章見出しが出ること自体はいいんだけど、そのデザインは他の章見出しとは違う特別なものにしたい。
そういう場合、グルーピングを使うといい。
では{
と}
で囲うことでグルーピングでき、その内側はローカルになって外側の定義に影響を与えずに変更することが出来る。
そこで、以下のようにグルーピングしてその中で章見出しのデザインを変えてから目次を出力するようにした:
% 目次 { % 目次の見出しだけデザインを変える \makeatletter \renewcommand{\@makeschapterhead}[1]{% #1: 見出し \vspace*{-2\baselineskip}% \noindent\hspace*{0.15\textwidth}\hrulefill\par% \vtop to 3\baselineskip{% 3行分の高さを確保 \noindent\hspace*{0.15\textwidth}% \textsf{\large \kintou{0.85\textwidth}{C O N T E N T S}}\par% }\par} \makeatother \tableofcontents }
章のタイトルの先頭と揃うように、テキスト幅(\textwidth
)の右側85%が目次の見出しになるようにして、そこに「CONTENTS」の文字を均等割りで配置している。
目次レベルの変更
目次でどの見出しレベルまで出すかは、tocdepth
というカウンターの値で指定する。
% 目次レベル \setcounter{tocdepth}{2} % 小節まで目次に出す
目次の章のデザイン変更
目次での章のデザインを変えるには、\l@chapter
という命令を再定義する。
オリジナル(bxjsbook.cls)では次のようになっている:
\newcommand*{\l@chapter}[2]{% \ifnum \c@tocdepth >\m@ne \addpenalty{-\@highpenalty}% \addvspace{1.0em \@plus\p@?} \begingroup \parindent\z@ \rightskip\@tocrmarg \parfillskip-\rightskip \leavevmode\headfont \setlength\@lnumwidth{\jsc@tocl@width}\advance\@lnumwidth 2.683\jsZw \advance\leftskip\@lnumwidth \hskip-\leftskip #1\nobreak\hfil\nobreak\hbox to\@pnumwidth{\hss#2}\par \penalty\@highpenalty \endgroup \fi}
うん、さっぱり分からないw
一応、カウンターのtocdepth
の値を比較して出力するかどうか決めてるのかなぁくらいは分かるけど、あとはのモードとか(水平モードとか垂直モードとか)ペナルティの話が分かってないと厳しそう。
(そして自分はまだそこらへんを理解しきれてない)
いろいろ試したりしつつ、以下のようにしてみた:
\makeatletter % 目次の章の体裁カスタマイズ \newif\ifmaincontents % メイン内の章かを区別するため \maincontentsfalse \renewcommand{\l@chapter}[2]{% \ifnum \c@tocdepth >\m@ne \setlength\@lnumwidth{0.15\textwidth} \ifmaincontents \noindent\hrulefill\par% \nobreak% \noindent {\large #1\hfill #2}\par \vspace*{0.5\baselineskip} \else \noindent {#1\hfill #2}\par \vspace*{0.5\baselineskip} \fi \fi} \makeatother
まず、メインコンテンツかどうかでデザインを変えたいので、\ifmaincontents
という条件判断を用意している。
これについては後述。
そして、\@lnumwidth
をテキスト幅の15%にしてるので、たしかこれがタイトルまでのインデント幅。
あとは、メインコンテンツなら横線を引いてから出力し、そうでなければ単に出力をしている。
目次の節、小節のデザイン変更
目次の節や小節のデザインを変えるには、\l@section
や\l@subsection
の定義を変更する。
これらのオリジナル(bxjsbook.cls)では定義がどうなっているかというと以下:
\newcommand*{\l@section}{% \@tempdima\jsc@tocl@width \advance\@tempdima -1\jsZw \@dottedtocline{1}{\@tempdima}{3.683\jsZw}} \newcommand*{\l@subsection}{% \@tempdima\jsc@tocl@width \advance\@tempdima 2.683\jsZw \@dottedtocline{2}{\@tempdima}{3.5\jsZw}}
長さを計算して実際の処理は\@dottedtocline
という命令に委譲してるのが分かる。
この命令は\@dottedtocline{<tocdepth>}{<margin>}{<numlength>}
という感じで、目次レベルとマージンサイズ、それと番号が出力される部分の長さを指定するようになっている。
これは次のように変更してみた:
\makeatletter % 目次の節の体裁カスタマイズ \renewcommand{\l@section}{\@dottedtocline{1}{0.15\textwidth}{2.5em}} % 目次の小節の体裁カスタマイズ \renewcommand{\l@subsection}{\@dottedtocline{2}{0.235\textwidth}{3.5em}} \makeatother
なお、0.235\textwidth
というのは目で見てそれっぽくなってる値にしただけ(^^;
ちゃんとやるなら足し算しないとダメ。
章番号なしの章の目次への追加
\chapter*{}
を使った章は章番号が出ないだけじゃなくて目次にも出てこない。
これを目次に出すようにするには\addcontentline
という命令を使う。
例えば、「はじめに」だとこんな感じ:
\chapter*{はじめに} \addcontentsline{toc}{chapter}{はじめに}
これで目次に章として「はじめに」が追加される。
ただ、これだと変更前の画像で見たとおり、章番号と同じインデントの深さにタイトルが出てしまう。
章番号のある章のタイトルと同じインデントの位置にタイトルは出て欲しい。
そこで以下のように変更してみた:
\chapter*{はじめに} \addcontentsline{toc}{chapter}{\protect\numberline{\null}はじめに}
どうしてこれでうまくいくのかを以下で説明していく。
まず、は目次をtocファイルから作るのだけど、上記のように変更せずにtocファイルを見てみると次のようになっている:
\contentsline {chapter}{はじめに}{i}{chapter*.1}% ... \contentsline {chapter}{\numberline {第1章}ポーカーのルール}{1}{chapter.1}% \contentsline {section}{\numberline {1.1}テキサス・ホールデム}{2}{section.1.1}% ...
つまり、章番号や節番号の部分は\numberline
という命令によって出力されていることが分かる。
なら、空の章番号を\numberline
で出力するようにすれば、インデント位置が揃うはずと。
ただし、単に\addcontentsline{toc}{chapter}{\numberline{\null}はじめに}
とするとうまくいかない。
これは\numberline{\null}
という命令がtocファイルに書き込まれる前に評価されて別の文字列に変わってしまうから。
それを抑制するために\protect
が付け加えられている。
上記の変更をしたあとのtocファイルの出力はこうなる:
\contentsline {chapter}{\numberline {\hbox {}}はじめに}{i}{chapter*.1}% ... \contentsline {chapter}{\numberline {第1章}ポーカーのルール}{1}{chapter.1}% \contentsline {section}{\numberline {1.1}テキサス・ホールデム}{2}{section.1.1}%
これで章番号がない章のタイトルの先頭も章番号がある章のタイトルの先頭に揃うようになる。
メインコンテンツ/非メインコンテンツの切り替え
上記までの変更を行なっての出力が以下:
メインコンテンツと非メインコンテンツの切り替えが出来ていないので、「第1章」の上に線が引かれてない。
あと、「はじめに」の前の空きも足りてない。
そこで、tocファイルに「非メインコンテンツの開始」「メインコンテンツの開始」の命令を書き込むようにした:
(どうやって書き込むのかは後述)
before
\contentsline {chapter}{\numberline {\hbox {}}はじめに}{i}{chapter*.1}% ... \contentsline {chapter}{\numberline {第1章}ポーカーのルール}{1}{chapter.1}% \contentsline {section}{\numberline {1.1}テキサス・ホールデム}{2}{section.1.1}%
after
\startnomaintoc \contentsline {chapter}{\numberline {\hbox {}}はじめに}{i}{chapter*.1}% ... \startmaintoc \contentsline {chapter}{\numberline {第1章}ポーカーのルール}{1}{chapter.1}% \contentsline {section}{\numberline {1.1}テキサス・ホールデム}{2}{section.1.1}%
そして、このtocファイルに書き込んだ命令を以下のように定義することで、メインコンテンツ/非メインコンテンツの切り替えを行い、また非メインコンテンツの前には空きを入れるようにした:
% \startmaintocで\ifmaincontentsがtrueになるようにする \newcommand{\startmaintoc}{\maincontentstrue} % \startnomaintocで\ifmaincontentsがfalseになるようにし2行分の空きを入れる \newcommand{\startnomaintoc}{\maincontentsfalse\vspace*{2\baselineskip}}
あとはこの\startmaintoc
および\startnomaintoc
をどうやってtocファイルに書き込むか。
調べてみると\addaddcontentsline
は以下のように「tocファイルに目次を書け」という命令をauxファイルに書き込んでいるようだった。
% latex.ltxから引用(コメントは自分が追記) \def\addcontentsline#1#2#3{% \addtocontents{#1}{\protect\contentsline{#2}{#3}{\thepage}% \protected@file@percent}} \long\def\addtocontents#1#2{% \protected@write\@auxout% ここがauxへ書けという命令 {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}% {\string\@writefile{#1}{#2}}}% auxに書く内容は「#1(toc)に#2を書け」という命令
そして、auxファイルが評価されることでtocファイルに目次が書き込まれる(そして\tableofcontents
命令はtocファイルの内容を実行することで目次を出力する)。
なので、同じように「tocファイルに\startmaintoc
を書け」という命令をauxファイルに書き込む命令を作って、それを呼び出せばいい。
そこでいろいろ調べながら次のような命令を用意した:
\newcommand{\startmaincontents}{% \immediate\write\@auxout{\string\@writefile{toc}{\string\startmaintoc}}} \newcommand{\startnomaincontents}{% \immediate\write\@auxout{\string\@writefile{toc}{\string\startnomaintoc}}}
あとは以下のように呼び出すだけ:
\startnomaincontents \chapter*{はじめに} \addcontentsline{toc}{chapter}{\protect\numberline{\null}はじめに}
\startmaincontents \chapter{ポーカーのルール}
これで冒頭のような目次が得られた。
宣伝です。
気になった人はチェックをお願いします!
今日はここまで!