23

I am trying to detect whether I am inside or outside a float. I know the way how caption works. It uses the internal \@captype. But in the example below you see that this test failed by using captionsetup{type=figure}. Of course this feature is really fussy.

I create a minimal example which changed the internal \@endfloatbox and \@floatboxreset to add a bool expression.

You will see that it works in the minimal example. Now my question: Do you know any reasons why I shouldn't do it. (It's for a package on CTAN)

\documentclass{article}
\parindent0pt
\usepackage{caption}
\usepackage{etoolbox}
\makeatletter
\newbool{detect@float}
\appto\@endfloatbox{\boolfalse{detect@float}}
\preto\@floatboxreset{\booltrue{detect@float}}
\newrobustcmd*\testiffloat[1]{%
in \texttt{#1}\ \ifbool{detect@float}{Inside float}{Outside float}%
}
\newrobustcmd*\testiffloatI[1]{%
in \texttt{#1}\ 
\ifx\@captype\@undefined
   Outside float%
 \else
   Inside float%
\fi
}
\makeatother
\usepackage{lipsum}
\begin{document}
\testiffloat{text}\qquad\testiffloatI{text}

\begin{figure}[!ht]
\testiffloat{figure}\qquad\testiffloatI{figure}
\end{figure}

\testiffloat{text}\qquad\testiffloatI{text}


\begin{figure*}[!ht]
\testiffloat{figure*}\qquad\testiffloatI{figure*}
\end{figure*}

\testiffloat{text}\qquad\testiffloatI{text}

\begin{flushleft}
\testiffloat{flushleft}\qquad\testiffloatI{flushleft}
\captionsetup{type=figure}
\end{flushleft}

\begin{flushleft}
\captionsetup{type=figure}
\testiffloat{flushleft}\qquad\testiffloatI{flushleft}
\end{flushleft}

\testiffloat{text}\qquad\testiffloatI{text}
\end{document}

2 Answers 2

19
\documentclass{book}
\usepackage{caption}

\makeatletter   
\def\InFloat{\ifnum\@floatpenalty<0\relax in float \else outside float \fi}
\makeatother
\begin{document}

\begin{figure}\relax
[figure]: \InFloat
\end{figure}

\begin{center}
[center]: \InFloat
\end{center}

\captionsetup{type=figure}
\begin{center}
[center]: \InFloat
\end{center}

\end{document}

The counter \@floatpenalty controls float processing. It defaults to 0, but is set to a negative value at a beginning of a float. This code checks for this value to be negative (inside float) or not (outside float) using low-level \ifnum test.

1
  • Oddly, this test doesn’t work when I’m using it to conditionally define a marginpar – I’m doing this, inside a macro: \ifnum\@floatpenalty<0\relax\let\mp\marginnote\else\let\mp\marginpar\fi\mp{Some text}, and that always goes into the float branch. However, if I take out the \let\mp… and instead print some text, it goes into the correct branch. Subsequently outputting a marginpar seems to influence the \IfFloat test in the past. Commented Feb 4, 2015 at 12:01
3

In most cases, test using \@captype should work:

\makeatletter
\newcommand\InFloat[2]{\@ifundefined{@captype}{#2}{#1}}
\makeatothe‌‌​​r

With the usage \InFloat{INSIDE}{OUTSIDE}.

The code is based on the idea that \@captype stores the type of the float in which we are, i.e. \@captype -> figure inside figure etc. Especially, \@captype is undefined outside any float since floats form a group and the value is "forgotten" once we exit the float. Macro \@ifundefined takes macro name (without the leading \) and tests for being defined.

(This answer is added to provide a reference for future questions.)

3
  • I used this test in my original question. Commented Feb 25, 2013 at 18:08
  • @MarcoDaniel I know. It is a bit strange situation where your question says "how to do X not using Y" where "Y" is quite natural answer to "X", one that suffices to some. If you felt it's better made CW, I would not complain.
    – yo'
    Commented Feb 25, 2013 at 18:17
  • No problem. I was a little bit confused ;-). Of course your answer shows the most general way. Commented Feb 25, 2013 at 18:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .