7

As a follow up to Adding TikZ code to TOC, I have a TikZ code added to each index entry. That code may contain these specific letters: A, N, C, P and Q. See the following example:

\documentclass{article}

\usepackage[titles]{tocloft}
\usepackage{tikz}

\newcommand*\info[1]{%
  \begin{tikzpicture}
    \node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm] {\tt\scriptsize #1};
  \end{tikzpicture}}

\newcommand{\listfoo}{List of foo}
\newlistof[section]{foo}{idf}{\listfoo}

\begin{document}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCP}\ Hello world.}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCPQ}\ Hello bar.}

\listoffoo

\end{document}

List of foo 1

As you can see, (pardon my possible misuse of the terms) both text objects are centralized, but the latter - because of the letter Q - does not look that aesthetic to me.

Since I know all the possible letters I may use, and as the only problematic letter is the Q, I wrote this fix using the xstring package and Martin Scharrer's suggestion:

\documentclass{article}

\usepackage[titles]{tocloft}
\usepackage{tikz}
\usepackage{xstring}

\newcommand*\info[1]{%
  \begin{tikzpicture}
    \IfSubStr{#1}{Q}{%
    \node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm] {\raisebox{\dimexpr-.5\height+.5\depth-.8ex\relax}{\tt\scriptsize #1}};}{%
    \node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm] {\tt\scriptsize #1};}
  \end{tikzpicture}}

\newcommand{\listfoo}{List of foo}
\newlistof[section]{foo}{idf}{\listfoo}

\begin{document}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCP}\ Hello world.}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCPQ}\ Hello bar.}

\listoffoo

\end{document}

List of foo 2

That pretty much solves my issue.

I'd like to know if there are better ideas of how to solve this particular alignment issue, dynamically or not.

3

Using \raisebox is actually the right direction. However, in this case I would use its second optional argument to set the depth of the text to zero: \raisebox{0pt}[\height][0pt]{...}. This ignores everything below the baseline, while the text is actually not raised and the height stays like it is.

\documentclass{article}

\usepackage[titles]{tocloft}
\usepackage{tikz}
\usepackage{xstring}

\newcommand*\info[1]{%
  \begin{tikzpicture}
      \node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm] {\tt\scriptsize\raisebox{0pt}[\height][0pt]{#1}};
  \end{tikzpicture}}

\newcommand{\listfoo}{List of foo}
\newlistof[section]{foo}{idf}{\listfoo}

\begin{document}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCP}\ Hello world.}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCPQ}\ Hello bar.}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCPQgyj}\ Hello bar.}

\listoffoo

\end{document}

Result

You could also use the baseline={(<the node name>.base)} option to place the picture baseline to the text baseline. Then the framed text and not its frame is based at the same line as the other text. Finally, you can also move the baseline a little to adjust how the frame lies relative to the normal text: baseline={([yshift=<length>]<the node name>.base)}

\documentclass{article}

\usepackage[titles]{tocloft}
\usepackage{tikz}
\usepackage{xstring}

\newcommand*\info[1]{%
  \begin{tikzpicture}[baseline={(TEXT.base)}]
      \node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm] (TEXT) {\tt\scriptsize\raisebox{0pt}[\height][0pt]{#1}};
  \end{tikzpicture}}

\newcommand{\listfoo}{List of foo}
\newlistof[section]{foo}{idf}{\listfoo}

\begin{document}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCP}\ Hello world.}

\refstepcounter{foo}
\addcontentsline{idf}{foo}{\protect \info{ANCPQ}\ Hello bar.}

\listoffoo

\end{document}

Result

3
  • It's a bit funny how it looks in the end better and worse at the same time. I think these boxes require font with all caps not (or only barely) crossing the baseline. Then box (after raising) will be able to fit within [baseline,cap height] and its bottom should lie on the baseline. This way weird look should be mostly dismissed. @Paulo: Maybe consider using TEX Gyre Cursor?
    – przemoc
    Jun 25 '11 at 23:39
  • Cool! I'll probably stick with the first one, since \raisebox sounds more semantic to me than the baseline option. Thanks a lot, Martin! Jun 26 '11 at 10:42
  • @przemoc: Hm I didn't know that font, thanks for mentioning it! Unfortunately, for this particular case, this font will be out of style with the rest of the document. =) Jun 26 '11 at 10:45
8

Another option would be to explicitly set text height and text depth:

\node[draw,inner sep=1pt, minimum height=0.32cm, minimum width=0.9cm,text height=0.6em,text depth=0.1em] {\ttfamily\scriptsize #1};
1
  • Cool, I didn't know of these parameters! I tried text centered, but since it didn't work, I gave up on trying anything else through TikZ. It's also a great solution, Gonzalo! Thanks! Jun 26 '11 at 10:36
2

Say

{\smash[b]{\tt\scriptsize #1}}

instead of only {\tt\scriptsize #1} in the original definition. Requires amsmath.

1
  • Hm it's an interesting idea, egreg! Unfortunately, I can't use amsmath for this particular code, but I'll definitely save it for later. =) Jun 26 '11 at 10:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.