Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

This is a follow-up question on Glossaries in List of Figures overflow, where it was asked how the first usage scheme of the glossaries package can be used with a glossary term in a figure caption. I gave an answer that works as long as the caption package is not loaded.

\documentclass{article}

\usepackage{caption}
\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makeglossaries
\newglossaryentry{acr}{%
  name        = {ACR-name},%
  description = {ACR-description},%
  first       = {ACR-first-description},%
}

\renewcommand{\glsdisplayfirst}[4]{#1 (1) #4}
\renewcommand{\glsdisplay}[4]{#1 (2+) #4}
\begin{document}
% \listoffigures %% even without \listoffigures the problem shows up

\begin{figure}[h]
  \caption[Short title \glshyperlink{acr}]{Long title \gls{acr}}
\end{figure}

\printglossary
\end{document}

As can be seen, without caption the figure caption contains the first usage form of the glossary entry as desired, but with caption it is the subsequent use form.

How can I keep that working while using caption?

share|improve this question
add comment

1 Answer 1

up vote 6 down vote accepted

LaTeX puts the caption inside a temporary scratch \hbox, measures its width. If the width is smaller than the line width, the box is reused to typeset the caption. Therefore \gls is called once. However if the caption width exceeds the line width, the caption text is set twice, this time as paragraph. Then \gls is called twice and you get the output for the second version of the glossary item.

Package caption makes the behaviour more predictable. If option singlelinecheck is set (default), then the caption text is always set twice, the first time for measuring the width to check if the text fits in one line and then the text is set again for the final result. With singlelinecheck=false, the measuring is disabled and the text is only set once, but the centering of the caption text gets lost.

A workaround is to put the result of \gls{acr} inside a temporary box and to use this box inside \caption:

\documentclass{article}

\usepackage{caption}
\usepackage{glossaries}

\newsavebox\glsscratchbox

\makeglossaries
\newglossaryentry{acr}{%
  name        = {ACR-name},%
  description = {ACR-description},%
  first       = {ACR-first-description},%
}

\renewcommand{\glsdisplayfirst}[4]{#1 (1) #4}
\renewcommand{\glsdisplay}[4]{#1 (2+) #4}
\begin{document}
\listoffigures %% even without \listoffigures the problem shows up

\begin{figure}[h]
  \sbox\glsscratchbox{\gls{acr}}
  \caption[Short title \glshyperlink{acr}]{Long title \unhcopy\glsscratchbox}
\end{figure}

\printglossary
\end{document}

(The command \unhcopy is used instead of \usebox (this is a \copy). It strips the outer \hbox layer and allows the spaces typeset in the same way as the other spaces in the line. Otherwise (\usebox) the space inside the reused box will always have the natural width.)

Result

Solution for \gls in the caption with package caption

Update: Simplification from Axel Sommerfeldt's comment added.

Package glossaries must remember first usages of the acronyms. The idea is to disable this, if the width of the caption is measured, but not, if the caption text is typeset finally.

Package caption is needed, because it separates the test from the final typesetting step. Also it provides macro \caption@prepareslc that precedes the measuring and is called before the measuring. There \glsunset is temporarily disabled for the measuring.

\documentclass{article}

\usepackage{glossaries}
\usepackage{caption}

\makeatletter
\g@addto@macro\caption@prepareslc{%
  \let\glsunset\@gobble
}
\makeatother

\makeglossaries
\newglossaryentry{acr}{%
  name        = {ACR-name},%
  description = {ACR-description},%
  first       = {ACR-first-description},%
}

\renewcommand{\glsdisplayfirst}[4]{#1 (1) #4}
\renewcommand{\glsdisplay}[4]{#1 (2+) #4}
\begin{document}
\listoffigures

\begin{figure}[h]
  \caption[Short title \glshyperlink{acr}]{Long title \gls{acr}}
\end{figure}

\printglossary
\end{document}

Refinement

If \gls{acr} is used, a global flag is set for the acronym acr to remember the state of the acronym usage. Thus subsequent calls can use the shorter form. The previous solution skipped the state setting, if the caption text is only measured. Thereby the state has not changed, when the caption text is finally set.

However, there is a situation that slips through. The caption text contains \gls with the same acronym several times including its first usage. Then the previous solution would contain the first usage form of the acronym for the usages of the acronym in the measuring step, because the state setting has been disabled there.

This is fixed by allowing the normal state changes of the acronyms in the measuring step, but remembering the first usages. There are reset afterwards before the final typesetting of the caption text.

Further remarks:

  • A switch \if@capmeasure is introduced. Normally it is set to \iffalse. Whenthe width of the text is checked inside \caption, then it is set to \iftrue.
  • Package caption is needed, because it separates the test from the final typesetting step. Also it provides macro \caption@prepareslc that precedes the measuring. Both are executed in the same local group. Therefore it is enough to add \@capmeasurefalse to \caption@prepareslc. The switch is automatically reset after the end of the group.
  • After the measuring the state of the first acronym usages are reset.
  • Package glossaries' \glsunset is patched to respect the setting of \if@capmeasure and remember first acronym usages.

Full example:

\documentclass{article}

\usepackage{glossaries}
\usepackage{caption}

\makeatletter
\newif\if@capmeasure
\g@addto@macro\caption@prepareslc{%
  \global\let\after@capmeasure\@empty
  \aftergroup\after@capmeasure
  \@capmeasuretrue
}
\CheckCommand*{\glsunset}[1]{%
  \glsdoifexists{#1}{%
    \expandafter \global \csname glo@#1@flagtrue\endcsname   
  }%
}
\renewcommand*{\glsunset}[1]{%
  \glsdoifexists{#1}{%
    \if@capmeasure
      \expandafter\ifx\csname ifglo@#1@flag\expandafter\endcsname
      \csname iftrue\endcsname
      \else 
        % first use
        \g@addto@macro\after@capmeasure{\glsreset{#1}}%
      \fi
    \fi
    \global\csname glo@#1@flagtrue\endcsname
  }%
}
\makeatother

\makeglossaries
\newglossaryentry{acr}{%
  name        = {ACR-name},%
  description = {ACR-description},%
  first       = {ACR-first-long-description},%
}

\renewcommand{\glsdisplayfirst}[4]{#1\textsuperscript{(1)}#4}
\renewcommand{\glsdisplay}[4]{#1\textsuperscript{(2+)}#4}
\begin{document}
\listoffigures

\begin{figure}[h]
  \caption[Short title \glshyperlink{acr}]%
  {Long title \textit{\gls{acr}} and \gls{acr}}
\end{figure}

\printglossary
\end{document}

Result with refinement

share|improve this answer
    
Thanks. Unfortunately, I don't see how this could be made into a nice interface, i.e., code that can be "hidden" in the preamble, or a small package, and let a user just use a special command like \glscaption. –  mafp Apr 12 '13 at 19:51
    
@mafp I have added a solution that patches packages caption and glossaries accordingly. –  Heiko Oberdiek Apr 12 '13 at 21:04
    
Wouldn't be \g@addto@macro\caption@prepareslc{\let\glsunset\@gobble} sufficient? (If yes, I would add it to my caption package. I really would like to avoid patching the glosseries package...) –  Axel Sommerfeldt Apr 13 '13 at 7:15
    
@AxelSommerfeldt Thanks, solution simplified accordingly. However, the solution does not work, if the same acronym is used several times including its first usage form. Then the glossaries packages still needs to be patched. –  Heiko Oberdiek Apr 13 '13 at 10:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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