Breadcrumb hyperlink header
How about automatically inserting a label at each part/chapter/section? Note this solution (modeled after How to get the section title by section number?) requires you to use part/chapter/section at least once each.
EDIT 3: Still WIP, but trying to generalize by keeping the breadcrumb as data in a sequence first, separating content from presentation. This basic tracking will enable more extensible functionality and different faces for the breadcrumbs. Those interested: keep checking GitHub for more information. (The stack code is not shown here, but can be browsed here.)
EDIT 2: Still WIP, but moved over to LaTeX3 syntax with egreg's help. Working on the previous. Bleeding edge on GitHub.
EDIT: Still a WIP, but now the breadcrumbs are variable-length per the comments. Still working on reversing the order of preference for chapterpage
, sectionpage
, etc, by digging through the fancyhdr
sources. I'd also like the current section at page-begin to be part of the breadcrumb, unless page-begin is a section header.
bredcrmb.sty
% GOAL: introduce a \pagestyle "breadcrumb" that will place the breadcrumb as a header.
\RequirePackage{xparse}
\RequirePackage{everypage
\RequirePackage{atbegshi}
\RequirePackage{fancyhdr}
\let\myhook\AtBeginShipout % playing with the two to see if I can get the desired output
% All credit to egreg for the following generalization: (#122823)
% My only additions were the booleans and related stuff.
\ExplSyntaxOn
% Macro to insert labels at the end of other macros
\NewDocumentCommand{\labelize}{mm}
{
\breadcrumbs_labelize:Nn #1 { #2 }
}
\myhook{\pagestyle{breadcrumb}}
\cs_new_protected:Npn \breadcrumbs_labelize:Nn #1 #2 {
% LaTeX3-ify
\bool_new:c { g_breadcrumbs_in_#2 }
\myhook{
\bool_gset_false:c { g_breadcrumbs_in_#2 }
}
\cs_set_eq:cN { original_ \cs_to_str:N #1 } #1
\RenewDocumentCommand #1 { som }
{
% Put page style stuff here
\bool_gset_true:c { g_breadcrumbs_in_#2 }
\thispagestyle{#2:style}
\IfBooleanTF{##1}
{
\use:c { original_ \cs_to_str:N #1 }*{##3}
}
{
\IfNoValueTF{##2}
{
\use:c { original_ \cs_to_str:N #1 } {##3}
}
{
\use:c { original_ \cs_to_str:N #1 } [##2]{##3}
}
\label{#2: \use:c{the\cs_to_str:N #1} }%
}
}
}
% Much nicer syntax. Thanks, egreg!
\labelize {\part} {breadcrumb:part}
\labelize {\chapter} {breadcrumb:chapter}
\labelize {\section} {breadcrumb:section}
\fancypagestyle{breadcrumb:part:style}{
\fancyhf{}
}
\fancypagestyle{breadcrumb:chapter:style}{
\fancyhf{}
\chead{
\nameref{breadcrumb:part:\thepart}
}
}
\fancypagestyle{breadcrumb:section:style}{
\fancyhf{}
\chead{
\nameref{breadcrumb:part:\thepart}~$\rightarrow$~
\nameref{breadcrumb:chapter:\thechapter}
}
}
\fancypagestyle{breadcrumb}{
\fancyhf{}
\chead{
\nameref{breadcrumb:part:\thepart}~$\rightarrow$~
\nameref{breadcrumb:chapter:\thechapter}~$\rightarrow$~
\nameref{breadcrumb:section:\thesection}
}
}
\ExplSyntaxOff
test.tex
\documentclass{memoir}
\let\footruleskip\relax
\usepackage{bredcrmb} % Moved code to style file
\usepackage{fancyhdr}
\usepackage[colorlinks]{hyperref}
\pagestyle{breadcrumb}
\usepackage{mwe}
\begin{document}
\part{Part the First}
\chapter{Chapter Primo}
\section{Section A}
\lipsum
\section{Section B}
\lipsum
\chapter{Chapter Secundo}
\section{Section A}
\lipsum
\section{Section B}
\lipsum
\part{Part the Second}
\chapter{Chapter Primo}
\section{Section A}
\lipsum
\section{Section B}
\lipsum
\chapter{Chapter Secundo}
\section{Section A}
\lipsum
\section{Section B}
\lipsum
\end{document}
The following example uses the fact that the anchors for the section commands are set and known before the header line is build. That means with careful timing it is possible to avoid the referencing system with a second LaTeX run.
The example uses class book
, where \chaptermark
, \sectionmark
and \subsectionmark
are redefined to include \hyperlink
with the current anchor \@currentHref
, which is defined quite right before either via \refstepcounter
or \phantomsection
for unnumbered section commands. Some patching is needed to insert \partmark
or to support starred section commands or commands. Also commands like \tableofcontents
, which uses \@markboth
, needs to be patched to get \chaptermark
.
The section titles in the example are taken from the start of the user manual of pgf
to get a closer real document feeling.
\documentclass{book}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{ragged2e}
\usepackage{etoolbox}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyfoot{}
\fancyhead{}
\cfoot{\thepage}
\lhead{%
\RaggedRight
% \HeaderFont
\hypersetup{linkcolor=blue}%
\rightmark
}
\newcommand*{\HeaderFont}{%
\usefont{T1}{qhv}{c}{n}%
\small
}
\makeatletter
\DeclareRobustCommand*{\BreadSep}{%
\,\textbf{\guilsinglright}\hspace{0pt}\,%
}
\newcount\breadnav@level
\breadnav@level=0 %
\newcommand*{\breadnav@starmark}[2]{%
\begingroup
\c@secnumdepth=-9 %
#1{#2}%
\endgroup
}
\patchcmd{\@part}{\markboth}{%
\partmark{#1}\@gobbletwo
}{}{}
\patchcmd{\@spart}{\normalfont}{%
\breadnav@starmark\partmark{#1}%
\normalfont
}{}{}
\newcommand*{\partmark}[1]{%
\protected@xdef\CurrentPart{%
\protect\hyperlink{\@currentHref}{%
\ifnum\value{secnumdepth}>-2 %
\thepart\@~%
\fi
#1%
}%
}%
\markright{%
\CurrentPart
}%
}
\newcommand*{\CurrentPart}{}
\patchcmd{\@schapterhead}{\normalfont}{%
\breadnav@starmark\chaptermark{#1}%
\normalfont
}{}{}
\patchcmd{\tableofcontents}{\@mkboth}{%
\breadnav@starmark\chaptermark{\contentsname}%
\@gobbletwo
}
\renewcommand*{\chaptermark}[1]{%
\protected@xdef\CurrentChapter{%
\protect\hyperlink{\@currentHref}{%
\ifnum\value{secnumdepth}>-1 %
\if@mainmatter
%\@chapapp~
\thechapter.\@~%
\fi
\fi
#1%
}%
}%
\markright{%
\ifx\CurrentPart\@empty
\else
\CurrentPart\BreadSep
\fi
\CurrentChapter
}%
}
\newcommand*{\CurrentChapter}{}
\patchcmd{\@startsection}{\@ifstar}{%
\edef\CurrentSectionType{#1}%
\@ifstar
}{%
\patchcmd{\@ssect}{\@tempskipa}{%
\expandafter\breadnav@starmark
\csname\CurrentSectionType mark\endcsname{#5}%
\@tempskipa
}{}{}%
}{}
\renewcommand*{\sectionmark}[1]{%
\protected@xdef\CurrentSection{%
\protect\hyperlink{%
\@currentHref
}{%
\ifnum\value{secnumdepth}>0 %
\thesection.\@~%
\fi
#1%
}%
}%
\markright{%
\ifx\CurrentPart\@empty
\else
\CurrentPart\BreadSep
\fi
\ifx\CurrentChapter\@empty
\else
\CurrentChapter\BreadSep
\fi
\CurrentSection
}%
}
\newcommand*{\CurrentSection}{}
\renewcommand*{\subsectionmark}[1]{%
\protected@xdef\CurrentSubsection{%
\protect\hyperlink{\@currentHref}{%
\ifnum\value{secnumdepth}>1 %
\thesubsection.\@~%
\fi
#1%
}%
}%
\markright{%
\ifx\CurrentPart\@empty
\else
\CurrentPart\BreadSep
\fi
\ifx\CurrentChapter\@empty
\else
\CurrentChapter\BreadSep
\fi
\ifx\CurrentSection\@empty
\else
\CurrentSection\BreadSep
\fi
\CurrentSubsection
}%
}
\newcommand*{\CurrentSubsection}{}
\let\ps@plain\ps@fancy
\makeatother
\usepackage[colorlinks]{hyperref}
\usepackage{bookmark}
\bookmarksetup{numbered,open}
\usepackage{lipsum}
\addtolength{\textheight}{\headheight}
\setlength{\headheight}{21pt}
\addtolength{\textheight}{-\headheight}
\begin{document}
\title{Test document}
\author{Me}
\date{\today}
\maketitle
\tableofcontents
\chapter{Introduction}
\lipsum
\section{Structure of the System}
\lipsum
\section{Comparison with Other Graphics Packages}
\lipsum
\section{Utility Packages}
\lipsum
\section{How to Read This Manual}
\lipsum
\section{Authors and Acknowledgements}
\lipsum
\section{Getting Help}
\lipsum
\part{Tutorials and Guidelines}
\chapter{Tutorial: A Picture for Karl's Students}
\lipsum
\section{Problem Statement}
\lipsum
\section{Setting up the Environment}
\lipsum
\subsection{Setting up the Environment in \LaTeX}
\lipsum
\subsection{Setting up the Environment in Plain \TeX}
\lipsum
\subsection{Setting up the Environment in Con\TeX t}
\lipsum
\section{Straigt Path Construction}
\lipsum
\section{Curved Path Construction}
\lipsum
\section{Circle Path Construction}
\lipsum
\section{Rectangle Path Construction}
\lipsum
\end{document}
Result, page 8:
and page 25:
Discussion
IMHO the main problem is that breadcrumb headers take a lot of space as seen in the second shapshot, where the header already needs three lines.
The place can be reduced by:
Using a shorter separation symbol, the example uses
\guilsinglright
instead of the larger\rightarrow
.Smaller font sizes (
\small
or\footnotesize
).Condensed font. Unfortunately these are not often available for the wanted font family.
The following snapshots show the result for the condensed font of Tex Gyre Hermes
in size \small
if \HeaderFont
is enabled in \lhead
. This reduces the three lines to two of the second screen shot above:
Variant
Even more clearly arranged looks the navigation path if the levels are shown in separate lines with indentation. This can be achieved by the following
definition of \BreadSep
(that does not support overlong titles that needs more than one line):
\DeclareRobustCommand*{\BreadSep}{%
\\%
\advance\breadnav@level by 1 %
\hspace*{\breadnav@level\dimexpr1em\relax}%
\textbf{\guilsinglright}\,%
}
Screen shot with this definition and using \small
as \HeaderFont
:
However, this needs as much lines as supported section levels.
It would be nice if smaller headers could give the unneeded space back to the text body. But the page is build before the header and its free space is known. Remember the header size in a label raises the problem that the header can change if the page material is rearranged. Similar to package varioref
this can cause documents that never stabilizes.