Gallery: Adjusting the alttree Style

image of glossary with names in coloured boxes in left margin and page number in coloured box in right margin with image below
This example uses the glossaries-extra package, which extends the glossaries package and provides better abbreviation handling.

This is quite a complicated example. It uses the tikz package to add a splash of colour to the name and location list. The location list is formatted according to \GlsXtrFormatLocationList (which takes the location list as the argument). This is redefined so that it typesets the locations in Plum after a curving arrow. This requires locally hiding the hyperlinks so that the link colour doesn’t override the text colour:

\renewcommand*{\GlsXtrFormatLocationList}[1]{%
 {% localise
  \hypersetup{hidelinks}%
  \textcolor{Plum}{\ding{230}~\textbf{#1}}%
 }%
}

The default top level indent is suppressed so that the description takes up the text width. This is done by setting \glsxtrtreetopindent to 0pt. The width of the maximum location list is computed and stored in \maxlocwidth and an extra 1em is added to provide a little padding. This is only suitable for short location lists that can fit on a single line. These lengths are all set by \glsxtralttreeInit.

\newlength\maxlocwidth

\renewcommand*{\glsxtralttreeInit}{%
% setup lengths
  \glsFindWidestAnyNameLocation[\currentglossary]%
    {\maxlocwidth}%
  \setlength{\glsxtrtreetopindent}{0pt}%
  \addtolength{\maxlocwidth}{1em}%
  \glsxtrAltTreeIndent=\parindent
}

The name is formatted according to \glstreenamebox. This is redefined to protrude out into the left margin and the contents are placed inside a tikz node to give it an Orchid rectangular background. Note that here the new definition of \glstreenamebox ignores its first argument as instead it uses \namewidth to determine its width.

\newlength\nameinnersep
\nameinnersep=2pt
\newlength\nameoutersep
\nameoutersep=2pt

\newlength\namewidth
\namewidth=1in

\renewcommand*{\glstreenamebox}[2]{%
  \makebox[\namewidth][r]%
  {%
    \smash{%
    \begin{tikzpicture}[baseline=(X.base)]
    \node[fill=Orchid,
          align=center,
          text width=\dimexpr\namewidth-2\nameinnersep-2\nameoutersep,
          inner sep=\nameinnersep,
          outer sep=\nameoutersep
         ] (X) {#2};
    \end{tikzpicture}%
    }%
   \quad
  }%
}

This document uses the dummy entries defined in the sample file example-glossaries-images.tex, which is provided with the glossaries package. These entries have multi-paragraph descriptions, and some of the entries use the user1 key to store the name of an associated image file. These are just the dummy image files provided by the mwe package.

A command is provided to format text (which will be the location list) in a blue box with rounded corners:

\newcommand*{\locbox}[1]{%
 \begin{tikzpicture}[baseline=(X.base)]
 \node[text width=\maxlocwidth,
       draw=CadetBlue,
       fill=CornflowerBlue,
       double,
       thick,
       align=center,
       rounded corners] 
  (X) {#1};
 \end{tikzpicture}%
}

The aim here is to place the location list in the right margin (which can be done with \marginpar) and below that the image (if one has been provided). This can be done with another \marginpar, but this can lead to the image dangling into the footer if there’s not enough room for it. The available space needs to be calculated. This depends on \pagegoal, \pagetotal and the height of the image, so the image is first saved in a box and its height is calculated. If there’s not enough space, the image is deferred until the next page (using \afterpage provided by the afterpage package). This could still potentially lead to a problem where there’s insufficient room for it on the next page, but, in this example, the descriptions are all long enough for this not to be a problem.

\newsavebox\imagebox

\newlength\tmplen
\newlength\imgheight


\newcommand{\deferredimage}{%
  \marginpar{\usebox\imagebox}%
}%

\newsavebox\slocbox
\newlength\locboxheight

\renewcommand{\glsxtralttreeSymbolDescLocation}[2]{%
  \sbox\slocbox{\locbox{#2}}%
  \settodepth{\tmplen}{\usebox\slocbox}%
  \settoheight{\locboxheight}{\usebox\slocbox}%
  \advance\locboxheight by \tmplen
  \marginpar{\usebox\slocbox}%
  \ifglshasfield{useri}{#1}%
  {%
     \sbox\imagebox{\includegraphics[width=\maxlocwidth]{\glsentryuseri{#1}}}%
     \settoheight{\imgheight}{\usebox\imagebox}%
     \setlength{\tmplen}{\dimexpr\pagegoal-\pagetotal-\imgheight-\locboxheight}%
     \relax
     \ifdim\tmplen<0pt\relax
       \afterpage{\deferredimage}%
     \else
       \marginpar{\usebox\imagebox}%
     \fi
  }%
  {}%
  % scope \par change
  {%
    \let\par\glsxtrAltTreePar
    \glossentrydesc{#1}\glspostdescription\par
    (Image file:
     \ifglshasfield{useri}{#1}{\texttt{\glsentryuseri{#1}}}{none}.)\par
  }%
  \indexspace
}

At the end of the above definition, \indexspace is added to provide a little visible separation between each entry, otherwise it looks too cluttered, especially with no paragraph indent at the start of the description. The intergroup space is suppressed using the nogroupskip package option.

The initial comment lines below are arara directives. You can remove them if you don’t use arara.

% arara: pdflatex
% arara: makeglossaries if found("aux", "@istfilename")
% arara: pdflatex
\documentclass[12pt]{report}

\usepackage[a4paper,left=1.5in,marginpar=70pt]{geometry}
\usepackage[T1]{fontenc}
\usepackage{tgtermes}
\usepackage[dvipsnames]{xcolor}
\usepackage{pifont}
\usepackage{tikz}
\usepackage{afterpage}

\usepackage[colorlinks]{hyperref}
\usepackage[stylemods=tree,style=alttree,nogroupskip,ucmark,savenumberlist]{glossaries-extra}

\makeglossaries

\loadglsentries{example-glossaries-images}

\glssetcategoryattribute{general}{glossname}{firstuc}

\renewcommand*{\GlsXtrFormatLocationList}[1]{%
 {%
  \hypersetup{hidelinks}%
  \textcolor{Plum}{\ding{230}~\textbf{#1}}%
 }%
}

\newlength\maxlocwidth

\renewcommand*{\glsxtralttreeInit}{%
% setup lengths
  \glsFindWidestAnyNameLocation[\currentglossary]%
    {\maxlocwidth}%
  \setlength{\glsxtrtreetopindent}{0pt}%
  \addtolength{\maxlocwidth}{1em}%
  \glsxtrAltTreeIndent=\parindent
}

\newlength\nameinnersep
\nameinnersep=2pt
\newlength\nameoutersep
\nameoutersep=2pt

\newlength\namewidth
\namewidth=1in

\renewcommand*{\glstreenamebox}[2]{%
  \makebox[\namewidth][r]%
  {%
    \smash{%
    \begin{tikzpicture}[baseline=(X.base)]
    \node[fill=Orchid,
          align=center,
          text width=\dimexpr\namewidth-2\nameinnersep-2\nameoutersep,
          inner sep=\nameinnersep,
          outer sep=\nameoutersep
         ] (X) {#2};
    \end{tikzpicture}%
    }%
   \quad
  }%
}

\newcommand*{\locbox}[1]{%
 \begin{tikzpicture}[baseline=(X.base)]
 \node[text width=\maxlocwidth,
       draw=CadetBlue,
       fill=CornflowerBlue,
       double,
       thick,
       align=center,
       rounded corners] 
  (X) {#1};
 \end{tikzpicture}%
}

\newsavebox\imagebox

\newlength\tmplen
\newlength\imgheight


\newcommand{\deferredimage}{%
  \marginpar{\usebox\imagebox}%
}%

\newsavebox\slocbox
\newlength\locboxheight

\renewcommand{\glsxtralttreeSymbolDescLocation}[2]{%
  \sbox\slocbox{\locbox{#2}}%
  \settodepth{\tmplen}{\usebox\slocbox}%
  \settoheight{\locboxheight}{\usebox\slocbox}%
  \advance\locboxheight by \tmplen
  \marginpar{\usebox\slocbox}%
  \ifglshasfield{useri}{#1}%
  {%
     \sbox\imagebox{\includegraphics[width=\maxlocwidth]{\glsentryuseri{#1}}}%
     \settoheight{\imgheight}{\usebox\imagebox}%
     \setlength{\tmplen}{\dimexpr\pagegoal-\pagetotal-\imgheight-\locboxheight}%
     \relax
     \ifdim\tmplen<0pt\relax
       \afterpage{\deferredimage}%
     \else
       \marginpar{\usebox\imagebox}%
     \fi
  }%
  {}%
  % scope \par change
  {%
    \let\par\glsxtrAltTreePar
    \glossentrydesc{#1}\glspostdescription\par
    (Image file:
     \ifglshasfield{useri}{#1}{\texttt{\glsentryuseri{#1}}}{none}.)\par
  }%
  \indexspace
}

\pagestyle{headings}

\begin{document}

\pagenumbering{roman}
\chapter*{Front Matter Test}
\forallglsentries{\thislabel}{\gls{\thislabel}.\newpage}

\pagenumbering{arabic}

\chapter{Main Matter Test}
\forallglsentries{\thislabel}{\gls{\thislabel}.\newpage}

\printglossaries

\end{document}

If you don’t use arara, you need to run the following commands:

pdflatex alttree-marginpar
makeglossaries alttree-marginpar
pdflatex alttree-marginpar

(See Incorporating makeglossaries or makeglossaries-lite or bib2gls into the document build.)

Download: PDF (198.68K), source code (2.95K), sample glossary definitions (14.11K).