3

I thought I was pretty cool when I modified \ref to also print a page number when the referenced float was more than a few pages back. But I really want it to be a nice link using the hyperref package as well!

How can I modify my command so that it will cause the page number to also be a link?

\documentclass{report}

\usepackage{mwe}
% \usepackage[% Un-commenting this causes the page number not to appear
  % pagebackref=true,
  % ]{hyperref}

\usepackage{ifthen}
\usepackage{calc}
\usepackage{xspace}
\let\oldref\ref
\renewcommand\ref[1]{%
  \newcount\cnt
  \cnt=\thepage
  \advance\cnt by -2
  \ifthenelse{%
    \pageref{#1} < \cnt%
    }{%
    \oldref{#1}~p.\,\pageref{#1}\xspace%
    }{%
    \oldref{#1}%
    }%
  }


\begin{document}

\blindtext[1]
Figure~\ref{fig:example_image_a} 
%
\begin{figure}
  \centering
  \includegraphics[width=0.6\textwidth]{example-image-a}%
  \caption{
  example-image-a
  \label{fig:example_image_a}
  }
\end{figure}

\Blindtext[10][10]

Figure~\ref{fig:example_image_a}

\end{document}
  • 1
    Why don't you just use the varioref package? – daleif Nov 06 '15 at 17:52
  • @daleif Ignorance! But also, a bit of digging around in tex.se revealed this gem from http://tex.stackexchange.com/a/83051/45296 : "There are too many problems with varioref. Nobody has time to sort them out. Therefore this package is now unsupported." That said, it has been a while so I will take another look at cleveref – repurposer Nov 06 '15 at 18:03
  • 1
    I've not had too many problems with varioref, and it is AFAIK still supported. Only problem is when it hits at a page boundary – daleif Nov 06 '15 at 18:24
  • @daleif I would have to mess around with it too much, I think. I want all off the page refs to be "p. X" and not "previous page" or even typed out "page" – repurposer Nov 06 '15 at 18:26
  • That would look strange if the ref is on the same page as the label. – daleif Nov 06 '15 at 18:28
  • \pageref isn't expandable, as far as I know and allocating \cnt each time when \ref is called is ... well ... –  Nov 06 '15 at 18:28
  • @daleif hence the conditional – repurposer Nov 06 '15 at 18:29
  • @ChristianHupfer the mwe does ok for me if hyperref it's not loaded, but I don't really know what is the meaning of expandable – repurposer Nov 06 '15 at 18:31
  • @repurposer: I am not sure that \pageref gets correctly evaluated inside that `\ifthenelse stuff –  Nov 06 '15 at 18:34
  • 1
    There are some useful tools in varioref that can be used to determine if you are on the same page as a given label – daleif Nov 06 '15 at 18:36

3 Answers3

4

hyperref overrules \ref, unless the new definition is in \AtBeginDocument

egreg will strike me down for keeping xspace ;-)

In addition: I doubt that \pageref{#1} will give a number at all, if it's inside the \ifthenelse expression.

I used \getpagerefnumber from refcount which provides a number which can be used in calculations.

Additionally, I shifted the allocation of \cnt outside of \ref -- otherwise there would be an allocation of a count register each time \ref is called!.

\documentclass{report}

\usepackage{mwe}

\usepackage[% Un-commenting this causes the page number not to appear
% pagebackref=true,
]{hyperref}


\usepackage{refcount}

\usepackage{calc}
\usepackage{xspace}
\let\oldref\ref

\newcount\cnt


\AtBeginDocument{%
   \renewcommand\ref[1]{%
     \cnt=\value{page}%
     \advance\cnt by -2
     \ifnum\cnt > \getpagerefnumber{#1}
     \oldref{#1}~p.\,\pageref{#1}\xspace%
     \else
     \oldref{#1}%
     \fi
    }
  }



\begin{document}

\blindtext[1]
Figure~\ref{fig:example_image_a} 
%
\begin{figure}
  \centering
  \includegraphics[width=0.6\textwidth]{example-image-a}%
  \caption{
  example-image-a
  \label{fig:example_image_a}
  }
\end{figure}

\Blindtext[10][10]

Figure~\ref{fig:example_image_a}

\end{document}
3

Rather than redefine \ref, you may want to look into loading the varioref package and using that package's \vref and \fullref macros. They basically do what your modified \ref macro does.

If the hyperref package is loaded as well, with \fullref the figure number (e.g., "n") and the page number (e.g, "m") are separate hypertargets. With \vref, the entire string [Figure] "n on page m" is a single hypertarget.

\documentclass{report}
\usepackage{mwe}
\usepackage{varioref}
\usepackage[colorlinks]{hyperref}

\begin{document}
Figure \vref{fig:example_image_a} 

\blindtext[1]

\begin{figure}[h!]
  \centering
  \includegraphics[width=0.6\textwidth]{example-image-a}%
  \caption{example-image-a}\label{fig:example_image_a}
\end{figure}

\Blindtext[10]

Figure \fullref{fig:example_image_a}

Figure \vref{fig:example_image_a}
\end{document}
Mico
  • 506,678
3

The following is a slightly different approach to Christian's. It creates an automated \label for each \ref in order to ensure that the page numbering will be accurate.

enter image description here

\documentclass{article}

\usepackage{lipsum}% Just for this example
\usepackage{refcount,hyperref,graphicx}

\newcounter{refcnt}

\AtBeginDocument{%
  \let\oldref\ref
  \renewcommand\ref[1]{%
    \oldref{#1}% Place reference...
    \stepcounter{refcnt}\label{mark-\therefcnt}% Mark current \ref
    \ifnum\getpagerefnumber{mark-\therefcnt} > \numexpr\getpagerefnumber{#1}+2\relax
      \nobreakspace p.\,\pageref{#1}% ...conditionally place page ref
    \fi
  }%
}

\begin{document}
\sloppy% Just for this example
\lipsum[1]

Figure~\ref{fig:example_image}.

\begin{figure}[ht]
  \centering
  \includegraphics[width=0.6\textwidth]{example-image}%
  \caption{example-image}\label{fig:example_image}
\end{figure}

\lipsum[2-15]

Figure~\ref{fig:example_image}.

\end{document}

The above approach only considers a reference backward of more than 2 pages. If the addition of a page number should be considered for a forward reference as well, that can be added.

Werner
  • 603,163
  • Why is it important to mark the ref but not the float? – repurposer Nov 06 '15 at 19:41
  • @repurposer: I have marked the float. However, I also mark the \ref with an internal \label{mark-\therefcnt} because the processing of your \ref could happen around the pages being shipped out. This might be problematic when working with the page counter directly an in Christian's answer. Here is an example where the \ref is around the page break and it's not properly picked up using his approach. – Werner Nov 06 '15 at 19:46